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/")
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/")
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 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 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 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 MyReportsTestCase(TestCase): """ Base class for all MyReports Tests. Identical to `django.test.TestCase` except that it provides a MyJobs TestClient instance and a logged in user. """ def setUp(self): self.client = TestClient() self.user = UserFactory(email='*****@*****.**') self.company = CompanyFactory(name='Test Company') self.partner = PartnerFactory(name='Test Partner', owner=self.company) # associate company to user CompanyUserFactory(user=self.user, company=self.company) self.client.login_user(self.user)
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))
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 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 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 TestSecureBlocks(DirectSEOBase): """ Tests that the secure blocks api view in various circumstances. """ fixtures = ['login_page.json'] def setUp(self): super(TestSecureBlocks, self).setUp() self.staff_user = UserFactory(is_staff=True) self.client = TestClient() self.client.login_user(self.staff_user) self.sb_url = reverse('secure_blocks') SeoSiteFactory(domain='jobs.example.com') def test_secure_blocks_empty(self): """Browser asks for no blocks.""" resp = make_cors_request(self.client, self.sb_url, '{"blocks": {}}') self.assertEqual(200, resp.status_code) result = json.loads(resp.content) self.assertEqual({u'errors':{}}, result, msg="got %s! secure block returned block when none was" " requested" % result) def test_secure_blocks_bad_parse(self): """Handle unparseable JSON.""" resp = make_cors_request(self.client, self.sb_url, '@@@@@@@@@') self.assertEqual(400, resp.status_code, msg="got %s! block request allowed unparseable json, check" " secure block json parser" % resp.status_code) def test_secure_blocks_render(self): """Ask for a real block.""" body = '{"blocks": {"my-jobs-logo-1": {}}}' resp = make_cors_request(self.client, self.sb_url, body) result = json.loads(resp.content) self.assertTrue('my-jobs-logo-1' in result, msg="block request not found in response. check fixture, " "secure blocks logic") def test_secure_blocks_bad_origin(self): """Check that secure blocks do not load from invalid origins""" body = '{"blocks": {"my-jobs-logo-1": {}}}' resp = make_cors_request(self.client, self.sb_url, body, http_origin='http://notparent.com/') self.assertEqual(resp.status_code, 404, msg="got %s! secure block call responded despite bad origin." " check cross site verify logic" % resp.status_code) def test_saved_search_includes_required_js(self): """ Ensure requests for saved search widget includes required js """ savedsearch = (SavedSearchWidgetBlock .objects .get(element_id='test_saved_search')) body = '{"blocks": {"test_saved_search": {}}}' resp = make_cors_request(self.client, self.sb_url, body) self.assertEqual(resp.status_code, 200, msg="Expected 200, got %s. User was not able to " "retrieve blocks for test" % resp.status_code) for js in savedsearch.required_js(): self.assertContains(resp, js, msg_prefix="Did not find %s in response," "missing required js" % js) def test_topbar_includes_cookies(self): body = '{"blocks": {"test_tools_widget": {}}}' resp = make_cors_request(self.client, self.sb_url, body) self.assertEqual(resp.status_code, 200, msg="Expected 200, got %s. User was not able to " "retrieve blocks for test" % resp.status_code) self.assertEqual(resp.cookies['lastmicrosite'].value, 'http://jobs.example.com')
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 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 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 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 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 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 TestSecureBlocks(DirectSEOBase): """ Tests that the secure blocks api view in various circumstances. """ fixtures = ['login_page.json'] def setUp(self): super(TestSecureBlocks, self).setUp() self.staff_user = UserFactory(is_staff=True) self.client = TestClient() self.client.login_user(self.staff_user) self.sb_url = reverse('secure_blocks') SeoSiteFactory(domain='jobs.example.com') def test_secure_blocks_empty(self): """Browser asks for no blocks.""" resp = make_cors_request(self.client, self.sb_url, '{"blocks": {}}') self.assertEqual(200, resp.status_code) result = json.loads(resp.content) self.assertEqual( {u'errors': {}}, result, msg="got %s! secure block returned block when none was" " requested" % result) def test_secure_blocks_bad_parse(self): """Handle unparseable JSON.""" resp = make_cors_request(self.client, self.sb_url, '@@@@@@@@@') self.assertEqual( 400, resp.status_code, msg="got %s! block request allowed unparseable json, check" " secure block json parser" % resp.status_code) def test_secure_blocks_render(self): """Ask for a real block.""" body = '{"blocks": {"my-jobs-logo-1": {}}}' resp = make_cors_request(self.client, self.sb_url, body) result = json.loads(resp.content) self.assertTrue( 'my-jobs-logo-1' in result, msg="block request not found in response. check fixture, " "secure blocks logic") def test_secure_blocks_bad_origin(self): """Check that secure blocks do not load from invalid origins""" body = '{"blocks": {"my-jobs-logo-1": {}}}' resp = make_cors_request(self.client, self.sb_url, body, http_origin='http://notparent.com/') self.assertEqual( resp.status_code, 404, msg="got %s! secure block call responded despite bad origin." " check cross site verify logic" % resp.status_code) def test_saved_search_includes_required_js(self): """ Ensure requests for saved search widget includes required js """ savedsearch = (SavedSearchWidgetBlock.objects.get( element_id='test_saved_search')) body = '{"blocks": {"test_saved_search": {}}}' resp = make_cors_request(self.client, self.sb_url, body) self.assertEqual(resp.status_code, 200, msg="Expected 200, got %s. User was not able to " "retrieve blocks for test" % resp.status_code) for js in savedsearch.required_js(): self.assertContains(resp, js, msg_prefix="Did not find %s in response," "missing required js" % js) def test_topbar_includes_cookies(self): body = '{"blocks": {"test_tools_widget": {}}}' resp = make_cors_request(self.client, self.sb_url, body) self.assertEqual(resp.status_code, 200, msg="Expected 200, got %s. User was not able to " "retrieve blocks for test" % resp.status_code) self.assertEqual(resp.cookies['lastmicrosite'].value, 'http://jobs.example.com')
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 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 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 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 MyDashboardViewsTests(MyJobsBase): def setUp(self): super(MyDashboardViewsTests, self).setUp() self.staff_user = UserFactory() group = Group.objects.get(name=CompanyUser.GROUP_NAME) self.staff_user.groups.add(group) self.business_unit = BusinessUnitFactory() self.company = CompanyFactory(id=1) self.company.job_source_ids.add(self.business_unit) self.admin = CompanyUserFactory(user=self.staff_user, company=self.company) self.microsite = SeoSiteFactory() self.microsite.business_units.add(self.business_unit) self.client = TestClient() self.client.login_user(self.staff_user) self.candidate_user = UserFactory(email="*****@*****.**") SavedSearchFactory(user=self.candidate_user, feed='http://test.jobs/jobs/feed/rss?', url='http://test.jobs/search?q=django', label='test Jobs') for i in range(5): # Create 5 new users user = UserFactory(email='*****@*****.**' % i) for search in SEARCH_OPTS: # Create 15 new searches and assign three per user SavedSearchFactory(user=user, url='http://test.jobs/search?q=%s' % search, feed='http://test.jobs/jobs/feed/rss?', label='%s Jobs' % search) update_solr_task(settings.TEST_SOLR_INSTANCE) def tearDown(self): super(MyDashboardViewsTests, self).tearDown() for location in settings.TEST_SOLR_INSTANCE.values(): solr = pysolr.Solr(location) solr.delete(q='*:*') def add_analytics_data(self, type_, num_to_add=2): """ Adds testing analytics data to Solr. Adds two entries per page category, one for unauthenticated and one for authenticated hits. """ dicts = [] base_dict = { 'domain': self.microsite.domain, 'view_date': datetime.now(), 'company_id': self.company.pk, } home_dict = { 'page_category': 'home' } view_dict = { 'job_view_guid': '1'*32, 'job_view_buid': self.business_unit.pk, 'page_category': 'listing' } search_dict = { 'page_category': 'results' } apply_dict = { 'job_view_guid': '2'*32, 'job_view_buid': self.business_unit.pk, 'page_category': 'redirect' } if type_ == 'home': analytics_dict = home_dict elif type_ == 'listing': analytics_dict = view_dict elif type_ == 'results': analytics_dict = search_dict else: analytics_dict = apply_dict analytics_dict.update(base_dict) for _ in range(num_to_add): dicts.append(analytics_dict.copy()) for analytics_dict in dicts: analytics_dict['aguid'] = uuid.uuid4().hex analytics_dict['uid'] = 'analytics##%s#%s' % ( analytics_dict['view_date'], analytics_dict['aguid'] ) for location in settings.TEST_SOLR_INSTANCE.values(): solr = pysolr.Solr(location) solr.add(dicts) @unittest.skip("Correct behavior undefined with respect to duplicates.") def test_number_of_searches_and_users_is_correct(self): response = self.client.post( reverse('dashboard')+'?company='+str(self.company.id)) # 6 users total self.assertEqual(response.context['total_candidates'], 6) old_search = SavedSearch.objects.all()[0] old_search.created_on -= timedelta(days=31) old_search.save() response = self.client.post( reverse('dashboard')+'?company='+str(self.company.id), {'microsite': 'test.jobs'}) self.assertEqual(response.context['total_candidates'], 6) def test_facets(self): education = EducationFactory(user=self.candidate_user) adr = AddressFactory(user=self.candidate_user) license = LicenseFactory(user=self.candidate_user) self.candidate_user.save() update_solr_task(settings.TEST_SOLR_INSTANCE) country_str = 'http://testserver/candidates/view?company=1&location={country}' education_str = 'http://testserver/candidates/view?company=1&education={education}' license_str = 'http://testserver/candidates/view?company=1&license={license_name}' country_str = country_str.format(country=adr.country_code) education_str = education_str.format(education=education.education_level_code) license_str = license_str.format(license_name=license.license_name) q = '?company={company}' q = q.format(company=str(self.company.id)) response = self.client.post(reverse('dashboard')+q) soup = BeautifulSoup(response.content) types = ['Country', 'Education', 'License'] hrefs = [] for facet_type in types: container = soup.select('#%s-details-table' % facet_type)[0] href = container.select('a')[0].attrs['href'] hrefs.append(href) self.assertIn(country_str, hrefs) self.assertIn(education_str, hrefs) self.assertIn(license_str, hrefs) def test_filters(self): adr = AddressFactory(user=self.candidate_user) self.candidate_user.save() update_solr_task(settings.TEST_SOLR_INSTANCE) country_str = 'http://testserver/candidates/view?company=1&location={country}' country_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company=1"><span>✖</span> {country_long}</a><br>' region_str = 'http://testserver/candidates/view?company=1&location={country}-{region}' region_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company=1&location={country}"><span>✖</span> {region}, {country}</a>' city_str = 'http://testserver/candidates/view?company=1&location={country}-{region}-{city}' city_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company=1&location={country}-{region}"><span>✖</span> {city}, {region}, {country}</a>' country_str = country_str.format(country=adr.country_code) country_filter_str = country_filter_str.format(country=adr.country_code, country_long=country_codes[adr.country_code]) region_str = region_str.format(country=adr.country_code, region=adr.country_sub_division_code) region_filter_str = region_filter_str.format(region=adr.country_sub_division_code, country=adr.country_code, country_long=country_codes[adr.country_code]) city_str = city_str.format(country=adr.country_code, region=adr.country_sub_division_code, city=adr.city_name) city_filter_str = city_filter_str.format(country=adr.country_code, region=adr.country_sub_division_code, city=adr.city_name, country_long=country_codes[adr.country_code]) q = '?company={company}' q = q.format(company=str(self.company.id)) response = self.client.post(reverse('dashboard')+q) self.assertIn(country_str, response.content) q = '?company={company}&location={country}' q = q.format(company=str(self.company.id), country=adr.country_code) response = self.client.post(reverse('dashboard')+q) self.assertIn(country_filter_str, response.content) self.assertIn(region_str, response.content) q = '?company={company}&location={country}-{region}' q = q.format(company=str(self.company.id), country=adr.country_code, region=adr.country_sub_division_code) response = self.client.post(reverse('dashboard')+q) self.assertIn(region_filter_str, response.content) self.assertIn(city_str, response.content) q = '?company={company}&location={country}-{region}-{city}' q = q.format(company=str(self.company.id), country=adr.country_code, region=adr.country_sub_division_code, city=adr.city_name) response = self.client.post(reverse('dashboard')+q) self.assertIn(city_filter_str, response.content) @unittest.skip("Correct behavior undefined with respect to duplicates.") def test_search_field(self): # Build url def build_url(search): q = '?company={company}&search={search}' q = q.format(company=str(self.company.id), search=search) return reverse('dashboard') + q # assert it finds all 5 searches. response = self.client.post(build_url('python')) soup = BeautifulSoup(response.content) count_box = soup.select('.count-box-left') count = int(count_box[0].text) self.assertEqual(count, 5) # 6 users total response = self.client.post(build_url('example')) soup = BeautifulSoup(response.content) count_box = soup.select('.count-box-left') count = int(count_box[0].text) self.assertIn(count, [6, 7]) def test_search_email(self): """We should be able to search for an exact email.""" user = UserFactory(email="*****@*****.**") SavedSearchFactory(user=user, url='http://test.jobs/search?q=python', feed='http://test.jobs/jobs/feed/rss?', label='Python Jobs') user.save() update_solr_task(settings.TEST_SOLR_INSTANCE) q = '?company={company}&search={search}' q = q.format(company=str(self.company.id), search='*****@*****.**') url = reverse('dashboard') + q response = self.client.post(url) soup = BeautifulSoup(response.content) self.assertEqual(len(soup.select('#row-link-table tr')), 1) def test_search_domain(self): """We should be able to search for domain.""" user = UserFactory(email="*****@*****.**") SavedSearchFactory(user=user, url='http://test.jobs/search?q=python', feed='http://test.jobs/jobs/feed/rss?', label='Python Jobs') user.save() update_solr_task(settings.TEST_SOLR_INSTANCE) q = '?company={company}&search={search}' q = q.format(company=str(self.company.id), search='shouldWork.com') url = reverse('dashboard') + q response = self.client.post(url) soup = BeautifulSoup(response.content) self.assertEqual(len(soup.select('#row-link-table tr')), 1) def test_search_updates_facet_counts(self): # Add ProfileData to the candidate_user EducationFactory(user=self.candidate_user) AddressFactory(user=self.candidate_user) LicenseFactory(user=self.candidate_user) self.candidate_user.save() # Create a new user with ProfileData user = UserFactory(email="*****@*****.**") SavedSearchFactory(user=user, url='http://test.jobs/search?q=python', feed='http://test.jobs/jobs/feed/rss?', label='Python Jobs') EducationFactory(user=user) AddressFactory(user=user) LicenseFactory(user=user) user.save() update_solr_task(settings.TEST_SOLR_INSTANCE) # Assert there are two users with country codes country_tag = '#Country-details-table .facet-count' q = '?company={company}' q = q.format(company=str(self.company.id)) response = self.client.post(reverse('dashboard') + q) soup = BeautifulSoup(response.content) self.assertEqual(int(soup.select(country_tag)[0].text), 2) # When we search, the facet count updates. q = '?company={company}&search={search}' q = q.format(company=str(self.company.id), search='find') response = self.client.post(reverse('dashboard') + q) soup = BeautifulSoup(response.content) self.assertEqual(int(soup.select(country_tag)[0].text), 1) # Tests to see if redirect from /candidates/ goes to candidates/view/ def test_redirect_to_candidates_views_default_page(self): response = self.client.post('/candidates/') # response returns HttpResponsePermanentRedirect which returns a 301 # status code instead of the normal 302 redirect status code self.assertRedirects(response, '/candidates/view/', status_code=301, target_status_code=200) response = self.client.post(reverse('dashboard')) self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content) company_name = soup.find('h1') company_name = company_name.next self.assertEqual(company_name, self.company.name) # Eventually these opted-in/out will be changed to # track if user is part of company's activity feed def test_candidate_has_opted_in(self): response = self.client.post( reverse('candidate_information', )+'?company='+str(self.company.id)+'&user='******'candidate_information', )+'?company='+str(self.company.id)+'&user='******'candidate_information', )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll( 'a', {'class': 'accordion-toggle'}) info = soup.find('div', {'id': 'candidate-content'}).findAll('li') self.assertEqual(len(titles), 6) self.assertEqual(len(info), 16) self.assertEqual(response.status_code, 200) def test_candidate_page_load_without_profileunits_with_activites(self): response = self.client.post( reverse('candidate_information', )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll( 'a', {'class': 'accordion-toggle'}) info = soup.find('div', {'id': 'candidate-content'}).findAll('li') self.assertEqual(len(titles), 1) self.assertEqual(len(info), 3) self.assertEqual(response.status_code, 200) def test_candidate_page_load_without_profileunits_and_activites(self): saved_search = SavedSearch.objects.get(user=self.candidate_user) saved_search.delete() response = self.client.post( reverse('candidate_information', )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}) self.assertFalse(info) self.assertEqual(response.status_code, 404) def test_export_csv(self): response = self.client.post( reverse('export_candidates')+'?company=' + str(self.company.id)+'&ex-t=csv') self.assertTrue(response.content) self.assertEqual(response.status_code, 200) def test_export_xml(self): response = self.client.post( reverse('export_candidates')+'?company=' + str(self.company.id)+'&ex-t=xml') self.assertTrue(response.content.index('candidates')) self.assertEqual(response.status_code, 200) def test_export_json(self): response = self.client.post( reverse('export_candidates')+'?company=' + str(self.company.id)+'&ex-t=json') self.assertTrue(response.content.index('candidates')) self.assertEqual(response.status_code, 200) def test_dashboard_analytics_no_data(self): response = self.client.post( reverse('dashboard')+'?company='+str(self.company.id), {'microsite': 'test.jobs'}) soup = BeautifulSoup(response.content) for selector in ['#total-clicks', '#total-home', '#total-job-views', '#total-search']: container = soup.select(selector) # Empty list means no elements were found. self.assertEqual(container, []) def test_dashboard_analytics_with_data(self): for type_ in ['home', 'listing', 'results']: self.add_analytics_data(type_) num_clicks = 1234 self.add_analytics_data('redirect', num_to_add=num_clicks) response = self.client.post( reverse('dashboard')+'?company='+str(self.company.id)) soup = BeautifulSoup(response.content) for selector in ['#total-clicks', '#total-home', '#total-job-views', '#total-search']: # This should be the parent container for all analytics data # of this type container = soup.select(selector)[0] # All hits, humanized all_hits = container.select('span')[0] if selector == '#total-clicks': expected = '1.2k' else: expected = '2' self.assertEqual(all_hits.text.strip(), expected) # All hits, raw number if selector == '#total-clicks': full = container.attrs['data-original-title'] self.assertEqual(full.strip(), '1,234') else: with self.assertRaises(KeyError): # This is marked as having no effect, which is intended container.attrs['data-original-title'] def test_dashboard_with_no_microsites(self): """ Trying to access the dashboard of a company that has no microsites associated with it should not create malformed solr queries. """ self.microsite.delete() response = self.client.post( reverse('dashboard')+'?company='+str(self.company.id)) self.assertEqual(response.status_code, 200)
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 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 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 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 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 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 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 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)