def test_3(self): """ User object created """ self.user = Account.objects().get(username=self.USER['email'], include="Store.Subscription,Store.Settings") return self.user is not None
def clean_email(self): email = self.cleaned_data.get('email').strip().lower() if Account.objects().count(email=email) > 0: if self.account.email != email: raise forms.ValidationError("Email is already " +\ "being used.") return email
def test_3(self): """ User object created """ self.user = Account.objects().get( username=self.USER['email'], include="Store.Subscription,Store.Settings") return self.user is not None
def delete(request, employee_id): """ This will also remove the employee from the ACL, delete the employee object and also delete the Parse.User object if and only if it has no pointer to a Store or a Patron. """ # get from the employees_approved_list in session cache employees_approved_list = SESSION.get_employees_approved_list(\ request.session) i_remove, employee = 0, None for ind, m in enumerate(employees_approved_list): if m.objectId == employee_id: employee = m i_remove = ind break if not employee: return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been removed.'})) employees_approved_list.pop(i_remove) request.session['employees_approved_list'] =\ employees_approved_list acc = Account.objects().get(Employee=employee.objectId) if not acc: # employee may have been deleted return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been deleted.'})) # Always save session first whenever calling a cloud code request.session.save() res = cloud_call("delete_employee", {"employee_id": employee.objectId}) request.session.clear() request.session.update(SessionStore(request.session.session_key)) if 'error' not in res: store = SESSION.get_store(request.session) payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY } if acc.objectId in store.ACL and not store.is_owner(acc): del store.ACL[acc.objectId] store.update() payload["updatedStore"] = store.jsonify() request.session['store'] = store # only need to pass in the objectId deleted_employee = Employee(objectId=employee.objectId) payload["deletedEmployee"] = deleted_employee.jsonify() comet_receive(store.objectId, payload) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has been deleted.'})) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been deleted.'}))
def delete(request, employee_id): """ This will also remove the employee from the ACL, delete the employee object and also delete the Parse.User object if and only if it has no pointer to a Store or a Patron. """ # get from the employees_approved_list in session cache employees_approved_list = SESSION.get_employees_approved_list(\ request.session) i_remove, employee = 0, None for ind, m in enumerate(employees_approved_list): if m.objectId == employee_id: employee = m i_remove = ind break if not employee: return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been removed.'})) employees_approved_list.pop(i_remove) request.session['employees_approved_list'] =\ employees_approved_list acc = Account.objects().get(Employee=employee.objectId) if not acc: # employee may have been deleted return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been deleted.'})) # Always save session first whenever calling a cloud code request.session.save() res = cloud_call("delete_employee", {"employee_id": employee.objectId}) request.session.clear() request.session.update(SessionStore(request.session.session_key)) if 'error' not in res: store = SESSION.get_store(request.session) payload = {COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY} if acc.objectId in store.ACL and not store.is_owner(acc): del store.ACL[acc.objectId] store.update() payload["updatedStore"] = store.jsonify() request.session['store'] = store # only need to pass in the objectId deleted_employee = Employee(objectId=employee.objectId) payload["deletedEmployee"] = deleted_employee.jsonify() comet_receive(store.objectId, payload) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has been deleted.'})) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been deleted.'}))
def deny(request, employee_id): """ same as delete except this uses the pending list """ # get from the employees_pending_list in session cache employees_pending_list = SESSION.get_employees_pending_list(\ request.session) i_remove, employee = 0, None for ind, m in enumerate(employees_pending_list): if m.objectId == employee_id: employee = m i_remove = ind break if not employee: return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Pending employee not found.'})) # update session cache for employees_pending_list employees_pending_list.pop(i_remove) request.session['employees_pending_list'] =\ employees_pending_list acc = Account.objects().get(Employee=employee.objectId) if not acc: # employee may have been deleted return redirect(reverse('employees_index')+ "?show_pending&%s" %\ urllib.urlencode({'success': 'Employee has already been denied.'})) # Always save session first whenever calling a cloud code request.session.save() res = cloud_call("delete_employee", {"employee_id": employee.objectId}) request.session.clear() request.session.update(SessionStore(request.session.session_key)) if 'error' not in res: payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY } store = SESSION.get_store(request.session) # no need to check acl here but just in case if acc.objectId in store.ACL and not store.is_owner(acc): del store.ACL[acc.objectId] store.update() payload["updatedStore"] = store.jsonify() request.session['store'] = store # only need to pass in the objectId deleted_employee = Employee(objectId=employee.objectId) payload["deletedEmployee"] = deleted_employee.jsonify() comet_receive(store.objectId, payload) return redirect(reverse('employees_index')+ "?show_pending&%s" %\ urllib.urlencode({'success': 'Employee has been denied.'})) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been deleted.'}))
def deny(request, employee_id): """ same as delete except this uses the pending list """ # get from the employees_pending_list in session cache employees_pending_list = SESSION.get_employees_pending_list(\ request.session) i_remove, employee = 0, None for ind, m in enumerate(employees_pending_list): if m.objectId == employee_id: employee = m i_remove = ind break if not employee: return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Pending employee not found.'})) # update session cache for employees_pending_list employees_pending_list.pop(i_remove) request.session['employees_pending_list'] =\ employees_pending_list acc = Account.objects().get(Employee=employee.objectId) if not acc: # employee may have been deleted return redirect(reverse('employees_index')+ "?show_pending&%s" %\ urllib.urlencode({'success': 'Employee has already been denied.'})) # Always save session first whenever calling a cloud code request.session.save() res = cloud_call("delete_employee", {"employee_id": employee.objectId}) request.session.clear() request.session.update(SessionStore(request.session.session_key)) if 'error' not in res: payload = {COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY} store = SESSION.get_store(request.session) # no need to check acl here but just in case if acc.objectId in store.ACL and not store.is_owner(acc): del store.ACL[acc.objectId] store.update() payload["updatedStore"] = store.jsonify() request.session['store'] = store # only need to pass in the objectId deleted_employee = Employee(objectId=employee.objectId) payload["deletedEmployee"] = deleted_employee.jsonify() comet_receive(store.objectId, payload) return redirect(reverse('employees_index')+ "?show_pending&%s" %\ urllib.urlencode({'success': 'Employee has been denied.'})) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has already been deleted.'}))
def manage_admin_controls(request): """ To turn on god_mode: ...repunch.com/manage/admin-controls?action=god_mode&flag=1& [email protected]&key=9p8437wk34z5ymurukdp9w34px7iuhsruhio """ if request.method == "GET": params = request.GET.dict() key = params.get("key") action = params.get("action") if key == ADMIN_CONTROL_KEY: if action == "god_mode": flag = params.get("flag") email = params.get("email", "") acc = Account.objects().get(email=email, Store__ne=None, include="Store.Subscription") if not acc: return HttpResponse("User with email %s not found." %\ (email,)) sub = acc.store.subscription sub.god_mode = flag != "0" sub.update() payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify(), } comet_receive(acc.store.objectId, payload) # go out with the latest session in case this user is # the one that triggered this action request.session.clear() request.session.update( SessionStore(request.session.session_key)) if sub.god_mode: on_off = "on" else: on_off = "off" return HttpResponse("Successfully turned god mode "+\ "%s for user with email %s" % (on_off, email)) else: return HttpResponse("Invalid action: %s" % (action, )) else: return HttpResponse("Wrong key: %s" % (key, )) return HttpResponse("Bad Request")
def rename_punchcode_username_to_userid(): """ PunchCode username column changed to user_id. WARNING! Assumes this assumes that # Patrons < 1000. """ for acc in Account.objects().filter(Patron__ne=None, include="Patron", limit=999): pc = PunchCode.objects().get(punch_code=acc.patron.punch_code) pc.user_id = acc.objectId pc.update() print "Updated PunchCode " + acc.patron.punch_code
def clean_email(self): # If an Account exist already with a Store object - then bad e = self.cleaned_data.get('email') if e: e = e.strip().lower() acc = Account.objects().get(email=e) if acc and acc.Store: raise forms.ValidationError(\ "Email is already being used.") elif acc: # save the object for later use setattr(self, "associated_account", acc) return e
def manage_admin_controls(request): """ To turn on god_mode: ...repunch.com/manage/admin-controls?action=god_mode&flag=1& [email protected]&key=9p8437wk34z5ymurukdp9w34px7iuhsruhio """ if request.method == "GET": params = request.GET.dict() key = params.get("key") action = params.get("action") if key == ADMIN_CONTROL_KEY: if action == "god_mode": flag = params.get("flag") email = params.get("email", "") acc = Account.objects().get(email=email, Store__ne=None, include="Store.Subscription") if not acc: return HttpResponse("User with email %s not found." %\ (email,)) sub = acc.store.subscription sub.god_mode = flag != "0" sub.update() payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify(), } comet_receive(acc.store.objectId, payload) # go out with the latest session in case this user is # the one that triggered this action request.session.clear() request.session.update(SessionStore(request.session.session_key)) if sub.god_mode: on_off = "on" else: on_off = "off" return HttpResponse("Successfully turned god mode "+\ "%s for user with email %s" % (on_off, email)) else: return HttpResponse("Invalid action: %s" % (action,)) else: return HttpResponse("Wrong key: %s" % (key,)) return HttpResponse("Bad Request")
def edit(request, employee_id): data = {'employees_nav': True, 'employee_id': employee_id} # get from the employees_approved_list in session cache employees_approved_list = SESSION.get_employees_approved_list(\ request.session) employee = None for m in employees_approved_list: if m.objectId == employee_id: employee = m break acc = Account.objects().get(Employee=employee.objectId) store = SESSION.get_store(request.session) if not employee or not acc: return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee does not exist.'})) if request.method == "POST": store.set_access_level(acc, request.POST["ACL"]) store.update() request.session['store'] = store # notify other dashboards of this change payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore":store.jsonify() } comet_receive(store.objectId, payload) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has been updated.'})) form = EmployeeForm(employee.__dict__.copy()) form.data['email'] = acc.get('email') data.update({ 'ACCESS_ADMIN': ACCESS_ADMIN[0], 'ACCESS_PUNCHREDEEM': ACCESS_PUNCHREDEEM[0], 'ACCESS_NONE': ACCESS_NONE[0], 'form': form, 'employee': employee, 'employee_acl': store.get_access_level(acc)[0], }) return render(request, 'manage/employee_edit.djhtml', data)
def edit(request, employee_id): data = {'employees_nav': True, 'employee_id': employee_id} # get from the employees_approved_list in session cache employees_approved_list = SESSION.get_employees_approved_list(\ request.session) employee = None for m in employees_approved_list: if m.objectId == employee_id: employee = m break acc = Account.objects().get(Employee=employee.objectId) store = SESSION.get_store(request.session) if not employee or not acc: return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee does not exist.'})) if request.method == "POST": store.set_access_level(acc, request.POST["ACL"]) store.update() request.session['store'] = store # notify other dashboards of this change payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore": store.jsonify() } comet_receive(store.objectId, payload) return redirect(reverse('employees_index')+ "?%s" %\ urllib.urlencode({'success': 'Employee has been updated.'})) form = EmployeeForm(employee.__dict__.copy()) form.data['email'] = acc.get('email') data.update({ 'ACCESS_ADMIN': ACCESS_ADMIN[0], 'ACCESS_PUNCHREDEEM': ACCESS_PUNCHREDEEM[0], 'ACCESS_NONE': ACCESS_NONE[0], 'form': form, 'employee': employee, 'employee_acl': store.get_access_level(acc)[0], }) return render(request, 'manage/employee_edit.djhtml', data)
def __init__(self, fetch_user=True, user_include="Patron,Store,Employee"): """ tests has the following format: [ {'test_name': "Test title"}, ... ] """ self.name = UN_CAMEL_RE.sub(r'\1 \2', self.__class__.__name__) self._tests = [] self._results = { "section_name": self.name, "parts": self._tests, } if fetch_user: self.account = Account.objects().get(email=\ self.USER['email'], include=user_include) self.patron = self.account.patron self.store = self.account.store self.employee = self.account.employee
def handle(self, *args, **options): # for logging when ran by CRON print "Running passed_user_limit: " + str(timezone.now()) now = timezone.now() b4_now = now + relativedelta(hours=-1) # get 500 subscriptions at a time LIMIT = 500 # first scan though all the stores and set their # date_passed_user_limit if so # TODO optimize with a relational query? possible with Parse? #### SUB_TYPE 0 skip = 0 sub_count = Subscription.objects().count(\ date_passed_user_limit=None, subscriptionType=0) max_users = sub_type[0]['max_users'] while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit=None, god_mode=False, limit=LIMIT, skip=skip, order="createdAt"): store = sub.store if store.get("patronStores", count=1, limit=0) >\ max_users: sub.date_passed_user_limit = b4_now sub.update() # notify the dashboards of these changes payload={ COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) # end of while loop sub_count -= LIMIT skip += LIMIT # TODO optimize with a relational query? possible with Parse? #### SUB_TYPE 1 skip = 0 sub_count = Subscription.objects().count(\ date_passed_user_limit=None, subscriptionType=1) max_users = sub_type[1]['max_users'] while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit=None, god_mode=False, limit=LIMIT, skip=skip, order="createdAt"): store = sub.store if store.get("patronStores", count=1, limit=0) >\ max_users: sub.date_passed_user_limit = b4_now sub.update() # notify the dashboards of these changes payload={ COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) # end of while loop sub_count -= LIMIT skip += LIMIT ################ conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() # 1st day time range day1_end = now.replace() day1_start = day1_end + relativedelta(hours=-24) # 4th day time range day4_end = now + relativedelta(days=-4) day4_start = day4_end + relativedelta(hours=-24) # 8th day time range day8_end = now + relativedelta(days=-8) day8_start = day8_end + relativedelta(hours=-24) # 14th day time range day14_end = now + relativedelta(days=-14) day14_start = day14_end + relativedelta(hours=-24) #### SUB_TYPE 0 ## 1st day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start, limit=LIMIT, skip=skip, order="createdAt"): # with pp_cc_id if sub.pp_cc_id and len(sub.pp_cc_id) > 0: sub.subscriptionType = 1 sub.date_passed_user_limit = None sub.update() # notify the dashboards of these changes payload={ COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) package = { "status": "upgraded", "sub_type": sub_type[0]["name"], "new_sub_type": sub_type[1]["name"], "new_sub_type_cost": sub_type[1]["monthly_cost"], "new_max_patronStore_count":\ sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), } # no pp_cc_id else: package = { "sub_type": sub_type[0]["name"], "max_patronStore_count": sub_type[0]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 4th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[0]["name"], "max_patronStore_count": sub_type[0]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 8th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[0]["name"], "max_patronStore_count": sub_type[0]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 14th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "status": "disabled" } # deactivate the store sub.store.active = False sub.store.update() payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore":sub.store.jsonify(), } comet_receive(sub.Store, payload) try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT #### SUB_TYPE 1 ## 1st day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start, limit=LIMIT, skip=skip, order="createdAt"): # with pp_cc_id if sub.pp_cc_id and len(sub.pp_cc_id) > 0: sub.subscriptionType = 2 sub.date_passed_user_limit = None sub.update() # notify the dashboards of these changes payload={ COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) package = { "status": "upgraded", "sub_type": sub_type[1]["name"], "new_sub_type": sub_type[2]["name"], "new_sub_type_cost": sub_type[2]["monthly_cost"], "new_max_patronStore_count": "Unlimited", "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), } # no pp_cc_id else: package = { "sub_type": sub_type[1]["name"], "max_patronStore_count": sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 4th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[1]["name"], "max_patronStore_count": sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 8th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[1]["name"], "max_patronStore_count": sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 14th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "status": "disabled" } # deactivate the store sub.store.active = False sub.store.update() payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore":sub.store.jsonify(), } comet_receive(sub.Store, payload) try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT try: conn.close() except Exception: pass
def test_employees(): """ Tests for employee approve, deny, remove, details. etc. """ # TODO test employee graph # TODO test employee punches history # delete the employees and associated User objects in the relation account = Account.objects().get(username=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings emps = store.get("employees") if emps: for emp in emps: Account.objects().get(Employee=emp.objectId).delete() emp.delete() store.set("employees", None) test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Cloud code register_employee works"}, {'test_name': "Employee is saved in store's Employees " +\ "relation"}, {'test_name': "Employee is initially pending (Parse)"}, {'test_name': "Employee is initially pending (Dashboard)"}, {'test_name': "Email must be valid (cloud code)"}, {'test_name': "Email must be unique (cloud code)"}, {'test_name': "Username must be unique (cloud code)"}, {'test_name': "Retailer PIN must exist (cloud code)"}, {'test_name': "Clicking deny prompts the user to confirm"}, {'test_name': "The user is redirected to employee index"}, {'test_name': "The denied employee is removed from the " +\ "pending table"}, {'test_name': "The employee is deleted from parse"}, {'test_name': "The account/user is deleted from parse"}, {'test_name': "Approving the employee moves it from " +\ "pending to approved"}, {'test_name': "Employee status is set to approved in Parse"}, {'test_name': "Employee initially has 0 punches."}, {'test_name': "Clicking on the approved employee row " +\ " redirects user to employee edit page"}, {'test_name': "Clicking delete prompts the user to confirm"}, {'test_name': "The user is redirected to employee index"}, {'test_name': "The deleted employee is removed from the " +\ "pending table"}, {'test_name': "The employee is deleted from parse"}, {'test_name': "The account/user is deleted from parse"}, {'test_name': "Multiple employees (3) registering at once" +\ " shows up in dashboard"}, ] section = { "section_name": "Employees page working properly?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page" test.open(reverse("employees_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("employees_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(7) def register_employee(first_name, last_name, username=None, password=None, email=None, retailer_pin=None): if username is None: username = first_name if password is None: password = first_name if email is None: email = first_name + "@" + last_name + ".com" if retailer_pin is None: retailer_pin = settings.retailer_pin return cloud_call("register_employee", { "first_name": first_name, "last_name": last_name, "username": username, "password": password, "email": email, "retailer_pin": retailer_pin, }) first_name, last_name, username, email =\ "vandolf1", "estrellado", "*****@*****.**", "*****@*****.**" ########## Cloud code register_employee works" try: res = register_employee(first_name, last_name, username, email=email) parts[1]['success'] = "error" not in res except Exception as e: print e parts[1]['test_message'] = str(e) ########## Employee is saved in store's Employees relation" try: emp = store.get("employees")[0] parts[2]['success'] = emp is not None except Exception as e: print e parts[2]['test_message'] = str(e) ########## Employee is initially pending (Parse)" try: parts[3]['success'] = emp.status == PENDING except Exception as e: print e parts[3]['test_message'] = str(e) ########## Employee is initially pending (Dashboard)" try: sleep(COMET_PULL_RATE*2 + 1) # wait for dashboard to receive test.find("#tab-pending-employees").click() parts[4]['success'] = test.element_exists(\ "#tab-body-pending-employees div.tr div.td.approve") except Exception as e: print e parts[4]['test_message'] = str(e) ########## Email must be valid (cloud code)" try: res = register_employee("vman", "vman", email="vmahs@vman") parts[5]['success'] = res['error'] == 'EMAIL_INVALID' except Exception as e: print e parts[5]['test_message'] = str(e) ########## Email must be unique (cloud code) " try: res = register_employee("vman", "vman", email=email) parts[6]['success'] = res['error'] == 'EMAIL_TAKEN' except Exception as e: print e parts[6]['test_message'] = str(e) ########## Username must be unique (cloud code) " try: res = register_employee("vman", "vman", username=username) parts[7]['success'] = res['error'] == 'USERNAME_TAKEN' except Exception as e: print e parts[7]['test_message'] = str(e) ########## Retailer PIN must exist (cloud code) " try: res = register_employee("vman", "vman", retailer_pin="sdgdgs") parts[8]['success'] = res['error'] == "RETAILER_PIN_INVALID" except Exception as e: print e parts[8]['test_message'] = str(e) ########## Clicking deny prompts the user to confirm" try: test.find("#tab-pending-employees").click() test.find("#tab-body-pending-employees div.tr " +\ "div.td.approve a.deny").click() alert = test.switch_to_alert() parts[9]['success'] = alert.text == "Deny employee?" except Exception as e: print e parts[9]['test_message'] = str(e) ########## The user is redirected to employee index" try: sleep(1) alert.accept() sleep(2) parts[10]['success'] = test.is_current_url(reverse(\ "employees_index") +\ "?show_pending&success=Employee+has+been+denied.") except Exception as e: print e parts[10]['test_message'] = str(e) ########## The denied employee is removed from the pending table" try: parts[11]['success'] = not test.element_exists(\ "#tab-body-pending-employees div.tr " +\ "div.td.approve a.approve") except Exception as e: print e parts[11]['test_message'] = str(e) ########## The employee is deleted from parse" try: store.set("employees", None) parts[12]['success'] = store.get("employees",\ first_name=first_name, last_name=last_name, count=1) == 0 except Exception as e: print e parts[12]['test_message'] = str(e) ########## The account/user is deleted from parse" try: parts[13]['success'] = Account.objects().count(\ username=username, email=email) == 0 except Exception as e: print e parts[13]['test_message'] = str(e) ########## Approving the employee moves it from pending to approved" try: register_employee(first_name, last_name, username, email=email) sleep(COMET_PULL_RATE*2 + 1) # wait for dashboard to receive test.find("#tab-pending-employees").click() approveRow = test.find("#tab-body-pending-employees " +\ "div.tr") approveId = approveRow.get_attribute("id") approveRow.find_element_by_css_selector(\ "div.td.approve a.approve").click() sleep(1) test.switch_to_alert().accept() sleep(2) test.find("#tab-approved-employees").click() parts[14]['success'] = test.element_exists(\ "#tab-body-approved-employees " +\ "div.tr div.td.remove a") except Exception as e: print e parts[14]['test_message'] = str(e) ########## Employee status is set to approved in Parse" try: store.set("employees", None) emp = store.get("employees", first_name=first_name, last_name=last_name)[0] parts[15]['success'] = emp.status == APPROVED except Exception as e: print e parts[15]['test_message'] = str(e) ########## Employee initially has 0 punches" try: parts[16]['success'] = emp.lifetime_punches == 0 except Exception as e: print e parts[16]['test_message'] = str(e) ########## Clicking on the approved employee row ### redirects user to employee edit page try: test.find("#tab-approved-employees").click() test.find("#tab-body-approved-employees div#%s a" %\ (emp.objectId,)).click() sleep(1) parts[17]['success'] = test.is_current_url(reverse(\ "employee_edit", args=(emp.objectId,))) except Exception as e: print e parts[17]['test_message'] = str(e) ########## Clicking delete prompts the user to confirm" try: test.find("#delete-button").click() alert = test.switch_to_alert() parts[18]['success'] = alert.text ==\ "Are you sure you want to delete this employee?" except Exception as e: print e parts[18]['test_message'] = str(e) ########## The user is redirected to employee index" try: sleep(1) alert.accept() sleep(2) parts[19]['success'] = test.is_current_url(reverse(\ "employees_index") +\ "?success=Employee+has+been+deleted.") except Exception as e: print e parts[19]['test_message'] = str(e) ########## The deleted employee is removed from the pending table" try: parts[20]['success'] = not test.element_exists(\ "#tab-body-approved-employees div#%s a" %(emp.objectId,)) except Exception as e: print e parts[20]['test_message'] = str(e) ########## The employee is deleted from parse" try: store.set("employees", None) parts[21]['success'] = store.get("employees", objectId=emp.objectId, count=1) == 0 except Exception as e: print e parts[21]['test_message'] = str(e) ########## The account/user is deleted from parse" try: parts[22]['success'] = Account.objects().count(\ username=username, email=email) == 0 except Exception as e: print e parts[22]['test_message'] = str(e) ########## Multiple employees (4) registering at once ### shows up in dashboard" try: for i in range(3): register_employee(first_name + str(i), last_name + str(i)) sleep(COMET_PULL_RATE*2 + 3) test.find("#tab-pending-employees").click() parts[23]['success'] = len(test.find(\ "#tab-body-pending-employees div.tr " +\ "div.td.approve a.approve", multiple=True)) == 3 except Exception as e: print e parts[23]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_messages(): # TODO test that patrons are getting the messages!!! # setup account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription # set subscriptionType to free subscription.subscriptionType = 0 subscription.update() # clear the sent messages relation sent_messages = store.get("sentMessages", keys="") if sent_messages: store.remove_relation("SentMessages_", [m.objectId for m in sent_messages]) store.set("sentMessages", None) # we can clear the list locally but just re-pull from parse account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, # FIRST {'test_name': "Send message. Filter all. No offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # SECOND {'test_name': "Send message. Filter all. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # THIRD {'test_name': "Send message. Filter idle. No offer. " +\ "Message limit passed (free) dialog appears"}, # LIMIT PASSED {'test_name': "Upgrading account from the dialog sends the " +\ "message and upgrades the account to middle"}, {'test_name': "Email is sent notifying user the upgrade"}, # {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # FOURTH {'test_name': "Send message. Filter idle. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # FIFTH {'test_name': "Send message. Filter most_loyal. No offer. " +\ "Message limit passed (middle) dialog appears"}, # LIMIT PASSED {'test_name': "Upgrading account from the dialog sends the" +\ " message and upgrades the account to heavy"}, {'test_name': "Email is sent notifying user the upgrade"}, # {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # SIXTH {'test_name': "Send message. Filter most_loyal. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # SEVENTH {'test_name': "Send message. Filter all. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # EIGHTH {'test_name': "Send message. Filter all. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # NINTH {'test_name': "Send message. Filter all. No offer. " +\ "Message limit passed (heavy) dialog appears"}, # LIMIT PASSED {'test_name': "Account can no longer be upgraded." +\ "Message cannot be sent. Clicking okay redirects "+\ "user to messages index."}, # {'test_name': "Subject is required"}, {'test_name': "Body is required"}, {'test_name': "Offer title not required if attach offer off"}, {'test_name': "Expiration not required if attach offer off"}, {'test_name': "Offer title is required if attach offer on"}, {'test_name': "Expiration date required if attach offer on"}, {'test_name': "Expiration date must be at a later date"}, {'test_name': "Expiration date must be at most 1 year later"}, ] section = { "section_name": "Sending messages works?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("messages_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("messages_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(5) def send_message(filter, subject, body, attach_offer=False, offer_title=None, exp_date=None,): """ Must be called at messages index page """ test.find("#create_message").click() sleep(1) # set the filter test.find("//select[@id='filter']/option[@value='%s']" %\ (filter,), type="xpath").click() # subject test.find("#id_subject").send_keys(subject) # body test.find("#id_body").send_keys(body) # attach_offer if attach_offer: test.find("#id_attach_offer").click() # offer title if offer_title: test.find("#id_offer_title").send_keys(offer_title) # exp_date if exp_date: test.find("#id_date_offer_expiration").send_keys(exp_date) # submit test.find("#send-now").click() sleep(5) def message_in_relation(message_id, test_number): if not message_id: return store.sentMessages = None parts[test_number]['success'] = store.get("sentMessages", objectId=message_id, count=1, limit=0) == 1 def message_in_page(message_id, test_number): if not message_id: return try: rows = test.find("#tab-body-sent div.tr a", multiple=True) for row in rows: if row.get_attribute("href").split("/")[5] ==\ message_id: parts[test_number]['success'] = True except Exception as e: print e parts[test_number]['test_message'] = str(e) def message_viewable(message_id, test_number): if not message_id: return href = reverse("message_details", args=(message_id,)) try: test.find("#tab-body-sent div.tr a[href='%s']" %\ (href,)).click() sleep(2) parts[test_number]['success'] = test.is_current_url(href) except Exception as e: print e parts[test_number]['test_message'] = str(e) finally: # must go back to messages index for the other tests test.open(reverse("messages_index")) # FIRST ########## Send message. Filter all. No offer. message_id = None try: send_message("all", "msg #1", "body #1") parts[1]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[1]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 2) ########## Message is visible in page. message_in_page(message_id, 3) ########## Message can be view by clicking on row. message_viewable(message_id, 4) # SECOND ########## Send message. Filter all. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("all", "msg #2", "body #2", True, "offer#2", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[5]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[5]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 6) ########## Message is visible in page. message_in_page(message_id, 7) ########## Message can be view by clicking on row. message_viewable(message_id, 8) # THIRD ########## Send message. Filter idle. No offer. ### Message limit passed (free) dialog appears. message_id = None try: send_message("idle", "msg #3", "body #3") parts[9]['success'] = test.find("#upgrade") is not None except Exception as e: print e parts[9]['test_message'] = str(e) test.open(reverse("messages_index")) # LIMIT PASSED ########## Upgrading account from the dialog sends the ### message and upgrades the account to middle. try: test.find("#upgrade").click() sleep(2) test.find("#id_cc_cvv").send_keys("123") test.find("#id_recurring").click() test.find("#update-form-submit").click() sleep(5) message_id = test.driver.current_url.split("/")[5] subscription.subscriptionType = None parts[10]['success'] = test.is_current_url(\ reverse("message_details", args=(message_id,))) and\ subscription.get("subscriptionType") == 1 except Exception as e: print e parts[10]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) # open the mail connection if SeleniumTest.CHECK_SENT_MAIL: mail = Mail() ########## Email is sent notifying user the upgrade. try: parts[11]['success'] = mail.is_mail_sent(\ EMAIL_UPGRADE_SUBJECT) except Exception as e: print e parts[11]['test_message'] = str(e) else: parts[11]['success'] = parts[10]['success'] ########## Message is in store's sentMessages relation. message_in_relation(message_id, 12) ########## Message is visible in page. message_in_page(message_id, 13) ########## Message can be view by clicking on row. message_viewable(message_id, 14) # FOURTH ########## Send message. Filter idle. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("idle", "msg #4", "body #4", True, "offer#4", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[15]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[15]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 16) ########## Message is visible in page. message_in_page(message_id, 17) ########## Message can be view by clicking on row. message_viewable(message_id, 18) # FIFTH ########## Send message. Filter most_loyal. No offer. ### Message limit passed (free) dialog appears. message_id = None try: send_message("most_loyal", "msg #5", "body #5") parts[19]['success'] = test.find("#upgrade") is not None except Exception as e: print e parts[19]['test_message'] = str(e) test.open(reverse("messages_index")) # LIMIT PASSED ########## Upgrading account from the dialog sends the ### message and upgrades the account to heavy. try: test.find("#upgrade").click() sleep(2) test.find("#id_cc_cvv").send_keys("123") test.find("#id_recurring").click() test.find("#update-form-submit").click() sleep(5) message_id = test.driver.current_url.split("/")[5] subscription.subscriptionType = None parts[20]['success'] = test.is_current_url(\ reverse("message_details", args=(message_id,))) and\ subscription.get("subscriptionType") == 2 except Exception as e: print e parts[20]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Email is sent notifying user the upgrade. if SeleniumTest.CHECK_SENT_MAIL: try: parts[21]['success'] = mail.is_mail_sent(\ EMAIL_UPGRADE_SUBJECT) except Exception as e: print e parts[21]['test_message'] = str(e) else: parts[21]['success'] = parts[20]['success'] ########## Message is in store's sentMessages relation. message_in_relation(message_id, 22) ########## Message is visible in page. message_in_page(message_id, 23) ########## Message can be view by clicking on row. message_viewable(message_id, 24) # SIXTH ########## Send message. Filter most_loyal. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("most_loyal", "msg #6", "body #6", True, "offer#6", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[25]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[25]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 26) ########## Message is visible in page. message_in_page(message_id, 27) ########## Message can be view by clicking on row. message_viewable(message_id, 28) # SEVENTH ########## Send message. Filter all. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("all", "msg #7", "body #7", True, "offer#7", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[29]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[29]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 30) ########## Message is visible in page. message_in_page(message_id, 31) ########## Message can be view by clicking on row. message_viewable(message_id, 32) # EIGHTH ########## Send message. Filter all. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("all", "msg #8", "body #8", True, "offer#8", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[33]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[33]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 34) ########## Message is visible in page. message_in_page(message_id, 35) ########## Message can be view by clicking on row. message_viewable(message_id, 36) # NINTH ########## Send message. Filter all. With offer. ### Message limit passed (heavy) dialog appears. message_id = None try: send_message("all", "msg #9", "body #9") parts[37]['success'] = test.element_exists("#maxed_out") except Exception as e: print e parts[37]['test_message'] = str(e) test.open(reverse("messages_index")) # LIMIT PASSED ########## Account can no longer be upgraded. Msg cannot be sent. ### Clicking Okay redirects user to messages index. try: test.find("#maxed_out").click() sleep(1) parts[38]['success'] =\ test.is_current_url(reverse("messages_index")) except Exception as e: print e parts[38]['test_message'] = str(e) test.open(reverse("messages_index")) # # goto edit message page test.find("#create_message").click() sleep(2) selectors = ( ("#id_subject", " "), ("#id_body", " "), ) test.action_chain(0, selectors, action="send_keys") test.find("#send-now").click() sleep(1) ########## Subject is required. try: parts[39]['success'] = test.find("#subject_e ul li").text ==\ "This field is required." except Exception as e: print e parts[39]['test_message']= str(e) ########## Body is required. try: parts[40]['success'] = test.find("#body_e ul li").text ==\ "This field is required." except Exception as e: print e parts[40]['test_message'] = str(e) ########## Offer title not required if attach offer off. try: parts[41]['success'] = not test.element_exists(\ "#offer_title_e ul li") except Exception as e: print e parts[41]['test_message'] = str(e) ########## Expiration not required if attach offer off. try: parts[42]['success'] = not test.element_exists(\ "#date_offer_expiration_e ul li") except Exception as e: print e parts[42]['test_message'] = str(e) test.find("#id_attach_offer").click() test.find("#send-now").click() sleep(1) ########## Offer title is required if attach offer on. try: parts[43]['success'] =\ test.find("#offer_title_e ul li").text ==\ "Please enter a title." except Exception as e: print e parts[43]['test_message'] = str(e) ########## Expiration date required if attach offer on. try: parts[44]['success'] =\ test.find("#date_offer_expiration_e ul li").text ==\ "Please enter an expiration date." except Exception as e: print e parts[44]['test_message'] = str(e) ########## Expiration date must be at a later date. try: # don't click attach offer again! # test.find("#id_attach_offer").click() exp_date = timezone.now() + relativedelta(days=-1) test.find("#id_date_offer_expiration").send_keys(\ exp_date.strftime(DATE_PICKER_STRFTIME)) test.find("#send-now").click() sleep(1) parts[45]['success'] = test.find(\ "#date_offer_expiration_e ul li").text ==\ "Please enter an expiration date that is later than today." except Exception as e: print e parts[45]['test_message'] = str(e) ########## Expiration date must be at most 1 year later. try: # don't click attach offer again! # test.find("#id_attach_offer").click() exp_date = timezone.now() + relativedelta(days=367) date_offer = test.find("#id_date_offer_expiration") date_offer.clear() date_offer.send_keys(\ exp_date.strftime(DATE_PICKER_STRFTIME)) test.find("#send-now").click() sleep(2) parts[46]['success'] = test.find(\ "#date_offer_expiration_e ul li").text ==\ "Please enter an expiration date that is less than a year." except Exception as e: print e parts[46]['test_message'] = str(e) # END OF ALL TESTS - cleanup if SeleniumTest.CHECK_SENT_MAIL: mail.logout() return test.tear_down()
def create_random_stores(self, amount): for i in range(amount): print "Creating store %s" % (str(i), ) # create the store street, city, state, zip, country, phone_number =\ self.addrs[i].split(", ") first_name, last_name = self.owners[i].split(" ") neighborhood = self.neighborhoods[i] store_name = self.stores[i] store_i = STORE.copy() store_location_i = STORE_LOCATION.copy() # create the thumbnaiil and cover (same image different size) self.get_store_location_image(i) thumbnail = create_png(TMP_IMG_PATH, IMAGE_THUMBNAIL_SIZE) while "error" in image: print "Retrying create_png" thumbnail = create_png(TMP_IMG_PATH) cover = create_png(TMP_IMG_PATH) while "error" in cover: print "Retrying create_png" cover = create_png(TMP_IMG_PATH) store_i.update({ "store_name": store_name, "first_name": first_name, "last_name": last_name, "thumbnail_image": thumbnail.get("name"), "cover_image": cover.get("name"), }) store_location_i.update({ "street": street, "city": city, "state": state, "zip": zip, "neighborhood": neighborhood, "country": country, "phone_number": phone_number, "coordinates": self.get_random_coordinates(), }) # create the store store = Store.objects().create(**store_i) # create the store location store_location = StoreLocation(**store_location_i) store_location.Store = store.objectId store_location.update() # create the settings settings = Settings.objects().create(Store=store.objectId) # create the subscription subscription =\ Subscription.objects().create(Store=store.objectId, date_last_billed=timezone.now()) # create the user email = first_name + str(randint(0, 99)) + USER_EMAIL_POSTFIX email = email.lower() acc = Account.objects().create(\ username=email, email=email, password=USER_PASSWORD, Store=store.objectId) if not acc.objectId: raise Exception("Account creation failed.") # link the store store.Settings = settings.objectId store.Subscription = subscription.objectId store.owner_id = acc.objectId store.ACL[acc.objectId] = {"read": True, "write": True} store.store_locations = [store_location] store.update()
def handle(self, *args, **options): """ get all of the subscriptions whose stores are active & who have been last billed 30+ days ago. IMPORTANT! This includes accounts of type FREE, which are not charged or included in the email notifications """ # for logging when ran by CRON print "Running monthly_billing: " + str(timezone.now()) date_30_ago = timezone.now() + relativedelta(days=-30) date_now = timezone.now() sub_count = pointer_query("Subscription", {"date_last_billed__lte":date_30_ago}, "Store", "Store", {"active":True}, count=True) asiss = [] # get 500 subscriptions at a time LIMIT, skip = 500, 0 while sub_count > 0: for each in pointer_query("Subscription", {"date_last_billed__lte":date_30_ago}, "Store", "Store", {"active":True}, limit=LIMIT, skip=skip, order="createdAt")['results']: subscription = Subscription(**each) sub_cost = sub_type[subscription.get(\ "subscriptionType")]["monthly_cost"] store = None # prevent UnboundLocalError update_store = False if sub_cost == 0: # FREE account subscription.date_last_billed =\ subscription.date_last_billed +\ relativedelta(days=30) subscription.update() else: # PAID account account = Account.objects().get(Store=\ subscription.get("Store"), include="Store") store = account.get("store") invoice = subscription.charge_cc(\ sub_cost, "Repunch Inc. Recurring " +\ "monthly subscription charge", MONTHLY) send_user_email = True if invoice: subscription.date_last_billed =\ subscription.date_last_billed +\ relativedelta(days=30) subscription.date_charge_failed = None subscription.update() else: subscription.date_charge_failed = date_now # force entering new credit card! subscription.cc_number = None subscription.date_cc_expiration = None subscription.update() # notify user via email- payment is done via # dashboard to also validate cc realtime # 1st day time range day0_end = date_30_ago.replace() day0_start = day0_end + relativedelta(hours=-24) # 4th day time range day4_end = date_30_ago + relativedelta(days=-4) day4_start = day4_end + relativedelta(hours=-24) # 8th day time range day8_end = date_30_ago + relativedelta(days=-8) day8_start = day8_end + relativedelta(hours=-24) # 14th day time range day14_end = date_30_ago + relativedelta(days=-14) day14_start = day14_end + relativedelta(hours=-24) # only send email after 1, 4, and 8 days last_billed = subscription.date_last_billed if (last_billed >= day0_start and\ last_billed <= day0_end) or\ (last_billed >= day4_start and\ last_billed <= day4_end) or\ (last_billed >= day8_start and\ last_billed <= day8_end): send_email_receipt_monthly_failed(account, store, subscription) elif last_billed >= day14_start and\ last_billed <= day14_end: # send final notification send_email_receipt_monthly_failed(account, store, subscription, account_disabled=True) else: send_user_email = False # make sure that the store is deactivated after the 14th day if last_billed <= day14_end: store.active = False store.update() update_store = True # do not send email after account deactivation if send_user_email: asiss.append((account, store, invoice, subscription)) # update the logged in users' subscription and store payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription":subscription.jsonify() } if store and update_store: payload.update({"updatedStore":store.jsonify()}) comet_receive(subscription.Store, payload) # end of while loop sub_count -= LIMIT skip += LIMIT # everything is done - send the emails send_email_receipt_monthly_batch(asiss)
def register(request): """ Adds a new employee to the currently logged in Store. This automatically sets this employee to approved. """ data = {'employees_nav': True} settings = SESSION.get_settings(request.session) store = SESSION.get_store(request.session) if request.method == "POST": from_associated_account = False # check if this post is from the associated account dialog # if it is then skip form validations aaf_nonce_id = request.POST.get('aaf-nonce') aaf_account_id = request.POST.get('aaf-account_id') if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0: aa_nonce = AssociatedAccountNonce.objects.filter(\ id=aaf_nonce_id, account_id=aaf_account_id) if len(aa_nonce) > 0 and aa_nonce[0].verified: aa_nonce[0].delete() from_associated_account = True account_form = EmployeeAccountSignUpForm(request.POST) employee_form = EmployeeForm(request.POST) if not from_associated_account: all_forms_valid = account_form.is_valid() and\ employee_form.is_valid() else: all_forms_valid = True if all_forms_valid: postDict = request.POST.dict() # make the cloud call # see cloud param for possible access level values acl = postDict['acl'] if acl == ACCESS_ADMIN[0]: access_level = "admin" elif acl == ACCESS_PUNCHREDEEM[0]: access_level = "punch_redeem" else: access_level = None params = { "retailer_pin": settings.get("retailer_pin"), "username": postDict['email'].strip().lower(), "first_name": postDict['first_name'].capitalize(), "last_name": postDict['last_name'].capitalize(), "email": postDict['email'].strip().lower(), "status": APPROVED, "access_level": access_level, } if from_associated_account: res = cloud_call("link_employee", params) else: params["password"] = postDict['password'] res = cloud_call("register_employee", params) # don't forget to retrieve the latest session request.session.clear() request.session.update(SessionStore(request.session.session_key)) # check if email already taken here to handle the case where # the user already has a patron/employee account # but also want to sign up for a Store account if "error" in res and res['error'] in ("EMAIL_TAKEN_AVAILABLE", "USERNAME_TAKEN_AVAILABLE"): aa = Account.objects().get( email=postDict['email'].strip().lower()) aan = AssociatedAccountNonce.objects.create(\ account_id=aa.objectId) return HttpResponse(json.dumps({"associated_account":\ aa.objectId, "associated_account_nonce":aan.id, "email": aa.email, "code": 0}), content_type="application/json") elif "error" in res and res['error'] in ("EMAIL_TAKEN", "USERNAME_TAKEN"): account_form._errors.setdefault( "email", ErrorList()).append(u"Email is already being used.") elif "error" not in res: # add the employee to the approved list employees_approved_list =\ SESSION.get_employees_approved_list(request.session) employees_approved_ids =\ [ emp.objectId for emp in employees_approved_list ] new_employee = Employee(**res["result"]) if new_employee.objectId not in employees_approved_ids: employees_approved_list.insert(0, new_employee) request.session['employees_approved_list'] =\ employees_approved_list # update our local store's acl - don't wait for # the cloud post store = SESSION.get_store(request.session) store.set_access_level(Account.objects().get(\ email=postDict['email'].strip().lower()), acl) request.session['store'] = store # notify other dashboards of this change payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore": store.jsonify() } comet_receive(store.objectId, payload) return HttpResponse(json.dumps({"code": 2}), content_type="application/json") else: return HttpResponse(json.dumps({"code": 3}), content_type="application/json") else: employee_form = EmployeeForm(initial={"acl":\ ACCESS_PUNCHREDEEM[0]}) account_form = EmployeeAccountSignUpForm() data["employee_form"] = employee_form data["account_form"] = account_form return render(request, 'manage/employee_register.djhtml', data)
def test_cancel_account(): """ A test just for the cancel account link. """ account = Account.objects().get(username=TEST_USER['username'], include="Store") store = account.store test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Clicking the cancel button brings up a " +\ "confirmation dialog"}, {'test_name': "Clicking cancel on the dialog dimisses the " +\ "dialog and the account remains active"}, {'test_name': "Clicking OK logs the user out"}, {'test_name': "Clicking OK sets the store's active field " +\ "to false on Parse"}, ] section = { "section_name": "Deactivate store link functional?", "parts": parts, } self.results.append(section) ########## User needs to be logged in to access page self.open(reverse("store_index")) sleep(1) parts[0]['success'] = self.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("store_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) self.action_chain(0, selectors, "send_keys") sleep(7) ########## Clicking the cancel button brings up a confrmtn dialog try: self.find("#deactivate_account").click() sleep(1) alert = self.switch_to_alert() parts[1]['success'] = alert is not None except Exception as e: print e parts[1]['test_message'] = str(e) ########## Clicking cancel on the dialog dimisses the ### dialog and the account remains active try: alert.dismiss() try: alert.text except NoAlertPresentException: store.active = None parts[2]['success'] = store.get("active") except Exception as e: print e parts[2]['test_message'] = str(e) ########## Clicking OK logs the user out try: self.find("#deactivate_account").click() sleep(1) alert = self.switch_to_alert() alert.accept() sleep(4) if SeleniumTest.DEV_LOGIN: parts[3]["success"] =\ self.is_current_url(reverse("manage_dev_login")+"?next=/") else: parts[3]["success"] =\ self.is_current_url(reverse("public_home")) except Exception as e: print e parts[3]['test_message'] = str(e) ########## Clicking OK sets the store's active ### field to false on Parse store.active = None parts[4]['success'] = not store.get("active") # undo store.active = True store.update() # END OF ALL TESTS - cleanup return self.tear_down()
def employee_is_owner(session, employee_id): account = Account.objects().get(Employee=employee_id) return SESSION.get_store(session).is_owner(account)
def handle(self, *args, **options): # for logging when ran by CRON print "Running passed_user_limit: " + str(timezone.now()) now = timezone.now() b4_now = now + relativedelta(hours=-1) # get 500 subscriptions at a time LIMIT = 500 # first scan though all the stores and set their # date_passed_user_limit if so # TODO optimize with a relational query? possible with Parse? #### SUB_TYPE 0 skip = 0 sub_count = Subscription.objects().count(\ date_passed_user_limit=None, subscriptionType=0) max_users = sub_type[0]['max_users'] while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit=None, god_mode=False, limit=LIMIT, skip=skip, order="createdAt"): store = sub.store if store.get("patronStores", count=1, limit=0) >\ max_users: sub.date_passed_user_limit = b4_now sub.update() # notify the dashboards of these changes payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) # end of while loop sub_count -= LIMIT skip += LIMIT # TODO optimize with a relational query? possible with Parse? #### SUB_TYPE 1 skip = 0 sub_count = Subscription.objects().count(\ date_passed_user_limit=None, subscriptionType=1) max_users = sub_type[1]['max_users'] while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit=None, god_mode=False, limit=LIMIT, skip=skip, order="createdAt"): store = sub.store if store.get("patronStores", count=1, limit=0) >\ max_users: sub.date_passed_user_limit = b4_now sub.update() # notify the dashboards of these changes payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) # end of while loop sub_count -= LIMIT skip += LIMIT ################ conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() # 1st day time range day1_end = now.replace() day1_start = day1_end + relativedelta(hours=-24) # 4th day time range day4_end = now + relativedelta(days=-4) day4_start = day4_end + relativedelta(hours=-24) # 8th day time range day8_end = now + relativedelta(days=-8) day8_start = day8_end + relativedelta(hours=-24) # 14th day time range day14_end = now + relativedelta(days=-14) day14_start = day14_end + relativedelta(hours=-24) #### SUB_TYPE 0 ## 1st day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start, limit=LIMIT, skip=skip, order="createdAt"): # with pp_cc_id if sub.pp_cc_id and len(sub.pp_cc_id) > 0: sub.subscriptionType = 1 sub.date_passed_user_limit = None sub.update() # notify the dashboards of these changes payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) package = { "status": "upgraded", "sub_type": sub_type[0]["name"], "new_sub_type": sub_type[1]["name"], "new_sub_type_cost": sub_type[1]["monthly_cost"], "new_max_patronStore_count":\ sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), } # no pp_cc_id else: package = { "sub_type": sub_type[0]["name"], "max_patronStore_count": sub_type[0]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 4th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[0]["name"], "max_patronStore_count": sub_type[0]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 8th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[0]["name"], "max_patronStore_count": sub_type[0]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 14th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=0, date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=0, include="Store", date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start, limit=LIMIT, skip=skip, order="createdAt"): package = {"status": "disabled"} # deactivate the store sub.store.active = False sub.store.update() payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore": sub.store.jsonify(), } comet_receive(sub.Store, payload) try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT #### SUB_TYPE 1 ## 1st day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day1_end, date_passed_user_limit__gte=day1_start, limit=LIMIT, skip=skip, order="createdAt"): # with pp_cc_id if sub.pp_cc_id and len(sub.pp_cc_id) > 0: sub.subscriptionType = 2 sub.date_passed_user_limit = None sub.update() # notify the dashboards of these changes payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedSubscription": sub.jsonify() } comet_receive(sub.Store, payload) package = { "status": "upgraded", "sub_type": sub_type[1]["name"], "new_sub_type": sub_type[2]["name"], "new_sub_type_cost": sub_type[2]["monthly_cost"], "new_max_patronStore_count": "Unlimited", "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), } # no pp_cc_id else: package = { "sub_type": sub_type[1]["name"], "max_patronStore_count": sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 4th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day4_end, date_passed_user_limit__gte=day4_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[1]["name"], "max_patronStore_count": sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 8th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day8_end, date_passed_user_limit__gte=day8_start, limit=LIMIT, skip=skip, order="createdAt"): package = { "sub_type": sub_type[1]["name"], "max_patronStore_count": sub_type[1]["max_users"], "patronStore_count": sub.store.get(\ "patronStores", limit=0, count=1), "disable_date": sub.date_passed_user_limit + relativedelta(days=\ USER_LIMIT_PASSED_DISABLE_DAYS), } try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT ## 14th day skip = 0 sub_count = Subscription.objects().count(\ subscriptionType=1, date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start) while sub_count > 0: for sub in Subscription.objects().filter(\ subscriptionType=1, include="Store", date_passed_user_limit__lte=day14_end, date_passed_user_limit__gte=day14_start, limit=LIMIT, skip=skip, order="createdAt"): package = {"status": "disabled"} # deactivate the store sub.store.active = False sub.store.update() payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore": sub.store.jsonify(), } comet_receive(sub.Store, payload) try: send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_passed_user_limit(Account.objects().get(\ Store=sub.Store), sub.store, package, conn) # end of while loop sub_count -= LIMIT skip += LIMIT try: conn.close() except Exception: pass
def test_employee_access(): """ Tests for employee dashboard access. This tests any user with ACL of ACCESS_PUNCHREDEEM and NO_ACCESS. Tests for ACCESS_ADMIN are not necessary since all other tests involving the store owner covers it. """ # delete the employees and associated User objects in the relation account = Account.objects().get(email=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings emps = store.get("employees") if emps: for emp in emps: Account.objects().get(Employee=emp.objectId).delete() emp.delete() store.set("employees", None) test = SeleniumTest() parts = [ {"test_name" : "Pending employee has no access"}, {"test_name" : "Approved employee initially not in store ACL"}, {"test_name" : "Employee with ACCESS_NONE cannot login " +\ "using the login dialog"}, {"test_name" : "Employee with ACCESS_NONE cannot login " +\ "using the dedicated login page"}, {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\ "login to the dashboard through the login dialog"}, {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\ "login to the dashboard through the dedicated dialog pg"}, {"test_name" : "Account settings accessible"}, {"test_name" : "No store edit button"}, {"test_name" : "Requesting edit store detail through url " +\ "redirects user to store index"}, {"test_name" : "No update subscription button"}, {"test_name" : "Requesting update subscription through url " +\ "redirects user to store index"}, {"test_name" : "No deactivate my store button"}, {"test_name" : "Requesting store deactivation through url " +\ "redirects user to store index"}, {"test_name" : "Rewards accessible"}, {"test_name" : "No create new reward button"}, {"test_name" : "Requesting create new reward through url " +\ "redirects user to rewards index"}, {"test_name" : "Rewards are not clickable"}, {"test_name" : "Requesting edit reward through url " +\ "redirects user to rewards index"}, {"test_name" : "Messages accessible"}, {"test_name" : "No create new message button"}, {"test_name" : "Requesting create new message through url " +\ "redirects user to messages index"}, {"test_name" : "Sent messages are viewable"}, {"test_name" : "Feedbacks are viewable"}, {"test_name" : "No reply button"}, {"test_name" : "Requesting reply through url " +\ "redirects user to messages index"}, {"test_name" : "No delete message button"}, {"test_name" : "Requesting delete message through url " +\ "redirects user to messages index"}, {"test_name" : "Analysis accessible"}, {"test_name" : "Employees accessible"}, {"test_name" : "No register new employee button"}, {"test_name" : "Requesting new employee registration"+\ "redirects user to employees_index"}, {"test_name" : "Approved employees are not clickable"}, {"test_name" : "Requesting edit employee through url " +\ "redirects user to employees index"}, {"test_name" : "No remove button in approved employees"}, {"test_name" : "Requesting remove employee through url " +\ "redirects user to employees index"}, {"test_name" : "No deny button in pending employees"}, {"test_name" : "Requesting deny employee through url " +\ "redirects user to employees index"}, {"test_name" : "No approve button in pending employees"}, {"test_name" : "Requesting approve employee through url " +\ "redirects user to employees index"}, {"test_name" : "Settings accessible"}, {"test_name" : "No refresh button for retailer pin"}, {"test_name" : "Requesting refresh through url returns " +\ "a json object with error Permission denied"}, {"test_name" : "Punches employee is readonly"}, {"test_name" : "Punches facebook is readonly"}, {"test_name" : "No save button"}, {"test_name" : "No cancel changes button"}, {"test_name" : "Workbench accessible"}, {"test_name" : "Employee can punch"}, {"test_name" : "Employee can reject redeem"}, {"test_name" : "Employee can validate redeem"}, ] section = { "section_name":\ "Employee dashboard access working as expected?", "parts": parts, } test.results.append(section) try: # register the test employee register_employee("employee", "ex", TEST_EMPLOYEE['username'], TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], settings.retailer_pin) sleep(3) employee_acc = Account.objects().get(username=TEST_EMPLOYEE[\ 'username'], include="Employee") employee = employee_acc.employee except Exception as e: print e ########## Pending employee has no access try: test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index")) parts[0]['success'] =\ test.find("#dialog-login-message").text ==\ "You are not yet approved." except Exception as e: print e parts[0]['test_message'] = str(e) try: # login to approve test.login(TEST_USER['username'], TEST_USER['password'], reverse("employees_index")) # approve test.find("#tab-pending-employees").click() approveRow = test.find("#tab-body-pending-employees " +\ "div.tr") approveRow.find_element_by_css_selector(\ "div.td.approve a.approve").click() sleep(1) test.switch_to_alert().accept() sleep(2) test.logout() except Exception as e: print e ########## Approved employee initially not in store ACL try: # store.ACL = None cannot retrieve Parse built-ins! account = Account.objects().get(email=TEST_USER['username'], include="Store.Settings") store = account.store parts[1]['success'] = employee_acc.objectId not in store.ACL except Exception as e: print e parts[1]['test_message'] = str(e) ########## Employee with ACCESS_NONE cannot login ### using the login dialog try: test.dev_login() test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password']) parts[2]['success'] =\ test.find("#dialog-login-message").text ==\ "You do not have permission to access the dashboard." except Exception as e: print e parts[2]['test_message'] = str(e) ########## Employee with ACCESS_NONE cannot login ### using the dedicated login page try: test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index")) parts[3]['success'] =\ test.find("#dialog-login-message").text ==\ "You do not have permission to access the dashboard." except Exception as e: print e parts[3]['test_message'] = str(e) ### Update the store's ACL store.ACL = {"*": {"read": True, "write": True}} store.set_access_level(employee_acc, ACCESS_PUNCHREDEEM[0]) store.update() test.new_driver(False) ########## Employee with ACCESS_PUNCHREDEEM can ### login to the dashboard through the login dialog try: test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], final_sleep=6) parts[4]['success'] = test.is_current_url(reverse("store_index")) test.logout() except Exception as e: print e parts[4]['test_message'] = str(e) ########## Employee with ACCESS_PUNCHREDEEM can ### login to the dashboard through the dedicated dialog page try: test.dev_login() test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index"), final_sleep=6) parts[5]['success'] = test.is_current_url(reverse("employees_index")) sleep(4) except Exception as e: print e parts[5]['test_message'] = str(e) ########## Account settings accessible try: test.find("#header-right a").click() sleep(2) parts[6]['success'] = test.is_current_url(reverse("account_edit")) except Exception as e: print e parts[6]['test_message'] = str(e) ########## No edit store detail button try: test.open(reverse("store_index")) sleep(2) test.set_to_implicit_wait(False) try: test.find("#store-details a[href='%s']" % (reverse("store_edit"),)) except NoSuchElementException: parts[7]['success'] = True except Exception as e: print e parts[7]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting edit store detail through url ### redirects user to store details try: test.open(reverse("store_edit")) sleep(2) parts[8]['success'] = test.is_current_url(reverse("store_index")+\ "?" + urlencode({'error': "Permission denied"})) except Exception as e: print e parts[8]['test_message'] = str(e) ########## No update subscription button try: test.set_to_implicit_wait(False) try: test.find("#account-options a[href='%s']" %\ (reverse("subscription_update"),)) except NoSuchElementException: parts[9]['success'] = True except Exception as e: print e parts[9]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting update subscription through url ### redirects user to store index try: test.open(reverse("subscription_update")) sleep(2) parts[10]['success'] = test.is_current_url(reverse(\ "store_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[10]['test_message'] = str(e) ########## No deactivate my store button try: test.set_to_implicit_wait(False) try: test.find("#deactivate_account") except NoSuchElementException: parts[11]['success'] = True except Exception as e: print e parts[11]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting store deactivation through url ### redirects user to store index try: test.open(reverse("store_deactivate")) sleep(2) parts[12]['success'] = test.is_current_url(reverse(\ "store_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[12]['test_message'] = str(e) ########## Rewards accessible try: test.open(reverse("rewards_index")) sleep(2) parts[13]['success'] = test.is_current_url(reverse("rewards_index")) except Exception as e: print e parts[13]['test_message'] = str(e) ########## No create new reward button try: test.set_to_implicit_wait(False) try: test.find("#add_reward") except NoSuchElementException: parts[14]['success'] = True except Exception as e: print e parts[14]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting create new reward through url ### redirects user to rewards index try: test.open(reverse("reward_edit", args=(-1,))) sleep(2) parts[15]['success'] = test.is_current_url(reverse(\ "rewards_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[15]['test_message'] = str(e) ########## Rewards are not clickable try: test.set_to_implicit_wait(False) try: test.find("div.tr.reward a") except NoSuchElementException: parts[16]['success'] = True except Exception as e: print e parts[16]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting edit reward through url ### redirects user to rewards index try: test.open(reverse("reward_edit", args=\ (int(test.find("div.tr.reward").get_attribute("id")),))) sleep(3) parts[17]['success'] = test.is_current_url(reverse(\ "rewards_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[17]['test_message'] = str(e) ########## Messages accessible try: test.open(reverse("messages_index")) sleep(3) parts[18]['success'] = test.is_current_url(reverse(\ "messages_index")) except Exception as e: print e parts[18]['test_message'] = str(e) ########## No create new message button try: test.set_to_implicit_wait(False) try: test.find("#create_message") except NoSuchElementException: parts[19]['success'] = True except Exception as e: print e parts[19]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting create new message through url ### redirects user to messages index try: test.open(reverse("message_edit", args=("0",))) sleep(3) parts[20]['success'] = test.is_current_url(reverse(\ "messages_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[20]['test_message'] = str(e) ########## Sent messages are viewable try: row = test.find("#tab-body-sent div.tr a") # get id from /manage/messages/H1llFritVJ/details message_id = MESSAGE_DETAIL_RE.search(\ row.get_attribute("href")).group(1) row.click() sleep(3) parts[21]['success'] = test.is_current_url(reverse(\ "message_details", args=(message_id,))) except Exception as e: print e parts[21]['test_message'] = str(e) ########## Feedbacks are viewable try: test.open(reverse("messages_index")) sleep(2) test.find("#tab-feedback").click() sleep(1) row = test.find("#tab-body-feedback div.tr a") # get id from /manage/messages/feedback/H1llFritVJ feedback_id = row.get_attribute("href").split("/")[-1] row.click() sleep(3) parts[22]['success'] = test.is_current_url(reverse(\ "feedback_details", args=(feedback_id,))) except Exception as e: print e parts[22]['test_message'] = str(e) ########## No reply button try: test.set_to_implicit_wait(False) try: test.find("#reply-button") except NoSuchElementException: parts[23]['success'] = True except Exception as e: print e parts[23]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting reply through url ### redirects user to messages index try: test.open(reverse("feedback_reply", args=(feedback_id,))) sleep(3) parts[24]['success'] = test.is_current_url(reverse(\ "messages_index")+ "?" + urlencode({'error':\ "Permission denied"}) + "&tab_feedback=1") except Exception as e: print e parts[24]['test_message'] = str(e) ########## No delete message button try: test.open(reverse("feedback_details", args=(feedback_id,))) sleep(3) test.set_to_implicit_wait(False) try: test.find("#delete-button") except NoSuchElementException: parts[25]['success'] = True except Exception as e: print e parts[25]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting delete message through url ### redirects user to messages index try: test.open(reverse("feedback_delete", args=(feedback_id,))) sleep(2) parts[26]['success'] = test.is_current_url(reverse(\ "messages_index")+ "?" + urlencode({'error':\ "Permission denied"}) + "&tab_feedback=1") except Exception as e: print e parts[26]['test_message'] = str(e) ########## Analysis accessible try: test.open(reverse("analysis_index")) sleep(4) parts[27]['success'] = test.is_current_url(reverse(\ "analysis_index")) except Exception as e: print e parts[27]['test_message'] = str(e) ########## Employees accessible try: test.open(reverse("employees_index")) sleep(4) parts[28]['success'] = test.is_current_url(reverse(\ "employees_index")) except Exception as e: print e parts[28]['test_message'] = str(e) ########## No register new employee button try: test.set_to_implicit_wait(False) try: test.find("#register_employee") except NoSuchElementException: parts[29]['success'] = True except Exception as e: print e parts[29]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting new employee registration ### redirects user to employees_index try: test.open(reverse("employee_register")) sleep(3) parts[30]['success'] = test.is_current_url(reverse(\ "employees_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[30]['test_message'] = str(e) ########## Approved employees are not clickable try: test.set_to_implicit_wait(False) try: test.find("#tab-body-approved-employees div.tr a") except NoSuchElementException: parts[31]['success'] = True except Exception as e: print e parts[31]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting edit employee through url ### redirects user to employees index try: row = test.find("#tab-body-approved-employees div.tr") employee_id = row.get_attribute("id") test.open(reverse("employee_edit", args=(employee_id,))) sleep(3) parts[32]['success'] = test.is_current_url(reverse(\ "employees_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[32]['test_message'] = str(e) ########## No remove button in approved employees try: test.set_to_implicit_wait(False) try: test.find("#tab-body-approved-employees div.tr "+\ "div.remove a") except NoSuchElementException: parts[33]['success'] = True except Exception as e: print e parts[33]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting remove employee through url ### redirects user to employees index try: test.open(reverse("employee_delete", args=(employee_id,))) sleep(3) parts[34]['success'] = test.is_current_url(reverse(\ "employees_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[34]['test_message'] = str(e) # create a pending register_rand_employee(store.objectId) test.new_driver(False) test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index"), final_sleep=6) ########## No deny button in pending employees try: test.find("#tab-pending-employees").click() sleep(1) test.set_to_implicit_wait(False) try: test.find("#tab-body-pending-employees div.tr "+\ "div.deny a") except NoSuchElementException: parts[35]['success'] = True except Exception as e: print e parts[35]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting deny employee through url ### redirects user to employees index try: test.find("#tab-pending-employees").click() row = test.find("#tab-body-pending-employees div.tr") employee_id = row.get_attribute("id") test.open(reverse("employee_deny", args=(employee_id,))) sleep(3) parts[36]['success'] = test.is_current_url(reverse(\ "employees_index") + "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[36]['test_message'] = str(e) ########## No approve button in pending employees try: test.find("#tab-pending-employees").click() sleep(1) test.set_to_implicit_wait(False) try: test.find("#tab-body-pending-employees div.tr "+\ "div.approve a") except NoSuchElementException: parts[37]['success'] = True except Exception as e: print e parts[37]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting approve employee through url ### redirects user to employees index try: test.open(reverse("employee_approve", args=(employee_id,))) sleep(3) parts[38]['success'] = test.is_current_url(reverse(\ "employees_index") + "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[38]['test_message'] = str(e) ########## Settings accessible try: test.open(reverse("store_settings")) sleep(3) parts[39]['success'] = test.is_current_url(reverse(\ "store_settings")) except Exception as e: print e parts[39]['test_message'] = str(e) ########## No refresh button for retailer pin try: test.set_to_implicit_wait(False) try: test.find("#link_refresh_retailer_pin") except NoSuchElementException: parts[40]['success'] = True except Exception as e: print e parts[40]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting refresh through url returns ### a json object with error Permission denied try: test.open(reverse("refresh_retailer_pin")) sleep(3) parts[41]['success'] = "Permission denied" in\ test.driver.page_source except Exception as e: print e parts[41]['test_message'] = str(e) ########## Punches employee is readonly try: test.open(reverse("store_settings")) sleep(3) parts[42]['success'] =\ test.find("#id_punches_employee").get_attribute(\ "readonly") == "true" except Exception as e: print e parts[42]['test_message'] = str(e) ########## Punches facebook is readonly try: parts[43]['success'] =\ test.find("#id_punches_facebook").get_attribute(\ "readonly") == "true" except Exception as e: print e parts[43]['test_message'] = str(e) ########## No save button try: test.set_to_implicit_wait(False) try: test.find("#settings-form-submit") except NoSuchElementException: parts[44]['success'] = True except Exception as e: print e parts[44]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## No cancel changes button try: test.set_to_implicit_wait(False) try: test.find("#settings-options a.red") except NoSuchElementException: parts[45]['success'] = True except Exception as e: print e parts[45]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Workbench accessible try: test.open(reverse("workbench_index")) sleep(3) parts[46]['success'] = test.is_current_url(\ reverse("workbench_index")) except Exception as e: print e parts[46]['test_message'] = str(e) ########## Employee can punch try: test.find("#punch_code").send_keys("00010") test.find("#punch_amount").send_keys("1") test.find("#punch-form a.button.blue").click() sleep(2) parts[47]['success'] =\ test.find(".notification.hide") is not None except Exception as e: print e parts[47]['test_message'] = str(e) ########## Employee can reject redeem try: request_redeem_ps("eiZa6Mzu7f") sleep(COMET_PULL_RATE*2+4) row = test.find("#tab-body-pending-redemptions div.tr") test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\ "div[contains(@class, 'redemption_redeem')]/a[2]", type="xpath").click() sleep(3) parts[48]['success'] = row.text.__contains__("Successfully") except Exception as e: print e parts[48]['test_message'] = str(e) ########## Employee can validate redeem try: request_redeem_ps("eiZa6Mzu7f") sleep(COMET_PULL_RATE*2+4) row = test.find("#tab-body-pending-redemptions div.tr") test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\ "div[contains(@class, 'redemption_redeem')]/a[1]", type="xpath").click() sleep(3) parts[49]['success'] = row.text.__contains__("Successfully") except Exception as e: print e parts[49]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_feedbacks(): """ This test also tests cloud code send_feedback. """ # we can clear the list locally but just re-pull from parse account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription account = Account.objects().get(username=TEST_PATRON['username'], include="Patron") patron = account.patron # make sure that the account is not used for these tests account = None # clear the received messages relation received_messages = store.get("receivedMessages", keys="") if received_messages: store.remove_relation("ReceivedMessages_", [m.objectId for m in received_messages]) store.set("receivedMessages", None) test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Cloud code send_feedback works"}, {'test_name': "Notification badge appears if there are" +\ " unread feedbacks"}, {'test_name': "A new row appears when feedback is received"}, {'test_name': "Feedback is initially unread (dashboard)"}, {'test_name': "Feedback is in store's ReceivedMessages " +\ "relation and is initially unread"}, {'test_name': "Clicking the row redirects user to the " +\ "feedback detail page"}, {'test_name': "Clicking back to feedback inbox redirects " +\ "user back to messages index with feedback tab active"}, {'test_name': "Feedback is now read (dashboard)"}, {'test_name': "Feedback is now read (Parse)"}, {'test_name': "Clicking reply redirects user to feedback " +\ "reply page"}, {'test_name': "Reply body is required."}, {'test_name': "Replying redirects user back to feedback " +\ "details"}, {'test_name': "The reply is visible"}, {'test_name': "The reply message is saved in the store's " +\ "sent messages relation with message_type of feedback"}, {'test_name': "The reply message is saved in the Patron's " +\ "received messages relation wrapped in a Message Status"}, {'test_name': "A feedback with a reply does not have a " +\ "reply button"}, {'test_name': "Clicking delete message prompts the user " +\ "to confirm the deletion"}, {'test_name': "The user is redirected to messages index " +\ "with feedback tab active"}, {'test_name': "Deleting the reply only removes the message" +\ " from the store's sent messages relation"}, {'test_name': "The deleted feedback is no longer in " +\ "the table"}, {'test_name': "Multiple feedbacks (testing 3 here) " +\ "can appear at the same time"}, ] section = { "section_name": "Receiving messages works?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("messages_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("messages_index")) # login selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(5) def send_feedback(subject, body): """ This is a consumer action - not dashboard """ return cloud_call( "send_feedback", { "store_id": store.objectId, "patron_id": patron.objectId, "sender_name": patron.get_fullname(), "subject": subject, "body": body, }) def feedback_id(feedback_tr): return feedback_tr.find_element_by_css_selector(\ "a").get_attribute("href").split("/")[-1] def feedback_unread(feedback_tr): """ check parse if the fb is unread """ fb_id = feedback_id(feedback_tr) store.set("receivedMessages", None) msg = store.get("receivedMessages", objectId=fb_id) if msg and len(msg) > 0: return not msg[0].is_read return False ########## Cloud code send_feedback works try: parts[1]['success'] = send_feedback( "feedback #1", "body #1").get("result") == "success" except Exception as e: print e parts[1]['test_message'] = str(e) ########## Notification badge appears if there are ### unread feedbacks try: sleep(COMET_PULL_RATE * 2 + 2) parts[2]['success'] = test.element_exists("#messages-nav " +\ "a div.nav-item-badge") except Exception as e: print e parts[2]['test_message'] = str(e) ########## A new row appears when feedback is received try: test.find("#tab-feedback").click() feedbacks =\ test.find("#tab-body-feedback div.tr", multiple=True) parts[3]['success'] = len(feedbacks) > 0 except Exception as e: print e parts[3]['test_message'] = str(e) ########## Feedback is initially unread (dashboard) try: parts[4]['success'] =\ feedbacks[0].get_attribute("class").__contains__("unread") except Exception as e: print e parts[4]['test_message'] = str(e) ########## Feedback is in store's ReceivedMessages ### relation and is initially unread try: parts[5]['success'] = feedback_unread(feedbacks[0]) except Exception as e: print e parts[5]['test_message'] = str(e) ########## Clicking the row redirects user to the ### feedback detail page try: fb_id = feedback_id(feedbacks[0]) feedbacks[0].find_element_by_css_selector("a").click() sleep(2) parts[6]['success'] = test.is_current_url(reverse(\ "feedback_details", args=(fb_id,))) except Exception as e: print e parts[6]['test_message'] = str(e) ########## Clicking back to feedback inbox redirects ### user back to messages index with feedback tab active try: test.find("#back_to_feedback").click() sleep(1) parts[7]['success'] =\ test.find("#tab-feedback").get_attribute(\ "class").__contains__("active") except Exception as e: print e parts[7]['test_message'] = str(e) ########## Feedback is now read (dashboard) try: feedbacks =\ test.find("#tab-body-feedback div.tr", multiple=True) parts[8]['success'] = not feedbacks[0].get_attribute(\ "class").__contains__("unread") except Exception as e: print e parts[8]['test_message'] = str(e) ########## Feedback is now read (Parse) try: parts[9]['success'] = not feedback_unread(feedbacks[0]) except Exception as e: print e parts[9]['test_message'] = str(e) ########## Clicking reply redirects user to feedback reply page try: fb_id = feedback_id(feedbacks[0]) feedbacks[0].find_element_by_css_selector("a").click() sleep(2) test.find("#reply-button").click() sleep(1) parts[10]['success'] = test.is_current_url(reverse(\ "feedback_reply", args=(fb_id,))) except Exception as e: print e parts[10]['test_message'] = str(e) ########## Reply body is required. try: test.find("#body").send_keys(" ") test.find("#reply-form-submit").click() sleep(2) parts[11]['success'] = test.find("div.notification.hide " +\ "div").text == "Please enter a message." except Exception as e: print e parts[11]['test_message'] = str(e) ########## Replying redirects user back to feedback details try: test.find("#body").send_keys("Hey") test.find("#reply-form-submit").click() parts[12]['success'] = test.is_current_url(reverse(\ "feedback_details", args=(fb_id,)) +\ "?%s" % urlencode({'success':\ 'Reply has been sent.'})) sleep(5) except Exception as e: print e parts[12]['test_message'] = str(e) ########## The reply is visible try: parts[13]['success'] = test.find("#reply-box " +\ "div.sect.body").text == "Hey" except Exception as e: print e parts[13]['test_message'] = str(e) ########## The reply message is saved in the store's ### sent messages relation with message_type of feedback try: test.find("#back_to_feedback").click() sleep(1) store.set("sentMessages", None) store.set("receivedMessages", None) parts[14]['success'] = len( store.get("sentMessages", objectId=store.get("receivedMessages", objectId=fb_id)[0].Reply, message_type=FEEDBACK)) > 0 except Exception as e: print e parts[14]['test_message'] = str(e) ########## The reply message is saved in the Patron's ### received messages relation wrapped in a Message Status try: patron.set("receivedMessages", None) parts[15]['success'] = len( patron.get("receivedMessages", Message=fb_id)) > 0 except Exception as e: print e parts[15]['test_message'] = str(e) ########## A feedback with a reply does not have a reply button try: feedbacks =\ test.find("#tab-body-feedback div.tr", multiple=True) feedbacks[0].find_element_by_css_selector("a").click() sleep(2) parts[16]['success'] = not test.element_exists(\ "#reply-form-submit") except Exception as e: print e parts[16]['test_message'] = str(e) ########## Clicking delete message prompts the user ### to confirm the deletion try: test.find("#delete-button").click() sleep(1) alert = test.switch_to_alert() parts[17]['success'] = alert.text ==\ "Are you sure you want to delete this feedback thread?" except Exception as e: print e parts[17]['test_message'] = str(e) ########## The user is redirected to messages index ### with feedback tab active try: alert.accept() sleep(4) parts[18]['success'] =\ test.find("#tab-feedback").get_attribute(\ "class").__contains__("active") except Exception as e: print e parts[18]['test_message'] = str(e) ########## Deleting the reply only removes the message ### from the store's sent messages relation try: store.set("receivedMessages", None) parts[19]['success'] = not store.get( "receivedMessages", objectId=fb_id, message_type=FEEDBACK) except Exception as e: print e parts[19]['test_message'] = str(e) ########## The deleted feedback is no longer in the table try: test.find("#tab-feedback").click() sleep(1) feedbacks =\ test.find("#tab-body-feedback div.tr a[href='%s']" %\ (fb_id,), multiple=True) parts[20]['success'] = len(feedbacks) == 0 except Exception as e: print e parts[20]['test_message'] = str(e) ########## Multiple feedbacks (testing 3 here) ### can appear at the same time try: send_feedback("feedback #2", "body #2") send_feedback("feedback #3", "body #3") send_feedback("feedback #4", "body #4") sleep(COMET_PULL_RATE * 3 + 4) feedbacks =\ test.find("#tab-body-feedback div.tr a", multiple=True) parts[21]['success'] = len(feedbacks) == 3 except Exception as e: print e parts[21]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_messages(): # TODO test that patrons are getting the messages!!! # setup account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription # set subscriptionType to free subscription.subscriptionType = 0 subscription.update() # clear the sent messages relation sent_messages = store.get("sentMessages", keys="") if sent_messages: store.remove_relation("SentMessages_", [m.objectId for m in sent_messages]) store.set("sentMessages", None) # we can clear the list locally but just re-pull from parse account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, # FIRST {'test_name': "Send message. Filter all. No offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # SECOND {'test_name': "Send message. Filter all. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # THIRD {'test_name': "Send message. Filter idle. No offer. " +\ "Message limit passed (free) dialog appears"}, # LIMIT PASSED {'test_name': "Upgrading account from the dialog sends the " +\ "message and upgrades the account to middle"}, {'test_name': "Email is sent notifying user the upgrade"}, # {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # FOURTH {'test_name': "Send message. Filter idle. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # FIFTH {'test_name': "Send message. Filter most_loyal. No offer. " +\ "Message limit passed (middle) dialog appears"}, # LIMIT PASSED {'test_name': "Upgrading account from the dialog sends the" +\ " message and upgrades the account to heavy"}, {'test_name': "Email is sent notifying user the upgrade"}, # {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # SIXTH {'test_name': "Send message. Filter most_loyal. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # SEVENTH {'test_name': "Send message. Filter all. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # EIGHTH {'test_name': "Send message. Filter all. With offer"}, {'test_name': "Message is in store's sentMessages relation"}, {'test_name': "Message is visible in page"}, {'test_name': "Message can be view by clicking on row"}, # NINTH {'test_name': "Send message. Filter all. No offer. " +\ "Message limit passed (heavy) dialog appears"}, # LIMIT PASSED {'test_name': "Account can no longer be upgraded." +\ "Message cannot be sent. Clicking okay redirects "+\ "user to messages index."}, # {'test_name': "Subject is required"}, {'test_name': "Body is required"}, {'test_name': "Offer title not required if attach offer off"}, {'test_name': "Expiration not required if attach offer off"}, {'test_name': "Offer title is required if attach offer on"}, {'test_name': "Expiration date required if attach offer on"}, {'test_name': "Expiration date must be at a later date"}, {'test_name': "Expiration date must be at most 1 year later"}, ] section = { "section_name": "Sending messages works?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("messages_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("messages_index")) # login selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(5) def send_message( filter, subject, body, attach_offer=False, offer_title=None, exp_date=None, ): """ Must be called at messages index page """ test.find("#create_message").click() sleep(1) # set the filter test.find("//select[@id='filter']/option[@value='%s']" %\ (filter,), type="xpath").click() # subject test.find("#id_subject").send_keys(subject) # body test.find("#id_body").send_keys(body) # attach_offer if attach_offer: test.find("#id_attach_offer").click() # offer title if offer_title: test.find("#id_offer_title").send_keys(offer_title) # exp_date if exp_date: test.find("#id_date_offer_expiration").send_keys(exp_date) # submit test.find("#send-now").click() sleep(5) def message_in_relation(message_id, test_number): if not message_id: return store.sentMessages = None parts[test_number]['success'] = store.get("sentMessages", objectId=message_id, count=1, limit=0) == 1 def message_in_page(message_id, test_number): if not message_id: return try: rows = test.find("#tab-body-sent div.tr a", multiple=True) for row in rows: if row.get_attribute("href").split("/")[5] ==\ message_id: parts[test_number]['success'] = True except Exception as e: print e parts[test_number]['test_message'] = str(e) def message_viewable(message_id, test_number): if not message_id: return href = reverse("message_details", args=(message_id, )) try: test.find("#tab-body-sent div.tr a[href='%s']" %\ (href,)).click() sleep(2) parts[test_number]['success'] = test.is_current_url(href) except Exception as e: print e parts[test_number]['test_message'] = str(e) finally: # must go back to messages index for the other tests test.open(reverse("messages_index")) # FIRST ########## Send message. Filter all. No offer. message_id = None try: send_message("all", "msg #1", "body #1") parts[1]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[1]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 2) ########## Message is visible in page. message_in_page(message_id, 3) ########## Message can be view by clicking on row. message_viewable(message_id, 4) # SECOND ########## Send message. Filter all. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("all", "msg #2", "body #2", True, "offer#2", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[5]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[5]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 6) ########## Message is visible in page. message_in_page(message_id, 7) ########## Message can be view by clicking on row. message_viewable(message_id, 8) # THIRD ########## Send message. Filter idle. No offer. ### Message limit passed (free) dialog appears. message_id = None try: send_message("idle", "msg #3", "body #3") parts[9]['success'] = test.find("#upgrade") is not None except Exception as e: print e parts[9]['test_message'] = str(e) test.open(reverse("messages_index")) # LIMIT PASSED ########## Upgrading account from the dialog sends the ### message and upgrades the account to middle. try: test.find("#upgrade").click() sleep(2) test.find("#id_cc_cvv").send_keys("123") test.find("#id_recurring").click() test.find("#update-form-submit").click() sleep(5) message_id = test.driver.current_url.split("/")[5] subscription.subscriptionType = None parts[10]['success'] = test.is_current_url(\ reverse("message_details", args=(message_id,))) and\ subscription.get("subscriptionType") == 1 except Exception as e: print e parts[10]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) # open the mail connection if SeleniumTest.CHECK_SENT_MAIL: mail = Mail() ########## Email is sent notifying user the upgrade. try: parts[11]['success'] = mail.is_mail_sent(\ EMAIL_UPGRADE_SUBJECT) except Exception as e: print e parts[11]['test_message'] = str(e) else: parts[11]['success'] = parts[10]['success'] ########## Message is in store's sentMessages relation. message_in_relation(message_id, 12) ########## Message is visible in page. message_in_page(message_id, 13) ########## Message can be view by clicking on row. message_viewable(message_id, 14) # FOURTH ########## Send message. Filter idle. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("idle", "msg #4", "body #4", True, "offer#4", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[15]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[15]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 16) ########## Message is visible in page. message_in_page(message_id, 17) ########## Message can be view by clicking on row. message_viewable(message_id, 18) # FIFTH ########## Send message. Filter most_loyal. No offer. ### Message limit passed (free) dialog appears. message_id = None try: send_message("most_loyal", "msg #5", "body #5") parts[19]['success'] = test.find("#upgrade") is not None except Exception as e: print e parts[19]['test_message'] = str(e) test.open(reverse("messages_index")) # LIMIT PASSED ########## Upgrading account from the dialog sends the ### message and upgrades the account to heavy. try: test.find("#upgrade").click() sleep(2) test.find("#id_cc_cvv").send_keys("123") test.find("#id_recurring").click() test.find("#update-form-submit").click() sleep(5) message_id = test.driver.current_url.split("/")[5] subscription.subscriptionType = None parts[20]['success'] = test.is_current_url(\ reverse("message_details", args=(message_id,))) and\ subscription.get("subscriptionType") == 2 except Exception as e: print e parts[20]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Email is sent notifying user the upgrade. if SeleniumTest.CHECK_SENT_MAIL: try: parts[21]['success'] = mail.is_mail_sent(\ EMAIL_UPGRADE_SUBJECT) except Exception as e: print e parts[21]['test_message'] = str(e) else: parts[21]['success'] = parts[20]['success'] ########## Message is in store's sentMessages relation. message_in_relation(message_id, 22) ########## Message is visible in page. message_in_page(message_id, 23) ########## Message can be view by clicking on row. message_viewable(message_id, 24) # SIXTH ########## Send message. Filter most_loyal. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("most_loyal", "msg #6", "body #6", True, "offer#6", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[25]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[25]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 26) ########## Message is visible in page. message_in_page(message_id, 27) ########## Message can be view by clicking on row. message_viewable(message_id, 28) # SEVENTH ########## Send message. Filter all. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("all", "msg #7", "body #7", True, "offer#7", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[29]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[29]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 30) ########## Message is visible in page. message_in_page(message_id, 31) ########## Message can be view by clicking on row. message_viewable(message_id, 32) # EIGHTH ########## Send message. Filter all. With offer. message_id = None try: exp_date = timezone.now() + relativedelta(days=1) send_message("all", "msg #8", "body #8", True, "offer#8", exp_date.strftime(DATE_PICKER_STRFTIME)) parts[33]['success'] = len(test.find(\ "div.notification.success", multiple=True)) > 0 message_id = test.driver.current_url.split("/")[5] except Exception as e: print e parts[33]['test_message'] = str(e) finally: # must go back to messages index test.open(reverse("messages_index")) ########## Message is in store's sentMessages relation. message_in_relation(message_id, 34) ########## Message is visible in page. message_in_page(message_id, 35) ########## Message can be view by clicking on row. message_viewable(message_id, 36) # NINTH ########## Send message. Filter all. With offer. ### Message limit passed (heavy) dialog appears. message_id = None try: send_message("all", "msg #9", "body #9") parts[37]['success'] = test.element_exists("#maxed_out") except Exception as e: print e parts[37]['test_message'] = str(e) test.open(reverse("messages_index")) # LIMIT PASSED ########## Account can no longer be upgraded. Msg cannot be sent. ### Clicking Okay redirects user to messages index. try: test.find("#maxed_out").click() sleep(1) parts[38]['success'] =\ test.is_current_url(reverse("messages_index")) except Exception as e: print e parts[38]['test_message'] = str(e) test.open(reverse("messages_index")) # # goto edit message page test.find("#create_message").click() sleep(2) selectors = ( ("#id_subject", " "), ("#id_body", " "), ) test.action_chain(0, selectors, action="send_keys") test.find("#send-now").click() sleep(1) ########## Subject is required. try: parts[39]['success'] = test.find("#subject_e ul li").text ==\ "This field is required." except Exception as e: print e parts[39]['test_message'] = str(e) ########## Body is required. try: parts[40]['success'] = test.find("#body_e ul li").text ==\ "This field is required." except Exception as e: print e parts[40]['test_message'] = str(e) ########## Offer title not required if attach offer off. try: parts[41]['success'] = not test.element_exists(\ "#offer_title_e ul li") except Exception as e: print e parts[41]['test_message'] = str(e) ########## Expiration not required if attach offer off. try: parts[42]['success'] = not test.element_exists(\ "#date_offer_expiration_e ul li") except Exception as e: print e parts[42]['test_message'] = str(e) test.find("#id_attach_offer").click() test.find("#send-now").click() sleep(1) ########## Offer title is required if attach offer on. try: parts[43]['success'] =\ test.find("#offer_title_e ul li").text ==\ "Please enter a title." except Exception as e: print e parts[43]['test_message'] = str(e) ########## Expiration date required if attach offer on. try: parts[44]['success'] =\ test.find("#date_offer_expiration_e ul li").text ==\ "Please enter an expiration date." except Exception as e: print e parts[44]['test_message'] = str(e) ########## Expiration date must be at a later date. try: # don't click attach offer again! # test.find("#id_attach_offer").click() exp_date = timezone.now() + relativedelta(days=-1) test.find("#id_date_offer_expiration").send_keys(\ exp_date.strftime(DATE_PICKER_STRFTIME)) test.find("#send-now").click() sleep(1) parts[45]['success'] = test.find(\ "#date_offer_expiration_e ul li").text ==\ "Please enter an expiration date that is later than today." except Exception as e: print e parts[45]['test_message'] = str(e) ########## Expiration date must be at most 1 year later. try: # don't click attach offer again! # test.find("#id_attach_offer").click() exp_date = timezone.now() + relativedelta(days=367) date_offer = test.find("#id_date_offer_expiration") date_offer.clear() date_offer.send_keys(\ exp_date.strftime(DATE_PICKER_STRFTIME)) test.find("#send-now").click() sleep(2) parts[46]['success'] = test.find(\ "#date_offer_expiration_e ul li").text ==\ "Please enter an expiration date that is less than a year." except Exception as e: print e parts[46]['test_message'] = str(e) # END OF ALL TESTS - cleanup if SeleniumTest.CHECK_SENT_MAIL: mail.logout() return test.tear_down()
def test_rewards(): # setup account = Account.objects().get(username=TEST_USER['username'], include="Store") store = account.store # start with no rewards store.rewards = [] store.update() test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Having no rewards shows a placeholder row"}, {'test_name': "Adding a reward works"}, {'test_name': "The new reward is saved to parse"}, {'test_name': "Redemption count starts at 0"}, {'test_name': "Reward id starts at 0"}, {'test_name': "Updating a reward works"}, {'test_name': "The updated reward is saved to parse"}, {'test_name': "The updated reward retains the reward_id"}, {'test_name': "The updated reward retains the " +\ "redemption_count"}, {'test_name': "Clicking delete brings up a confirmation " +\ "dialog"}, {'test_name': "Deleting a reward works"}, {'test_name': "The deleted reward is deleted from parse"}, {'test_name': "Reward name is required"}, {'test_name': "Punches is required"}, {'test_name': "Description is not required"}, {'test_name': "Clicking cancel redirects user " +\ "back to rewards index"}, {'test_name': "Punches must be a number"}, {'test_name': "Punches must be greater than 0"}, {'test_name': "Rewards are initially sorted by Punches " +\ "from least to greatest"}, {'test_name': "Punches is sortable"}, {'test_name': "Name is sortable"}, {'test_name': "Updating a reward with the reset redemption" +\ " count option resets the redemption count to 0"}, ] section = { "section_name": "Rewards page working properly?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("rewards_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("rewards_index")) # login selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(7) ########## Having no rewards shows a placeholder row try: parts[1]['success'] =\ test.find("//div[@id='rewards_section']/div[@class=" +\ "'tr reward']/div[@class='td reward_summary']/span[1]", type="xpath").text == "No Rewards" except Exception as e: print e parts[1]['test_message'] = str(e) def add_reward(name, description, punches): test.find("#add_reward").click() sleep(1) selectors = ( ("#id_reward_name", name), ("#id_description", description), ("#id_punches", str(punches)), ) test.action_chain(0, selectors, action="send_keys") test.find("#submit-reward-form").click() sleep(5) reward1_name = "Reward #1" reward1_description = "First reward" reward1_punches = 5 ########## Adding a reward works try: add_reward(reward1_name, reward1_description, reward1_punches) parts[2]['success'] = test.find("//div[@id='0']/a/div[2]" +\ "/span[1]", type="xpath").text == reward1_name except Exception as e: print e parts[2]['test_message'] = str(e) ########## The new reward is saved to parse try: store.rewards = None reward = store.get("rewards")[0] parts[3]['success'] = reward['reward_name'] ==\ reward1_name and reward['description'] ==\ reward1_description and\ reward['punches'] == reward1_punches except Exception as e: print e parts[3]['test_message'] = str(e) ########## Redemption count starts at 0 try: parts[4]['success'] = reward['redemption_count'] == 0 except Exception as e: print e parts[4]['test_message'] = str(e) ########## Redemption count starts at 0 try: parts[5]['success'] = reward['reward_id'] == 0 except Exception as e: print e parts[5]['test_message'] = str(e) # let's add 3 more rewards! reward2_name = "reward dos" reward2_description = "DOS" reward2_punches = 10 reward3_name = "reward tres" reward3_description = "TRES" reward3_punches = 12 reward4_name = "reward quatro" reward4_description = "QUATRO" reward4_punches = 15 add_reward(reward2_name, reward2_description, reward2_punches) add_reward(reward3_name, reward3_description, reward3_punches) add_reward(reward4_name, reward4_description, reward4_punches) ################ reward1_name = "reward uno" reward1_description = "UNO" reward1_punches = 1 ########## Updating a reward works try: test.find("//div[@id='0']/a", type="xpath").click() sleep(1) selectors = ( ("#id_reward_name", reward1_name), ("#id_description", reward1_description), ("#id_punches", str(reward1_punches)), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#submit-reward-form").click() sleep(4) parts[6]['success'] = test.find("//div[@id='0']/a/div[2]" +\ "/span[1]", type="xpath").text == reward1_name except Exception as e: print e parts[6]['test_message'] = str(e) ########## The updated reward is saved to parse try: store.rewards = None reward = store.get("rewards")[0] # list is sorted by punches parts[7]['success'] = reward['reward_name'] ==\ reward1_name and\ reward['description'] == reward1_description and\ reward['punches'] == reward1_punches except Exception as e: print e parts[7]['test_message'] = str(e) ########## The updated reward retains the reward_id try: parts[8]['success'] = reward['reward_id'] == 0 except Exception as e: print e parts[8]['test_message'] = str(e) ########## The updated reward retains the redemption_count try: parts[9]['success'] = reward['redemption_count'] == 0 except Exception as e: print e parts[9]['test_message'] = str(e) ########## Clicking delete brings up a confirmation dialog try: test.find("//div[@id='0']/a", type="xpath").click() sleep(1) test.find("#delete-link").click() alert = test.switch_to_alert() parts[10]['success'] = alert is not None except Exception as e: print e parts[10]['test_message'] = str(e) ########## Deleting a reward works try: alert.accept() sleep(5) parts[11]['success'] = test.find("//div[@id='1']/a/div[2]" +\ "/span[1]", type="xpath").text == reward2_name try: # first reward should be gone test.find("//div[@id='0']/a/div[2]" +\ "/span[1]", type="xpath").text except Exception: parts[11]['success'] = parts[11]['success'] else: parts[11]['success'] = False except Exception as e: print e parts[11]['test_message'] = str(e) ########## The deleted reward is deleted from parse try: store.rewards = None rewards = store.get("rewards") parts[12]['success'] = reward1_name not in\ [r['reward_name'] for r in rewards] and\ 0 not in [r['reward_id'] for r in rewards] except Exception as e: print e parts[12]['test_message'] = str(e) # field required add_reward(" ", "", "") ########## Reward name is required try: parts[13]['success'] =\ test.find("#reward_name_ic ul li").text ==\ "This field is required." except Exception as e: print e parts[13]['test_message'] = str(e) ########## Punches is required try: parts[14]['success'] =\ test.find("#punches_ic ul li").text ==\ "This field is required." except Exception as e: print e parts[14]['test_message'] = str(e) ########## Description is not required try: parts[15]['success'] =\ not test.element_exists("#description_ic ul li") except Exception as e: print e parts[15]['test_message'] = str(e) ########## Clicking cancel redirects user back to rewards index try: test.find("//div [@id='edit-reward-options']/a[2]", type="xpath").click() sleep(2) parts[16]['success'] =\ test.is_current_url(reverse("rewards_index")) except Exception as e: print e parts[16]['test_message'] = str(e) ########## Punches must be a number try: add_reward("", "", "ba") parts[17]['success'] =\ test.find("#punches_ic ul li").text ==\ "Enter a whole number." test.find("//div [@id='edit-reward-options']/a[2]", type="xpath").click() sleep(2) except Exception as e: print e parts[17]['test_message'] = str(e) ########## Punches must be greater than 0 try: add_reward("", "", "0") parts[18]['success'] =\ test.find("#punches_ic ul li").text ==\ "Ensure this value is greater than or equal to 1." test.find("//div [@id='edit-reward-options']/a[2]", type="xpath").click() sleep(2) except Exception as e: print e parts[18]['test_message'] = str(e) ########## Rewards are initially sorted by Punchess ### from least to greatest try: store.rewards = None rewards = store.get('rewards') punches_map = {r['punches']: r for r in rewards} ascending = [r['punches'] for r in rewards] descending = ascending[:] ascending.sort() descending.sort(reverse=True) success = True for i in range(3): if int( test.find("//div[@id='%s']/a/div[1]" % (str(i + 1), ), type="xpath").text) != ascending[i]: success = False break parts[19]['success'] = success except Exception as e: print e parts[19]['test_message'] = str(e) ########## Punches is sortable try: test.find("#header-reward_punches").click() rows = test.find("//div[@id='rewards_section']/" +\ "div[contains(@class, 'reward')]", type="xpath", multiple=True) if len(rows) == len(descending): success = True for i in range(len(rows)): # check both the punches and id row = rows[i] if int(row.text.split("\n")[0]) !=\ descending[i] or int(row.get_attribute("id")) !=\ punches_map[descending[i]]['reward_id']: success = False break parts[20]['success'] = success except Exception as e: print e parts[20]['test_message'] = str(e) ########## Name is sortable try: name_map = {r['reward_name']: r for r in rewards} ascending = [r['reward_name'] for r in rewards] descending = ascending[:] ascending.sort() descending.sort(reverse=True) # ascending order test.find("#header-reward_summary").click() rows = test.find("//div[@id='rewards_section']/" +\ "div[contains(@class, 'reward')]", type="xpath", multiple=True) if len(rows) == len(ascending): success1 = True for i in range(len(rows)): # check both the name and id row = rows[i] if row.text.split("\n")[1] !=\ ascending[i] or int(row.get_attribute("id")) !=\ name_map[ascending[i]]['reward_id']: success1 = False break # descending order test.find("#header-reward_summary").click() rows = test.find("//div[@id='rewards_section']/" +\ "div[contains(@class, 'reward')]", type="xpath", multiple=True) if len(rows) == len(descending): success2 = True for i in range(len(rows)): # check both the name and id row = rows[i] if row.text.split("\n")[1] !=\ descending[i] or int(row.get_attribute("id")) !=\ name_map[descending[i]]['reward_id']: success2 = False break parts[21]['success'] = success1 and success2 except Exception as e: print e parts[21]['test_message'] = str(e) ########## Updating a reward with the reset redemption ### count option resets the redemption count to 0 try: # logout test.logout() test.dev_login() sleep(1) # modify store the rewards redemption count store.rewards = None for r in store.get("rewards"): r['redemption_count'] = 99 store.update() # login test.open(reverse("rewards_index")) # ACTION! sleep(1) selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(7) # now test test.find("//div[@id='2']/a", type="xpath").click() sleep(1) red_count = int(test.find("#redemption_count").text.split(" ")[1]) test.find("#reset_red_count").click() test.find("#submit-reward-form").click() sleep(5) test.find("//div[@id='2']/a", type="xpath").click() new_red_count =\ int(test.find("#redemption_count").text.split(" ")[1]) parts[22]['success'] = new_red_count == 0 and red_count !=\ new_red_count except Exception as e: print e parts[22]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def create_random_stores(self, amount): for i in range(amount): print "Creating store %s" % (str(i),) # create the store street, city, state, zip, country, phone_number =\ self.addrs[i].split(", ") first_name, last_name = self.owners[i].split(" ") neighborhood = self.neighborhoods[i] store_name = self.stores[i] store_i = STORE.copy() store_location_i = STORE_LOCATION.copy() # create the thumbnaiil and cover (same image different size) self.get_store_location_image(i) thumbnail = create_png(TMP_IMG_PATH, IMAGE_THUMBNAIL_SIZE) while "error" in image: print "Retrying create_png" thumbnail = create_png(TMP_IMG_PATH) cover = create_png(TMP_IMG_PATH) while "error" in cover: print "Retrying create_png" cover = create_png(TMP_IMG_PATH) store_i.update({ "store_name": store_name, "first_name": first_name, "last_name": last_name, "thumbnail_image": thumbnail.get("name"), "cover_image": cover.get("name"), }) store_location_i.update({ "street": street, "city": city, "state": state, "zip": zip, "neighborhood": neighborhood, "country": country, "phone_number": phone_number, "coordinates": self.get_random_coordinates(), }) # create the store store = Store.objects().create(**store_i) # create the store location store_location = StoreLocation(**store_location_i) store_location.Store = store.objectId store_location.update() # create the settings settings = Settings.objects().create(Store=store.objectId) # create the subscription subscription =\ Subscription.objects().create(Store=store.objectId, date_last_billed=timezone.now()) # create the user email = first_name+str(randint(0, 99))+USER_EMAIL_POSTFIX email = email.lower() acc = Account.objects().create(\ username=email, email=email, password=USER_PASSWORD, Store=store.objectId) if not acc.objectId: raise Exception("Account creation failed.") # link the store store.Settings = settings.objectId store.Subscription = subscription.objectId store.owner_id = acc.objectId store.ACL[acc.objectId] = {"read": True,"write": True} store.store_locations = [store_location] store.update()
def test_settings(): # setup account = Account.objects().get(username=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings # set punches facebook and employees to 1 store.punches_facebook = 1 settings.punches_employee = 1 store.update() settings.update() test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Changes to Punches employee are visible"}, {'test_name': "Changes to Punches facebook are visible"}, {'test_name': "Changes to Punches employee are saved to Parse"}, {'test_name': "Changes to Punches facebook are saved to Parse"}, {'test_name': "Punches employee is required"}, {'test_name': "Punches facebook is required"}, {'test_name': "Punches employee must be a number"}, {'test_name': "Punches facebook must be a number."}, {'test_name': "Punches employee must be greater than 0"}, {'test_name': "Punches facebook must be greater than or = 0"}, {'test_name': "Retailer PIN is refreshable"}, {'test_name': "Changes to Retailer PIN is immediately " +\ "commited to Parse without having to save settings."}, {'test_name': "Clicking cancle redirects user back to " +\ "settings page"}, {'test_name': "Clicking cancel changes will not undo the " +\ "change made to Retailer PIN"}, {'test_name': "Clicking cancel changes will not save " +\ "changes to punches facebook and punches employee"}, ] section = { "section_name": "Settings page working properly?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("store_settings")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("store_settings")) # login selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(5) try: selectors = ( ("#id_punches_employee", "5"), ("#id_punches_facebook", "5"), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#settings-form-submit").click() sleep(5) except Exception as e: print e ########## Changes to Punches employee are visible try: parts[1]['success'] = test.find(\ "#id_punches_employee").get_attribute("value") == "5" except Exception as e: print e parts[1]['test_message'] = str(e) ########## Changes to Punches facebook are visible try: parts[2]['success'] = test.find(\ "#id_punches_facebook").get_attribute("value") == "5" except Exception as e: print e parts[2]['test_message'] = str(e) ########## Changes to Punches employee are saved to Parse try: settings.punches_employee = None parts[3]['success'] = settings.get("punches_employee") ==\ int(test.find("#id_punches_employee").get_attribute("value")) except Exception as e: print e parts[3]['test_message'] = str(e) ########## Changes to Punches facebook are saved to Parse try: store.punches_facebook = None parts[4]['success'] = store.get("punches_facebook") ==\ int(test.find("#id_punches_facebook").get_attribute("value")) except Exception as e: print e parts[4]['test_message'] = str(e) try: selectors = ("#id_punches_employee", "#id_punches_facebook") test.action_chain(0, selectors, action="clear") test.find("#settings-form-submit").click() sleep(1) except Exception: pass ########## Punches employee is required try: parts[5]['success'] =\ test.find("#punches_employee_e ul li").text ==\ "This field is required." except Exception as e: print e parts[5]['test_message'] = str(e) ########## Punches facebook is required try: parts[6]['success'] =\ test.find("#punches_facebook_e ul li").text ==\ "This field is required." except Exception as e: print e parts[6]['test_mesage'] = str(e) try: selectors = ( ("#id_punches_employee", "a"), ("#id_punches_facebook", "b"), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#settings-form-submit").click() sleep(1) except Exception: pass ########## Punches employee must be a number try: parts[7]['success'] =\ test.find("#punches_employee_e ul li").text==\ "Enter a whole number." except Exception as e: print e parts[7]['test_message'] = str(e) ########## Punches facebook must be a number try: parts[8]['success'] =\ test.find("#punches_facebook_e ul li").text==\ "Enter a whole number." except Exception as e: print e parts[8]['test_message'] = str(e) try: selectors = ( ("#id_punches_employee", "-1"), ("#id_punches_facebook", "-1"), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#settings-form-submit").click() sleep(1) except Exception: pass ########## Punches employee must be greater than 0 try: parts[9]['success'] =\ test.find("#punches_employee_e ul li").text ==\ "Ensure this value is greater than or equal to 1." except Exception as e: print e parts[9]['test_message'] = str(e) ########## Punches facebook must be greater than or equal to 0 try: parts[10]['success'] =\ test.find("#punches_facebook_e ul li").text ==\ "Ensure this value is greater than or equal to 0." except Exception as e: print e parts[10]['test_message'] = str(e) ########## Retailer PIN is refreshable try: prev_pin = test.find("#retailer_pin").text test.find("#link_refresh_retailer_pin").click() sleep(10) # yea this takes a while new_pin = test.find("#retailer_pin").text parts[11]['success'] = prev_pin != new_pin except Exception as e: print e parts[11]['test_message'] = str(e) ########## Changes to Retailer PIN is immediately ### commited to Parse without having to save settings try: settings.retailer_pin = None parts[12]['success'] = settings.get("retailer_pin") == new_pin except Exception as e: print e parts[12]['test_message'] = str(e) ########## Clicking cancel redirects user back to settings page try: current_pin = test.find("#retailer_pin").text test.find("//div[@id='settings-options']/a[2]", type="xpath").click() sleep(1) parts[13]['success'] =\ test.is_current_url(reverse("store_settings")) except Exception as e: print e parts[13]['test_message'] = str(e) ########## Clicking cancel changes will not undo the ### change made to Retailer PIN try: parts[14]['success'] = current_pin ==\ test.find("#retailer_pin").text except Exception as e: print e parts[14]['test_message'] = str(e) ########## Clicking cancel changes will not save ### changes to punches facebook and punches employee try: current_ep =\ test.find("#id_punches_employee").get_attribute("value") current_fbp =\ test.find("#id_punches_facebook").get_attribute("value") test.find("//div[@id='settings-options']/a[2]", type="xpath").click() sleep(1) parts[15]['success'] = current_ep == test.find(\ "#id_punches_employee").get_attribute("value") and\ current_fbp == test.find(\ "#id_punches_facebook").get_attribute("value") except Exception as e: print e parts[15]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_update_subscription(): # TODO test place_order account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription subscription.update_locally(SUBSCRIPTION_INFO, False) subscription.update() test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Update account page reachable"}, {'test_name': "Changes to first name are visible"}, {'test_name': "Changes to first name are saved to parse"}, {'test_name': "Changes to last name are visible"}, {'test_name': "Changes to last name are saved to parse"}, {'test_name': "Changes to card number are visible"}, {'test_name': "Changes to card number are saved to parse"}, {'test_name': "A paypal credit card id is generated & saved"}, {'test_name': "Changes to cc expiration are visible"}, {'test_name': "Changes to cc expiration are saved to parse"}, {'test_name': "Changes to address are visible"}, {'test_name': "Changes to address are saved to parse"}, {'test_name': "Changes to city are visible"}, {'test_name': "Changes to city are saved to parse"}, {'test_name': "Changes to state are visible"}, {'test_name': "Changes to state are saved to parse"}, {'test_name': "Changes to zip are visible"}, {'test_name': "Changes to zip are saved to parse"}, {'test_name': "First name is required"}, {'test_name': "Last name is required"}, {'test_name': "Card number is required"}, {'test_name': "Security code (cvc) is required"}, {'test_name': "Address is required"}, {'test_name': "City is required"}, {'test_name': "State is required"}, {'test_name': "Zip is required"}, {'test_name': "ToS checked is required"}, {'test_name': "Invalid credit card number shows error"}, {'test_name': "Past expiration date is invalid"}, {'test_name': "Only the last 4 digits of the card number" +\ " are shown"}, {'test_name': "Not changing the card number does not " +\ "generate new paypal credit card id"}, ] section = { "section_name": "Edit account/subscription working properly?", "parts": parts, } self.results.append(section) ########## User needs to be logged in to access page self.open(reverse("store_index")) sleep(1) parts[0]['success'] = self.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("store_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) self.action_chain(0, selectors, "send_keys") sleep(7) ########## Update account page reachable try: self.find("//div[@id='account-options']/a[1]", type="xpath").click() sleep(3) parts[1]['success'] =\ self.is_current_url(reverse("subscription_update")) except Exception as e: print e parts[1]['test_message'] = str(e) ## Make changes # first clear all inputs for el in self.find("input[type='text']", multiple=True): el.clear() selectors = ( ("#id_first_name", TEST_SUBSCRIPTION_INFO['first_name']), ("#id_last_name", TEST_SUBSCRIPTION_INFO['last_name']), ("#id_cc_number", TEST_SUBSCRIPTION_INFO['cc_number']), ("#id_cc_cvv", "905"), ("#id_address", TEST_SUBSCRIPTION_INFO['address']), ("#id_city", TEST_SUBSCRIPTION_INFO['city']), ("#id_state", TEST_SUBSCRIPTION_INFO['state']), ("#id_zip", TEST_SUBSCRIPTION_INFO['zip']), ) self.action_chain(0, selectors, action="send_keys") month_el =\ self.find("//select[@id='id_date_cc_expiration_month']/" +\ "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].month),), type="xpath") year_el =\ self.find("//select[@id='id_date_cc_expiration_year']/" +\ "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].year),), type="xpath") month = month_el.get_attribute("value") year = year_el.get_attribute("value") month_el.click() year_el.click() self.find("#id_recurring").click() self.find("#update-form-submit").click() sleep(5) # back to update account page self.find("//div[@id='account-options']/a[1]", type="xpath").click() sleep(3) ########## Changes to first name are visible parts[2]['success'] =\ self.find("#id_first_name").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['first_name'] ########## Changes to first name are saved to parse subscription.first_name = None parts[3]['success'] = subscription.get("first_name") ==\ TEST_SUBSCRIPTION_INFO['first_name'] ########## Changes to last name are visible parts[4]['success'] =\ self.find("#id_last_name").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['last_name'] ########## Changes to last name are saved to parse subscription.last_name = None parts[5]['success'] = subscription.get("last_name") ==\ TEST_SUBSCRIPTION_INFO['last_name'] ########## Changes to card number are visible parts[6]['success'] =\ self.find("#id_cc_number").get_attribute("value")[-4:] ==\ TEST_SUBSCRIPTION_INFO['cc_number'][-4:] ########## Changes to card number are saved to parse subscription.cc_number = None parts[7]['success'] = subscription.get("cc_number") ==\ TEST_SUBSCRIPTION_INFO['cc_number'][-4:] ########## A paypal credit card id is generated & saved # CARD-97223025G70599255KHHCCVQ subscription.pp_cc_id = None parts[8]['success'] = subscription.get("pp_cc_id").__contains__(\ "CARD") and len(subscription.get("pp_cc_id")) == 29 ########## Changes to cc expiration are visible parts[9]['success'] = month == self.get_selected("//select" +\ "[@id='id_date_cc_expiration_month']/option", type="xpath").get_attribute("value") and\ year == self.get_selected(\ "//select[@id='id_date_cc_expiration_year']/option", type="xpath").get_attribute("value") ########## Changes to cc expiration are saved to parse subscription.date_cc_expiration = None exp = subscription.get("date_cc_expiration") parts[10]['success'] = exp.month == TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].month and exp.year ==\ TEST_SUBSCRIPTION_INFO['date_cc_expiration'].year ########## Changes to address are visible parts[11]['success'] =\ self.find("#id_address").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['address'] ########## Changes to address are saved to parse subscription.address = None parts[12]['success'] = subscription.get("address") ==\ TEST_SUBSCRIPTION_INFO['address'] ########## Changes to city are visible parts[13]['success'] =\ self.find("#id_city").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['city'] ########## Changes to city are saved to parse subscription.city = None parts[14]['success'] = subscription.get("city") ==\ TEST_SUBSCRIPTION_INFO['city'] ########## Changes to state are visible self.find("//select[@id='id_date_cc_expiration_year']/" +\ "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].year)), type="xpath") parts[15]['success'] =\ self.find("#id_state").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['state'] ########## Changes to state are saved to parse subscription.state = None parts[16]['success'] = subscription.get("state") ==\ TEST_SUBSCRIPTION_INFO['state'] ########## Changes to zip are visible parts[17]['success'] =\ self.find("#id_zip").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['zip'] ########## Changes to zip are saved to parse subscription.zip = None parts[18]['success'] = subscription.get("zip") ==\ TEST_SUBSCRIPTION_INFO['zip'] ## Make changes selectors = [ "#id_first_name", "#id_last_name", "#id_cc_number", "#id_cc_cvv", "#id_address", "#id_city", "#id_state", "#id_zip", ] self.action_chain(0, selectors, action="clear") for i in range(len(selectors)): selectors[i] = (selectors[i], " ") self.action_chain(0, selectors, action="send_keys") self.find("#update-form-submit").click() sleep(3) ########## First name is required ########## Last name is required ########## Card number is required ########## Security code (cvc) is required ########## Address is required ########## City is required ########## State is required ########## Zip is required ########## ToS checked is required def field_is_required(part, selector, message="This field is required."): try: parts[part]['success'] = self.find(selector).text==message except Exception as e: print e parts[part]['test_message'] = str(e) selectors = ( (19, "#first_name_ic ul.errorlist li"), (20, "#last_name_ic ul.errorlist li"), (21, "#card_number_container ul.errorlist li", "Enter a valid credit card number."), (22, "#cc_cvv_ic ul.errorlist li"), (23, "#address_ic ul.errorlist li"), (24, "#city_ic ul.errorlist li"), (25, "#state_ic ul.errorlist li"), (26, "#zip_ic ul.errorlist li"), (27, "#recurring_charge_container ul.errorlist li", "You must accept the Terms & Conditions to continue."), ) for selector in selectors: field_is_required(*selector) ########## Invalid credit card number shows error try: cc_number = self.find("#id_cc_number") cc_number.clear() cc_number.send_keys("8769233313929990") self.find("#update-form-submit").click() sleep(3) parts[28]['success'] = self.find("#card_number_container " +\ "ul.errorlist li").text ==\ "Enter a valid credit card number." except Exception as e: print e parts[28]['test_message'] = str(e) ########## Past expiration date is invalid if timezone.now().month == 1: # note that if this test is being run on a January, this will # fail so to prevent that just skip the test if it is January parts[29]['test_message'] = "READ ME. This test has been " +\ "skipped because the month is January, which means " +\ "that this test will always fail due to limited " +\ "select options." else: try: # select january of this year. self.find("//select[@id='id_date_cc_expiration_month']/" +\ "option[@value='1']", type="xpath").click() self.find("//select[@id='id_date_cc_expiration_year']/" +\ "option[@value='%s']" %\ (str(timezone.now().year),), type="xpath").click() self.find("#update-form-submit").click() sleep(3) parts[29]['success'] =\ self.find("#date_cc_expiration_ic ul.errorlist " +\ "li").text == "Your credit card has expired!" except Exception as e: print e parts[29]['test_message'] = str(e) ########## Only the last 4 digits of the card number are shown try: self.find("//div[@class='form-options']/a[2]", type="xpath").click() sleep(1) self.find("//div[@id='account-options']/a[1]", type="xpath").click() sleep(3) masked_number =\ self.find("#id_cc_number").get_attribute("value") parts[30]['success'] = masked_number[:-4] ==\ "************" and str(masked_number[-4:]).isdigit() except Exception as e: print e parts[30]['test_message'] = str(e) ########## Not changing the card number does not ###### generate new paypal credit card id try: subscription.pp_cc_id = None cc_id = subscription.get("pp_cc_id") self.find("#id_cc_cvv").send_keys("123") self.find("#id_recurring").click() self.find("#update-form-submit").click() sleep(5) subscription.pp_cc_id = None parts[31]['success'] = cc_id == subscription.get("pp_cc_id") except Exception as e: print e parts[31]['test_message'] = str(e) # END OF ALL TESTS - cleanup return self.tear_down()
def sign_up(request): """ Creates User, store, subscription, and settings objects. """ # renders the signup page on GET and returns a json object on POST. data = {'sign_up_nav': True} if request.method == 'POST': # this conversion to a regular dictionay is important postDict = request.POST.dict() from_associated_account = False # check if this post is from the associated account dialog # if it is then skip form validations aaf_nonce_id = postDict.get('aaf-nonce') aaf_account_id = postDict.get('aaf-account_id') if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0: aa_nonce = AssociatedAccountNonce.objects.filter(\ id=aaf_nonce_id, account_id=aaf_account_id) if len(aa_nonce) > 0 and aa_nonce[0].verified: aa_nonce[0].delete() from_associated_account = True # some keys are repeated so must catch this at init store_form = StoreSignUpForm(request.POST) store_location_form = StoreLocationForm(request.POST) account_form = AccountSignUpForm(request.POST) cats = postDict.get("categories") category_names = None if cats and len(cats) > 0: category_names = cats.split("|")[:-1] # make sure that there are only up to 2 categories while len(category_names) > 2: category_names.pop() data["category_names"] = category_names if not from_associated_account: all_forms_valid = store_form.is_valid() and\ store_location_form.is_valid() and account_form.is_valid() else: all_forms_valid = True if all_forms_valid: # check if email already taken here to handle the case where # the user already has a patron/employee account # but also want to sign up for a Store account if hasattr(account_form, "associated_account"): aa = account_form.associated_account aan = AssociatedAccountNonce.objects.create(\ account_id=aa.objectId) return HttpResponse(json.dumps({"associated_account":\ aa.objectId, "associated_account_nonce":aan.id, "email": aa.email, "code": 0}), content_type="application/json") ######################################################### # create store store = Store(**postDict) # set defaults for these guys to prevent # ParseObjects from making parse calls repeatedly store.punches_facebook = 1 store.set("rewards", []) store.set("categories", []) if category_names: for name in category_names: alias = Category.objects.filter(name__iexact=name) if len(alias) > 0: store.categories.append({ "alias": alias[0].alias, "name": name }) # create settings settings = Settings(Store=store.objectId) store.set('settings', settings) # create account if not from_associated_account: account = Account(**postDict) # username = email # we should be doing this in the form but ehh account.set("username", postDict['email'].strip().lower()) account.set("email", postDict['email'].strip().lower()) account.set_password(postDict.get('password')) else: account =\ Account.objects().get(objectId=aaf_account_id) account.set("store", store) # create subscription subscription = Subscription() subscription.subscriptionType = 0 subscription.date_last_billed = timezone.now() subscription.create() # create settings settings.create() # create store store.Settings = settings.objectId store.Subscription = subscription.objectId store.create() # add the pointer to the created store settings.Store = store.objectId settings.update() subscription.Store = store.objectId subscription.update() # create the store location store_location = StoreLocation(**postDict) # format the phone number store_location.store_timezone =\ rputils.get_timezone(postDict.get("zip")).zone store_location.set("hours", []) # coordinates and neighborhood # the call to get map data is actually also in the clean full_address = " ".join(\ store_location.get_full_address().split(", ")) map_data = rputils.get_map_data(full_address) store_location.set("coordinates", map_data.get("coordinates")) store_location.set("neighborhood", store_location.get_best_fit_neighborhood(\ map_data.get("neighborhood"))) store_location.phone_number =\ format_phone_number(postDict["phone_number"]) store_location.Store = store.objectId store_location.create() # add the StoreLocation to the relation store.store_locations = [store_location] store.update() # create account account.Store = store.objectId if not from_associated_account: account.create() else: account.update() # create the store ACL with the account having r/w access store.ACL = { "*": { "read": True, "write": True }, account.objectId: { "read": True, "write": True }, } store.owner_id = account.objectId store.update() # note that username has been fed the email # this shouldn't change anything though shouldn't matter # need to put username and pass in request postDict['username'] = account.username postDict['password'] = account.password # send matt and new user a pretty email. send_email_signup(account) # auto login user_login = login(request, postDict, no_recaptcha=True) if user_login != None: data = {"code": -1} # response to signup.js - not login returns # 0 - Associated account already exists # 2 - subscription is not active # 3 - success (login now) if type(user_login) is int: # subscription not active data['code'] = 2 else: # required for datetime awareness! rputils.set_timezone(request, tz) data['code'] = 3 return HttpResponse(json.dumps(data), content_type="application/json") else: store_form = StoreSignUpForm() store_location_form = StoreLocationForm() account_form = AccountSignUpForm() data['store_form'] = store_form data['store_location_form'] = store_location_form data['account_form'] = account_form return render(request, 'public/signup.djhtml', data)
def handle(self, *args, **options): # for logging when ran by CRON print "Running detect_suspicious_activity: " + str(timezone.now()) # first count the number of active stores store_count = Store.objects().count(active=True) # store_count = Store.objects().count(objectId="o72LmDy0YK") end = timezone.now() start = end + relativedelta(hours=-24) conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() # to send to the admins admin_chunks = [] # get 500 stores at a time LIMIT, skip = 500, 0 while store_count > 0: for store in Store.objects().filter(active=True, include="store_locations", limit=LIMIT, skip=skip, order="createdAt"): # for store in Store.objects().filter(\ # objectId="o72LmDy0YK", include="store_locations"): ### CHUNK1 #################################### chunk1, account_patron, patron_punch = {}, {}, {} total_punches = [] # check approved EMPLOYEES employees = store.get("employees", status=APPROVED, limit=900) employee_punches = [] def add_to_patron_punch(punch, employee=None): if punch.Patron not in patron_punch: patron_punch[punch.Patron] =\ [{"punch":punch, "employee": employee}] else: patron_punch[punch.Patron].append({"punch":\ punch, "employee":employee}) def get_location(location_id): for loc in store.store_locations: if loc.objectId == location_id: return loc if employees and len(employees) > 0: # check all the punches of each employee for employee in employees: # get all the punches for today punches = employee.get("punches", limit=900, createdAt__lte=end, createdAt__gte=start) if not punches: continue # for querying the dashboard punches employee_punches.extend([p.objectId for p in\ punches]) # group the punches by patron for punch in punches: add_to_patron_punch(punch, employee) # now check DASHBOARD punches = store.get("punches", limit=900, createdAt__lte=end, createdAt__gte=start, objectId__nin=employee_punches) # group the punches by patron if punches: for punch in punches: add_to_patron_punch(punch, None) # check for a group with a list >= 6 for key, val in patron_punch.iteritems(): suspicious_punches = [] if val and len(val) >= 6: for punch in val: suspicious_punches.append({ "store_location":\ get_location(punch["punch"].store_location_id), "punch": punch["punch"], "employee": punch["employee"] }) # cache the account and patron if key not in account_patron: acc = Account.objects().get(Patron=key, include="Patron") account_patron[key] = { "account": acc, "patron": acc.patron, } if key not in chunk1: chunk1[key] = { "account":\ account_patron[key]['account'], "patron":\ account_patron[key]['patron'], "punches": suspicious_punches } else: chunk1[key]['punches'].extend(suspicious_punches) ### CHUNK2 #################################### # hours per location # punches are still grouped per patron chunk2 = {} for loc in store.store_locations: if loc.hours and len(loc.hours) > 0 and\ loc.hours[0]['day'] != 0: # 24/7 # check for punches out of hours tz = pytz.timezone(loc.store_timezone) start = timezone.localtime(start, tz) end = timezone.localtime(end, tz) # isoweekday is from 1-7 monday to sunday # convert to 1-7 sunday to saturday day1_weekday = (start.isoweekday()) % 7 + 1 day2_weekday = (end.isoweekday()) % 7 + 1 # get the hours for day1 and day2 def get_hours_range(weekday, d): for hr in loc.hours: if hr["day"] == weekday: hr_start_hour =\ int(hr["open_time"][:2]) hr_start_minute =\ int(hr["open_time"][2:]) hr_end_hour =\ int(hr["close_time"][:2]) hr_end_minute =\ int(hr["close_time"][2:]) return d.replace(hour=hr_start_hour, minute=hr_start_minute),\ d.replace(hour=hr_end_hour, minute=hr_end_minute) return None, None (hours1_start, hours1_end) =\ get_hours_range(day1_weekday, start) (hours2_start, hours2_end) =\ get_hours_range(day2_weekday, end) # now convert to utc since punch times are in utc if hours1_start: hours1_start =\ timezone.localtime(hours1_start, tzutc()) hours1_end =\ timezone.localtime(hours1_end, tzutc()) if hours2_start: hours2_start =\ timezone.localtime(hours2_start, tzutc()) hours2_end =\ timezone.localtime(hours2_end, tzutc()) for key, val in patron_punch.iteritems(): if not val: continue suspicious_punches = [] # process only those punches that are in this location for p in [ x for x in val if x["punch"].store_location_id == loc.objectId ]: punch = p["punch"] # suspicious if not in hours1 and 2 if not (hours1_start and\ punch.createdAt>hours1_start and\ punch.createdAt<hours1_end) and\ not (hours2_start and\ punch.createdAt>hours2_start and\ punch.createdAt<hours2_end): # not in hours1 or 2 so suspicious! suspicious_punches.append({ "store_location": loc, "punch": punch, "employee": p["employee"], }) if len(suspicious_punches) == 0: continue # cache the account and patron if key not in account_patron: acc = Account.objects().get(Patron=key, include="Patron") account_patron[key] = { "account": acc, "patron": acc.patron, } if key not in chunk2: chunk2[key] = { "account":\ account_patron[key]['account'], "patron":\ account_patron[key]['patron'], "punches": suspicious_punches } else: chunk2[key]['punches'].extend( suspicious_punches) # all tasks are done for this store - send email if len(chunk1) > 0 or len(chunk2) > 0: store_acc = Account.objects().get(Store=store.objectId) admin_chunks.append({ "store_acc": store_acc, "store": store, "data": (chunk1, chunk2), }) try: send_email_suspicious_activity(store_acc, store, chunk1, chunk2, conn) except SMTPServerDisconnected: conn = mail.get_connection(fail_silently=(not DEBUG)) conn.open() send_email_suspicious_activity(store_acc, store, chunk1, chunk2, conn) # end of while loop store_count -= LIMIT skip += LIMIT if len(admin_chunks) > 0: send_email_suspicious_activity_admin(admin_chunks, start, end, conn) # everything is done. close the connection try: conn.close() except Exception: pass
def test_employees(): """ Tests for employee approve, deny, remove, details. etc. """ # TODO test employee graph # TODO test employee punches history # delete the employees and associated User objects in the relation account = Account.objects().get(username=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings emps = store.get("employees") if emps: for emp in emps: Account.objects().get(Employee=emp.objectId).delete() emp.delete() store.set("employees", None) test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Cloud code register_employee works"}, {'test_name': "Employee is saved in store's Employees " +\ "relation"}, {'test_name': "Employee is initially pending (Parse)"}, {'test_name': "Employee is initially pending (Dashboard)"}, {'test_name': "Email must be valid (cloud code)"}, {'test_name': "Email must be unique (cloud code)"}, {'test_name': "Username must be unique (cloud code)"}, {'test_name': "Retailer PIN must exist (cloud code)"}, {'test_name': "Clicking deny prompts the user to confirm"}, {'test_name': "The user is redirected to employee index"}, {'test_name': "The denied employee is removed from the " +\ "pending table"}, {'test_name': "The employee is deleted from parse"}, {'test_name': "The account/user is deleted from parse"}, {'test_name': "Approving the employee moves it from " +\ "pending to approved"}, {'test_name': "Employee status is set to approved in Parse"}, {'test_name': "Employee initially has 0 punches."}, {'test_name': "Clicking on the approved employee row " +\ " redirects user to employee edit page"}, {'test_name': "Clicking delete prompts the user to confirm"}, {'test_name': "The user is redirected to employee index"}, {'test_name': "The deleted employee is removed from the " +\ "pending table"}, {'test_name': "The employee is deleted from parse"}, {'test_name': "The account/user is deleted from parse"}, {'test_name': "Multiple employees (3) registering at once" +\ " shows up in dashboard"}, ] section = { "section_name": "Employees page working properly?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page" test.open(reverse("employees_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("employees_index")) # login selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(7) def register_employee(first_name, last_name, username=None, password=None, email=None, retailer_pin=None): if username is None: username = first_name if password is None: password = first_name if email is None: email = first_name + "@" + last_name + ".com" if retailer_pin is None: retailer_pin = settings.retailer_pin return cloud_call( "register_employee", { "first_name": first_name, "last_name": last_name, "username": username, "password": password, "email": email, "retailer_pin": retailer_pin, }) first_name, last_name, username, email =\ "vandolf1", "estrellado", "*****@*****.**", "*****@*****.**" ########## Cloud code register_employee works" try: res = register_employee(first_name, last_name, username, email=email) parts[1]['success'] = "error" not in res except Exception as e: print e parts[1]['test_message'] = str(e) ########## Employee is saved in store's Employees relation" try: emp = store.get("employees")[0] parts[2]['success'] = emp is not None except Exception as e: print e parts[2]['test_message'] = str(e) ########## Employee is initially pending (Parse)" try: parts[3]['success'] = emp.status == PENDING except Exception as e: print e parts[3]['test_message'] = str(e) ########## Employee is initially pending (Dashboard)" try: sleep(COMET_PULL_RATE * 2 + 1) # wait for dashboard to receive test.find("#tab-pending-employees").click() parts[4]['success'] = test.element_exists(\ "#tab-body-pending-employees div.tr div.td.approve") except Exception as e: print e parts[4]['test_message'] = str(e) ########## Email must be valid (cloud code)" try: res = register_employee("vman", "vman", email="vmahs@vman") parts[5]['success'] = res['error'] == 'EMAIL_INVALID' except Exception as e: print e parts[5]['test_message'] = str(e) ########## Email must be unique (cloud code) " try: res = register_employee("vman", "vman", email=email) parts[6]['success'] = res['error'] == 'EMAIL_TAKEN' except Exception as e: print e parts[6]['test_message'] = str(e) ########## Username must be unique (cloud code) " try: res = register_employee("vman", "vman", username=username) parts[7]['success'] = res['error'] == 'USERNAME_TAKEN' except Exception as e: print e parts[7]['test_message'] = str(e) ########## Retailer PIN must exist (cloud code) " try: res = register_employee("vman", "vman", retailer_pin="sdgdgs") parts[8]['success'] = res['error'] == "RETAILER_PIN_INVALID" except Exception as e: print e parts[8]['test_message'] = str(e) ########## Clicking deny prompts the user to confirm" try: test.find("#tab-pending-employees").click() test.find("#tab-body-pending-employees div.tr " +\ "div.td.approve a.deny").click() alert = test.switch_to_alert() parts[9]['success'] = alert.text == "Deny employee?" except Exception as e: print e parts[9]['test_message'] = str(e) ########## The user is redirected to employee index" try: sleep(1) alert.accept() sleep(2) parts[10]['success'] = test.is_current_url(reverse(\ "employees_index") +\ "?show_pending&success=Employee+has+been+denied.") except Exception as e: print e parts[10]['test_message'] = str(e) ########## The denied employee is removed from the pending table" try: parts[11]['success'] = not test.element_exists(\ "#tab-body-pending-employees div.tr " +\ "div.td.approve a.approve") except Exception as e: print e parts[11]['test_message'] = str(e) ########## The employee is deleted from parse" try: store.set("employees", None) parts[12]['success'] = store.get("employees",\ first_name=first_name, last_name=last_name, count=1) == 0 except Exception as e: print e parts[12]['test_message'] = str(e) ########## The account/user is deleted from parse" try: parts[13]['success'] = Account.objects().count(\ username=username, email=email) == 0 except Exception as e: print e parts[13]['test_message'] = str(e) ########## Approving the employee moves it from pending to approved" try: register_employee(first_name, last_name, username, email=email) sleep(COMET_PULL_RATE * 2 + 1) # wait for dashboard to receive test.find("#tab-pending-employees").click() approveRow = test.find("#tab-body-pending-employees " +\ "div.tr") approveId = approveRow.get_attribute("id") approveRow.find_element_by_css_selector(\ "div.td.approve a.approve").click() sleep(1) test.switch_to_alert().accept() sleep(2) test.find("#tab-approved-employees").click() parts[14]['success'] = test.element_exists(\ "#tab-body-approved-employees " +\ "div.tr div.td.remove a") except Exception as e: print e parts[14]['test_message'] = str(e) ########## Employee status is set to approved in Parse" try: store.set("employees", None) emp = store.get("employees", first_name=first_name, last_name=last_name)[0] parts[15]['success'] = emp.status == APPROVED except Exception as e: print e parts[15]['test_message'] = str(e) ########## Employee initially has 0 punches" try: parts[16]['success'] = emp.lifetime_punches == 0 except Exception as e: print e parts[16]['test_message'] = str(e) ########## Clicking on the approved employee row ### redirects user to employee edit page try: test.find("#tab-approved-employees").click() test.find("#tab-body-approved-employees div#%s a" %\ (emp.objectId,)).click() sleep(1) parts[17]['success'] = test.is_current_url(reverse(\ "employee_edit", args=(emp.objectId,))) except Exception as e: print e parts[17]['test_message'] = str(e) ########## Clicking delete prompts the user to confirm" try: test.find("#delete-button").click() alert = test.switch_to_alert() parts[18]['success'] = alert.text ==\ "Are you sure you want to delete this employee?" except Exception as e: print e parts[18]['test_message'] = str(e) ########## The user is redirected to employee index" try: sleep(1) alert.accept() sleep(2) parts[19]['success'] = test.is_current_url(reverse(\ "employees_index") +\ "?success=Employee+has+been+deleted.") except Exception as e: print e parts[19]['test_message'] = str(e) ########## The deleted employee is removed from the pending table" try: parts[20]['success'] = not test.element_exists(\ "#tab-body-approved-employees div#%s a" %(emp.objectId,)) except Exception as e: print e parts[20]['test_message'] = str(e) ########## The employee is deleted from parse" try: store.set("employees", None) parts[21]['success'] = store.get("employees", objectId=emp.objectId, count=1) == 0 except Exception as e: print e parts[21]['test_message'] = str(e) ########## The account/user is deleted from parse" try: parts[22]['success'] = Account.objects().count(\ username=username, email=email) == 0 except Exception as e: print e parts[22]['test_message'] = str(e) ########## Multiple employees (4) registering at once ### shows up in dashboard" try: for i in range(3): register_employee(first_name + str(i), last_name + str(i)) sleep(COMET_PULL_RATE * 2 + 3) test.find("#tab-pending-employees").click() parts[23]['success'] = len(test.find(\ "#tab-body-pending-employees div.tr " +\ "div.td.approve a.approve", multiple=True)) == 3 except Exception as e: print e parts[23]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def sign_up(request): """ Creates User, store, subscription, and settings objects. """ # renders the signup page on GET and returns a json object on POST. data = {'sign_up_nav': True} if request.method == 'POST': # this conversion to a regular dictionay is important postDict = request.POST.dict() from_associated_account = False # check if this post is from the associated account dialog # if it is then skip form validations aaf_nonce_id = postDict.get('aaf-nonce') aaf_account_id = postDict.get('aaf-account_id') if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0: aa_nonce = AssociatedAccountNonce.objects.filter(\ id=aaf_nonce_id, account_id=aaf_account_id) if len(aa_nonce) > 0 and aa_nonce[0].verified: aa_nonce[0].delete() from_associated_account = True # some keys are repeated so must catch this at init store_form = StoreSignUpForm(request.POST) store_location_form = StoreLocationForm(request.POST) account_form = AccountSignUpForm(request.POST) cats = postDict.get("categories") category_names = None if cats and len(cats) > 0: category_names = cats.split("|")[:-1] # make sure that there are only up to 2 categories while len(category_names) > 2: category_names.pop() data["category_names"] = category_names if not from_associated_account: all_forms_valid = store_form.is_valid() and\ store_location_form.is_valid() and account_form.is_valid() else: all_forms_valid = True if all_forms_valid: # check if email already taken here to handle the case where # the user already has a patron/employee account # but also want to sign up for a Store account if hasattr(account_form, "associated_account"): aa = account_form.associated_account aan = AssociatedAccountNonce.objects.create(\ account_id=aa.objectId) return HttpResponse(json.dumps({"associated_account":\ aa.objectId, "associated_account_nonce":aan.id, "email": aa.email, "code": 0}), content_type="application/json") ######################################################### # create store store = Store(**postDict) # set defaults for these guys to prevent # ParseObjects from making parse calls repeatedly store.punches_facebook = 1 store.set("rewards", []) store.set("categories", []) if category_names: for name in category_names: alias = Category.objects.filter(name__iexact=name) if len(alias) > 0: store.categories.append({ "alias":alias[0].alias, "name":name }) # create settings settings = Settings(Store=store.objectId) store.set('settings', settings) # create account if not from_associated_account: account = Account(**postDict) # username = email # we should be doing this in the form but ehh account.set("username", postDict['email'].strip().lower()) account.set("email", postDict['email'].strip().lower()) account.set_password(postDict.get('password')) else: account =\ Account.objects().get(objectId=aaf_account_id) account.set("store", store) # create subscription subscription = Subscription() subscription.subscriptionType = 0 subscription.date_last_billed = timezone.now() subscription.create() # create settings settings.create() # create store store.Settings = settings.objectId store.Subscription = subscription.objectId store.create() # add the pointer to the created store settings.Store = store.objectId settings.update() subscription.Store = store.objectId subscription.update() # create the store location store_location = StoreLocation(**postDict) # format the phone number store_location.store_timezone =\ rputils.get_timezone(postDict.get("zip")).zone store_location.set("hours", []) # coordinates and neighborhood # the call to get map data is actually also in the clean full_address = " ".join(\ store_location.get_full_address().split(", ")) map_data = rputils.get_map_data(full_address) store_location.set("coordinates", map_data.get("coordinates")) store_location.set("neighborhood", store_location.get_best_fit_neighborhood(\ map_data.get("neighborhood"))) store_location.phone_number =\ format_phone_number(postDict["phone_number"]) store_location.Store = store.objectId store_location.create() # add the StoreLocation to the relation store.store_locations = [store_location] store.update() # create account account.Store = store.objectId if not from_associated_account: account.create() else: account.update() # create the store ACL with the account having r/w access store.ACL = { "*": {"read": True, "write": True}, account.objectId: {"read": True, "write": True}, } store.owner_id = account.objectId store.update() # note that username has been fed the email # this shouldn't change anything though shouldn't matter # need to put username and pass in request postDict['username'] = account.username postDict['password'] = account.password # send matt and new user a pretty email. send_email_signup(account) # auto login user_login = login(request, postDict, no_recaptcha=True) if user_login != None: data = {"code":-1} # response to signup.js - not login returns # 0 - Associated account already exists # 2 - subscription is not active # 3 - success (login now) if type(user_login) is int: # subscription not active data['code'] = 2 else: # required for datetime awareness! rputils.set_timezone(request, tz) data['code'] = 3 return HttpResponse(json.dumps(data), content_type="application/json") else: store_form = StoreSignUpForm() store_location_form = StoreLocationForm() account_form = AccountSignUpForm() data['store_form'] = store_form data['store_location_form'] = store_location_form data['account_form'] = account_form return render(request, 'public/signup.djhtml', data)
def test_punch(): """ Tests for punch customers section of the workbench. Assumes that at least 1 PatronStore exists for the above Store. """ account = Account.objects().get(username=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings ps = store.get("patronStores", include="Patron", limit=1)[0] patron = ps.patron test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Punching works"}, {'test_name': "PatronStore punch_count is updated"}, {'test_name': "PatronStore all_time_punches is updated"}, {'test_name': "Punch Code is required"}, {'test_name': "Punch Codes consist of only numbers"}, {'test_name': "Punch Codes are 5 characters long"}, {'test_name': "Amount of punches is required"}, {'test_name': "Amount should not exceed maximum employee punches allowed"}, {'test_name': "Amount must be greater than 0"}, {'test_name': "Non-existent Punch Code shows approprirate message"}, ] section = { "section_name": "Punch working properly?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("workbench_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("workbench_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(5) def punch(punch_code="", punch_amount="", sleep_prior=0, sleep_after=0): if sleep_prior > 0: sleep(sleep_prior) test.find("#punch_code").clear() test.find("#punch_amount").clear() test.find("#punch_code").send_keys(punch_code) test.find("#punch_amount").send_keys(punch_amount) test.find("#punch-form a.button.blue").click() if sleep_after > 0: sleep(sleep_after) ########## Punching works try: punch_count, all_time_punches =\ ps.punch_count, ps.all_time_punches punch(patron.punch_code, "1", sleep_after=3) parts[1]['success'] =\ test.find("#punch-notification") is not None except Exception as e: print e parts[1]['test_message'] = str(e) ########## PatronStore punch_count is updated try: ps.punch_count = None parts[2]['success'] = punch_count+1 == ps.get("punch_count") except Exception as e: print e parts[2]['test_message'] = str(e) ########## PatronStore all_time_punches is updated try: ps.all_time_punches = None parts[3]['success'] =\ all_time_punches+1 == ps.get("all_time_punches") except Exception as e: print e parts[3]['test_message'] = str(e) ########## Punch Code is required try: punch(sleep_prior=5, sleep_after=1) parts[4]['success'] =\ test.find("#punch-notification").text ==\ "Please enter the customer's punch code." except Exception as e: print e parts[4]['test_message'] = str(e) ########## Punch Codes consist of only numbers try: punch("123ab", sleep_prior=5, sleep_after=1) parts[5]['success'] =\ test.find("#punch-notification").text ==\ "Punch Codes consist of only numbers." except Exception as e: print e parts[5]['test_message'] = str(e) ########## Punch Codes are 5 characters long try: punch("123", sleep_prior=5, sleep_after=1) parts[6]['success'] =\ test.find("#punch-notification").text ==\ "Punch Codes are 5 characters long." except Exception as e: print e parts[6]['test_message'] = str(e) ########## Amount of punches is required try: punch(patron.punch_code, sleep_prior=5, sleep_after=1) parts[7]['success'] =\ test.find("#punch-notification").text ==\ "Please enter the number of punches to give." except Exception as e: print e parts[7]['test_message'] = str(e) ########## Amount should not exceed maximum employee punches allowed try: punch(patron.punch_code, str(settings.punches_employee+1), sleep_prior=5, sleep_after=1) parts[8]['success'] =\ test.find("#punch-notification").text ==\ "Maximum amount of punches is %s." % (str(settings.punches_employee),) except Exception as e: print e parts[8]['test_message'] = str(e) ########## Amount must be greater than 0 try: punch(patron.punch_code, "-1", sleep_prior=5, sleep_after=1) parts[9]['success'] =\ test.find("#punch-notification").text ==\ "Amount of punches must be greater than 0." except Exception as e: print e parts[9]['test_message'] = str(e) ########## Non-existent Punch Code shows approprirate message try: punch("39393", "1", sleep_prior=5, sleep_after=1) parts[10]['success'] =\ test.find("#punch-notification").text ==\ "A customer with that Punch Code was not found." pass except Exception as e: print e parts[10]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_employee_access(): """ Tests for employee dashboard access. This tests any user with ACL of ACCESS_PUNCHREDEEM and NO_ACCESS. Tests for ACCESS_ADMIN are not necessary since all other tests involving the store owner covers it. """ # delete the employees and associated User objects in the relation account = Account.objects().get(email=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings emps = store.get("employees") if emps: for emp in emps: Account.objects().get(Employee=emp.objectId).delete() emp.delete() store.set("employees", None) test = SeleniumTest() parts = [ {"test_name" : "Pending employee has no access"}, {"test_name" : "Approved employee initially not in store ACL"}, {"test_name" : "Employee with ACCESS_NONE cannot login " +\ "using the login dialog"}, {"test_name" : "Employee with ACCESS_NONE cannot login " +\ "using the dedicated login page"}, {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\ "login to the dashboard through the login dialog"}, {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\ "login to the dashboard through the dedicated dialog pg"}, {"test_name" : "Account settings accessible"}, {"test_name" : "No store edit button"}, {"test_name" : "Requesting edit store detail through url " +\ "redirects user to store index"}, {"test_name" : "No update subscription button"}, {"test_name" : "Requesting update subscription through url " +\ "redirects user to store index"}, {"test_name" : "No deactivate my store button"}, {"test_name" : "Requesting store deactivation through url " +\ "redirects user to store index"}, {"test_name" : "Rewards accessible"}, {"test_name" : "No create new reward button"}, {"test_name" : "Requesting create new reward through url " +\ "redirects user to rewards index"}, {"test_name" : "Rewards are not clickable"}, {"test_name" : "Requesting edit reward through url " +\ "redirects user to rewards index"}, {"test_name" : "Messages accessible"}, {"test_name" : "No create new message button"}, {"test_name" : "Requesting create new message through url " +\ "redirects user to messages index"}, {"test_name" : "Sent messages are viewable"}, {"test_name" : "Feedbacks are viewable"}, {"test_name" : "No reply button"}, {"test_name" : "Requesting reply through url " +\ "redirects user to messages index"}, {"test_name" : "No delete message button"}, {"test_name" : "Requesting delete message through url " +\ "redirects user to messages index"}, {"test_name" : "Analysis accessible"}, {"test_name" : "Employees accessible"}, {"test_name" : "No register new employee button"}, {"test_name" : "Requesting new employee registration"+\ "redirects user to employees_index"}, {"test_name" : "Approved employees are not clickable"}, {"test_name" : "Requesting edit employee through url " +\ "redirects user to employees index"}, {"test_name" : "No remove button in approved employees"}, {"test_name" : "Requesting remove employee through url " +\ "redirects user to employees index"}, {"test_name" : "No deny button in pending employees"}, {"test_name" : "Requesting deny employee through url " +\ "redirects user to employees index"}, {"test_name" : "No approve button in pending employees"}, {"test_name" : "Requesting approve employee through url " +\ "redirects user to employees index"}, {"test_name" : "Settings accessible"}, {"test_name" : "No refresh button for retailer pin"}, {"test_name" : "Requesting refresh through url returns " +\ "a json object with error Permission denied"}, {"test_name" : "Punches employee is readonly"}, {"test_name" : "Punches facebook is readonly"}, {"test_name" : "No save button"}, {"test_name" : "No cancel changes button"}, {"test_name" : "Workbench accessible"}, {"test_name" : "Employee can punch"}, {"test_name" : "Employee can reject redeem"}, {"test_name" : "Employee can validate redeem"}, ] section = { "section_name":\ "Employee dashboard access working as expected?", "parts": parts, } test.results.append(section) try: # register the test employee register_employee("employee", "ex", TEST_EMPLOYEE['username'], TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], settings.retailer_pin) sleep(3) employee_acc = Account.objects().get(username=TEST_EMPLOYEE[\ 'username'], include="Employee") employee = employee_acc.employee except Exception as e: print e ########## Pending employee has no access try: test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index")) parts[0]['success'] =\ test.find("#dialog-login-message").text ==\ "You are not yet approved." except Exception as e: print e parts[0]['test_message'] = str(e) try: # login to approve test.login(TEST_USER['username'], TEST_USER['password'], reverse("employees_index")) # approve test.find("#tab-pending-employees").click() approveRow = test.find("#tab-body-pending-employees " +\ "div.tr") approveRow.find_element_by_css_selector(\ "div.td.approve a.approve").click() sleep(1) test.switch_to_alert().accept() sleep(2) test.logout() except Exception as e: print e ########## Approved employee initially not in store ACL try: # store.ACL = None cannot retrieve Parse built-ins! account = Account.objects().get(email=TEST_USER['username'], include="Store.Settings") store = account.store parts[1]['success'] = employee_acc.objectId not in store.ACL except Exception as e: print e parts[1]['test_message'] = str(e) ########## Employee with ACCESS_NONE cannot login ### using the login dialog try: test.dev_login() test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password']) parts[2]['success'] =\ test.find("#dialog-login-message").text ==\ "You do not have permission to access the dashboard." except Exception as e: print e parts[2]['test_message'] = str(e) ########## Employee with ACCESS_NONE cannot login ### using the dedicated login page try: test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index")) parts[3]['success'] =\ test.find("#dialog-login-message").text ==\ "You do not have permission to access the dashboard." except Exception as e: print e parts[3]['test_message'] = str(e) ### Update the store's ACL store.ACL = {"*": {"read": True, "write": True}} store.set_access_level(employee_acc, ACCESS_PUNCHREDEEM[0]) store.update() test.new_driver(False) ########## Employee with ACCESS_PUNCHREDEEM can ### login to the dashboard through the login dialog try: test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], final_sleep=6) parts[4]['success'] = test.is_current_url(reverse("store_index")) test.logout() except Exception as e: print e parts[4]['test_message'] = str(e) ########## Employee with ACCESS_PUNCHREDEEM can ### login to the dashboard through the dedicated dialog page try: test.dev_login() test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index"), final_sleep=6) parts[5]['success'] = test.is_current_url(reverse("employees_index")) sleep(4) except Exception as e: print e parts[5]['test_message'] = str(e) ########## Account settings accessible try: test.find("#header-right a").click() sleep(2) parts[6]['success'] = test.is_current_url(reverse("account_edit")) except Exception as e: print e parts[6]['test_message'] = str(e) ########## No edit store detail button try: test.open(reverse("store_index")) sleep(2) test.set_to_implicit_wait(False) try: test.find("#store-details a[href='%s']" % (reverse("store_edit"), )) except NoSuchElementException: parts[7]['success'] = True except Exception as e: print e parts[7]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting edit store detail through url ### redirects user to store details try: test.open(reverse("store_edit")) sleep(2) parts[8]['success'] = test.is_current_url(reverse("store_index")+\ "?" + urlencode({'error': "Permission denied"})) except Exception as e: print e parts[8]['test_message'] = str(e) ########## No update subscription button try: test.set_to_implicit_wait(False) try: test.find("#account-options a[href='%s']" %\ (reverse("subscription_update"),)) except NoSuchElementException: parts[9]['success'] = True except Exception as e: print e parts[9]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting update subscription through url ### redirects user to store index try: test.open(reverse("subscription_update")) sleep(2) parts[10]['success'] = test.is_current_url(reverse(\ "store_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[10]['test_message'] = str(e) ########## No deactivate my store button try: test.set_to_implicit_wait(False) try: test.find("#deactivate_account") except NoSuchElementException: parts[11]['success'] = True except Exception as e: print e parts[11]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting store deactivation through url ### redirects user to store index try: test.open(reverse("store_deactivate")) sleep(2) parts[12]['success'] = test.is_current_url(reverse(\ "store_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[12]['test_message'] = str(e) ########## Rewards accessible try: test.open(reverse("rewards_index")) sleep(2) parts[13]['success'] = test.is_current_url(reverse("rewards_index")) except Exception as e: print e parts[13]['test_message'] = str(e) ########## No create new reward button try: test.set_to_implicit_wait(False) try: test.find("#add_reward") except NoSuchElementException: parts[14]['success'] = True except Exception as e: print e parts[14]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting create new reward through url ### redirects user to rewards index try: test.open(reverse("reward_edit", args=(-1, ))) sleep(2) parts[15]['success'] = test.is_current_url(reverse(\ "rewards_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[15]['test_message'] = str(e) ########## Rewards are not clickable try: test.set_to_implicit_wait(False) try: test.find("div.tr.reward a") except NoSuchElementException: parts[16]['success'] = True except Exception as e: print e parts[16]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting edit reward through url ### redirects user to rewards index try: test.open(reverse("reward_edit", args=\ (int(test.find("div.tr.reward").get_attribute("id")),))) sleep(3) parts[17]['success'] = test.is_current_url(reverse(\ "rewards_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[17]['test_message'] = str(e) ########## Messages accessible try: test.open(reverse("messages_index")) sleep(3) parts[18]['success'] = test.is_current_url(reverse(\ "messages_index")) except Exception as e: print e parts[18]['test_message'] = str(e) ########## No create new message button try: test.set_to_implicit_wait(False) try: test.find("#create_message") except NoSuchElementException: parts[19]['success'] = True except Exception as e: print e parts[19]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting create new message through url ### redirects user to messages index try: test.open(reverse("message_edit", args=("0", ))) sleep(3) parts[20]['success'] = test.is_current_url(reverse(\ "messages_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[20]['test_message'] = str(e) ########## Sent messages are viewable try: row = test.find("#tab-body-sent div.tr a") # get id from /manage/messages/H1llFritVJ/details message_id = MESSAGE_DETAIL_RE.search(\ row.get_attribute("href")).group(1) row.click() sleep(3) parts[21]['success'] = test.is_current_url(reverse(\ "message_details", args=(message_id,))) except Exception as e: print e parts[21]['test_message'] = str(e) ########## Feedbacks are viewable try: test.open(reverse("messages_index")) sleep(2) test.find("#tab-feedback").click() sleep(1) row = test.find("#tab-body-feedback div.tr a") # get id from /manage/messages/feedback/H1llFritVJ feedback_id = row.get_attribute("href").split("/")[-1] row.click() sleep(3) parts[22]['success'] = test.is_current_url(reverse(\ "feedback_details", args=(feedback_id,))) except Exception as e: print e parts[22]['test_message'] = str(e) ########## No reply button try: test.set_to_implicit_wait(False) try: test.find("#reply-button") except NoSuchElementException: parts[23]['success'] = True except Exception as e: print e parts[23]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting reply through url ### redirects user to messages index try: test.open(reverse("feedback_reply", args=(feedback_id, ))) sleep(3) parts[24]['success'] = test.is_current_url(reverse(\ "messages_index")+ "?" + urlencode({'error':\ "Permission denied"}) + "&tab_feedback=1") except Exception as e: print e parts[24]['test_message'] = str(e) ########## No delete message button try: test.open(reverse("feedback_details", args=(feedback_id, ))) sleep(3) test.set_to_implicit_wait(False) try: test.find("#delete-button") except NoSuchElementException: parts[25]['success'] = True except Exception as e: print e parts[25]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting delete message through url ### redirects user to messages index try: test.open(reverse("feedback_delete", args=(feedback_id, ))) sleep(2) parts[26]['success'] = test.is_current_url(reverse(\ "messages_index")+ "?" + urlencode({'error':\ "Permission denied"}) + "&tab_feedback=1") except Exception as e: print e parts[26]['test_message'] = str(e) ########## Analysis accessible try: test.open(reverse("analysis_index")) sleep(4) parts[27]['success'] = test.is_current_url(reverse(\ "analysis_index")) except Exception as e: print e parts[27]['test_message'] = str(e) ########## Employees accessible try: test.open(reverse("employees_index")) sleep(4) parts[28]['success'] = test.is_current_url(reverse(\ "employees_index")) except Exception as e: print e parts[28]['test_message'] = str(e) ########## No register new employee button try: test.set_to_implicit_wait(False) try: test.find("#register_employee") except NoSuchElementException: parts[29]['success'] = True except Exception as e: print e parts[29]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting new employee registration ### redirects user to employees_index try: test.open(reverse("employee_register")) sleep(3) parts[30]['success'] = test.is_current_url(reverse(\ "employees_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[30]['test_message'] = str(e) ########## Approved employees are not clickable try: test.set_to_implicit_wait(False) try: test.find("#tab-body-approved-employees div.tr a") except NoSuchElementException: parts[31]['success'] = True except Exception as e: print e parts[31]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting edit employee through url ### redirects user to employees index try: row = test.find("#tab-body-approved-employees div.tr") employee_id = row.get_attribute("id") test.open(reverse("employee_edit", args=(employee_id, ))) sleep(3) parts[32]['success'] = test.is_current_url(reverse(\ "employees_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[32]['test_message'] = str(e) ########## No remove button in approved employees try: test.set_to_implicit_wait(False) try: test.find("#tab-body-approved-employees div.tr "+\ "div.remove a") except NoSuchElementException: parts[33]['success'] = True except Exception as e: print e parts[33]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting remove employee through url ### redirects user to employees index try: test.open(reverse("employee_delete", args=(employee_id, ))) sleep(3) parts[34]['success'] = test.is_current_url(reverse(\ "employees_index")+ "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[34]['test_message'] = str(e) # create a pending register_rand_employee(store.objectId) test.new_driver(False) test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'], reverse("employees_index"), final_sleep=6) ########## No deny button in pending employees try: test.find("#tab-pending-employees").click() sleep(1) test.set_to_implicit_wait(False) try: test.find("#tab-body-pending-employees div.tr "+\ "div.deny a") except NoSuchElementException: parts[35]['success'] = True except Exception as e: print e parts[35]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting deny employee through url ### redirects user to employees index try: test.find("#tab-pending-employees").click() row = test.find("#tab-body-pending-employees div.tr") employee_id = row.get_attribute("id") test.open(reverse("employee_deny", args=(employee_id, ))) sleep(3) parts[36]['success'] = test.is_current_url(reverse(\ "employees_index") + "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[36]['test_message'] = str(e) ########## No approve button in pending employees try: test.find("#tab-pending-employees").click() sleep(1) test.set_to_implicit_wait(False) try: test.find("#tab-body-pending-employees div.tr "+\ "div.approve a") except NoSuchElementException: parts[37]['success'] = True except Exception as e: print e parts[37]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting approve employee through url ### redirects user to employees index try: test.open(reverse("employee_approve", args=(employee_id, ))) sleep(3) parts[38]['success'] = test.is_current_url(reverse(\ "employees_index") + "?" + urlencode({'error':\ "Permission denied"})) except Exception as e: print e parts[38]['test_message'] = str(e) ########## Settings accessible try: test.open(reverse("store_settings")) sleep(3) parts[39]['success'] = test.is_current_url(reverse(\ "store_settings")) except Exception as e: print e parts[39]['test_message'] = str(e) ########## No refresh button for retailer pin try: test.set_to_implicit_wait(False) try: test.find("#link_refresh_retailer_pin") except NoSuchElementException: parts[40]['success'] = True except Exception as e: print e parts[40]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Requesting refresh through url returns ### a json object with error Permission denied try: test.open(reverse("refresh_retailer_pin")) sleep(3) parts[41]['success'] = "Permission denied" in\ test.driver.page_source except Exception as e: print e parts[41]['test_message'] = str(e) ########## Punches employee is readonly try: test.open(reverse("store_settings")) sleep(3) parts[42]['success'] =\ test.find("#id_punches_employee").get_attribute(\ "readonly") == "true" except Exception as e: print e parts[42]['test_message'] = str(e) ########## Punches facebook is readonly try: parts[43]['success'] =\ test.find("#id_punches_facebook").get_attribute(\ "readonly") == "true" except Exception as e: print e parts[43]['test_message'] = str(e) ########## No save button try: test.set_to_implicit_wait(False) try: test.find("#settings-form-submit") except NoSuchElementException: parts[44]['success'] = True except Exception as e: print e parts[44]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## No cancel changes button try: test.set_to_implicit_wait(False) try: test.find("#settings-options a.red") except NoSuchElementException: parts[45]['success'] = True except Exception as e: print e parts[45]['test_message'] = str(e) finally: test.set_to_implicit_wait(True) ########## Workbench accessible try: test.open(reverse("workbench_index")) sleep(3) parts[46]['success'] = test.is_current_url(\ reverse("workbench_index")) except Exception as e: print e parts[46]['test_message'] = str(e) ########## Employee can punch try: test.find("#punch_code").send_keys("00010") test.find("#punch_amount").send_keys("1") test.find("#punch-form a.button.blue").click() sleep(2) parts[47]['success'] =\ test.find(".notification.hide") is not None except Exception as e: print e parts[47]['test_message'] = str(e) ########## Employee can reject redeem try: request_redeem_ps("eiZa6Mzu7f") sleep(COMET_PULL_RATE * 2 + 4) row = test.find("#tab-body-pending-redemptions div.tr") test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\ "div[contains(@class, 'redemption_redeem')]/a[2]", type="xpath").click() sleep(3) parts[48]['success'] = row.text.__contains__("Successfully") except Exception as e: print e parts[48]['test_message'] = str(e) ########## Employee can validate redeem try: request_redeem_ps("eiZa6Mzu7f") sleep(COMET_PULL_RATE * 2 + 4) row = test.find("#tab-body-pending-redemptions div.tr") test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\ "div[contains(@class, 'redemption_redeem')]/a[1]", type="xpath").click() sleep(3) parts[49]['success'] = row.text.__contains__("Successfully") except Exception as e: print e parts[49]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_redemptions(): """ Tests for redemptions section of the workbench. Does not test offers/gifts. Assumes that at least 1 PatronStore exists for the above Store. Assumes that at least 1 reward exists for the above Store. """ account = Account.objects().get(username=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings ps = store.get("patronStores", include="Patron", limit=1)[0] patron = ps.patron reward = store.rewards[0] reward_id = reward["reward_id"] test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Approving redeem works"}, {'test_name': "PatronStore's punch_count is updated"}, {'test_name': "PatronStore's pending_reward is set to false"}, {'test_name': "The reward's redemption_count is updated"}, {'test_name': "Rejecting redeem works"}, {'test_name': "PatronStore's punch_count remains the same"}, {'test_name': "PatronStore's pending_reward is set to false"}, {'test_name': "Approved redeem is in the history tab"}, {'test_name': "Rejected redeem is not in the history tab"}, {'test_name': "Approving a redeem when the PatronStore does" +\ " not have enough punches shows error"}, {'test_name': "PatronStore's punch_count remains the same"}, {'test_name': "PatronStore's pending_reward is set to false"}, {'test_name': "Approving redeem from a PatronStore that does" +\ " not exist shows error"}, ] section = { "section_name": "Redeems working properly?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("workbench_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("workbench_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(5) ########## Approving redeem works try: punch_count = ps.punch_count red_count = reward["redemption_count"] request_redeem_ps(ps.objectId, reward_id=reward_id, num_punches=1) sleep(COMET_PULL_RATE*2+4) row_id = test.find("#tab-body-pending-redemptions div.tr").get_attribute("id") test.find("//div[@id='tab-body-pending-redemptions']/"+\ "div[contains(@class, 'tr')]/"+\ "div[contains(@class, 'redemption_redeem')]/a[1]", type="xpath").click() sleep(4) parts[1]['success'] = test.find("#"+row_id).text.__contains__("Successfully") except Exception as e: print e parts[1]['test_message'] = str(e) ########## PatronStore's punch_count is updated try: ps.punch_count = None parts[2]['success'] = punch_count-1 == ps.get("punch_count") except Exception as e: print e parts[2]['test_message'] = str(e) ########## PatronStore's pending_reward is set to false try: ps.pending_reward = None parts[3]['success'] = not ps.get("pending_reward") except Exception as e: print e parts[3]['test_message'] = str(e) ########## The reward's redemption_count is updated try: store.rewards = None parts[4]['success'] = red_count+1 ==\ store.get("rewards")[0]["redemption_count"] except Exception as e: print e parts[4]['test_message'] = str(e) ########## Rejecting redeem works TODO try: pass except Exception as e: print e parts[5]['test_message'] = str(e) ########## PatronStore's punch_count remains the same TODO try: pass except Exception as e: print e parts[6]['test_message'] = str(e) ########## PatronStore's pending_reward is set to false TODO try: pass except Exception as e: print e parts[7]['test_message'] = str(e) ########## Approved redeem is in the history tab TODO try: pass except Exception as e: print e parts[8]['test_message'] = str(e) ########## Rejected redeem is not in the history tab TODO try: pass except Exception as e: print e parts[9]['test_message'] = str(e) ########## Approving a redeem when the PatronStore does ### not have enough punches shows error TODO try: pass except Exception as e: print e parts[10]['test_message'] = str(e) ########## PatronStore's punch_count remains the same TODO try: pass except Exception as e: print e parts[11]['test_message'] = str(e) ########## PatronStore's pending_reward is set to false TODO try: pass except Exception as e: print e parts[12]['test_message'] = str(e) ########## Approving redeem from a PatronStore that does ### not exist shows error TODO try: pass except Exception as e: print e parts[13]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_update_subscription(): # TODO test place_order account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription subscription.update_locally(SUBSCRIPTION_INFO, False) subscription.update() test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Update account page reachable"}, {'test_name': "Changes to first name are visible"}, {'test_name': "Changes to first name are saved to parse"}, {'test_name': "Changes to last name are visible"}, {'test_name': "Changes to last name are saved to parse"}, {'test_name': "Changes to card number are visible"}, {'test_name': "Changes to card number are saved to parse"}, {'test_name': "A paypal credit card id is generated & saved"}, {'test_name': "Changes to cc expiration are visible"}, {'test_name': "Changes to cc expiration are saved to parse"}, {'test_name': "Changes to address are visible"}, {'test_name': "Changes to address are saved to parse"}, {'test_name': "Changes to city are visible"}, {'test_name': "Changes to city are saved to parse"}, {'test_name': "Changes to state are visible"}, {'test_name': "Changes to state are saved to parse"}, {'test_name': "Changes to zip are visible"}, {'test_name': "Changes to zip are saved to parse"}, {'test_name': "First name is required"}, {'test_name': "Last name is required"}, {'test_name': "Card number is required"}, {'test_name': "Security code (cvc) is required"}, {'test_name': "Address is required"}, {'test_name': "City is required"}, {'test_name': "State is required"}, {'test_name': "Zip is required"}, {'test_name': "ToS checked is required"}, {'test_name': "Invalid credit card number shows error"}, {'test_name': "Past expiration date is invalid"}, {'test_name': "Only the last 4 digits of the card number" +\ " are shown"}, {'test_name': "Not changing the card number does not " +\ "generate new paypal credit card id"}, ] section = { "section_name": "Edit account/subscription working properly?", "parts": parts, } self.results.append(section) ########## User needs to be logged in to access page self.open(reverse("store_index")) sleep(1) parts[0]['success'] = self.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("store_index")) # login selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) self.action_chain(0, selectors, "send_keys") sleep(7) ########## Update account page reachable try: self.find("//div[@id='account-options']/a[1]", type="xpath").click() sleep(3) parts[1]['success'] =\ self.is_current_url(reverse("subscription_update")) except Exception as e: print e parts[1]['test_message'] = str(e) ## Make changes # first clear all inputs for el in self.find("input[type='text']", multiple=True): el.clear() selectors = ( ("#id_first_name", TEST_SUBSCRIPTION_INFO['first_name']), ("#id_last_name", TEST_SUBSCRIPTION_INFO['last_name']), ("#id_cc_number", TEST_SUBSCRIPTION_INFO['cc_number']), ("#id_cc_cvv", "905"), ("#id_address", TEST_SUBSCRIPTION_INFO['address']), ("#id_city", TEST_SUBSCRIPTION_INFO['city']), ("#id_state", TEST_SUBSCRIPTION_INFO['state']), ("#id_zip", TEST_SUBSCRIPTION_INFO['zip']), ) self.action_chain(0, selectors, action="send_keys") month_el =\ self.find("//select[@id='id_date_cc_expiration_month']/" +\ "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].month),), type="xpath") year_el =\ self.find("//select[@id='id_date_cc_expiration_year']/" +\ "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].year),), type="xpath") month = month_el.get_attribute("value") year = year_el.get_attribute("value") month_el.click() year_el.click() self.find("#id_recurring").click() self.find("#update-form-submit").click() sleep(5) # back to update account page self.find("//div[@id='account-options']/a[1]", type="xpath").click() sleep(3) ########## Changes to first name are visible parts[2]['success'] =\ self.find("#id_first_name").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['first_name'] ########## Changes to first name are saved to parse subscription.first_name = None parts[3]['success'] = subscription.get("first_name") ==\ TEST_SUBSCRIPTION_INFO['first_name'] ########## Changes to last name are visible parts[4]['success'] =\ self.find("#id_last_name").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['last_name'] ########## Changes to last name are saved to parse subscription.last_name = None parts[5]['success'] = subscription.get("last_name") ==\ TEST_SUBSCRIPTION_INFO['last_name'] ########## Changes to card number are visible parts[6]['success'] =\ self.find("#id_cc_number").get_attribute("value")[-4:] ==\ TEST_SUBSCRIPTION_INFO['cc_number'][-4:] ########## Changes to card number are saved to parse subscription.cc_number = None parts[7]['success'] = subscription.get("cc_number") ==\ TEST_SUBSCRIPTION_INFO['cc_number'][-4:] ########## A paypal credit card id is generated & saved # CARD-97223025G70599255KHHCCVQ subscription.pp_cc_id = None parts[8]['success'] = subscription.get("pp_cc_id").__contains__(\ "CARD") and len(subscription.get("pp_cc_id")) == 29 ########## Changes to cc expiration are visible parts[9]['success'] = month == self.get_selected("//select" +\ "[@id='id_date_cc_expiration_month']/option", type="xpath").get_attribute("value") and\ year == self.get_selected(\ "//select[@id='id_date_cc_expiration_year']/option", type="xpath").get_attribute("value") ########## Changes to cc expiration are saved to parse subscription.date_cc_expiration = None exp = subscription.get("date_cc_expiration") parts[10]['success'] = exp.month == TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].month and exp.year ==\ TEST_SUBSCRIPTION_INFO['date_cc_expiration'].year ########## Changes to address are visible parts[11]['success'] =\ self.find("#id_address").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['address'] ########## Changes to address are saved to parse subscription.address = None parts[12]['success'] = subscription.get("address") ==\ TEST_SUBSCRIPTION_INFO['address'] ########## Changes to city are visible parts[13]['success'] =\ self.find("#id_city").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['city'] ########## Changes to city are saved to parse subscription.city = None parts[14]['success'] = subscription.get("city") ==\ TEST_SUBSCRIPTION_INFO['city'] ########## Changes to state are visible self.find("//select[@id='id_date_cc_expiration_year']/" +\ "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\ 'date_cc_expiration'].year)), type="xpath") parts[15]['success'] =\ self.find("#id_state").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['state'] ########## Changes to state are saved to parse subscription.state = None parts[16]['success'] = subscription.get("state") ==\ TEST_SUBSCRIPTION_INFO['state'] ########## Changes to zip are visible parts[17]['success'] =\ self.find("#id_zip").get_attribute("value") ==\ TEST_SUBSCRIPTION_INFO['zip'] ########## Changes to zip are saved to parse subscription.zip = None parts[18]['success'] = subscription.get("zip") ==\ TEST_SUBSCRIPTION_INFO['zip'] ## Make changes selectors = [ "#id_first_name", "#id_last_name", "#id_cc_number", "#id_cc_cvv", "#id_address", "#id_city", "#id_state", "#id_zip", ] self.action_chain(0, selectors, action="clear") for i in range(len(selectors)): selectors[i] = (selectors[i], " ") self.action_chain(0, selectors, action="send_keys") self.find("#update-form-submit").click() sleep(3) ########## First name is required ########## Last name is required ########## Card number is required ########## Security code (cvc) is required ########## Address is required ########## City is required ########## State is required ########## Zip is required ########## ToS checked is required def field_is_required(part, selector, message="This field is required."): try: parts[part]['success'] = self.find(selector).text == message except Exception as e: print e parts[part]['test_message'] = str(e) selectors = ( (19, "#first_name_ic ul.errorlist li"), (20, "#last_name_ic ul.errorlist li"), (21, "#card_number_container ul.errorlist li", "Enter a valid credit card number."), (22, "#cc_cvv_ic ul.errorlist li"), (23, "#address_ic ul.errorlist li"), (24, "#city_ic ul.errorlist li"), (25, "#state_ic ul.errorlist li"), (26, "#zip_ic ul.errorlist li"), (27, "#recurring_charge_container ul.errorlist li", "You must accept the Terms & Conditions to continue."), ) for selector in selectors: field_is_required(*selector) ########## Invalid credit card number shows error try: cc_number = self.find("#id_cc_number") cc_number.clear() cc_number.send_keys("8769233313929990") self.find("#update-form-submit").click() sleep(3) parts[28]['success'] = self.find("#card_number_container " +\ "ul.errorlist li").text ==\ "Enter a valid credit card number." except Exception as e: print e parts[28]['test_message'] = str(e) ########## Past expiration date is invalid if timezone.now().month == 1: # note that if this test is being run on a January, this will # fail so to prevent that just skip the test if it is January parts[29]['test_message'] = "READ ME. This test has been " +\ "skipped because the month is January, which means " +\ "that this test will always fail due to limited " +\ "select options." else: try: # select january of this year. self.find("//select[@id='id_date_cc_expiration_month']/" +\ "option[@value='1']", type="xpath").click() self.find("//select[@id='id_date_cc_expiration_year']/" +\ "option[@value='%s']" %\ (str(timezone.now().year),), type="xpath").click() self.find("#update-form-submit").click() sleep(3) parts[29]['success'] =\ self.find("#date_cc_expiration_ic ul.errorlist " +\ "li").text == "Your credit card has expired!" except Exception as e: print e parts[29]['test_message'] = str(e) ########## Only the last 4 digits of the card number are shown try: self.find("//div[@class='form-options']/a[2]", type="xpath").click() sleep(1) self.find("//div[@id='account-options']/a[1]", type="xpath").click() sleep(3) masked_number =\ self.find("#id_cc_number").get_attribute("value") parts[30]['success'] = masked_number[:-4] ==\ "************" and str(masked_number[-4:]).isdigit() except Exception as e: print e parts[30]['test_message'] = str(e) ########## Not changing the card number does not ###### generate new paypal credit card id try: subscription.pp_cc_id = None cc_id = subscription.get("pp_cc_id") self.find("#id_cc_cvv").send_keys("123") self.find("#id_recurring").click() self.find("#update-form-submit").click() sleep(5) subscription.pp_cc_id = None parts[31]['success'] = cc_id == subscription.get("pp_cc_id") except Exception as e: print e parts[31]['test_message'] = str(e) # END OF ALL TESTS - cleanup return self.tear_down()
def test_cancel_account(): """ A test just for the cancel account link. """ account = Account.objects().get(username=TEST_USER['username'], include="Store") store = account.store test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Clicking the cancel button brings up a " +\ "confirmation dialog"}, {'test_name': "Clicking cancel on the dialog dimisses the " +\ "dialog and the account remains active"}, {'test_name': "Clicking OK logs the user out"}, {'test_name': "Clicking OK sets the store's active field " +\ "to false on Parse"}, ] section = { "section_name": "Deactivate store link functional?", "parts": parts, } self.results.append(section) ########## User needs to be logged in to access page self.open(reverse("store_index")) sleep(1) parts[0]['success'] = self.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("store_index")) # login selectors = (("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN)) self.action_chain(0, selectors, "send_keys") sleep(7) ########## Clicking the cancel button brings up a confrmtn dialog try: self.find("#deactivate_account").click() sleep(1) alert = self.switch_to_alert() parts[1]['success'] = alert is not None except Exception as e: print e parts[1]['test_message'] = str(e) ########## Clicking cancel on the dialog dimisses the ### dialog and the account remains active try: alert.dismiss() try: alert.text except NoAlertPresentException: store.active = None parts[2]['success'] = store.get("active") except Exception as e: print e parts[2]['test_message'] = str(e) ########## Clicking OK logs the user out try: self.find("#deactivate_account").click() sleep(1) alert = self.switch_to_alert() alert.accept() sleep(4) if SeleniumTest.DEV_LOGIN: parts[3]["success"] =\ self.is_current_url(reverse("manage_dev_login")+"?next=/") else: parts[3]["success"] =\ self.is_current_url(reverse("public_home")) except Exception as e: print e parts[3]['test_message'] = str(e) ########## Clicking OK sets the store's active ### field to false on Parse store.active = None parts[4]['success'] = not store.get("active") # undo store.active = True store.update() # END OF ALL TESTS - cleanup return self.tear_down()
def test_feedbacks(): """ This test also tests cloud code send_feedback. """ # we can clear the list locally but just re-pull from parse account = Account.objects().get(username=TEST_USER['username'], include="Store.Subscription") store = account.store subscription = store.subscription account = Account.objects().get(username=TEST_PATRON['username'], include="Patron") patron = account.patron # make sure that the account is not used for these tests account = None # clear the received messages relation received_messages = store.get("receivedMessages", keys="") if received_messages: store.remove_relation("ReceivedMessages_", [m.objectId for m in received_messages]) store.set("receivedMessages", None) test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Cloud code send_feedback works"}, {'test_name': "Notification badge appears if there are" +\ " unread feedbacks"}, {'test_name': "A new row appears when feedback is received"}, {'test_name': "Feedback is initially unread (dashboard)"}, {'test_name': "Feedback is in store's ReceivedMessages " +\ "relation and is initially unread"}, {'test_name': "Clicking the row redirects user to the " +\ "feedback detail page"}, {'test_name': "Clicking back to feedback inbox redirects " +\ "user back to messages index with feedback tab active"}, {'test_name': "Feedback is now read (dashboard)"}, {'test_name': "Feedback is now read (Parse)"}, {'test_name': "Clicking reply redirects user to feedback " +\ "reply page"}, {'test_name': "Reply body is required."}, {'test_name': "Replying redirects user back to feedback " +\ "details"}, {'test_name': "The reply is visible"}, {'test_name': "The reply message is saved in the store's " +\ "sent messages relation with message_type of feedback"}, {'test_name': "The reply message is saved in the Patron's " +\ "received messages relation wrapped in a Message Status"}, {'test_name': "A feedback with a reply does not have a " +\ "reply button"}, {'test_name': "Clicking delete message prompts the user " +\ "to confirm the deletion"}, {'test_name': "The user is redirected to messages index " +\ "with feedback tab active"}, {'test_name': "Deleting the reply only removes the message" +\ " from the store's sent messages relation"}, {'test_name': "The deleted feedback is no longer in " +\ "the table"}, {'test_name': "Multiple feedbacks (testing 3 here) " +\ "can appear at the same time"}, ] section = { "section_name": "Receiving messages works?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("messages_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("messages_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(5) def send_feedback(subject, body): """ This is a consumer action - not dashboard """ return cloud_call("send_feedback", { "store_id": store.objectId, "patron_id": patron.objectId, "sender_name": patron.get_fullname(), "subject": subject, "body": body, }) def feedback_id(feedback_tr): return feedback_tr.find_element_by_css_selector(\ "a").get_attribute("href").split("/")[-1] def feedback_unread(feedback_tr): """ check parse if the fb is unread """ fb_id = feedback_id(feedback_tr) store.set("receivedMessages", None) msg = store.get("receivedMessages", objectId=fb_id) if msg and len(msg) > 0: return not msg[0].is_read return False ########## Cloud code send_feedback works try: parts[1]['success'] = send_feedback("feedback #1", "body #1").get("result") == "success" except Exception as e: print e parts[1]['test_message'] = str(e) ########## Notification badge appears if there are ### unread feedbacks try: sleep(COMET_PULL_RATE*2 + 2) parts[2]['success'] = test.element_exists("#messages-nav " +\ "a div.nav-item-badge") except Exception as e: print e parts[2]['test_message'] = str(e) ########## A new row appears when feedback is received try: test.find("#tab-feedback").click() feedbacks =\ test.find("#tab-body-feedback div.tr", multiple=True) parts[3]['success'] = len(feedbacks) > 0 except Exception as e: print e parts[3]['test_message'] = str(e) ########## Feedback is initially unread (dashboard) try: parts[4]['success'] =\ feedbacks[0].get_attribute("class").__contains__("unread") except Exception as e: print e parts[4]['test_message'] = str(e) ########## Feedback is in store's ReceivedMessages ### relation and is initially unread try: parts[5]['success'] = feedback_unread(feedbacks[0]) except Exception as e: print e parts[5]['test_message'] = str(e) ########## Clicking the row redirects user to the ### feedback detail page try: fb_id = feedback_id(feedbacks[0]) feedbacks[0].find_element_by_css_selector("a").click() sleep(2) parts[6]['success'] = test.is_current_url(reverse(\ "feedback_details", args=(fb_id,))) except Exception as e: print e parts[6]['test_message'] = str(e) ########## Clicking back to feedback inbox redirects ### user back to messages index with feedback tab active try: test.find("#back_to_feedback").click() sleep(1) parts[7]['success'] =\ test.find("#tab-feedback").get_attribute(\ "class").__contains__("active") except Exception as e: print e parts[7]['test_message'] = str(e) ########## Feedback is now read (dashboard) try: feedbacks =\ test.find("#tab-body-feedback div.tr", multiple=True) parts[8]['success'] = not feedbacks[0].get_attribute(\ "class").__contains__("unread") except Exception as e: print e parts[8]['test_message'] = str(e) ########## Feedback is now read (Parse) try: parts[9]['success'] = not feedback_unread(feedbacks[0]) except Exception as e: print e parts[9]['test_message'] = str(e) ########## Clicking reply redirects user to feedback reply page try: fb_id = feedback_id(feedbacks[0]) feedbacks[0].find_element_by_css_selector("a").click() sleep(2) test.find("#reply-button").click() sleep(1) parts[10]['success'] = test.is_current_url(reverse(\ "feedback_reply", args=(fb_id,))) except Exception as e: print e parts[10]['test_message'] = str(e) ########## Reply body is required. try: test.find("#body").send_keys(" ") test.find("#reply-form-submit").click() sleep(2) parts[11]['success'] = test.find("div.notification.hide " +\ "div").text == "Please enter a message." except Exception as e: print e parts[11]['test_message'] = str(e) ########## Replying redirects user back to feedback details try: test.find("#body").send_keys("Hey") test.find("#reply-form-submit").click() parts[12]['success'] = test.is_current_url(reverse(\ "feedback_details", args=(fb_id,)) +\ "?%s" % urlencode({'success':\ 'Reply has been sent.'})) sleep(5) except Exception as e: print e parts[12]['test_message'] = str(e) ########## The reply is visible try: parts[13]['success'] = test.find("#reply-box " +\ "div.sect.body").text == "Hey" except Exception as e: print e parts[13]['test_message'] = str(e) ########## The reply message is saved in the store's ### sent messages relation with message_type of feedback try: test.find("#back_to_feedback").click() sleep(1) store.set("sentMessages", None) store.set("receivedMessages", None) parts[14]['success'] = len(store.get("sentMessages", objectId=store.get("receivedMessages", objectId=fb_id)[0].Reply, message_type=FEEDBACK)) > 0 except Exception as e: print e parts[14]['test_message'] = str(e) ########## The reply message is saved in the Patron's ### received messages relation wrapped in a Message Status try: patron.set("receivedMessages", None) parts[15]['success'] = len(patron.get("receivedMessages", Message=fb_id)) > 0 except Exception as e: print e parts[15]['test_message'] = str(e) ########## A feedback with a reply does not have a reply button try: feedbacks =\ test.find("#tab-body-feedback div.tr", multiple=True) feedbacks[0].find_element_by_css_selector("a").click() sleep(2) parts[16]['success'] = not test.element_exists(\ "#reply-form-submit") except Exception as e: print e parts[16]['test_message'] = str(e) ########## Clicking delete message prompts the user ### to confirm the deletion try: test.find("#delete-button").click() sleep(1) alert = test.switch_to_alert() parts[17]['success'] = alert.text ==\ "Are you sure you want to delete this feedback thread?" except Exception as e: print e parts[17]['test_message'] = str(e) ########## The user is redirected to messages index ### with feedback tab active try: alert.accept() sleep(4) parts[18]['success'] =\ test.find("#tab-feedback").get_attribute(\ "class").__contains__("active") except Exception as e: print e parts[18]['test_message'] = str(e) ########## Deleting the reply only removes the message ### from the store's sent messages relation try: store.set("receivedMessages", None) parts[19]['success'] = not store.get("receivedMessages", objectId=fb_id, message_type=FEEDBACK) except Exception as e: print e parts[19]['test_message'] = str(e) ########## The deleted feedback is no longer in the table try: test.find("#tab-feedback").click() sleep(1) feedbacks =\ test.find("#tab-body-feedback div.tr a[href='%s']" %\ (fb_id,), multiple=True) parts[20]['success'] = len(feedbacks) == 0 except Exception as e: print e parts[20]['test_message'] = str(e) ########## Multiple feedbacks (testing 3 here) ### can appear at the same time try: send_feedback("feedback #2", "body #2") send_feedback("feedback #3", "body #3") send_feedback("feedback #4", "body #4") sleep(COMET_PULL_RATE*3 + 4) feedbacks =\ test.find("#tab-body-feedback div.tr a", multiple=True) parts[21]['success'] = len(feedbacks) == 3 except Exception as e: print e parts[21]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_employee_registration(): """ Tests for employee registrain via dashboard. """ # delete the employees and associated User objects in the relation account = Account.objects().get(email=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings emps = store.get("employees") if emps: for emp in emps: Account.objects().get(Employee=emp.objectId).delete() emp.delete() store.set("employees", None) test = SeleniumTest() parts = [ {"test_name" : "Clicking register new employee button "+\ " redirects user to employee register page."}, {"test_name" : "New registered employee is immediately placed"+\ " in the approved group."}, {"test_name" : "Access level of new employee is the same as"+\ " the one chosen in the registration form."}, {"test_name" : "A valid email is required."}, {"test_name" : "Email must be unique."}, {"test_name" : "Email is required."}, {"test_name" : "First name is required."}, {"test_name" : "Last name is required."}, {"test_name" : "Password is required."}, {"test_name" : "Password confirm is required."}, {"test_name" : "Passwords must match."}, {"test_name" : "Password must be at least 6 characters long."}, ] section = { "section_name":\ "Employee registration functional?", "parts": parts, } test.results.append(section) test.login(TEST_USER['username'], TEST_USER['password'], reverse("employees_index")) ########## Clicking register new employee button ### redirects user to employee register page. try: test.find("#register_employee").click() sleep(3) parts[0]['success'] = test.is_current_url(reverse("employee_register")) except Exception as e: print e parts[0]['test_message'] = str(e) ########## New registered employee is immediately placed ### in the approved group. try: acl = test.find("#id_acl option[selected]").get_attribute("value") selectors = ( ("#id_email", TEST_EMPLOYEE['username']), ("#id_password", TEST_EMPLOYEE['password']), ("#id_confirm_password", TEST_EMPLOYEE['password']), ("#id_first_name", TEST_EMPLOYEE['first_name']), ("#id_last_name", TEST_EMPLOYEE['last_name']), ) test.action_chain(0, selectors, action="send_keys") test.find("#register-employee-submit").click() sleep(7) test.open(reverse("employees_index")) sleep(3) parts[1]['success'] = test.find("#tab-body-approved-employees"+\ " div.tr a div.td.first_name_approved").text ==\ TEST_EMPLOYEE['first_name'] except Exception as e: print e parts[1]['test_message'] = str(e) ########## Access level of new employee is the same as ### the one chosen in the registration form. try: test.find("#tab-body-approved-employees div.tr a").click() sleep(2) parts[2]['success'] = acl ==\ test.find("#ACL option[selected]").get_attribute("value") except Exception as e: print e parts[2]['test_message'] = str(e) ########## A valid email is required. try: test.open(reverse("employee_register")) sleep(2) test.find("#id_email").send_keys("jhfghjdfg@jfgh") test.find("#register-employee-submit").click() sleep(3) parts[3]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\ "Enter a valid email address." except Exception as e: print e parts[3]['test_message'] = str(e) ########## Email must be unique. try: selectors = ( ("#id_email", TEST_EMPLOYEE['username']), ("#id_password", "123456123"), ("#id_confirm_password", "123456123"), ("#id_first_name", "YOLO"), ("#id_last_name", "BOLO"), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#register-employee-submit").click() sleep(5) parts[4]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\ "Email is already being used." except Exception as e: print e parts[4]['test_message'] = str(e) ########## Email is required. 5 ########## First name is required. 6 ########## Last name is required. 7 ########## Password is required. 8 ########## Password confirm is required. 9 try: selectors = ( "#id_email", "#id_password", "#id_confirm_password", "#id_first_name", "#id_last_name", ) test.action_chain(0, selectors, action="clear") test.find("#register-employee-submit").click() sleep(3) for i, sel in enumerate(selectors): id = sel.replace("#id_", "") + "_ic" parts[i+5]['success'] =\ test.find("#%s > ul.errorlist > li" % (id,)).text ==\ "This field is required." except Exception as e: print e for i, sel in enumerate(selectors): parts[i+5]['test_message'] = str(e) ########## Passwords must match. try: selectors = ( ("#id_password", "123456"), ("#id_confirm_password", "abcdefg"), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#register-employee-submit").click() sleep(3) parts[10]['success'] = test.find("#password_ic > ul.errorlist > li").text ==\ "Passwords don't match." except Exception as e: print e parts[10]['test_message'] = str(e) ########## Password must be at least 6 characters long. try: test.find("#id_password").clear() test.find("#id_password").send_keys("123") test.find("#register-employee-submit").click() sleep(3) parts[11]['success'] =\ test.find("#password_ic > ul.errorlist > li").text ==\ "Ensure this value has at least 6 characters (it has 3)." except Exception as e: print e parts[11]['success'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def register(request): """ Adds a new employee to the currently logged in Store. This automatically sets this employee to approved. """ data = {'employees_nav': True} settings = SESSION.get_settings(request.session) store = SESSION.get_store(request.session) if request.method == "POST": from_associated_account = False # check if this post is from the associated account dialog # if it is then skip form validations aaf_nonce_id = request.POST.get('aaf-nonce') aaf_account_id = request.POST.get('aaf-account_id') if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0: aa_nonce = AssociatedAccountNonce.objects.filter(\ id=aaf_nonce_id, account_id=aaf_account_id) if len(aa_nonce) > 0 and aa_nonce[0].verified: aa_nonce[0].delete() from_associated_account = True account_form = EmployeeAccountSignUpForm(request.POST) employee_form = EmployeeForm(request.POST) if not from_associated_account: all_forms_valid = account_form.is_valid() and\ employee_form.is_valid() else: all_forms_valid = True if all_forms_valid: postDict = request.POST.dict() # make the cloud call # see cloud param for possible access level values acl = postDict['acl'] if acl == ACCESS_ADMIN[0]: access_level = "admin" elif acl == ACCESS_PUNCHREDEEM[0]: access_level = "punch_redeem" else: access_level = None params = { "retailer_pin": settings.get("retailer_pin"), "username": postDict['email'].strip().lower(), "first_name": postDict['first_name'].capitalize(), "last_name": postDict['last_name'].capitalize(), "email": postDict['email'].strip().lower(), "status": APPROVED, "access_level": access_level, } if from_associated_account: res = cloud_call("link_employee", params) else: params["password"] = postDict['password'] res = cloud_call("register_employee", params) # don't forget to retrieve the latest session request.session.clear() request.session.update(SessionStore(request.session.session_key)) # check if email already taken here to handle the case where # the user already has a patron/employee account # but also want to sign up for a Store account if "error" in res and res['error'] in ("EMAIL_TAKEN_AVAILABLE", "USERNAME_TAKEN_AVAILABLE"): aa = Account.objects().get(email=postDict['email'].strip().lower()) aan = AssociatedAccountNonce.objects.create(\ account_id=aa.objectId) return HttpResponse(json.dumps({"associated_account":\ aa.objectId, "associated_account_nonce":aan.id, "email": aa.email, "code": 0}), content_type="application/json") elif "error" in res and res['error'] in ("EMAIL_TAKEN", "USERNAME_TAKEN"): account_form._errors.setdefault("email", ErrorList()).append(u"Email is already being used.") elif "error" not in res: # add the employee to the approved list employees_approved_list =\ SESSION.get_employees_approved_list(request.session) employees_approved_ids =\ [ emp.objectId for emp in employees_approved_list ] new_employee = Employee(**res["result"]) if new_employee.objectId not in employees_approved_ids: employees_approved_list.insert(0, new_employee) request.session['employees_approved_list'] =\ employees_approved_list # update our local store's acl - don't wait for # the cloud post store = SESSION.get_store(request.session) store.set_access_level(Account.objects().get(\ email=postDict['email'].strip().lower()), acl) request.session['store'] = store # notify other dashboards of this change payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "updatedStore":store.jsonify() } comet_receive(store.objectId, payload) return HttpResponse(json.dumps({"code": 2}), content_type="application/json") else: return HttpResponse(json.dumps({"code": 3}), content_type="application/json") else: employee_form = EmployeeForm(initial={"acl":\ ACCESS_PUNCHREDEEM[0]}) account_form = EmployeeAccountSignUpForm() data["employee_form"] = employee_form data["account_form"] = account_form return render(request, 'manage/employee_register.djhtml', data)
def test_rewards(): # setup account = Account.objects().get(username=TEST_USER['username'], include="Store") store = account.store # start with no rewards store.rewards = [] store.update() test = SeleniumTest() parts = [ {'test_name': "User needs to be logged in to access page"}, {'test_name': "Having no rewards shows a placeholder row"}, {'test_name': "Adding a reward works"}, {'test_name': "The new reward is saved to parse"}, {'test_name': "Redemption count starts at 0"}, {'test_name': "Reward id starts at 0"}, {'test_name': "Updating a reward works"}, {'test_name': "The updated reward is saved to parse"}, {'test_name': "The updated reward retains the reward_id"}, {'test_name': "The updated reward retains the " +\ "redemption_count"}, {'test_name': "Clicking delete brings up a confirmation " +\ "dialog"}, {'test_name': "Deleting a reward works"}, {'test_name': "The deleted reward is deleted from parse"}, {'test_name': "Reward name is required"}, {'test_name': "Punches is required"}, {'test_name': "Description is not required"}, {'test_name': "Clicking cancel redirects user " +\ "back to rewards index"}, {'test_name': "Punches must be a number"}, {'test_name': "Punches must be greater than 0"}, {'test_name': "Rewards are initially sorted by Punches " +\ "from least to greatest"}, {'test_name': "Punches is sortable"}, {'test_name': "Name is sortable"}, {'test_name': "Updating a reward with the reset redemption" +\ " count option resets the redemption count to 0"}, ] section = { "section_name": "Rewards page working properly?", "parts": parts, } test.results.append(section) ########## User needs to be logged in to access page test.open(reverse("rewards_index")) # ACTION! sleep(1) parts[0]['success'] = test.is_current_url(reverse(\ 'manage_login') + "?next=" + reverse("rewards_index")) # login selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(7) ########## Having no rewards shows a placeholder row try: parts[1]['success'] =\ test.find("//div[@id='rewards_section']/div[@class=" +\ "'tr reward']/div[@class='td reward_summary']/span[1]", type="xpath").text == "No Rewards" except Exception as e: print e parts[1]['test_message'] = str(e) def add_reward(name, description, punches): test.find("#add_reward").click() sleep(1) selectors = ( ("#id_reward_name", name), ("#id_description", description), ("#id_punches", str(punches)), ) test.action_chain(0, selectors, action="send_keys") test.find("#submit-reward-form").click() sleep(5) reward1_name = "Reward #1" reward1_description = "First reward" reward1_punches = 5 ########## Adding a reward works try: add_reward(reward1_name, reward1_description, reward1_punches) parts[2]['success'] = test.find("//div[@id='0']/a/div[2]" +\ "/span[1]", type="xpath").text == reward1_name except Exception as e: print e parts[2]['test_message'] = str(e) ########## The new reward is saved to parse try: store.rewards = None reward = store.get("rewards")[0] parts[3]['success'] = reward['reward_name'] ==\ reward1_name and reward['description'] ==\ reward1_description and\ reward['punches'] == reward1_punches except Exception as e: print e parts[3]['test_message'] = str(e) ########## Redemption count starts at 0 try: parts[4]['success'] = reward['redemption_count'] == 0 except Exception as e: print e parts[4]['test_message'] = str(e) ########## Redemption count starts at 0 try: parts[5]['success'] = reward['reward_id'] == 0 except Exception as e: print e parts[5]['test_message'] = str(e) # let's add 3 more rewards! reward2_name = "reward dos" reward2_description = "DOS" reward2_punches = 10 reward3_name = "reward tres" reward3_description = "TRES" reward3_punches = 12 reward4_name = "reward quatro" reward4_description = "QUATRO" reward4_punches = 15 add_reward(reward2_name, reward2_description, reward2_punches) add_reward(reward3_name, reward3_description, reward3_punches) add_reward(reward4_name, reward4_description, reward4_punches) ################ reward1_name = "reward uno" reward1_description = "UNO" reward1_punches = 1 ########## Updating a reward works try: test.find("//div[@id='0']/a", type="xpath").click() sleep(1) selectors = ( ("#id_reward_name", reward1_name), ("#id_description", reward1_description), ("#id_punches", str(reward1_punches)), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#submit-reward-form").click() sleep(4) parts[6]['success'] = test.find("//div[@id='0']/a/div[2]" +\ "/span[1]", type="xpath").text == reward1_name except Exception as e: print e parts[6]['test_message'] = str(e) ########## The updated reward is saved to parse try: store.rewards = None reward = store.get("rewards")[0] # list is sorted by punches parts[7]['success'] = reward['reward_name'] ==\ reward1_name and\ reward['description'] == reward1_description and\ reward['punches'] == reward1_punches except Exception as e: print e parts[7]['test_message'] = str(e) ########## The updated reward retains the reward_id try: parts[8]['success'] = reward['reward_id'] == 0 except Exception as e: print e parts[8]['test_message'] = str(e) ########## The updated reward retains the redemption_count try: parts[9]['success'] = reward['redemption_count'] == 0 except Exception as e: print e parts[9]['test_message'] = str(e) ########## Clicking delete brings up a confirmation dialog try: test.find("//div[@id='0']/a", type="xpath").click() sleep(1) test.find("#delete-link").click() alert = test.switch_to_alert() parts[10]['success'] = alert is not None except Exception as e: print e parts[10]['test_message'] = str(e) ########## Deleting a reward works try: alert.accept() sleep(5) parts[11]['success'] = test.find("//div[@id='1']/a/div[2]" +\ "/span[1]", type="xpath").text == reward2_name try: # first reward should be gone test.find("//div[@id='0']/a/div[2]" +\ "/span[1]", type="xpath").text except Exception: parts[11]['success'] = parts[11]['success'] else: parts[11]['success'] = False except Exception as e: print e parts[11]['test_message'] = str(e) ########## The deleted reward is deleted from parse try: store.rewards = None rewards = store.get("rewards") parts[12]['success'] = reward1_name not in\ [r['reward_name'] for r in rewards] and\ 0 not in [r['reward_id'] for r in rewards] except Exception as e: print e parts[12]['test_message'] = str(e) # field required add_reward(" ", "", "") ########## Reward name is required try: parts[13]['success'] =\ test.find("#reward_name_ic ul li").text ==\ "This field is required." except Exception as e: print e parts[13]['test_message'] = str(e) ########## Punches is required try: parts[14]['success'] =\ test.find("#punches_ic ul li").text ==\ "This field is required." except Exception as e: print e parts[14]['test_message'] = str(e) ########## Description is not required try: parts[15]['success'] =\ not test.element_exists("#description_ic ul li") except Exception as e: print e parts[15]['test_message'] = str(e) ########## Clicking cancel redirects user back to rewards index try: test.find("//div [@id='edit-reward-options']/a[2]", type="xpath").click() sleep(2) parts[16]['success'] =\ test.is_current_url(reverse("rewards_index")) except Exception as e: print e parts[16]['test_message'] = str(e) ########## Punches must be a number try: add_reward("", "", "ba") parts[17]['success'] =\ test.find("#punches_ic ul li").text ==\ "Enter a whole number." test.find("//div [@id='edit-reward-options']/a[2]", type="xpath").click() sleep(2) except Exception as e: print e parts[17]['test_message'] = str(e) ########## Punches must be greater than 0 try: add_reward("", "", "0") parts[18]['success'] =\ test.find("#punches_ic ul li").text ==\ "Ensure this value is greater than or equal to 1." test.find("//div [@id='edit-reward-options']/a[2]", type="xpath").click() sleep(2) except Exception as e: print e parts[18]['test_message'] = str(e) ########## Rewards are initially sorted by Punchess ### from least to greatest try: store.rewards = None rewards = store.get('rewards') punches_map = {r['punches']:r for r in rewards} ascending = [r['punches'] for r in rewards] descending = ascending[:] ascending.sort() descending.sort(reverse=True) success = True for i in range(3): if int(test.find("//div[@id='%s']/a/div[1]" %(str(i+1),), type="xpath").text) != ascending[i]: success = False break parts[19]['success'] = success except Exception as e: print e parts[19]['test_message'] = str(e) ########## Punches is sortable try: test.find("#header-reward_punches").click() rows = test.find("//div[@id='rewards_section']/" +\ "div[contains(@class, 'reward')]", type="xpath", multiple=True) if len(rows) == len(descending): success = True for i in range(len(rows)): # check both the punches and id row = rows[i] if int(row.text.split("\n")[0]) !=\ descending[i] or int(row.get_attribute("id")) !=\ punches_map[descending[i]]['reward_id']: success = False break parts[20]['success'] = success except Exception as e: print e parts[20]['test_message'] = str(e) ########## Name is sortable try: name_map = {r['reward_name']:r for r in rewards} ascending = [r['reward_name'] for r in rewards] descending = ascending[:] ascending.sort() descending.sort(reverse=True) # ascending order test.find("#header-reward_summary").click() rows = test.find("//div[@id='rewards_section']/" +\ "div[contains(@class, 'reward')]", type="xpath", multiple=True) if len(rows) == len(ascending): success1 = True for i in range(len(rows)): # check both the name and id row = rows[i] if row.text.split("\n")[1] !=\ ascending[i] or int(row.get_attribute("id")) !=\ name_map[ascending[i]]['reward_id']: success1 = False break # descending order test.find("#header-reward_summary").click() rows = test.find("//div[@id='rewards_section']/" +\ "div[contains(@class, 'reward')]", type="xpath", multiple=True) if len(rows) == len(descending): success2 = True for i in range(len(rows)): # check both the name and id row = rows[i] if row.text.split("\n")[1] !=\ descending[i] or int(row.get_attribute("id")) !=\ name_map[descending[i]]['reward_id']: success2 = False break parts[21]['success'] = success1 and success2 except Exception as e: print e parts[21]['test_message'] = str(e) ########## Updating a reward with the reset redemption ### count option resets the redemption count to 0 try: # logout test.logout() test.dev_login() sleep(1) # modify store the rewards redemption count store.rewards = None for r in store.get("rewards"): r['redemption_count'] = 99 store.update() # login test.open(reverse("rewards_index")) # ACTION! sleep(1) selectors = ( ("#login_username", TEST_USER['username']), ("#login_password", TEST_USER['password']), ("", Keys.RETURN) ) test.action_chain(0, selectors, "send_keys") # ACTION! sleep(7) # now test test.find("//div[@id='2']/a", type="xpath").click() sleep(1) red_count = int(test.find("#redemption_count").text.split(" ")[1]) test.find("#reset_red_count").click() test.find("#submit-reward-form").click() sleep(5) test.find("//div[@id='2']/a", type="xpath").click() new_red_count =\ int(test.find("#redemption_count").text.split(" ")[1]) parts[22]['success'] = new_red_count == 0 and red_count !=\ new_red_count except Exception as e: print e parts[22]['test_message'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()
def test_employee_registration(): """ Tests for employee registrain via dashboard. """ # delete the employees and associated User objects in the relation account = Account.objects().get(email=TEST_USER['username'], include="Store.Settings") store = account.store settings = store.settings emps = store.get("employees") if emps: for emp in emps: Account.objects().get(Employee=emp.objectId).delete() emp.delete() store.set("employees", None) test = SeleniumTest() parts = [ {"test_name" : "Clicking register new employee button "+\ " redirects user to employee register page."}, {"test_name" : "New registered employee is immediately placed"+\ " in the approved group."}, {"test_name" : "Access level of new employee is the same as"+\ " the one chosen in the registration form."}, {"test_name" : "A valid email is required."}, {"test_name" : "Email must be unique."}, {"test_name" : "Email is required."}, {"test_name" : "First name is required."}, {"test_name" : "Last name is required."}, {"test_name" : "Password is required."}, {"test_name" : "Password confirm is required."}, {"test_name" : "Passwords must match."}, {"test_name" : "Password must be at least 6 characters long."}, ] section = { "section_name":\ "Employee registration functional?", "parts": parts, } test.results.append(section) test.login(TEST_USER['username'], TEST_USER['password'], reverse("employees_index")) ########## Clicking register new employee button ### redirects user to employee register page. try: test.find("#register_employee").click() sleep(3) parts[0]['success'] = test.is_current_url(reverse("employee_register")) except Exception as e: print e parts[0]['test_message'] = str(e) ########## New registered employee is immediately placed ### in the approved group. try: acl = test.find("#id_acl option[selected]").get_attribute("value") selectors = ( ("#id_email", TEST_EMPLOYEE['username']), ("#id_password", TEST_EMPLOYEE['password']), ("#id_confirm_password", TEST_EMPLOYEE['password']), ("#id_first_name", TEST_EMPLOYEE['first_name']), ("#id_last_name", TEST_EMPLOYEE['last_name']), ) test.action_chain(0, selectors, action="send_keys") test.find("#register-employee-submit").click() sleep(7) test.open(reverse("employees_index")) sleep(3) parts[1]['success'] = test.find("#tab-body-approved-employees"+\ " div.tr a div.td.first_name_approved").text ==\ TEST_EMPLOYEE['first_name'] except Exception as e: print e parts[1]['test_message'] = str(e) ########## Access level of new employee is the same as ### the one chosen in the registration form. try: test.find("#tab-body-approved-employees div.tr a").click() sleep(2) parts[2]['success'] = acl ==\ test.find("#ACL option[selected]").get_attribute("value") except Exception as e: print e parts[2]['test_message'] = str(e) ########## A valid email is required. try: test.open(reverse("employee_register")) sleep(2) test.find("#id_email").send_keys("jhfghjdfg@jfgh") test.find("#register-employee-submit").click() sleep(3) parts[3]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\ "Enter a valid email address." except Exception as e: print e parts[3]['test_message'] = str(e) ########## Email must be unique. try: selectors = ( ("#id_email", TEST_EMPLOYEE['username']), ("#id_password", "123456123"), ("#id_confirm_password", "123456123"), ("#id_first_name", "YOLO"), ("#id_last_name", "BOLO"), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#register-employee-submit").click() sleep(5) parts[4]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\ "Email is already being used." except Exception as e: print e parts[4]['test_message'] = str(e) ########## Email is required. 5 ########## First name is required. 6 ########## Last name is required. 7 ########## Password is required. 8 ########## Password confirm is required. 9 try: selectors = ( "#id_email", "#id_password", "#id_confirm_password", "#id_first_name", "#id_last_name", ) test.action_chain(0, selectors, action="clear") test.find("#register-employee-submit").click() sleep(3) for i, sel in enumerate(selectors): id = sel.replace("#id_", "") + "_ic" parts[i+5]['success'] =\ test.find("#%s > ul.errorlist > li" % (id,)).text ==\ "This field is required." except Exception as e: print e for i, sel in enumerate(selectors): parts[i + 5]['test_message'] = str(e) ########## Passwords must match. try: selectors = ( ("#id_password", "123456"), ("#id_confirm_password", "abcdefg"), ) test.action_chain(0, selectors, action="clear") test.action_chain(0, selectors, action="send_keys") test.find("#register-employee-submit").click() sleep(3) parts[10]['success'] = test.find("#password_ic > ul.errorlist > li").text ==\ "Passwords don't match." except Exception as e: print e parts[10]['test_message'] = str(e) ########## Password must be at least 6 characters long. try: test.find("#id_password").clear() test.find("#id_password").send_keys("123") test.find("#register-employee-submit").click() sleep(3) parts[11]['success'] =\ test.find("#password_ic > ul.errorlist > li").text ==\ "Ensure this value has at least 6 characters (it has 3)." except Exception as e: print e parts[11]['success'] = str(e) # END OF ALL TESTS - cleanup return test.tear_down()