def test_not_disabled(self): """ An anonymous user who provides the :verify: query string or user with is_disabled set to True should be redirected to the home page. An anonymous user who does not should see a 404. A user with is_active set to False should proceed to their destination. """ client = TestClient() user = UserFactory() #Anonymous user resp = client.get(reverse('view_profile')) path = resp.request.get('PATH_INFO') self.assertRedirects(resp, reverse('home') + '?next=' + path) # This is ugly, but it is an artifact of the way Django redirects # users who fail the `user_passes_test` decorator. qs = '?verify=%s' % user.user_guid next_qs = '?next=' + urlquote('/profile/view/%s' % qs) # Anonymous user navigates to url with :verify: in query string resp = client.get(reverse('view_profile') + qs) # Old path + qs is urlquoted and added to the url as the :next: param self.assertRedirects(resp, "http://testserver/" + next_qs) # Active user client.login_user(user) resp = client.get(reverse('view_profile')) self.assertTrue(resp.status_code, 200) #Disabled user user.is_disabled = True user.save() resp = client.get(reverse('view_profile')) self.assertRedirects(resp, "http://testserver/?next=/profile/view/")
def test_not_disabled(self): """ An anonymous user who provides the :verify: query string or user with is_disabled set to True should be redirected to the home page. An anonymous user who does not should see a 404. A user with is_active set to False should proceed to their destination. """ client = TestClient() user = UserFactory(email="*****@*****.**") # Anonymous user resp = client.get(reverse('view_profile')) path = resp.request.get('PATH_INFO') self.assertRedirects(resp, reverse('home') + '?next=' + path) # This is ugly, but it is an artifact of the way Django redirects # users who fail the `user_passes_test` decorator. qs = '?verify=%s' % user.user_guid next_qs = '?next=' + urlquote('/profile/view/%s' % qs) # Anonymous user navigates to url with :verify: in query string resp = client.get(reverse('view_profile') + qs) # Old path + qs is urlquoted and added to the url as the :next: param self.assertRedirects(resp, "http://testserver/" + next_qs) # Active user client.login_user(user) resp = client.get(reverse('view_profile')) self.assertTrue(resp.status_code, 200) # Disabled user user.is_disabled = True user.save() resp = client.get(reverse('view_profile')) self.assertRedirects(resp, "http://testserver/?next=/profile/view/")
class TestDownloads(MyReportsTestCase): """Tests the reports view.""" def setUp(self): super(TestDownloads, self).setUp() self.client = TestClient(path=reverse('downloads'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner__owner=self.company) def test_column_order(self): """Tests that column order is preserved""" # create a report whose results is for all contact records in the # company response = self.client.post(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' })) report_name = response.content report = Report.objects.get(name=report_name) report.values = json.dumps(['partner', 'contact name', 'contact_type']) report.save() response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['columns'].items()[:3], [('Partner', True), ('Contact Name', True), ('Communication Type', True)]) def test_blacklisted_columns(self): """Test that blacklisted columns aren't visible.""" blacklist = ['pk', 'approval_status'] response = self.client.post( path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' }), data={'values': ['partner', 'contact__name', 'contact_type']}) report_name = response.content report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.id}) self.assertFalse( set(response.context['columns']).intersection(blacklist))
class TestDownloadReport(MyReportsTestCase): """Tests that reports can be downloaded.""" def setUp(self): super(TestDownloadReport, self).setUp() self.client = TestClient(path=reverse('download_report')) self.client.login_user(self.user) ContactRecordFactory.create_batch(5, partner__owner=self.company) ContactRecordFactory.create_batch( 5, contact_type='job', job_applications=1, partner__owner=self.company) ContactRecordFactory.create_batch( 5, contact_type='job', job_hires=1, partner__owner=self.company) def test_download_csv(self): """Test that a report can be downloaded in CSV format.""" # create a report whose results is for all contact records in the # company response = self.client.post(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) report_name = response.content report = Report.objects.get(name=report_name) # download the report response = self.client.get(data={'id': report.pk}) self.assertEqual(response['Content-Type'], 'text/csv')
class TestDownloads(MyReportsTestCase): """Tests the reports view.""" def setUp(self): super(TestDownloads, self).setUp() self.client = TestClient(path=reverse('downloads'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner__owner=self.company) def test_column_order(self): """Tests that column order is preserved""" # create a report whose results is for all contact records in the # company response = self.client.post( path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'}), data={'values': ['partner', 'contact__name', 'contact_type']}) report_name = response.content report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['columns'], { 'Partner': True, 'Contact Name': True, 'Contact Type': True})
class TestDownloadReport(MyReportsTestCase): """Tests that reports can be downloaded.""" def setUp(self): super(TestDownloadReport, self).setUp() self.client = TestClient(path=reverse("download_report")) self.client.login_user(self.user) ContactRecordFactory.create_batch(5, partner__owner=self.company) ContactRecordFactory.create_batch(5, contact_type="job", job_applications=1, partner__owner=self.company) ContactRecordFactory.create_batch(5, contact_type="job", job_hires=1, partner__owner=self.company) def test_download_csv(self): """Test that a report can be downloaded in CSV format.""" # create a report whose results is for all contact records in the # company response = self.client.post(path=reverse("reports", kwargs={"app": "mypartners", "model": "contactrecord"})) report_name = response.content report = Report.objects.get(name=report_name) python = report.python # download the report response = self.client.get(data={"id": report.pk, "values": ["contact", "contact_email", "contact_phone"]}) self.assertEqual(response["Content-Type"], "text/csv") # specifying export values shouldn't modify the underlying report self.assertEqual(len(python[0].keys()), len(report.python[0].keys()))
class TestDownloads(MyReportsTestCase): """Tests the reports view.""" def setUp(self): super(TestDownloads, self).setUp() self.client = TestClient(path=reverse('downloads'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner__owner=self.company) def test_column_order(self): """Tests that column order is preserved""" # create a report whose results is for all contact records in the # company response = self.client.post( path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) report_name = response.content report = Report.objects.get(name=report_name) report.values = json.dumps(['partner', 'contact name', 'contact_type']) report.save() response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['columns'].items()[:3], [('Partner', True), ('Contact Name', True), ('Communication Type', True)]) def test_blacklisted_columns(self): """Test that blacklisted columns aren't visible.""" blacklist = ['pk', 'approval_status'] response = self.client.post( path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'}), data={'values': ['partner', 'contact__name', 'contact_type']}) report_name = response.content report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.id}) self.assertFalse( set(response.context['columns']).intersection(blacklist))
class UserResourceTestCase(MyJobsBase): def setUp(self): super(UserResourceTestCase, self).setUp() create_api_key(User, instance=self.user, created=True) self.client = TestClient(path='/api/v1/user/', data={ 'email': '*****@*****.**', 'username': self.user.email, 'api_key': self.user.api_key.key }) def test_create_new_user(self): self.assertEqual(len(mail.outbox), 0) response = self.client.get() self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, 'Account Activation for my.jobs') content = json.loads(response.content) self.assertEqual(content, { 'user_created': True, 'email': '*****@*****.**' }) self.assertEqual(response.status_code, 200) self.assertEqual(User.objects.count(), 2) user = User.objects.get(email=self.client.data['email']) for field, value in [('is_active', True), ('is_verified', False)]: self.assertEqual(getattr(user, field), value) def test_no_email(self): self.client.data['email'] = '' response = self.client.get() content = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(content['email'], 'No email provided') def test_existing_user(self): for email in [self.user.email, self.user.email.upper()]: self.client.data['email'] = email response = self.client.get() content = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertFalse(content['user_created']) self.assertEqual(content['email'].lower(), '*****@*****.**')
def test_inactive_user_sees_message(self): """ A user with is_verified or is_active set to False should see an activation message instead of the content they were originally meaning to see. """ client = TestClient(path=reverse('saved_search_main')) user = UserFactory(email="*****@*****.**") # Active user client.login_user(user) resp = client.get() self.assertIn('Saved Search', resp.content) # Inactive user user.is_verified = False user.save() resp = client.get() self.assertIn('unavailable', resp.content)
def test_inactive_user_sees_message(self): """ A user with is_verified or is_active set to False should see an activation message instead of the content they were originally meaning to see. """ client = TestClient(path=reverse('saved_search_main')) user = UserFactory() # Active user client.login_user(user) resp = client.get() self.assertIn('Saved Search', resp.content) # Inactive user user.is_verified= False user.save() resp = client.get() self.assertIn('unavailable', resp.content)
class TestDownloads(MyReportsTestCase): """Tests the reports view.""" def setUp(self): super(TestDownloads, self).setUp() self.client = TestClient(path=reverse("downloads"), HTTP_X_REQUESTED_WITH="XMLHttpRequest") self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner__owner=self.company) def test_column_order(self): """Tests that column order is preserved""" # create a report whose results is for all contact records in the # company response = self.client.post(path=reverse("reports", kwargs={"app": "mypartners", "model": "contactrecord"})) report_name = response.content report = Report.objects.get(name=report_name) report.values = json.dumps(["partner", "contact name", "contact_type"]) report.save() response = self.client.get(data={"id": report.id}) self.assertEqual(response.status_code, 200) self.assertEqual( response.context["columns"].items()[:3], [("Partner", True), ("Contact Name", True), ("Communication Type", True)], ) def test_blacklisted_columns(self): """Test that blacklisted columns aren't visible.""" blacklist = ["pk", "approval_status"] response = self.client.post( path=reverse("reports", kwargs={"app": "mypartners", "model": "contactrecord"}), data={"values": ["partner", "contact__name", "contact_type"]}, ) report_name = response.content report = Report.objects.get(name=report_name) response = self.client.get(data={"id": report.id}) self.assertFalse(set(response.context["columns"]).intersection(blacklist))
class UserResourceTests(MyJobsBase): def setUp(self): super(UserResourceTests, self).setUp() self.user = UserFactory() create_api_key(User, instance=self.user, created=True) self.client = TestClient( path='/api/v1/user/', data={'email': '*****@*****.**', 'username': self.user.email, 'api_key': self.user.api_key.key}) def test_create_new_user(self): self.assertEqual(len(mail.outbox), 0) response = self.client.get() self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, 'Account Activation for my.jobs') content = json.loads(response.content) self.assertEqual(content, {'user_created': True, 'email': '*****@*****.**'}) self.assertEqual(response.status_code, 200) self.assertEqual(User.objects.count(), 2) user = User.objects.get(email=self.client.data['email']) for field, value in [('is_active', True), ('is_verified', False)]: self.assertEqual(getattr(user, field), value) def test_no_email(self): self.client.data['email'] = '' response = self.client.get() content = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(content['email'], 'No email provided') def test_existing_user(self): for email in [self.user.email, self.user.email.upper()]: self.client.data['email'] = email response = self.client.get() content = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertFalse(content['user_created']) self.assertEqual(content['email'].lower(), '*****@*****.**')
class TestRegenerate(MyReportsTestCase): """Tests the reports can be regenerated.""" def setUp(self): super(TestRegenerate, self).setUp() self.client = TestClient(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner__owner=self.company) def test_regenerate(self): # create a report whose results is for all contact records in the # company response = self.client.post( path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'}), data={'values': ['partner', 'contact__name', 'contact_type']}) report_name = response.content report = Report.objects.get(name=report_name) results = report.results response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) # remove report results and ensure we can still get a resonable # response report.results.delete() report.save() self.assertFalse(report.results) response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) # regenerate results and ensure they are the same as the original response = self.client.get(path=reverse('regenerate'), data={ 'id': report.pk}) report = Report.objects.get(name=report_name) self.assertEqual(response.status_code, 200) self.assertTrue(report.results)
class RemoteAccessRequestModelTests(MyJobsBase): def setUp(self): super(RemoteAccessRequestModelTests, self).setUp() self.password = '******' self.client = TestClient() self.client.login(email=self.user.email, password=self.password) self.account_owner = UserFactory(email='*****@*****.**', password=self.password) self.impersonate_url = reverse('impersonate-start', kwargs={ 'uid': self.account_owner.pk}) self.site = SeoSite.objects.first() def test_create_request_sends_messages(self): """ The requesting of remote access should send both a My.jobs message and an email to the account owner. """ msg = "User had %s messages, expected %s" mail.outbox = [] spar = SecondPartyAccessRequest.objects.create( account_owner=self.account_owner, second_party=self.user, site=self.site, reason='just cuz') self.assertEqual(len(mail.outbox), 1) # We're logged in as the requesting user at this point and should # not have any messages. response = self.client.get(reverse('home')) self.assertEqual(len(response.context['new_messages']), 0, msg=msg % (len(response.context['new_messages']), 0)) response = self.client.get(reverse('impersonate-approve', kwargs={'access_id': spar.id})) self.assertEqual(response.status_code, 403, msg=("Unauthorized approval of a request should not " "happen but did")) # Log out then log in as the account owner. self.client.get(reverse('auth_logout')) self.client.login(email=self.account_owner.email, password=self.password) response = self.client.get(reverse('home')) # We should now have one My.jobs message. messages = response.context['new_messages'] self.assertEqual(len(messages), 1, msg=msg % (len(response.context['new_messages']), 1)) message = messages[0] email = mail.outbox[0] self.assertEqual(message.message.body, email.body, msg="Message and email bodies were not identical") for text in ['>Allow<', '>Deny<', spar.reason, self.user.get_full_name(default=self.user.email)]: self.assertTrue(text in email.body, msg="%s not in email body" % text) response = self.client.get(reverse('impersonate-approve', kwargs={'access_id': spar.id})) spar = SecondPartyAccessRequest.objects.get(pk=spar.pk) self.assertEqual(spar.accepted, True, msg="Acceptance status was not updated")
class TestReportView(MyReportsTestCase): """ Tests the ReportView class, which is used to create and retrieve reports. """ def setUp(self): super(TestReportView, self).setUp() self.client = TestClient(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) self.client.login_user(self.user) ContactRecordFactory.create_batch(5, partner__owner=self.company) ContactRecordFactory.create_batch( 5, contact_type='job', job_applications=1, partner__owner=self.company) ContactRecordFactory.create_batch( 5, contact_type='job', job_hires=1, partner__owner=self.company) def test_create_report(self): """Test that a report model instance is properly created.""" # create a report whose results is for all contact records in the # company response = self.client.post() report_name = response.content report = Report.objects.get(name=report_name) self.assertEqual(len(report.python), 15) # we use this in other tests return report_name def test_get_report(self): """Test that chart data is retreived from record results.""" report_name = self.test_create_report() report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.pk}) data = json.loads(response.content) # check contact record stats for key in ['applications', 'hires', 'communications', 'emails']: self.assertEqual(data[key], 5) # check contact stats self.assertEqual(data['contacts'][0]['records'], 1) self.assertEqual(data['contacts'][0]['referrals'], 10)
class UserResourceTestCase(MyJobsBase): def setUp(self): super(UserResourceTestCase, self).setUp() create_api_key(User, instance=self.user, created=True) self.client = TestClient( path="/api/v1/user/", data={"email": "*****@*****.**", "username": self.user.email, "api_key": self.user.api_key.key}, ) def test_create_new_user(self): self.assertEqual(len(mail.outbox), 0) response = self.client.get() self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, "Account Activation for my.jobs") content = json.loads(response.content) self.assertEqual(content, {"user_created": True, "email": "*****@*****.**"}) self.assertEqual(response.status_code, 200) self.assertEqual(User.objects.count(), 2) user = User.objects.get(email=self.client.data["email"]) for field, value in [("is_active", True), ("is_verified", False)]: self.assertEqual(getattr(user, field), value) def test_no_email(self): self.client.data["email"] = "" response = self.client.get() content = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(content["email"], "No email provided") def test_existing_user(self): for email in [self.user.email, self.user.email.upper()]: self.client.data["email"] = email response = self.client.get() content = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertFalse(content["user_created"]) self.assertEqual(content["email"].lower(), "*****@*****.**")
class TestDownloadReport(MyReportsTestCase): """Tests that reports can be downloaded.""" def setUp(self): super(TestDownloadReport, self).setUp() self.client = TestClient(path=reverse('download_report')) self.client.login_user(self.user) ContactRecordFactory.create_batch(5, partner__owner=self.company) ContactRecordFactory.create_batch(5, contact_type='job', job_applications=1, partner__owner=self.company) ContactRecordFactory.create_batch(5, contact_type='job', job_hires=1, partner__owner=self.company) def test_download_csv(self): """Test that a report can be downloaded in CSV format.""" # create a report whose results is for all contact records in the # company response = self.client.post(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' })) report_name = response.content report = Report.objects.get(name=report_name) python = report.python # download the report response = self.client.get( data={ 'id': report.pk, 'values': ['contact', 'contact_email', 'contact_phone'] }) self.assertEqual(response['Content-Type'], 'text/csv') # specifying export values shouldn't modify the underlying report self.assertEqual(len(python[0].keys()), len(report.python[0].keys()))
class TestViewRecords(MyReportsTestCase): """ Tests the `view_records` view which is used to query various models. """ def setUp(self): super(TestViewRecords, self).setUp() self.client = TestClient(path="/reports/ajax/mypartners", HTTP_X_REQUESTED_WITH="XMLHttpRequest") self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner=self.partner, contact__name="Joe Shmoe") def test_restricted_to_ajax(self): """View should only be reachable through AJAX.""" self.client.path += "/partner" self.client.defaults.pop("HTTP_X_REQUESTED_WITH") response = self.client.post() self.assertEqual(response.status_code, 404) def test_restricted_to_get(self): """POST requests should raise a 404.""" self.client.path += "/partner" response = self.client.post() self.assertEqual(response.status_code, 404) def test_json_output(self): """Test that filtering contact records through ajax works properly.""" # records to be filtered out ContactRecordFactory.create_batch(10, contact__name="John Doe") self.client.path += "/contactrecord" response = self.client.get(data={"contact__name": "Joe Shmoe"}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_only_user_results_returned(self): """Results should only contain records user has access to.""" # records not owned by user partner = PartnerFactory(name="Wrong Partner") ContactRecordFactory.create_batch(10, partner=partner) self.client.path += "/contactrecord" response = self.client.get() output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filtering_on_partner(self): """Test the ability to filter by partner.""" # we already have one because of self.partner PartnerFactory.create_batch(9, name="Test Partner", owner=self.company) self.client.path += "/partner" response = self.client.get(data={"name": "Test Partner"}) output = json.loads(response.content) # ContactRecordFactory creates 10 partners in setUp self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_list_query_params(self): """Test that query parameters that are lists are parsed correctly.""" contacts = ContactFactory.create_batch(10, partner__owner=self.company) pks = [contact.pk for contact in contacts[:5]] self.client.path += "/partner" response = self.client.get(data={"contact": pks}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 5) def test_filtering_on_contact(self): """Test the ability to filter by contact.""" ContactFactory.create_batch(10, name="Jen Doe", partner=self.partner) # contacts with the wrong name ContactFactory.create_batch(10, name="Jen Smith", partner=self.partner) self.client.path += "/contact" response = self.client.get(data={"name": "Jen Doe"}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filter_by_state(self): """Tests that filtering by state works.""" indiana = LocationFactory(state="IN") ContactFactory.create_batch(10, name="Jen Doe", partner=self.partner, locations=[indiana]) self.client.path += "/contact" response = self.client.get(data={"state": "IN"}) output = json.loads(response.content) self.assertEqual(len(output), 10) def test_filter_by_city(self): """Tests that filtering by city works.""" indianapolis = LocationFactory(city="Indianapolis") ContactFactory.create_batch(10, name="Jen Doe", partner=self.partner, locations=[indianapolis]) self.client.path += "/contact" response = self.client.get(data={"city": "indianapolis"}) output = json.loads(response.content) self.assertEqual(len(output), 10) def test_filter_by_tag(self): """Tests that records can be found by tag.""" tag = TagFactory(name="Test", company=self.company) ContactRecord.objects.first().tags.add(tag) # explicitly add tag to partner to make sure that a tag associated wiht # multiple models doesn't cause issues self.partner.tags.add(tag) self.client.path += "/tag" # make a call that mimicks static/reporting:721 (as of 7/1/15) response = self.client.get( data={"name": "Test", "contactrecord__isnull": "false", "values": ["name"], "order_by": "name"} ) output = json.loads(response.content) self.assertEqual(len(output), 1)
class MyProfileViewsTests(MyJobsBase): def setUp(self): super(MyProfileViewsTests, self).setUp() self.client = TestClient() self.client.login_user(self.user) self.name = PrimaryNameFactory(user=self.user) def test_edit_profile(self): """ Going to the edit_profile view generates a list of existing profile items in the main content section and a list of profile sections that don't have data filled out in the sidebar. """ resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item = soup.find('div', id='profileTitleBar') # Page should have fake user's email as title self.assertIsNotNone(soup.find_all('h3', text="*****@*****.**")) # The only module that is complete at this point is 'Name'. So there # should only be one module displayed in the moduleColumn div self.assertEquals(1, len(soup.findAll("div", { "class" : "card-wrapper" }))) # The 'Add a New Section' section should have many items # Check for each one self.assertEquals(10, len(soup.findAll("tr", { "class" : "profile-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Education-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Address-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Telephone-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Employment History-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Secondary Email-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Military Service-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Website-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "License-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Summary-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Volunteer History-new-section" }))) self.assertEquals(1, len(soup.findAll("a", { "id" : "Summary-new-section" }))) def test_handle_form_post_new_valid(self): """ Invoking the handle_form view as a POST request for a new item creates that object in the database and returns the item snippet to be rendered on the page. """ resp = self.client.post(reverse('handle_form'), data={'module': 'Name', 'id': 'new', 'given_name': 'Susy', 'family_name': 'Smith'}) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual(Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_delete_item(self): """ Invoking the delete_item view deletes the item and returns the 'Deleted!' HttpResponse """ resp = self.client.post(reverse('delete_item')+'?item='+str(self.name.id)) self.assertEqual(resp.content, '') self.assertEqual(Name.objects.filter(id=self.name.id).count(), 0) def test_edit_summary(self): """ See test_edit_profile """ summary = SummaryFactory(user=self.user) resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item = soup.find('div', id='summary-' + str(summary.id) + '-item') self.assertIsNotNone(item) link = item.find('a').attrs['href'] resp = self.client.get(link) self.assertEqual(resp.status_code, 200) def test_handle_form_post_invalid(self): """ Invoking the handle_form view as a POST request with an invalid form returns the list of form errors. """ resp = self.client.post(reverse('handle_form'), data={'module': 'Name', 'id': 'new', 'given_name': 'Susy'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'family_name': [u'This field is required.']}) resp = self.client.post(reverse('handle_form'), data={'module': 'Name', 'id': 'new', 'family_name': 'Smithers'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'given_name': [u'This field is required.']}) def test_handle_form_post_existing_valid(self): """ Invoking the handle_form view as a POST request for an existing item updates that item and returns the update item snippet. """ resp = self.client.post(reverse('handle_form'), data={'module': 'Name', 'id': self.name.id, 'given_name': 'Susy', 'family_name': 'Smith'}) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual(Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_handle_form_json_serialize_get(self): """When an ajax requests wants to GET json, serialize the form.""" resp = self.client.get(reverse('handle_form'), HTTP_ACCEPT='application/json', data={'module': 'Name'}) self.assertEquals(200, resp.status_code) self.assertIn('application/json', resp['content-type']) data = json.loads(resp.content) self.assertEquals(3, len(data['ordered_fields'])) self.assertIsInstance(data['ordered_fields'], list) self.assertEquals(3, len(data['fields'])) self.assertIsInstance(data['fields'], dict) self.assertIsInstance(data['fields']['family_name'], dict) self.assertIsInstance(data['fields']['given_name'], dict) self.assertIsInstance(data['fields']['primary'], dict) self.assertEquals(3, len(data['data'])) self.assertIsInstance(data['data'], dict) def test_add_duplicate_primary_email(self): """ Attempting to add a secondary email with a value equal to the user's current primary email results in an error. Due to how the instance is constructed, this validation is form-level rather than model-level. """ resp = self.client.post(reverse('handle_form'), data={'module': 'SecondaryEmail', 'id': 'new', 'email': self.user.email}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'email': [u'This email is already registered.']})
class RemoteAccessRequestModelTests(MyJobsBase): def setUp(self): super(RemoteAccessRequestModelTests, self).setUp() self.password = '******' self.client = TestClient() self.client.login(email=self.user.email, password=self.password) self.account_owner = UserFactory(email='*****@*****.**', password=self.password) self.impersonate_url = reverse('impersonate-start', kwargs={'uid': self.account_owner.pk}) self.site = SeoSite.objects.first() def test_create_request_sends_messages(self): """ The requesting of remote access should send both a My.jobs message and an email to the account owner. """ msg = "User had %s messages, expected %s" mail.outbox = [] spar = SecondPartyAccessRequest.objects.create( account_owner=self.account_owner, second_party=self.user, site=self.site, reason='just cuz') self.assertEqual(len(mail.outbox), 1) # We're logged in as the requesting user at this point and should # not have any messages. response = self.client.get(reverse('home')) self.assertEqual(len(response.context['new_messages']), 0, msg=msg % (len(response.context['new_messages']), 0)) response = self.client.get( reverse('impersonate-approve', kwargs={'access_id': spar.id})) self.assertEqual(response.status_code, 403, msg=("Unauthorized approval of a request should not " "happen but did")) # Log out then log in as the account owner. self.client.get(reverse('auth_logout')) self.client.login(email=self.account_owner.email, password=self.password) response = self.client.get(reverse('home')) # We should now have one My.jobs message. messages = response.context['new_messages'] self.assertEqual(len(messages), 1, msg=msg % (len(response.context['new_messages']), 1)) message = messages[0] email = mail.outbox[0] self.assertEqual(message.message.body, email.body, msg="Message and email bodies were not identical") for text in [ '>Allow<', '>Deny<', spar.reason, self.user.get_full_name(default=self.user.email) ]: self.assertTrue(text in email.body, msg="%s not in email body" % text) response = self.client.get( reverse('impersonate-approve', kwargs={'access_id': spar.id})) spar = SecondPartyAccessRequest.objects.get(pk=spar.pk) self.assertEqual(spar.accepted, True, msg="Acceptance status was not updated")
class TestReportView(MyReportsTestCase): """ Tests the ReportView class, which is used to create and retrieve reports. """ def setUp(self): super(TestReportView, self).setUp() self.client = TestClient(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' })) self.client.login_user(self.user) ContactRecordFactory.create_batch(5, partner=self.partner) ContactRecordFactory.create_batch(5, contact_type='job', job_applications="1", job_interviews="0", job_hires="0", partner=self.partner) ContactRecordFactory.create_batch(5, contact_type='job', job_applications="0", job_interviews="0", job_hires="1", partner=self.partner) def test_create_report(self): """Test that a report model instance is properly created.""" # create a report whose results is for all contact records in the # company response = self.client.post() report_name = response.content report = Report.objects.get(name=report_name) self.assertEqual(len(report.python), 15) # we use this in other tests return report_name def test_get_report(self): """Test that chart data is retreived from record results.""" report_name = self.test_create_report() report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.pk}) data = json.loads(response.content) # check contact record stats for key in ['applications', 'hires', 'communications', 'emails']: self.assertEqual(data[key], 5) for contact in data['contacts']: self.assertTrue(contact['records'] < 2) self.assertTrue(contact['referrals'] < 2) total = contact['records'] + contact['referrals'] self.assertEqual(total, 1) def test_reports_exclude_archived(self): """ Test that reports exclude archived records as appropriate. This includes non-archived records associated with archived records. """ self.client.path = reverse('view_records', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' }) response = self.client.post(HTTP_X_REQUESTED_WITH='XMLHttpRequest') content = json.loads(response.content) self.assertEqual(len(content), 15) ContactRecord.objects.last().archive() # Archiving one communication record should result in one fewer entry # in the returned json. response = self.client.post(HTTP_X_REQUESTED_WITH='XMLHttpRequest') content = json.loads(response.content) self.assertEqual(len(content), 14) Partner.objects.last().archive() # Archiving the partner governing these communication records should # exclude all of them from the returned json even if they aren't # archived. response = self.client.post(HTTP_X_REQUESTED_WITH='XMLHttpRequest') content = json.loads(response.content) self.assertEqual(len(content), 0)
class MessageViewTests(MyJobsBase): def setUp(self): super(MessageViewTests, self).setUp() self.message = Message.objects.create(subject='subject', body='body', message_type='success') for group in Group.objects.all(): self.message.group.add(group.pk) self.messageinfo = MessageInfo.objects.create(user=self.user, message=self.message) self.client = TestClient() self.client.login_user(self.user) def test_user_post_mark_message_read(self): self.client.get(reverse('read'), data={ 'name': 'message-read-' + str(self.message.id) + '-' + str(self.user.id) }, follow=True, HTTP_X_REQUESTED_WITH='XMLHttpRequest') m = MessageInfo.objects.get(user=self.user, message=self.message) self.assertTrue(m.read) self.assertTrue(m.read_at) def test_delete_message(self): """ Deleting a MessageInfo should instead mark it as deleted. """ self.assertTrue(self.messageinfo.deleted_on is None) self.client.get(reverse('delete'), data={ 'name': 'message-delete-' + str(self.message.id) + '-' + str(self.user.id) }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.messageinfo = MessageInfo.objects.get(pk=self.messageinfo.pk) self.assertIsNotNone(self.messageinfo.deleted_on) def test_auto_page_inbox(self): """ If a "message=%d" parameter is passed on an inbox view, we should detect which page that message appears on and select it. """ infos = MessageInfoFactory.create_batch(11, user=self.user) request = self.client.get(reverse('inbox')) self.assertTrue('Page 1 of 2' in request.content) # Messages are displayed in reverse creation order, so the first item # in the list is the last item on the last page. request = self.client.get( reverse('inbox') + '?message=%s' % infos[0].message.pk) self.assertTrue('Page 2 of 2' in request.content) def test_system_message_as_alert(self): """ Only system messages should show as alerts. """ button_class = 'mymessage-read-{message}-{user}'.format( message=self.message.pk, user=self.user.pk) response = self.client.get(reverse('home')) self.assertNotIn(button_class, response.content) self.message.system = True self.message.save() response = self.client.get(reverse('home')) self.assertIn(button_class, response.content)
class MyProfileViewsTests(MyJobsBase): def setUp(self): super(MyProfileViewsTests, self).setUp() self.client = TestClient() self.client.login_user(self.user) self.name = PrimaryNameFactory(user=self.user) def test_edit_profile(self): """ Going to the edit_profile view generates a list of existing profile items in the main content section and a list of profile sections that don't have data filled out in the sidebar. """ resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item = soup.find('div', id='profileTitleBar') # Page should have fake user's email as title self.assertIsNotNone(soup.find_all('h3', text="*****@*****.**")) # The only module that is complete at this point is 'Name'. So there # should only be one module displayed in the moduleColumn div self.assertEquals(1, len(soup.findAll("div", {"class": "card-wrapper"}))) # The 'Add a New Section' section should have many items # Check for each one self.assertEquals( 10, len(soup.findAll("tr", {"class": "profile-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Education-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Address-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Telephone-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Employment History-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Secondary Email-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Military Service-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Website-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "License-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Summary-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Volunteer History-new-section"}))) self.assertEquals( 1, len(soup.findAll("a", {"id": "Summary-new-section"}))) def test_handle_form_post_new_valid(self): """ Invoking the handle_form view as a POST request for a new item creates that object in the database and returns the item snippet to be rendered on the page. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'Name', 'id': 'new', 'given_name': 'Susy', 'family_name': 'Smith' }) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual( Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_delete_item(self): """ Invoking the delete_item view deletes the item and returns the 'Deleted!' HttpResponse """ resp = self.client.post( reverse('delete_item') + '?item=' + str(self.name.id)) self.assertEqual(resp.content, '') self.assertEqual(Name.objects.filter(id=self.name.id).count(), 0) def test_edit_summary(self): """ See test_edit_profile """ summary = SummaryFactory(user=self.user) resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item = soup.find('div', id='summary-' + str(summary.id) + '-item') self.assertIsNotNone(item) link = item.find('a').attrs['href'] resp = self.client.get(link) self.assertEqual(resp.status_code, 200) def test_handle_form_post_invalid(self): """ Invoking the handle_form view as a POST request with an invalid form returns the list of form errors. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'Name', 'id': 'new', 'given_name': 'Susy' }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'family_name': [u'This field is required.']}) resp = self.client.post(reverse('handle_form'), data={ 'module': 'Name', 'id': 'new', 'family_name': 'Smithers' }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'given_name': [u'This field is required.']}) def test_handle_form_post_existing_valid(self): """ Invoking the handle_form view as a POST request for an existing item updates that item and returns the update item snippet. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'Name', 'id': self.name.id, 'given_name': 'Susy', 'family_name': 'Smith' }) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual( Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_handle_form_json_serialize_get(self): """When an ajax requests wants to GET json, serialize the form.""" resp = self.client.get(reverse('handle_form'), HTTP_ACCEPT='application/json', data={'module': 'Name'}) self.assertEquals(200, resp.status_code) self.assertIn('application/json', resp['content-type']) data = json.loads(resp.content) self.assertEquals(3, len(data['ordered_fields'])) self.assertIsInstance(data['ordered_fields'], list) self.assertEquals(3, len(data['fields'])) self.assertIsInstance(data['fields'], dict) self.assertIsInstance(data['fields']['family_name'], dict) self.assertIsInstance(data['fields']['given_name'], dict) self.assertIsInstance(data['fields']['primary'], dict) self.assertEquals(3, len(data['data'])) self.assertIsInstance(data['data'], dict) def test_add_duplicate_primary_email(self): """ Attempting to add a secondary email with a value equal to the user's current primary email results in an error. Due to how the instance is constructed, this validation is form-level rather than model-level. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'SecondaryEmail', 'id': 'new', 'email': self.user.email }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'email': [u'This email is already registered.']})
class MyProfileViewsTests(MyJobsBase): def setUp(self): super(MyProfileViewsTests, self).setUp() self.client = TestClient() self.client.login_user(self.user) self.name = PrimaryNameFactory(user=self.user) def test_edit_profile(self): """ Going to the edit_profile view generates a list of existing profile items in the main content section and a list of profile sections that don't have data filled out in the sidebar. """ resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item_id = self.name.id # The existing name object should be rendered on the main content # section self.assertIsNotNone( soup.find('div', id='name-' + str(item_id) + '-item')) # profile-section contains the name of a profile section that has no # information filled out yet and shows up in the sidebar self.assertTrue(soup.findAll('tr', {'class': 'profile-section'})) def test_edit_summary(self): """ See test_edit_profile """ summary = SummaryFactory(user=self.user) resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item = soup.find('div', id='summary-' + str(summary.id) + '-item') self.assertIsNotNone(item) link = item.find('a').attrs['href'] resp = self.client.get(link) self.assertEqual(resp.status_code, 200) def test_handle_form_get_new(self): """ Invoking the handle_form view without an id parameter returns an empty form with the correct form id """ resp = self.client.get(reverse('handle_form'), data={'module': 'Name'}) self.assertTemplateUsed(resp, 'myprofile/profile_form.html') soup = BeautifulSoup(resp.content) self.assertEquals(soup.form.attrs['id'], 'profile-unit-form') with self.assertRaises(KeyError): soup.find('input', id='id_name-given_name').attrs['value'] def test_handle_form_get_existing(self): """ Invoking the handle_form view with and id paraemeter returns a form filled out with the corresponding profile/ID combination """ resp = self.client.get(reverse('handle_form'), data={ 'module': 'Name', 'id': self.name.id }) self.assertTemplateUsed(resp, 'myprofile/profile_form.html') soup = BeautifulSoup(resp.content) self.assertEquals(soup.form.attrs['id'], 'profile-unit-form') self.assertEquals( soup.find('input', id='id_name-given_name').attrs['value'], 'Alice') self.assertEquals( soup.find('input', id='id_name-family_name').attrs['value'], 'Smith') self.assertEquals( soup.find('input', id='id_name-primary').attrs['checked'], 'checked') def test_handle_form_post_new_valid(self): """ Invoking the handle_form view as a POST request for a new item creates that object in the database and returns the item snippet to be rendered on the page. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'Name', 'id': 'new', 'given_name': 'Susy', 'family_name': 'Smith' }) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual( Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_handle_form_post_invalid(self): """ Invoking the handle_form view as a POST request with an invalid form returns the list of form errors. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'Name', 'id': 'new', 'given_name': 'Susy' }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'family_name': [u'This field is required.']}) def test_handle_form_post_existing_valid(self): """ Invoking the handle_form view as a POST request for an existing item updates that item and returns the update item snippet. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'Name', 'id': self.name.id, 'given_name': 'Susy', 'family_name': 'Smith' }) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual( Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_handle_form_redirect_summary(self): """ When a user has a summary already if they try to make a new summary handle form should redirect the user to edit the summary they already have. User is only allowed one summary per account. """ summary_instance = SummaryFactory(user=self.user) summary_instance.save() resp = self.client.get(reverse('handle_form'), data={'module': 'Summary'}) self.assertRedirects( resp, reverse('handle_form') + '?id=%s&module=Summary' % summary_instance.id) def test_delete_item(self): """ Invoking the delete_item view deletes the item and returns the 'Deleted!' HttpResponse """ resp = self.client.post( reverse('delete_item') + '?item=' + str(self.name.id)) self.assertEqual(resp.content, '') self.assertEqual(Name.objects.filter(id=self.name.id).count(), 0) def test_add_duplicate_primary_email(self): """ Attempting to add a secondary email with a value equal to the user's current primary email results in an error. Due to how the instance is constructed, this validation is form-level rather than model-level. """ resp = self.client.post(reverse('handle_form'), data={ 'module': 'SecondaryEmail', 'id': 'new', 'email': self.user.email }, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'email': [u'This email is already registered.']}) def test_default_country_changes(self): """ The displayed country when editing an address should update to reflect the chosen country. """ resp = self.client.get(reverse('handle_form'), data={'module': 'Address'}) content = BeautifulSoup(resp.content) selected = content.find('option', attrs={'selected': True}) self.assertEqual(selected.attrs['value'], 'USA') address = AddressFactory(user=self.user, country_code='AFG') resp = self.client.get(reverse('handle_form'), data={ 'module': 'Address', 'id': address.id }) content = BeautifulSoup(resp.content) selected = content.find('option', attrs={'selected': True}) self.assertEqual(selected.attrs['value'], 'AFG')
class TestReportView(MyReportsTestCase): """ Tests the ReportView class, which is used to create and retrieve reports. """ def setUp(self): super(TestReportView, self).setUp() self.client = TestClient(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) self.client.login_user(self.user) ContactRecordFactory.create_batch(5, partner=self.partner) ContactRecordFactory.create_batch( 5, contact_type='job', job_applications="1", job_interviews="0", job_hires="0", partner=self.partner) ContactRecordFactory.create_batch( 5, contact_type='job', job_applications="0", job_interviews="0", job_hires="1", partner=self.partner) def test_create_report(self): """Test that a report model instance is properly created.""" # create a report whose results is for all contact records in the # company response = self.client.post() report_name = response.content report = Report.objects.get(name=report_name) self.assertEqual(len(report.python), 15) # we use this in other tests return report_name def test_get_report(self): """Test that chart data is retreived from record results.""" report_name = self.test_create_report() report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.pk}) data = json.loads(response.content) # check contact record stats for key in ['applications', 'hires', 'communications', 'emails']: self.assertEqual(data[key], 5) # check contact stats self.assertEqual(data['contacts'][0]['records'], 5) self.assertEqual(data['contacts'][0]['referrals'], 10) def test_reports_exclude_archived(self): """ Test that reports exclude archived records as appropriate. This includes non-archived records associated with archived records. """ self.client.path = reverse('view_records', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'}) response = self.client.post(HTTP_X_REQUESTED_WITH='XMLHttpRequest') content = json.loads(response.content) self.assertEqual(len(content), 15) ContactRecord.objects.last().archive() # Archiving one communication record should result in one fewer entry # in the returned json. response = self.client.post(HTTP_X_REQUESTED_WITH='XMLHttpRequest') content = json.loads(response.content) self.assertEqual(len(content), 14) Partner.objects.last().archive() # Archiving the partner governing these communication records should # exclude all of them from the returned json even if they aren't # archived. response = self.client.post(HTTP_X_REQUESTED_WITH='XMLHttpRequest') content = json.loads(response.content) self.assertEqual(len(content), 0)
class TestViewRecords(MyReportsTestCase): """ Tests the `view_records` view which is used to query various models. """ def setUp(self): super(TestViewRecords, self).setUp() self.client = TestClient(path='/reports/ajax/mypartners', HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.client.login_user(self.user) ContactRecordFactory.create_batch( 10, partner=self.partner, contact__name='Joe Shmoe') def test_restricted_to_ajax(self): """View should only be reachable through AJAX.""" self.client.path += '/partner' self.client.defaults.pop('HTTP_X_REQUESTED_WITH') response = self.client.post() self.assertEqual(response.status_code, 404) def test_restricted_to_post(self): """POST requests should raise a 404.""" self.client.path += '/partner' response = self.client.get() self.assertEqual(response.status_code, 404) def test_json_output(self): """Test that filtering contact records through ajax works properly.""" # records to be filtered out ContactRecordFactory.create_batch(10, contact__name='John Doe') self.client.path += '/contactrecord' filters = json.dumps({ 'contact': { 'name': { 'icontains': 'Joe Shmoe' } } }) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_only_user_results_returned(self): """Results should only contain records user has access to.""" # records not owned by user partner = PartnerFactory(name="Wrong Partner") ContactRecordFactory.create_batch(10, partner=partner) self.client.path += '/contactrecord' response = self.client.post() output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filtering_on_model(self): """Test the ability to filter on a model's field's.""" # we already have one because of self.partner PartnerFactory.create_batch(9, name='Test Partner', owner=self.company) self.client.path += '/partner' filters = json.dumps({ 'name': { 'icontains': 'Test Partner' } }) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) # ContactRecordFactory creates 10 partners in setUp self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filtering_on_foreign_key(self): """Test the ability to filter on a model's foreign key fields.""" PartnerFactory.create_batch(5, name='Test Partner', owner=self.company) ContactRecordFactory.create_batch( 5, partner=self.partner, contact__name='Jane Doe') self.client.path += '/partner' filters = json.dumps({ 'name': { 'icontains': 'Test Partner', }, 'contactrecord': { 'contact': { 'name': { 'icontains': 'Jane Doe' } } } }) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) # We look for distinct records self.assertEqual(len(output), 1) def test_list_query_params(self): """Test that query parameters that are lists are parsed correctly.""" contacts = ContactFactory.create_batch(10, partner__owner=self.company) pks = [contact.pk for contact in contacts[:5]] self.client.path += '/partner' filters = json.dumps({ 'contact': { 'in': pks } }) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 5)
class TestViewRecords(MyReportsTestCase): """ Tests the `view_records` view which is used to query various models. """ def setUp(self): super(TestViewRecords, self).setUp() self.client = TestClient(path='/reports/ajax/mypartners', HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.client.login_user(self.user) ContactRecordFactory.create_batch( 10, partner=self.partner, contact__name='Joe Shmoe') def test_restricted_to_ajax(self): """View should only be reachable through AJAX.""" self.client.path += '/partner' self.client.defaults.pop('HTTP_X_REQUESTED_WITH') response = self.client.post() self.assertEqual(response.status_code, 404) def test_restricted_to_get(self): """POST requests should raise a 404.""" self.client.path += '/partner' response = self.client.post() self.assertEqual(response.status_code, 404) def test_json_output(self): """Test that filtering contact records through ajax works properly.""" # records to be filtered out ContactRecordFactory.create_batch(10, contact__name='John Doe') self.client.path += '/contactrecord' response = self.client.get(data={'contact__name': 'Joe Shmoe'}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_only_user_results_returned(self): """Results should only contain records user has access to.""" # records not owned by user partner = PartnerFactory(name="Wrong Partner") ContactRecordFactory.create_batch(10, partner=partner) self.client.path += '/contactrecord' response = self.client.get() output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filtering_on_partner(self): """Test the ability to filter by partner.""" # we already have one because of self.partner PartnerFactory.create_batch(9, name="Test Partner", owner=self.company) self.client.path += '/partner' response = self.client.get(data={'name': 'Test Partner'}) output = json.loads(response.content) # ContactRecordFactory creates 10 partners in setUp self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_list_query_params(self): """Test that query parameters that are lists are parsed correctly.""" contacts = ContactFactory.create_batch(10, partner__owner=self.company) pks = [contact.pk for contact in contacts[:5]] self.client.path += '/partner' response = self.client.get(data={'contact': pks}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 5) def test_filtering_on_contact(self): """Test the ability to filter by contact.""" ContactFactory.create_batch(10, name="Jen Doe", partner=self.partner) # contacts with the wrong name ContactFactory.create_batch(10, name="Jen Smith", partner=self.partner) self.client.path += '/contact' response = self.client.get(data={'name': 'Jen Doe'}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filter_by_state(self): """Tests that filtering by state works.""" indiana = LocationFactory(state="IN") ContactFactory.create_batch(10, name="Jen Doe", partner=self.partner, locations=[indiana]) self.client.path += '/contact' response = self.client.get(data={'state': 'IN'}) output = json.loads(response.content) self.assertEqual(len(output), 10) def test_filter_by_city(self): """Tests that filtering by city works.""" indianapolis = LocationFactory(city="Indianapolis") ContactFactory.create_batch(10, name="Jen Doe", partner=self.partner, locations=[indianapolis]) self.client.path += '/contact' response = self.client.get(data={'city': 'indianapolis'}) output = json.loads(response.content) self.assertEqual(len(output), 10)
class TestRegenerate(MyReportsTestCase): """Tests the reports can be regenerated.""" def setUp(self): super(TestRegenerate, self).setUp() self.client = TestClient(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' })) self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner__owner=self.company) def test_regenerate(self): # create a new report response = self.client.post(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' })) report_name = response.content report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) # remove report results and ensure we can still get a reasonable # response report.results.delete() report.save() self.assertFalse(report.results) response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) # regenerate results and ensure they are the same as the original response = self.client.get(path=reverse('regenerate'), data={'id': report.pk}) report = Report.objects.get(name=report_name) self.assertEqual(response.status_code, 200) self.assertTrue(report.results) # regenerate report without deleting the report prior # see if it overwrites other report. results = report.results response = self.client.get(path=reverse('regenerate'), data={'id': report.pk}) report = Report.objects.get(name=report_name) self.assertEqual(response.status_code, 200) self.assertEqual(results.name, report.results.name) def test_regenerating_missing_file(self): """Tests that a report can be regenerated when file is missing.""" # create a new report response = self.client.post(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord' })) report_name = response.content report = Report.objects.get(name=report_name) # report should have results self.assertTrue(report.results) # delete physical file and ensure that json reflects the missing link os.remove(report.results.file.name) report = Report.objects.get(pk=report.pk) self.assertEqual(report.json, u'{}') self.assertEqual(report.python, {}) # regenerate the report even though the file is physically missing report.regenerate() self.assertTrue(report.results)
class TestViewRecords(MyReportsTestCase): """ Tests the `view_records` view which is used to query various models. """ def setUp(self): super(TestViewRecords, self).setUp() self.client = TestClient(path='/reports/ajax/mypartners', HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner=self.partner, contact__name='Joe Shmoe') def test_restricted_to_ajax(self): """View should only be reachable through AJAX.""" self.client.path += '/partner' self.client.defaults.pop('HTTP_X_REQUESTED_WITH') response = self.client.post() self.assertEqual(response.status_code, 404) def test_restricted_to_post(self): """POST requests should raise a 404.""" self.client.path += '/partner' response = self.client.get() self.assertEqual(response.status_code, 404) def test_json_output(self): """Test that filtering contact records through ajax works properly.""" # records to be filtered out ContactRecordFactory.create_batch(10, contact__name='John Doe') self.client.path += '/contactrecord' filters = json.dumps({'contact': {'name': {'icontains': 'Joe Shmoe'}}}) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_only_user_results_returned(self): """Results should only contain records user has access to.""" # records not owned by user partner = PartnerFactory(name="Wrong Partner") ContactRecordFactory.create_batch(10, partner=partner) self.client.path += '/contactrecord' response = self.client.post() output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filtering_on_model(self): """Test the ability to filter on a model's field's.""" # we already have one because of self.partner PartnerFactory.create_batch(9, name='Test Partner', owner=self.company) self.client.path += '/partner' filters = json.dumps({'name': {'icontains': 'Test Partner'}}) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) # ContactRecordFactory creates 10 partners in setUp self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 10) def test_filtering_on_foreign_key(self): """Test the ability to filter on a model's foreign key fields.""" PartnerFactory.create_batch(5, name='Test Partner', owner=self.company) ContactRecordFactory.create_batch(5, partner=self.partner, contact__name='Jane Doe') self.client.path += '/partner' filters = json.dumps({ 'name': { 'icontains': 'Test Partner', }, 'contactrecord': { 'contact': { 'name': { 'icontains': 'Jane Doe' } } } }) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) # We look for distinct records self.assertEqual(len(output), 1) def test_list_query_params(self): """Test that query parameters that are lists are parsed correctly.""" contacts = ContactFactory.create_batch(10, partner__owner=self.company) pks = [contact.pk for contact in contacts[:5]] self.client.path += '/partner' filters = json.dumps({'contact': {'in': pks}}) response = self.client.post(data={'filters': filters}) output = json.loads(response.content) self.assertEqual(response.status_code, 200) self.assertEqual(len(output), 5)
class MessageViewTests(MyJobsBase): def setUp(self): super(MessageViewTests, self).setUp() self.user = UserFactory() self.message = Message.objects.create(subject='subject', body='body', message_type='success') for group in Group.objects.all(): self.message.group.add(group.pk) self.messageinfo = MessageInfo.objects.create(user=self.user, message=self.message) self.client = TestClient() self.client.login_user(self.user) def test_user_post_mark_message_read(self): self.client.get(reverse('read'), data={'name': 'message-read-'+str(self.message.id) + '-'+str(self.user.id)}, follow=True, HTTP_X_REQUESTED_WITH='XMLHttpRequest') m = MessageInfo.objects.get(user=self.user, message=self.message) self.assertTrue(m.read) self.assertTrue(m.read_at) def test_delete_message(self): """ Deleting a MessageInfo should instead mark it as deleted. """ self.assertTrue(self.messageinfo.deleted_on is None) self.client.get(reverse('delete'), data={'name': 'message-delete-'+str(self.message.id) + '-'+str(self.user.id)}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.messageinfo = MessageInfo.objects.get(pk=self.messageinfo.pk) self.assertIsNotNone(self.messageinfo.deleted_on) def test_auto_page_inbox(self): """ If a "message=%d" parameter is passed on an inbox view, we should detect which page that message appears on and select it. """ infos = MessageInfoFactory.create_batch(11, user=self.user) request = self.client.get(reverse('inbox')) self.assertTrue('Page 1 of 2' in request.content) # Messages are displayed in reverse creation order, so the first item # in the list is the last item on the last page. request = self.client.get(reverse('inbox') + '?message=%s' % infos[0].message.pk) self.assertTrue('Page 2 of 2' in request.content) def test_system_message_as_alert(self): """ Only system messages should show as alerts. """ button_class = 'mymessage-read-{message}-{user}'.format( message=self.message.pk, user=self.user.pk) response = self.client.get(reverse('home')) self.assertNotIn(button_class, response.content) self.message.system = True self.message.save() response = self.client.get(reverse('home')) self.assertIn(button_class, response.content)
class MergeUserTests(MyJobsBase): def setUp(self): super(MergeUserTests, self).setUp() self.client = TestClient() self.password = '******' self.key = '56effea3df2bcdcfe377ca4bf30f2844be47d012' self.existing = User.objects.create(email="*****@*****.**", user_guid="a") self.existing.set_password(self.password) self.new_user = User.objects.create(email="*****@*****.**", user_guid="b") self.activation_profile = ActivationProfile.objects.create( user=self.new_user, email="*****@*****.**") self.activation_profile.activation_key = self.key self.activation_profile.save() self.partner = PartnerFactory() for _ in range(0, 10): Contact.objects.create(user=self.new_user, partner=self.partner) SavedSearch.objects.create(user=self.new_user) def test_expired_key_doesnt_merge(self): expired_request = self.activation_profile expired_request.sent -= datetime.timedelta( days=settings.ACCOUNT_ACTIVATION_DAYS) expired_request.save() self.client.login_user(self.existing) merge_url = reverse('merge_accounts', kwargs={'activation_key': self.key}) response = self.client.get(merge_url) self.assertTrue( User.objects.filter(email=self.new_user.email).exists(), msg="The new user should not have been deleted.") self.assertEqual(response.status_code, 200, msg=("The page should have returned a 200 code." \ "Instead received %s" % response.status_code)) phrases = [ 'Something went wrong while merging your account.', "The activation code was wrong", "Your account has already been merged", "You waited longer than 2 weeks to activate your account"] for phrase in phrases: self.assertIn(phrase, response.content, msg=\ "The phrase '%s' is missing from the final response" % phrase) def test_invalid_key_doesnt_merge(self): self.client.login_user(self.existing) key = self.key.replace('5', 'b') merge_url = reverse('merge_accounts', kwargs={'activation_key': key}) response = self.client.get(merge_url) self.assertTrue( User.objects.filter(email=self.new_user.email).exists(), msg="The new user should not have been deleted.") self.assertEqual(response.status_code, 200, msg=("The page should have returned a 200 code." \ "Instead received %s" % response.status_code)) phrases = [ 'Something went wrong while merging your account.', "The activation code was wrong", "Your account has already been merged", "You waited longer than 2 weeks to activate your account"] for phrase in phrases: self.assertIn(phrase, response.content, msg=\ "The phrase '%s' is missing from the final response" % phrase) def test_successfully_merged_account(self): self.client.login_user(self.existing) # Access the merge URL merge_url = reverse('merge_accounts', kwargs={'activation_key': self.key}) response = self.client.get(merge_url) self.assertEqual(response.status_code, 200, msg=("The page should have returned a 200 code." "Instead received %s" % response.status_code)) # Assert the correct text is displayed. phrases = [ 'Your account has been successfully merged, and you are'\ ' now logged in.', "Add to your profile", "Manage your saved searches", "Manage your account"] for phrase in phrases: self.assertIn(phrase, response.content, msg=\ "The phrase '%s' is missing from the final response" % phrase) # Assert the new user doesn't exist. self.assertFalse( User.objects.filter(email=self.new_user.email).exists(), msg="The new user should have been deleted.") # Assert the new email address is associated with the existing user self.assertTrue( SecondaryEmail.objects.filter(user=self.existing, email=self.activation_profile.email).exists(), msg="A secondary email should have been added "\ "for the deleted user account") # Assert the contacts associated with the new user now point to the # existing user self.assertEqual(Contact.objects.all().count(), 10, msg="The Contacts should not have been deleted.") for contact in Contact.objects.all(): self.assertEqual(contact.user, self.existing, msg="The contacts were not moved to the existing contact") # Assert the saved searches associated with the new user now point to # the existing user self.assertEqual(SavedSearch.objects.all().count(), 10, msg="The SavedSearches should not have been deleted.") for search in SavedSearch.objects.all(): self.assertEqual(search.user, self.existing, msg="The contacts were not moved to the existing contact")
class MySignOn(MyJobsBase): def setUp(self): super(MySignOn, self).setUp() self.user = UserFactory() self.auth_callback_url = 'https://secure.my.jobs/account' self.auth_callback = '?auth_callback=%s' % self.auth_callback_url self.key_qs = '%s&key=%s' self.client = TestClient() self.client.login_user(self.user) def test_anonymous_auth(self): """ Anonymous users must first login before being redirected. This redirection happens automatically if JavaScript is disabled. JSON is returned and the redirect takes place via JavaScript otherwise. """ login_data = {'username': self.user.email, 'password': '******', 'auth_callback': self.auth_callback_url, 'action': 'login'} self.client.logout() self.assertEqual(AuthorizedClient.objects.count(), 0) self.assertTrue(self.client.session.get('key') is None) response = self.client.post(reverse('sso_authorize'), login_data) self.assertEqual(AuthorizedClient.objects.count(), 1) self.assertTrue(self.client.session.get('key') is not None) self.assertEqual(response.get('Location'), self.auth_callback_url + '?key=%s' % self.client.session.get('key')) self.client.logout() response = self.client.post(reverse('sso_authorize'), login_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') content = json.loads(response.content) self.assertEqual(content['url'], self.auth_callback_url + '?key=%s' % self.client.session['key']) def test_authenticated_auth(self): """ Users who are already logged in can simply click a button to authorize a given site and are then redirected to the given callback url. If a given user has already authorized a given site and that site provides the key that it was given, this redirect is automatic. """ self.assertEqual(AuthorizedClient.objects.count(), 0) self.assertTrue(self.client.session.get('key') is None) response = self.client.post(reverse('sso_authorize'), {'auth_callback': self.auth_callback_url, 'action': 'authorize'}) self.assertEqual(self.user.authorizedclient_set.count(), 1) self.assertTrue(self.client.session.get('key') is not None) self.assertEqual(response.get('Location'), self.auth_callback_url + '?key=%s' % self.client.session.get('key')) good_qs = self.key_qs % (self.auth_callback, self.client.session.get('key')) response = self.client.get(reverse('sso_authorize') + good_qs) self.assertEqual(response.get('Location'), self.auth_callback_url + '?key=%s' % self.client.session.get('key')) def test_bad_key(self): """ Providing a bad key will always cause the user to have to log back into their account. Bad keys are defined as providing a key that doesn't match the user's current key or providing a key when the user doesn't currently have a key defined. """ # no key no_key = self.key_qs % (self.auth_callback, AuthorizedClient.create_key(self.user)) response = self.client.get(reverse('sso_authorize') + no_key) self.assertEqual(AuthorizedClient.objects.count(), 0) # Ensure that user was logged out response = self.client.get(reverse('view_profile')) path = response.request.get('PATH_INFO') self.assertRedirects(response, reverse('home')+'?next='+path) # wrong key self.client.login_user(self.user) session = self.client.session session['key'] = AuthorizedClient.create_key(self.user) session.save() # key is a hex string; we can invalidate it by taking a substring wrong_key = self.key_qs % (self.auth_callback, AuthorizedClient.create_key(self.user)[:-1]) AuthorizedClientFactory(user=self.user) response = self.client.get(reverse('sso_authorize') + wrong_key) # Ensure that user was logged out again response = self.client.get(reverse('view_profile')) path = response.request.get('PATH_INFO') self.assertRedirects(response, reverse('home')+'?next='+path)
class RegistrationViewTests(MyJobsBase): """ Test the registration views. """ def setUp(self): """ These tests use the default backend, since we know it's available; that needs to have ``ACCOUNT_ACTIVATION_DAYS`` set. """ super(RegistrationViewTests, self).setUp() self.client = TestClient() self.old_activation = getattr(settings, 'ACCOUNT_ACTIVATION_DAYS', None) if self.old_activation is None: settings.ACCOUNT_ACTIVATION_DAYS = 7 # pragma: no cover self.data = {'email': '*****@*****.**', 'password1': 'swordfish', 'send_email': True} self.user, _ = User.objects.create_user(**self.data) # Update the only existing site so we're working with # my.jobs for historical/aesthetic purposes. site = SeoSite.objects.get() site.domain = 'my.jobs' site.save() def test_valid_activation(self): """ Test that the ``activate`` view properly handles a valid activation (in this case, based on the default backend's activation window). """ self.client.login_user(self.user) profile = ActivationProfile.objects.get(user__email=self.user.email) response = self.client.get(reverse('registration_activate', args=[profile.activation_key])) self.assertEqual(response.status_code, 200) self.failUnless(User.objects.get(email=self.user.email).is_active) def test_anonymous_activation(self): """ Test that the ``activate`` view properly handles activation when the user to be activated is not currently logged in. The page should also contain a login link. """ self.client.post(reverse('auth_logout')) profile = ActivationProfile.objects.get(user__email=self.user.email) response = self.client.get(reverse('registration_activate', args=[profile.activation_key]) + '?verify=%s' % self.user.user_guid) self.assertEqual(response.status_code, 200) self.assertContains(response, self.data['email']) contents = BeautifulSoup(response.content) bank = contents.find(id='moduleBank') anchors = bank.findAll('a') self.assertEqual(len(anchors), 1) self.assertEqual(anchors[0].attrs['href'], '/') self.assertEqual(anchors[0].text, 'Log In') def test_invalid_activation(self): """ Test that the ``activate`` view properly handles an invalid activation (in this case, based on the default backend's activation window). """ self.client.login_user(self.user) expired_profile = ActivationProfile.objects.get(user=self.user) expired_profile.sent -= datetime.timedelta( days=settings.ACCOUNT_ACTIVATION_DAYS) expired_profile.save() response = self.client.get(reverse('registration_activate', args=[expired_profile.activation_key])) self.assertEqual(response.status_code, 200) self.assertNotEqual(response.context['activated'], expired_profile.activation_key_expired()) self.failIf(User.objects.get(email=self.user.email).is_verified) def test_resend_activation(self): x, created = User.objects.create_user( **{'email': '*****@*****.**', 'password1': '5UuYquA@'}) self.client.login_user(x) self.assertEqual(len(mail.outbox), 1) resp = self.client.get(reverse('resend_activation')) self.assertEqual(resp.status_code, 200) # one email sent for creating a user, another one for resend self.assertEqual(len(mail.outbox), 2) def test_resend_activation_with_secondary_emails(self): user, _ = User.objects.create_user( email='*****@*****.**', password1='5UuYquA@', create_user=True) self.assertEqual(ActivationProfile.objects.count(), 1) self.client.login_user(user) self.client.get(reverse('resend_activation')) self.assertEqual(len(mail.outbox), 2) SecondaryEmail.objects.create(user=user, email='*****@*****.**') self.assertEqual(len(mail.outbox), 3) self.assertEqual(ActivationProfile.objects.count(), 2) self.client.get(reverse('resend_activation')) self.assertEqual(len(mail.outbox), 4) def test_site_name_in_password_reset_email(self): domain = settings.SITE.domain.lower() mail.outbox = [] self.user.is_active = True self.user.save() self.client.post(reverse('password_reset'), data={'email': self.user.email}) self.assertEqual(len(mail.outbox), 1, [msg.subject for msg in mail.outbox]) msg = mail.outbox[0] self.assertEqual(msg.subject, "Password Reset on {0}".format(domain)) self.assertIn("The {0} Team".format(domain.lower()), msg.body) self.assertIn("user account at {0}.".format(domain.lower()), msg.body) def test_inactive_user_requesting_password_reset(self): """ Requesting a password reset as an inactive user should activate the account, allowing the password reset to proceed. """ self.user.is_active = False self.user.save() mail.outbox = [] self.client.post(reverse('password_reset'), {'email': self.user.email}) self.assertEqual(len(mail.outbox), 1) user = User.objects.get(pk=self.user.pk) self.assertFalse(user.is_active) def test_invitation_asks_for_password_change(self): """ When activating an account via an invitation, the user should still be prompted to change their password. """ invitation = InvitationFactory(inviting_user=self.user) key = invitation.invitee.activationprofile_set.first().activation_key response = self.client.get( reverse('invitation_activate', kwargs={'activation_key': key}), data={'verify-email': invitation.invitee_email}) invitee = User.objects.get(pk=invitation.invitee.pk) self.assertTrue(invitee.password_change) def test_accept_invitation_already_activated(self): """ Since invitations use the same keys as activations, we should ensure that invitation acceptance doesn't show an error message when the link has already been used. """ invitation = InvitationFactory(invitee_email=self.user.email) self.assertFalse(invitation.accepted) profile = self.user.activationprofile_set.all()[0] key = profile.activation_key self.user.in_reserve = True self.user.save() # Quickly activate and ensure that activation was successful self.assertEqual(ActivationProfile.objects.activate_user(key), self.user) self.client.login_user(self.user) response = self.client.get(reverse('invitation_activate', args=[key])) self.assertTrue('Thanks for registering!' in response.content) invitation = Invitation.objects.get() self.assertTrue(invitation.accepted) user = User.objects.get(pk=self.user.pk) self.assertFalse(user.in_reserve)
class MyProfileViewsTests(MyJobsBase): def setUp(self): super(MyProfileViewsTests, self).setUp() self.client = TestClient() self.client.login_user(self.user) self.name = PrimaryNameFactory(user=self.user) def test_edit_profile(self): """ Going to the edit_profile view generates a list of existing profile items in the main content section and a list of profile sections that don't have data filled out in the sidebar. """ resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item_id = self.name.id # The existing name object should be rendered on the main content # section self.assertIsNotNone(soup.find('div', id='name-' + str(item_id) + '-item')) # profile-section contains the name of a profile section that has no # information filled out yet and shows up in the sidebar self.assertTrue(soup.findAll('tr', {'class': 'profile-section'})) def test_edit_summary(self): """ See test_edit_profile """ summary = SummaryFactory(user=self.user) resp = self.client.get(reverse('view_profile')) soup = BeautifulSoup(resp.content) item = soup.find('div', id='summary-' + str(summary.id) + '-item') self.assertIsNotNone(item) link = item.find('a').attrs['href'] resp = self.client.get(link) self.assertEqual(resp.status_code, 200) def test_handle_form_get_new(self): """ Invoking the handle_form view without an id parameter returns an empty form with the correct form id """ resp = self.client.get(reverse('handle_form'), data={'module': 'Name'}) self.assertTemplateUsed(resp, 'myprofile/profile_form.html') soup = BeautifulSoup(resp.content) self.assertEquals(soup.form.attrs['id'], 'profile-unit-form') with self.assertRaises(KeyError): soup.find('input', id='id_name-given_name').attrs['value'] def test_handle_form_get_existing(self): """ Invoking the handle_form view with and id paraemeter returns a form filled out with the corresponding profile/ID combination """ resp = self.client.get(reverse('handle_form'), data={'module': 'Name', 'id': self.name.id}) self.assertTemplateUsed(resp, 'myprofile/profile_form.html') soup = BeautifulSoup(resp.content) self.assertEquals(soup.form.attrs['id'], 'profile-unit-form') self.assertEquals(soup.find('input', id='id_name-given_name') .attrs['value'], 'Alice') self.assertEquals(soup.find('input', id='id_name-family_name') .attrs['value'], 'Smith') self.assertEquals(soup.find('input', id='id_name-primary') .attrs['checked'], 'checked') def test_handle_form_post_new_valid(self): """ Invoking the handle_form view as a POST request for a new item creates that object in the database and returns the item snippet to be rendered on the page. """ resp = self.client.post(reverse('handle_form'), data={'module': 'Name', 'id': 'new', 'given_name': 'Susy', 'family_name': 'Smith'}) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual(Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_handle_form_post_invalid(self): """ Invoking the handle_form view as a POST request with an invalid form returns the list of form errors. """ resp = self.client.post(reverse('handle_form'), data={'module': 'Name', 'id': 'new', 'given_name': 'Susy'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'family_name': [u'This field is required.']}) def test_handle_form_post_existing_valid(self): """ Invoking the handle_form view as a POST request for an existing item updates that item and returns the update item snippet. """ resp = self.client.post(reverse('handle_form'), data={'module': 'Name', 'id': self.name.id, 'given_name': 'Susy', 'family_name': 'Smith'}) self.assertRedirects(resp, reverse('view_profile')) self.assertEqual(Name.objects.filter(given_name='Susy', family_name='Smith').count(), 1) def test_handle_form_json_serialize_get(self): """When an ajax requests wants to GET json, serialize the form.""" resp = self.client.get(reverse('handle_form'), HTTP_ACCEPT='application/json', data={'module': 'Name'}) self.assertEquals(200, resp.status_code) self.assertIn('application/json', resp['content-type']) data = json.loads(resp.content) self.assertEquals(3, len(data['ordered_fields'])) self.assertIsInstance(data['ordered_fields'], list) self.assertEquals(3, len(data['fields'])) self.assertIsInstance(data['fields'], dict) self.assertIsInstance(data['fields']['family_name'], dict) self.assertIsInstance(data['fields']['given_name'], dict) self.assertIsInstance(data['fields']['primary'], dict) self.assertEquals(3, len(data['data'])) self.assertIsInstance(data['data'], dict) def test_handle_form_redirect_summary(self): """ When a user has a summary already if they try to make a new summary handle form should redirect the user to edit the summary they already have. User is only allowed one summary per account. """ summary_instance = SummaryFactory(user=self.user) summary_instance.save() resp = self.client.get(reverse('handle_form'), data={'module': 'Summary'}) self.assertRedirects(resp, reverse( 'handle_form')+'?id=%s&module=Summary' % summary_instance.id) def test_delete_item(self): """ Invoking the delete_item view deletes the item and returns the 'Deleted!' HttpResponse """ resp = self.client.post(reverse('delete_item')+'?item='+str(self.name.id)) self.assertEqual(resp.content, '') self.assertEqual(Name.objects.filter(id=self.name.id).count(), 0) def test_add_duplicate_primary_email(self): """ Attempting to add a secondary email with a value equal to the user's current primary email results in an error. Due to how the instance is constructed, this validation is form-level rather than model-level. """ resp = self.client.post(reverse('handle_form'), data={'module': 'SecondaryEmail', 'id': 'new', 'email': self.user.email}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(resp.content), {u'email': [u'This email is already registered.']}) def test_default_country_changes(self): """ The displayed country when editing an address should update to reflect the chosen country. """ resp = self.client.get(reverse('handle_form'), data={'module': 'Address'}) content = BeautifulSoup(resp.content) selected = content.find('option', attrs={'selected': True}) self.assertEqual(selected.attrs['value'], 'USA') address = AddressFactory(user=self.user, country_code='AFG') resp = self.client.get(reverse('handle_form'), data={'module': 'Address', 'id': address.id}) content = BeautifulSoup(resp.content) selected = content.find('option', attrs={'selected': True}) self.assertEqual(selected.attrs['value'], 'AFG')
class SavedSearchResourceTests(MyJobsBase): def setUp(self): super(SavedSearchResourceTests, self).setUp() self.client = TestClient( path='/api/v1/savedsearch/', data={'email': '*****@*****.**', 'url': 'www.my.jobs/jobs'}) create_api_key(User, instance=self.user, created=True) self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key def test_special_characters_in_url(self): """ Magic happens before control is handed to our view, resulting in quoted things becoming unquoted. We should not unquote said things inside our views as bad things can happen (%23 unquoting to # and becoming a fragment). """ self.client.data['url'] = 'www.my.jobs/search?q=c%23' response = self.client.get() self.assertEqual(response.status_code, 200) search = SavedSearch.objects.last() self.assertFalse(search.feed.endswith('#')) self.assertTrue(search.feed.endswith('%23')) def test_new_search_existing_user(self): for data in [('*****@*****.**', 'www.my.jobs/search?q=django'), ('*****@*****.**', 'www.my.jobs/search?q=python')]: self.client.data['email'] = data[0] self.client.data['url'] = data[1] response = self.client.get() self.assertEqual(response.status_code, 200) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertTrue(content['new_search']) self.assertEqual(SavedSearch.objects.filter(user=self.user).count(), 2) self.client.data['url'] = 'http://www.my.jobs/jobs' self.client.get() for search in SavedSearch.objects.all(): self.assertTrue('www.my.jobs' in search.notes) def test_new_search_new_user(self): self.client.data['email'] = '*****@*****.**' response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 0) self.assertEqual(User.objects.count(), 1) content = json.loads(response.content) self.assertEqual(content['error'], 'No user with email %s exists' % self.client.data['email']) self.assertEqual(len(content), 1) def test_new_search_secondary_email(self): SecondaryEmail.objects.create(user=self.user, email='*****@*****.**') self.client.data['email'] = '*****@*****.**' response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 1) self.assertEqual(User.objects.count(), 1) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) self.assertEqual(search.email, '*****@*****.**') content = json.loads(response.content) self.assertEqual(len(content), 3) def test_new_search_invalid_url(self): self.client.data['url'] = 'google.com' response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'This is not a valid .JOBS feed') self.assertEqual(SavedSearch.objects.count(), 0) def test_new_search_no_url(self): del self.client.data['url'] response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'No .JOBS feed provided') self.assertEqual(SavedSearch.objects.count(), 0) def test_no_email(self): del self.client.data['email'] response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'No email provided') self.assertEqual(SavedSearch.objects.count(), 0) def test_no_auth(self): del self.client.data['username'] del self.client.data['api_key'] response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, '') self.assertEqual(SavedSearch.objects.count(), 0) def test_invalid_auth(self): headers = [(self.user.email, 'invalid_key'), ('*****@*****.**', self.user.api_key.key), ('*****@*****.**', 'invalid_key')] for header in headers: self.client.data['username'] = header[0] self.client.data['api_key'] = header[1] response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, '') self.assertEqual(SavedSearch.objects.count(), 0) def test_existing_search(self): response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(content['new_search'], True) for email in [self.user.email, self.user.email.upper()]: self.client.data['email'] = email response = self.client.get() content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertFalse(content['new_search']) self.assertEqual(SavedSearch.objects.count(), 1) def test_user_creation_source_override(self): """ Providing a source parameter to the account creation API should override user.source with its value. """ self.client.get( reverse('topbar') + '?site_name=Indianapolis%20Jobs&site=http%3A%2F%2Findianapolis.jobs&callback=foo', HTTP_REFERER='http://indianapolis.jobs') self.client.data['source'] = 'redirect' self.client.get() user = User.objects.get(email=self.client.data['email']) self.assertTrue(user.source, self.client.data['source'])
class SavedSearchResourceTests(MyJobsBase): def setUp(self): super(SavedSearchResourceTests, self).setUp() self.user = UserFactory() self.client = TestClient( path='/api/v1/savedsearch/', data={'email': '*****@*****.**', 'url': 'www.my.jobs/jobs'}) create_api_key(User, instance=self.user, created=True) self.credentials = (self.user.email, self.user.api_key.key) self.patcher = patch('urllib2.urlopen', return_file()) self.patcher.start() def tearDown(self): super(SavedSearchResourceTests, self).tearDown() self.patcher.stop() def test_new_search_existing_user(self): for data in [('*****@*****.**', 'www.my.jobs/search?q=django'), ('*****@*****.**', 'www.my.jobs/search?q=python')]: self.client.data['email'] = data[0] self.client.data['url'] = data[1] self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key response = self.client.get() self.assertEqual(response.status_code, 200) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertTrue(content['new_search']) self.assertEqual(SavedSearch.objects.filter(user=self.user).count(), 2) self.client.data['url'] = 'http://www.my.jobs/jobs' self.client.get() for search in SavedSearch.objects.all(): self.assertTrue('www.my.jobs' in search.notes) def test_new_search_new_user(self): self.client.data['email'] = '*****@*****.**' self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 0) self.assertEqual(User.objects.count(), 1) content = json.loads(response.content) self.assertEqual(content['error'], 'No user with email %s exists' % self.client.data['email']) self.assertEqual(len(content), 1) def test_new_search_secondary_email(self): SecondaryEmail.objects.create(user=self.user, email='*****@*****.**') self.client.data['email'] = '*****@*****.**' self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 1) self.assertEqual(User.objects.count(), 1) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) self.assertEqual(search.email, '*****@*****.**') content = json.loads(response.content) self.assertEqual(len(content), 3) def test_new_search_invalid_url(self): self.client.data['url'] = 'google.com' self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'This is not a valid .JOBS feed') self.assertEqual(SavedSearch.objects.count(), 0) def test_new_search_no_url(self): del self.client.data['url'] self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'No .JOBS feed provided') self.assertEqual(SavedSearch.objects.count(), 0) def test_no_email(self): del self.client.data['email'] self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'No email provided') self.assertEqual(SavedSearch.objects.count(), 0) def test_no_auth(self): response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, '') self.assertEqual(SavedSearch.objects.count(), 0) def test_invalid_auth(self): headers = [(self.user.email, 'invalid_key'), ('*****@*****.**', self.user.api_key.key), ('*****@*****.**', 'invalid_key')] for header in headers: self.client.data['username'] = header[0] self.client.data['api_key'] = header[1] response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, '') self.assertEqual(SavedSearch.objects.count(), 0) def test_existing_search(self): self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(content['new_search'], True) for email in [self.user.email, self.user.email.upper()]: self.client.data['email'] = email response = self.client.get() content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertFalse(content['new_search']) self.assertEqual(SavedSearch.objects.count(), 1) def test_user_creation_source_override(self): """ Providing a source parameter to the account creation API should override user.source with its value. """ self.client.get( reverse('toolbar') + '?site_name=Indianapolis%20Jobs&site=http%3A%2F%2Findianapolis.jobs&callback=foo', HTTP_REFERER='http://indianapolis.jobs') self.client.data['source'] = 'redirect' self.client.get() user = User.objects.get(email=self.client.data['email']) self.assertTrue(user.source, self.client.data['source'])
class SavedSearchResourceTestCase(MyJobsBase): def setUp(self): super(SavedSearchResourceTestCase, self).setUp() self.client = TestClient( path="/api/v1/savedsearch/", data={"email": "*****@*****.**", "url": "www.my.jobs/jobs"} ) create_api_key(User, instance=self.user, created=True) self.client.data["username"] = self.user.email self.client.data["api_key"] = self.user.api_key.key def test_special_characters_in_url(self): """ Magic happens before control is handed to our view, resulting in quoted things becoming unquoted. We should not unquote said things inside our views as bad things can happen (%23 unquoting to # and becoming a fragment). """ self.client.data["url"] = "www.my.jobs/search?q=c%23" response = self.client.get() self.assertEqual(response.status_code, 200) search = SavedSearch.objects.last() self.assertFalse(search.feed.endswith("#")) self.assertTrue(search.feed.endswith("%23")) def test_new_search_existing_user(self): for data in [ ("*****@*****.**", "www.my.jobs/search?q=django"), ("*****@*****.**", "www.my.jobs/search?q=python"), ]: self.client.data["email"] = data[0] self.client.data["url"] = data[1] response = self.client.get() self.assertEqual(response.status_code, 200) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertTrue(content["new_search"]) self.assertEqual(SavedSearch.objects.filter(user=self.user).count(), 2) self.client.data["url"] = "http://www.my.jobs/jobs" self.client.get() for search in SavedSearch.objects.all(): self.assertTrue("www.my.jobs" in search.notes) def test_new_search_new_user(self): self.client.data["email"] = "*****@*****.**" response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 0) self.assertEqual(User.objects.count(), 1) content = json.loads(response.content) self.assertEqual(content["error"], "No user with email %s exists" % self.client.data["email"]) self.assertEqual(len(content), 1) def test_new_search_secondary_email(self): SecondaryEmail.objects.create(user=self.user, email="*****@*****.**") self.client.data["email"] = "*****@*****.**" response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 1) self.assertEqual(User.objects.count(), 1) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) self.assertEqual(search.email, "*****@*****.**") content = json.loads(response.content) self.assertEqual(len(content), 3) def test_new_search_invalid_url(self): self.client.data["url"] = "google.com" response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content["error"], "This is not a valid .JOBS feed") self.assertEqual(SavedSearch.objects.count(), 0) def test_new_search_no_url(self): del self.client.data["url"] response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content["error"], "No .JOBS feed provided") self.assertEqual(SavedSearch.objects.count(), 0) def test_no_email(self): del self.client.data["email"] response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content["error"], "No email provided") self.assertEqual(SavedSearch.objects.count(), 0) def test_no_auth(self): del self.client.data["username"] del self.client.data["api_key"] response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, "") self.assertEqual(SavedSearch.objects.count(), 0) def test_invalid_auth(self): headers = [ (self.user.email, "invalid_key"), ("*****@*****.**", self.user.api_key.key), ("*****@*****.**", "invalid_key"), ] for header in headers: self.client.data["username"] = header[0] self.client.data["api_key"] = header[1] response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, "") self.assertEqual(SavedSearch.objects.count(), 0) def test_existing_search(self): response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(content["new_search"], True) for email in [self.user.email, self.user.email.upper()]: self.client.data["email"] = email response = self.client.get() content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertFalse(content["new_search"]) self.assertEqual(SavedSearch.objects.count(), 1) def test_user_creation_source_override(self): """ Providing a source parameter to the account creation API should override user.source with its value. """ self.client.get( reverse("topbar") + "?site_name=Indianapolis%20Jobs&site=http%3A%2F%2Findianapolis.jobs&callback=foo", HTTP_REFERER="http://indianapolis.jobs", ) self.client.data["source"] = "redirect" self.client.get() user = User.objects.get(email=self.client.data["email"]) self.assertTrue(user.source, self.client.data["source"])
class TestRegenerate(MyReportsTestCase): """Tests the reports can be regenerated.""" def setUp(self): super(TestRegenerate, self).setUp() self.client = TestClient(path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) self.client.login_user(self.user) ContactRecordFactory.create_batch(10, partner__owner=self.company) def test_regenerate(self): # create a new report response = self.client.post( path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) report_name = response.content report = Report.objects.get(name=report_name) response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) # remove report results and ensure we can still get a reasonable # response report.results.delete() report.save() self.assertFalse(report.results) response = self.client.get(data={'id': report.id}) self.assertEqual(response.status_code, 200) # regenerate results and ensure they are the same as the original response = self.client.get(path=reverse('regenerate'), data={ 'id': report.pk}) report = Report.objects.get(name=report_name) self.assertEqual(response.status_code, 200) self.assertTrue(report.results) # regenerate report without deleting the report prior # see if it overwrites other report. results = report.results response = self.client.get(path=reverse('regenerate'), data={ 'id': report.pk}) report = Report.objects.get(name=report_name) self.assertEqual(response.status_code, 200) self.assertEqual(results.name, report.results.name) def test_regenerating_missing_file(self): """Tests that a report can be regenerated when file is missing.""" # create a new report response = self.client.post( path=reverse('reports', kwargs={ 'app': 'mypartners', 'model': 'contactrecord'})) report_name = response.content report = Report.objects.get(name=report_name) # report should have results self.assertTrue(report.results) # delete physical file and ensure that json reflects the missing link os.remove(report.results.file.name) report = Report.objects.get(pk=report.pk) self.assertEqual(report.json, u'{}') self.assertEqual(report.python, {}) # regenerate the report even though the file is physically missing report.regenerate() self.assertTrue(report.results)
class MySearchViewTests(MyJobsBase): def setUp(self): super(MySearchViewTests, self).setUp() self.client = TestClient() self.user = UserFactory() self.client.login_user(self.user) self.new_form_data = { 'url': 'www.my.jobs/jobs', 'feed': 'http://www.my.jobs/jobsfeed/rss?', 'label': 'Jobs Label', 'email': self.user.email, 'frequency': 'D', 'is_active': 'True', 'jobs_per_email': 5, 'sort_by': 'Relevance', } self.new_digest_data = { 'is_active': 'True', 'user': self.user, 'email': self.user.email, 'frequency': 'M', 'day_of_month': 1, } self.new_form = forms.SavedSearchForm(user=self.user, data=self.new_form_data) self.patcher = patch('urllib2.urlopen', return_file()) self.patcher.start() def tearDown(self): super(MySearchViewTests, self).tearDown() try: self.patcher.stop() except RuntimeError: # patcher was stopped in a test pass def test_search_main(self): response = self.client.get(reverse('saved_search_main')) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'mysearches/saved_search_main.html') self.failUnless(isinstance(response.context['form'], forms.DigestForm)) self.failUnless(isinstance(response.context['add_form'], forms.SavedSearchForm)) def test_saved_search_digest_options(self): response = self.client.get(reverse('saved_search_main')) self.assertTrue('Digest Options' in response.content) self.assertFalse('digest-option' in response.content) self.assertTrue(self.new_form.is_valid()) self.new_form.save() response = self.client.get(reverse('saved_search_main')) self.assertTrue('Digest Options' in response.content) self.assertTrue('digest-option' in response.content) def test_save_new_search_form(self): response = self.client.post(reverse('save_search_form'), data=self.new_form_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '') def test_save_new_search_invalid(self): del self.new_form_data['frequency'] response = self.client.post(reverse('save_search_form'), data=self.new_form_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) self.assertEqual(json.loads(response.content).keys(), ['frequency']) def test_get_edit_page(self): self.assertTrue(self.new_form.is_valid()) self.new_form.save() search_id = self.new_form.instance.id response = self.client.get( reverse('edit_search')+'?id=%s' % search_id) self.assertEqual(response.status_code, 200) self.assertEqual(self.new_form.instance, response.context['form'].instance) self.assertTemplateUsed(response, 'mysearches/saved_search_edit.html') search_id += 1 response = self.client.get( reverse('edit_search')+'?id=%s' % search_id) self.assertEqual(response.status_code, 404) def test_save_edit_form(self): self.assertTrue(self.new_form.is_valid()) self.new_form.save() search_id = self.new_form.instance.id self.new_form_data['frequency'] = 'W' self.new_form_data['day_of_week'] = 1 self.new_form_data['url'] = 'www.my.jobs/search?' self.new_form_data['search_id'] = search_id new_form = forms.SavedSearchForm(user=self.user, data=self.new_form_data) response = self.client.post(reverse('save_search_form'), data=self.new_form_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '') del self.new_form_data['frequency'] response = self.client.post(reverse('save_search_form'), data=self.new_form_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) self.assertEqual(json.loads(response.content).keys(), ['frequency']) def test_validate_url(self): response = self.client.post(reverse('validate_url'), data={'url': self.new_form_data['url']}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) data = {u'rss_url': u'http://www.my.jobs/jobs/feed/rss', u'feed_title': u'My.jobs - Jobs', u'url_status': u'valid'} content = json.loads(response.content) self.assertEqual(content['rss_url'], data['rss_url']) self.assertEqual(content['url_status'], data['url_status']) response = self.client.post(reverse('validate_url'), data={'url': 'google.com'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) self.assertEqual(json.loads(response.content), {'url_status': 'not valid'}) def test_save_digest_form(self): response = self.client.post(reverse('save_digest_form'), self.new_digest_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '') del self.new_digest_data['email'] response = self.client.post(reverse('save_digest_form'), self.new_digest_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '{"email": ["This field is required."]}') def test_unsubscribe_owned_search(self): """ Unsubscribing an owned saved search should result in that search being deactivated """ search = SavedSearchFactory(user=self.user) self.assertTrue(search.is_active) response = self.client.get(reverse('unsubscribe')+'?id=%s' % search.id) search = models.SavedSearch.objects.get(id=search.id) self.assertFalse(search.is_active) self.assertTemplateUsed(response, 'mysearches/saved_search_disable.html') def test_unsubscribe_unowned_search(self): """ Attempting to unsubscribe using a search that isn't yours should result in nothing happening to the search """ user = UserFactory(email='*****@*****.**') search = SavedSearchFactory(user=user) response = self.client.get(reverse('unsubscribe')+'?id=%s' % search.id) search = models.SavedSearch.objects.get(id=search.id) self.assertTrue(search.is_active) self.assertEqual(response.status_code, 404) def test_unsubscribe_digest(self): """ Unsubscribing a saved search digest should result in all of the owner's saved searches being disabled """ digest = SavedSearchDigestFactory(user=self.user) searches = [] for url in ['www.my.jobs/search?q=python', 'jobs.jobs/search?q=django']: searches.append(SavedSearchFactory(url=url, user=self.user)) for search in searches: self.assertTrue(search.is_active) response = self.client.get(reverse('unsubscribe')+'?id=digest') searches = list(models.SavedSearch.objects.all()) for search in searches: self.assertFalse(search.is_active) self.assertTemplateUsed(response, 'mysearches/saved_search_disable.html') self.assertEqual(response.status_code, 200) def test_anonymous_unsubscribe(self): search = SavedSearchFactory(user=self.user) Session.objects.all().delete() # Navigating to the 'unsubscribe' page while logged out... response = self.client.get( reverse('unsubscribe')+'?id='+str(search.id)) path = response.request.get('PATH_INFO') + "?id=" + str(search.id) self.assertRedirects(response, reverse('home')+'?next='+path) # or with the wrong email address... response = self.client.get( reverse('unsubscribe') + '?id='+str( search.id)+'&[email protected]') # results in being redirected to the login page and the searches # remaining unchanged self.assertRedirects(response, reverse('home')) search = models.SavedSearch.objects.get(id=search.id) self.assertTrue(search.is_active) response = self.client.get( reverse('unsubscribe') + '?id=%s&verify=%s' % ( search.id, self.user.user_guid)) search = models.SavedSearch.objects.get(id=search.id) self.assertFalse(search.is_active) def test_delete_owned_search(self): search = SavedSearchFactory(user=self.user) self.assertEqual(models.SavedSearch.objects.count(), 1) response = self.client.get( reverse('delete_saved_search')+'?id=%s' % search.id) self.assertEqual(models.SavedSearch.objects.count(), 0) self.assertRedirects(response, reverse( 'saved_search_main_query')+'?d='+str(urllib2.quote( search.label))) def test_delete_all_searches(self): """ Deleting all searches should only remove regular saved searches if the partner saved searches weren't created by the user trying to use it. """ user = UserFactory(email='*****@*****.**') company = CompanyFactory(id=2423, name="Bacon Factory", user_created=False) SavedSearchFactory(user=self.user) pss = PartnerSavedSearchFactory(user=self.user, created_by=user, provider=company) response = self.client.get(reverse('delete_saved_search') + '?id=ALL') self.assertEqual(response.status_code, 302) # partner saved search should still exist... self.assertTrue(models.PartnerSavedSearch.objects.filter( pk=pss.pk).exists()) # ... but the regular saved search shouldn't self.assertFalse(models.SavedSearch.objects.filter( partnersavedsearch__isnull=True).exists()) def test_delete_unowned_search(self): """ Attempting to delete a search that isn't yours should result in nothing happening to the search """ user = UserFactory(email='*****@*****.**') search = SavedSearchFactory(user=user) response = self.client.get( reverse('delete_saved_search') + '?id=%s' % search.id) self.assertEqual(models.SavedSearch.objects.count(), 1) self.assertEqual(response.status_code, 404) def test_delete_owned_searches_by_digest(self): """ Deleting with a saved search digest should result in all of the user's saved searches being deleted """ digest = SavedSearchDigestFactory(user=self.user) searches = [] for url in ['www.my.jobs/search?q=python', 'jobs.jobs/search?q=django']: searches.append(SavedSearchFactory(url=url, user=self.user)) self.assertEqual(models.SavedSearch.objects.count(), 2) response = self.client.get(reverse( 'delete_saved_search') + '?id=digest') self.assertEqual(models.SavedSearch.objects.count(), 0) self.assertRedirects(response, reverse( 'saved_search_main_query') + '?d=all') def test_anonymous_delete_searches(self): search = SavedSearchFactory(user=self.user) Session.objects.all().delete() # Navigating to the 'delete saved search' page while logged out... response = self.client.get( reverse('delete_saved_search') + '?id=' + str(search.id)) path = response.request.get('PATH_INFO') + "?id=" + str(search.id) self.assertRedirects(response, reverse('home') + '?next=' + path) self.assertEqual(models.SavedSearch.objects.count(), 1) # or with the wrong email address... response = self.client.get( reverse('delete_saved_search') + '?id=' + str( search.id) + '&[email protected]') # results in being redirected to the login page and no searches being # deleted self.assertRedirects(response, reverse('home')) self.assertEqual(models.SavedSearch.objects.count(), 1) response = self.client.get( reverse('delete_saved_search') + '?id=%s&verify=%s' % ( search.id, self.user.user_guid)) self.assertEqual(models.SavedSearch.objects.count(), 0) # assertRedirects follows any redirect and waits for a 200 status code; # anonymous users will always redirect, never returning a 200. self.client.login_user(self.user) self.assertRedirects(response, reverse( 'saved_search_main_query') + '?d=' + str(urllib2.quote( search.label))) def test_widget_with_saved_search(self): search = SavedSearchFactory(user=self.user) response = self.client.get(reverse('saved_search_widget') + '?url=%s&callback=callback' % ( search.url, )) edit_url = '\\"https://secure.my.jobs%s?id=%s\\"' % ( reverse('edit_search'), search.pk) self.assertTrue(edit_url in response.content) def test_widget_with_partner_saved_search(self): company = CompanyFactory() partner = PartnerFactory(owner=company) ContactFactory(user=self.user, partner=partner) search = PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=company, partner=partner) response = self.client.get(reverse('saved_search_widget') + '?url=%s&callback=callback' % ( search.url, )) edit_url = '\\"https://secure.my.jobs%s?id=%s&pss=True\\"' % ( reverse('edit_search'), search.pk) self.assertTrue(edit_url in response.content) def test_viewing_feed_on_bad_search(self): search = SavedSearchFactory(user=self.user, url='http://404.com', feed='http://404.com/feed/json') response = self.client.get(reverse( 'view_full_feed') + '?id=%s' % search.id) self.assertIn('The domain for this saved search is no longer valid.', response.content) def test_send_link_appearance(self): """ The button to manually send a saved search should not be displayed when DEBUG=False. If the url is guessed, nothing bad should happen. """ self.user.is_superuser = True self.user.save() saved_search = SavedSearchFactory(user=self.user) partner_search = PartnerSavedSearchFactory(user=self.user, created_by=self.user) ContactFactory(partner=partner_search.partner, user=self.user) for search in [saved_search, partner_search]: full_feed = reverse('view_full_feed') + '?id=%s' % search.id send_url = reverse('send_saved_search') + '?id=%s' % search.id if hasattr(search, 'partnersavedsearch'): send_url += '&is_pss=True' self.client.login_user(self.user) response = self.client.get(full_feed) self.assertNotIn('>Send</a>', response.content) send = self.client.get(send_url) self.assertEqual(send.status_code, 404) self.assertEqual(len(mail.outbox), 0) settings.DEBUG = True self.client.login_user(self.user) response = self.client.get(full_feed) self.assertIn('>Send</a>', response.content) send = self.client.get(send_url) self.assertEqual(send.status_code, 302) self.assertEqual(len(mail.outbox), 1) mail.outbox = [] settings.DEBUG = False def test_send_link_respects_permissions(self): # The send_saved_search view requires that DEBUG be enabled. settings.DEBUG = True self.user.is_superuser = True self.user.save() search = SavedSearchFactory(user=self.user) search_2 = SavedSearchFactory(user=UserFactory(email='*****@*****.**')) send_url = reverse('send_saved_search') + '?id=%s' self.assertEqual(len(mail.outbox), 0) response = self.client.get(send_url % search.pk) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 1) response = self.client.get(send_url % search_2.pk) self.assertEqual(response.status_code, 302) self.assertEqual(len(mail.outbox), 2) settings.DEBUG = False
class MergeUserTests(MyJobsBase): def setUp(self): super(MergeUserTests, self).setUp() self.client = TestClient() self.password = '******' self.key = '56effea3df2bcdcfe377ca4bf30f2844be47d012' self.existing = User.objects.create(email="*****@*****.**", user_guid="a") self.existing.set_password(self.password) self.new_user = User.objects.create(email="*****@*****.**", user_guid="b") self.activation_profile = ActivationProfile.objects.create( user=self.new_user, email="*****@*****.**") self.activation_profile.activation_key = self.key self.activation_profile.save() self.partner = PartnerFactory() for _ in range(0, 10): Contact.objects.create(user=self.new_user, partner=self.partner) SavedSearch.objects.create(user=self.new_user) def test_expired_key_doesnt_merge(self): expired_request = self.activation_profile expired_request.sent -= datetime.timedelta( days=settings.ACCOUNT_ACTIVATION_DAYS) expired_request.save() self.client.login_user(self.existing) merge_url = reverse('merge_accounts', kwargs={'activation_key': self.key}) response = self.client.get(merge_url) self.assertTrue( User.objects.filter(email=self.new_user.email).exists(), msg="The new user should not have been deleted.") self.assertEqual(response.status_code, 200, msg=("The page should have returned a 200 code." \ "Instead received %s" % response.status_code)) phrases = [ 'Something went wrong while merging your account.', "The activation code was wrong", "Your account has already been merged", "You waited longer than 2 weeks to activate your account" ] for phrase in phrases: self.assertIn(phrase, response.content, msg=\ "The phrase '%s' is missing from the final response" % phrase) def test_invalid_key_doesnt_merge(self): self.client.login_user(self.existing) key = self.key.replace('5', 'b') merge_url = reverse('merge_accounts', kwargs={'activation_key': key}) response = self.client.get(merge_url) self.assertTrue( User.objects.filter(email=self.new_user.email).exists(), msg="The new user should not have been deleted.") self.assertEqual(response.status_code, 200, msg=("The page should have returned a 200 code." \ "Instead received %s" % response.status_code)) phrases = [ 'Something went wrong while merging your account.', "The activation code was wrong", "Your account has already been merged", "You waited longer than 2 weeks to activate your account" ] for phrase in phrases: self.assertIn(phrase, response.content, msg=\ "The phrase '%s' is missing from the final response" % phrase) def test_successfully_merged_account(self): self.client.login_user(self.existing) # Access the merge URL merge_url = reverse('merge_accounts', kwargs={'activation_key': self.key}) response = self.client.get(merge_url) self.assertEqual(response.status_code, 200, msg=("The page should have returned a 200 code." "Instead received %s" % response.status_code)) # Assert the correct text is displayed. phrases = [ 'Your account has been successfully merged, and you are'\ ' now logged in.', "Add to your profile", "Manage your saved searches", "Manage your account"] for phrase in phrases: self.assertIn(phrase, response.content, msg=\ "The phrase '%s' is missing from the final response" % phrase) # Assert the new user doesn't exist. self.assertFalse( User.objects.filter(email=self.new_user.email).exists(), msg="The new user should have been deleted.") # Assert the new email address is associated with the existing user self.assertTrue( SecondaryEmail.objects.filter(user=self.existing, email=self.activation_profile.email).exists(), msg="A secondary email should have been added "\ "for the deleted user account") # Assert the contacts associated with the new user now point to the # existing user self.assertEqual(Contact.objects.all().count(), 10, msg="The Contacts should not have been deleted.") for contact in Contact.objects.all(): self.assertEqual( contact.user, self.existing, msg="The contacts were not moved to the existing contact") # Assert the saved searches associated with the new user now point to # the existing user self.assertEqual(SavedSearch.objects.all().count(), 10, msg="The SavedSearches should not have been deleted.") for search in SavedSearch.objects.all(): self.assertEqual( search.user, self.existing, msg="The contacts were not moved to the existing contact")
class SavedSearchResourceTestCase(MyJobsBase): def setUp(self): super(SavedSearchResourceTestCase, self).setUp() self.client = TestClient(path='/api/v1/savedsearch/', data={ 'email': '*****@*****.**', 'url': 'www.my.jobs/jobs' }) create_api_key(User, instance=self.user, created=True) self.client.data['username'] = self.user.email self.client.data['api_key'] = self.user.api_key.key def test_special_characters_in_url(self): """ Magic happens before control is handed to our view, resulting in quoted things becoming unquoted. We should not unquote said things inside our views as bad things can happen (%23 unquoting to # and becoming a fragment). """ self.client.data['url'] = 'www.my.jobs/search?q=c%23' response = self.client.get() self.assertEqual(response.status_code, 200) search = SavedSearch.objects.last() self.assertFalse(search.feed.endswith('#')) self.assertTrue(search.feed.endswith('%23')) def test_new_search_existing_user(self): for data in [('*****@*****.**', 'www.my.jobs/search?q=django'), ('*****@*****.**', 'www.my.jobs/search?q=python')]: self.client.data['email'] = data[0] self.client.data['url'] = data[1] response = self.client.get() self.assertEqual(response.status_code, 200) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertTrue(content['new_search']) self.assertEqual(SavedSearch.objects.filter(user=self.user).count(), 2) self.client.data['url'] = 'http://www.my.jobs/jobs' self.client.get() for search in SavedSearch.objects.all(): self.assertTrue('www.my.jobs' in search.notes) def test_new_search_new_user(self): self.client.data['email'] = '*****@*****.**' response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 0) self.assertEqual(User.objects.count(), 1) content = json.loads(response.content) self.assertEqual( content['error'], 'No user with email %s exists' % self.client.data['email']) self.assertEqual(len(content), 1) def test_new_search_secondary_email(self): SecondaryEmail.objects.create(user=self.user, email='*****@*****.**') self.client.data['email'] = '*****@*****.**' response = self.client.get() self.assertEqual(response.status_code, 200) self.assertEqual(SavedSearch.objects.count(), 1) self.assertEqual(User.objects.count(), 1) search = SavedSearch.objects.all()[0] self.assertEqual(search.user, self.user) self.assertEqual(search.email, '*****@*****.**') content = json.loads(response.content) self.assertEqual(len(content), 3) def test_new_search_invalid_url(self): self.client.data['url'] = 'google.com' response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'This is not a valid .JOBS feed') self.assertEqual(SavedSearch.objects.count(), 0) def test_new_search_no_url(self): del self.client.data['url'] response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'No .JOBS feed provided') self.assertEqual(SavedSearch.objects.count(), 0) def test_no_email(self): del self.client.data['email'] response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(len(content), 1) self.assertEqual(content['error'], 'No email provided') self.assertEqual(SavedSearch.objects.count(), 0) def test_no_auth(self): del self.client.data['username'] del self.client.data['api_key'] response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, '') self.assertEqual(SavedSearch.objects.count(), 0) def test_invalid_auth(self): headers = [(self.user.email, 'invalid_key'), ('*****@*****.**', self.user.api_key.key), ('*****@*****.**', 'invalid_key')] for header in headers: self.client.data['username'] = header[0] self.client.data['api_key'] = header[1] response = self.client.get() self.assertEqual(response.status_code, 401) self.assertEqual(response.content, '') self.assertEqual(SavedSearch.objects.count(), 0) def test_existing_search(self): response = self.client.get() self.assertEqual(response.status_code, 200) content = json.loads(response.content) self.assertEqual(content['new_search'], True) for email in [self.user.email, self.user.email.upper()]: self.client.data['email'] = email response = self.client.get() content = json.loads(response.content) self.assertEqual(len(content), 3) self.assertFalse(content['new_search']) self.assertEqual(SavedSearch.objects.count(), 1) def test_user_creation_source_override(self): """ Providing a source parameter to the account creation API should override user.source with its value. """ self.client.get( reverse('topbar') + '?site_name=Indianapolis%20Jobs&site=http%3A%2F%2Findianapolis.jobs&callback=foo', HTTP_REFERER='http://indianapolis.jobs') self.client.data['source'] = 'redirect' self.client.get() user = User.objects.get(email=self.client.data['email']) self.assertTrue(user.source, self.client.data['source'])