From f46a91f5e4adfa587018ed8ae7004ebf1a23e17f Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 2 Feb 2024 13:59:23 -0500 Subject: [PATCH] reorganized test_views into three files --- src/registrar/tests/test_views.py | 3740 ----------------- src/registrar/tests/test_views_application.py | 2199 ++++++++++ src/registrar/tests/test_views_domain.py | 1611 +++++++ 3 files changed, 3810 insertions(+), 3740 deletions(-) create mode 100644 src/registrar/tests/test_views_application.py create mode 100644 src/registrar/tests/test_views_domain.py diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py index dcb6ba9e0..ac0ec0cdb 100644 --- a/src/registrar/tests/test_views.py +++ b/src/registrar/tests/test_views.py @@ -333,3743 +333,3 @@ class LoggedInTests(TestWithUser): self.assertEqual(response.status_code, 403) -class DomainApplicationTests(TestWithUser, WebTest): - - """Webtests for domain application to test filling and submitting.""" - - # Doesn't work with CSRF checking - # hypothesis is that CSRF_USE_SESSIONS is incompatible with WebTest - csrf_checks = False - - def setUp(self): - super().setUp() - self.app.set_user(self.user.username) - self.TITLES = ApplicationWizard.TITLES - - def test_application_form_intro_acknowledgement(self): - """Tests that user is presented with intro acknowledgement page""" - intro_page = self.app.get(reverse("application:")) - self.assertContains(intro_page, "You’re about to start your .gov domain request") - - def test_application_form_intro_is_skipped_when_edit_access(self): - """Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'""" - completed_application(status=DomainApplication.ApplicationStatus.STARTED, user=self.user) - home_page = self.app.get("/") - self.assertContains(home_page, "city.gov") - # click the "Edit" link - detail_page = home_page.click("Edit", index=0) - # Check that the response is a redirect - self.assertEqual(detail_page.status_code, 302) - # You can access the 'Location' header to get the redirect URL - redirect_url = detail_page.url - self.assertEqual(redirect_url, "/request/organization_type/") - - def test_application_form_empty_submit(self): - """Tests empty submit on the first page after the acknowledgement page""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - # submitting should get back the same page if the required field is empty - result = type_page.forms[0].submit() - self.assertIn("What kind of U.S.-based government organization do you represent?", result) - - def test_application_multiple_applications_exist(self): - """Test that an info message appears when user has multiple applications already""" - # create and submit an application - application = completed_application(user=self.user) - mock_client = MockSESClient() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - application.submit() - application.save() - - # now, attempt to create another one - with less_console_noise(): - intro_page = self.app.get(reverse("application:")) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - self.assertContains(type_page, "You cannot submit this request yet") - - @boto3_mocking.patching - def test_application_form_submission(self): - """ - Can fill out the entire form and submit. - As we add additional form pages, we need to include them here to make - this test work. - - This test also looks for the long organization name on the summary page. - - This also tests for the presence of a modal trigger and the dynamic test - in the modal header on the submit page. - """ - num_pages_tested = 0 - # elections, type_of_work, tribal_government - SKIPPED_PAGES = 3 - num_pages = len(self.TITLES) - SKIPPED_PAGES - - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - # ---- TYPE PAGE ---- - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = "federal" - # test next button and validate data - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - # should see results in db - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.organization_type, "federal") - # the post request should return a redirect to the next form in - # the application - self.assertEqual(type_result.status_code, 302) - self.assertEqual(type_result["Location"], "/request/organization_federal/") - num_pages_tested += 1 - - # ---- FEDERAL BRANCH PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - federal_page = type_result.follow() - federal_form = federal_page.forms[0] - federal_form["organization_federal-federal_type"] = "executive" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_result = federal_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.federal_type, "executive") - # the post request should return a redirect to the next form in - # the application - self.assertEqual(federal_result.status_code, 302) - self.assertEqual(federal_result["Location"], "/request/organization_contact/") - num_pages_tested += 1 - - # ---- ORG CONTACT PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - org_contact_page = federal_result.follow() - org_contact_form = org_contact_page.forms[0] - # federal agency so we have to fill in federal_agency - org_contact_form["organization_contact-federal_agency"] = "General Services Administration" - org_contact_form["organization_contact-organization_name"] = "Testorg" - org_contact_form["organization_contact-address_line1"] = "address 1" - org_contact_form["organization_contact-address_line2"] = "address 2" - org_contact_form["organization_contact-city"] = "NYC" - org_contact_form["organization_contact-state_territory"] = "NY" - org_contact_form["organization_contact-zipcode"] = "10002" - org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - org_contact_result = org_contact_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.organization_name, "Testorg") - self.assertEqual(application.address_line1, "address 1") - self.assertEqual(application.address_line2, "address 2") - self.assertEqual(application.city, "NYC") - self.assertEqual(application.state_territory, "NY") - self.assertEqual(application.zipcode, "10002") - self.assertEqual(application.urbanization, "URB Royal Oaks") - # the post request should return a redirect to the next form in - # the application - self.assertEqual(org_contact_result.status_code, 302) - self.assertEqual(org_contact_result["Location"], "/request/authorizing_official/") - num_pages_tested += 1 - - # ---- AUTHORIZING OFFICIAL PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page = org_contact_result.follow() - ao_form = ao_page.forms[0] - ao_form["authorizing_official-first_name"] = "Testy ATO" - ao_form["authorizing_official-last_name"] = "Tester ATO" - ao_form["authorizing_official-title"] = "Chief Tester" - ao_form["authorizing_official-email"] = "testy@town.com" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_result = ao_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.authorizing_official.first_name, "Testy ATO") - self.assertEqual(application.authorizing_official.last_name, "Tester ATO") - self.assertEqual(application.authorizing_official.title, "Chief Tester") - self.assertEqual(application.authorizing_official.email, "testy@town.com") - # the post request should return a redirect to the next form in - # the application - self.assertEqual(ao_result.status_code, 302) - self.assertEqual(ao_result["Location"], "/request/current_sites/") - num_pages_tested += 1 - - # ---- CURRENT SITES PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - current_sites_page = ao_result.follow() - current_sites_form = current_sites_page.forms[0] - current_sites_form["current_sites-0-website"] = "www.city.com" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - current_sites_result = current_sites_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual( - application.current_websites.filter(website="http://www.city.com").count(), - 1, - ) - # the post request should return a redirect to the next form in - # the application - self.assertEqual(current_sites_result.status_code, 302) - self.assertEqual(current_sites_result["Location"], "/request/dotgov_domain/") - num_pages_tested += 1 - - # ---- DOTGOV DOMAIN PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - dotgov_page = current_sites_result.follow() - dotgov_form = dotgov_page.forms[0] - dotgov_form["dotgov_domain-requested_domain"] = "city" - dotgov_form["dotgov_domain-0-alternative_domain"] = "city1" - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - dotgov_result = dotgov_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.requested_domain.name, "city.gov") - self.assertEqual(application.alternative_domains.filter(website="city1.gov").count(), 1) - # the post request should return a redirect to the next form in - # the application - self.assertEqual(dotgov_result.status_code, 302) - self.assertEqual(dotgov_result["Location"], "/request/purpose/") - num_pages_tested += 1 - - # ---- PURPOSE PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - purpose_page = dotgov_result.follow() - purpose_form = purpose_page.forms[0] - purpose_form["purpose-purpose"] = "For all kinds of things." - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - purpose_result = purpose_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.purpose, "For all kinds of things.") - # the post request should return a redirect to the next form in - # the application - self.assertEqual(purpose_result.status_code, 302) - self.assertEqual(purpose_result["Location"], "/request/your_contact/") - num_pages_tested += 1 - - # ---- YOUR CONTACT INFO PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - your_contact_page = purpose_result.follow() - your_contact_form = your_contact_page.forms[0] - - your_contact_form["your_contact-first_name"] = "Testy you" - your_contact_form["your_contact-last_name"] = "Tester you" - your_contact_form["your_contact-title"] = "Admin Tester" - your_contact_form["your_contact-email"] = "testy-admin@town.com" - your_contact_form["your_contact-phone"] = "(201) 555 5556" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - your_contact_result = your_contact_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.submitter.first_name, "Testy you") - self.assertEqual(application.submitter.last_name, "Tester you") - self.assertEqual(application.submitter.title, "Admin Tester") - self.assertEqual(application.submitter.email, "testy-admin@town.com") - self.assertEqual(application.submitter.phone, "(201) 555 5556") - # the post request should return a redirect to the next form in - # the application - self.assertEqual(your_contact_result.status_code, 302) - self.assertEqual(your_contact_result["Location"], "/request/other_contacts/") - num_pages_tested += 1 - - # ---- OTHER CONTACTS PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = your_contact_result.follow() - - # This page has 3 forms in 1. - # Let's set the yes/no radios to enable the other contacts fieldsets - other_contacts_form = other_contacts_page.forms[0] - - other_contacts_form["other_contacts-has_other_contacts"] = "True" - - other_contacts_form["other_contacts-0-first_name"] = "Testy2" - other_contacts_form["other_contacts-0-last_name"] = "Tester2" - other_contacts_form["other_contacts-0-title"] = "Another Tester" - other_contacts_form["other_contacts-0-email"] = "testy2@town.com" - other_contacts_form["other_contacts-0-phone"] = "(201) 555 5557" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_result = other_contacts_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual( - application.other_contacts.filter( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(201) 555 5557", - ).count(), - 1, - ) - # the post request should return a redirect to the next form in - # the application - self.assertEqual(other_contacts_result.status_code, 302) - self.assertEqual(other_contacts_result["Location"], "/request/anything_else/") - num_pages_tested += 1 - - # ---- ANYTHING ELSE PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - anything_else_page = other_contacts_result.follow() - anything_else_form = anything_else_page.forms[0] - - anything_else_form["anything_else-anything_else"] = "Nothing else." - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - anything_else_result = anything_else_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.anything_else, "Nothing else.") - # the post request should return a redirect to the next form in - # the application - self.assertEqual(anything_else_result.status_code, 302) - self.assertEqual(anything_else_result["Location"], "/request/requirements/") - num_pages_tested += 1 - - # ---- REQUIREMENTS PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - requirements_page = anything_else_result.follow() - requirements_form = requirements_page.forms[0] - - requirements_form["requirements-is_policy_acknowledged"] = True - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - requirements_result = requirements_form.submit() - # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one - self.assertEqual(application.is_policy_acknowledged, True) - # the post request should return a redirect to the next form in - # the application - self.assertEqual(requirements_result.status_code, 302) - self.assertEqual(requirements_result["Location"], "/request/review/") - num_pages_tested += 1 - - # ---- REVIEW AND FINSIHED PAGES ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - review_page = requirements_result.follow() - review_form = review_page.forms[0] - - # Review page contains all the previously entered data - # Let's make sure the long org name is displayed - self.assertContains(review_page, "Federal") - self.assertContains(review_page, "Executive") - self.assertContains(review_page, "Testorg") - self.assertContains(review_page, "address 1") - self.assertContains(review_page, "address 2") - self.assertContains(review_page, "NYC") - self.assertContains(review_page, "NY") - self.assertContains(review_page, "10002") - self.assertContains(review_page, "URB Royal Oaks") - self.assertContains(review_page, "Testy ATO") - self.assertContains(review_page, "Tester ATO") - self.assertContains(review_page, "Chief Tester") - self.assertContains(review_page, "testy@town.com") - self.assertContains(review_page, "city.com") - self.assertContains(review_page, "city.gov") - self.assertContains(review_page, "city1.gov") - self.assertContains(review_page, "For all kinds of things.") - self.assertContains(review_page, "Testy you") - self.assertContains(review_page, "Tester you") - self.assertContains(review_page, "Admin Tester") - self.assertContains(review_page, "testy-admin@town.com") - self.assertContains(review_page, "(201) 555-5556") - self.assertContains(review_page, "Testy2") - self.assertContains(review_page, "Tester2") - self.assertContains(review_page, "Another Tester") - self.assertContains(review_page, "testy2@town.com") - self.assertContains(review_page, "(201) 555-5557") - self.assertContains(review_page, "Nothing else.") - - # We can't test the modal itself as it relies on JS for init and triggering, - # but we can test for the existence of its trigger: - self.assertContains(review_page, "toggle-submit-domain-request") - # And the existence of the modal's data parked and ready for the js init. - # The next assert also tests for the passed requested domain context from - # the view > application_form > modal - self.assertContains(review_page, "You are about to submit a domain request for city.gov") - - # final submission results in a redirect to the "finished" URL - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - with less_console_noise(): - review_result = review_form.submit() - - self.assertEqual(review_result.status_code, 302) - self.assertEqual(review_result["Location"], "/request/finished/") - num_pages_tested += 1 - - # following this redirect is a GET request, so include the cookie - # here too. - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - with less_console_noise(): - final_result = review_result.follow() - self.assertContains(final_result, "Thanks for your domain request!") - - # check that any new pages are added to this test - self.assertEqual(num_pages, num_pages_tested) - - # This is the start of a test to check an existing application, it currently - # does not work and results in errors as noted in: - # https://github.com/cisagov/getgov/pull/728 - @skip("WIP") - def test_application_form_started_allsteps(self): - num_pages_tested = 0 - # elections, type_of_work, tribal_government - SKIPPED_PAGES = 3 - DASHBOARD_PAGE = 1 - num_pages = len(self.TITLES) - SKIPPED_PAGES + DASHBOARD_PAGE - - application = completed_application(user=self.user) - application.save() - home_page = self.app.get("/") - self.assertContains(home_page, "city.gov") - self.assertContains(home_page, "Started") - num_pages_tested += 1 - - # TODO: For some reason this click results in a new application being generated - # This appraoch is an alternatie to using get as is being done below - # - # type_page = home_page.click("Edit") - - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - url = reverse("edit-application", kwargs={"id": application.pk}) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - # TODO: The following line results in a django error on middleware - response = self.client.get(url, follow=True) - self.assertContains(response, "Type of organization") - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # TODO: Step through the remaining pages - - self.assertEqual(num_pages, num_pages_tested) - - def test_application_form_conditional_federal(self): - """Federal branch question is shown for federal organizations.""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - # ---- TYPE PAGE ---- - - # the conditional step titles shouldn't appear initially - self.assertNotContains(type_page, self.TITLES["organization_federal"]) - self.assertNotContains(type_page, self.TITLES["organization_election"]) - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = "federal" - - # set the session ID before .submit() - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - - # the post request should return a redirect to the federal branch - # question - self.assertEqual(type_result.status_code, 302) - self.assertEqual(type_result["Location"], "/request/organization_federal/") - - # and the step label should appear in the sidebar of the resulting page - # but the step label for the elections page should not appear - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_page = type_result.follow() - self.assertContains(federal_page, self.TITLES["organization_federal"]) - self.assertNotContains(federal_page, self.TITLES["organization_election"]) - - # continuing on in the flow we need to see top-level agency on the - # contact page - federal_page.forms[0]["organization_federal-federal_type"] = "executive" - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_result = federal_page.forms[0].submit() - # the post request should return a redirect to the contact - # question - self.assertEqual(federal_result.status_code, 302) - self.assertEqual(federal_result["Location"], "/request/organization_contact/") - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - contact_page = federal_result.follow() - self.assertContains(contact_page, "Federal agency") - - def test_application_form_conditional_elections(self): - """Election question is shown for other organizations.""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - # ---- TYPE PAGE ---- - - # the conditional step titles shouldn't appear initially - self.assertNotContains(type_page, self.TITLES["organization_federal"]) - self.assertNotContains(type_page, self.TITLES["organization_election"]) - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = "county" - - # set the session ID before .submit() - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - - # the post request should return a redirect to the elections question - self.assertEqual(type_result.status_code, 302) - self.assertEqual(type_result["Location"], "/request/organization_election/") - - # and the step label should appear in the sidebar of the resulting page - # but the step label for the elections page should not appear - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - election_page = type_result.follow() - self.assertContains(election_page, self.TITLES["organization_election"]) - self.assertNotContains(election_page, self.TITLES["organization_federal"]) - - # continuing on in the flow we need to NOT see top-level agency on the - # contact page - election_page.forms[0]["organization_election-is_election_board"] = "True" - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - election_result = election_page.forms[0].submit() - # the post request should return a redirect to the contact - # question - self.assertEqual(election_result.status_code, 302) - self.assertEqual(election_result["Location"], "/request/organization_contact/") - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - contact_page = election_result.follow() - self.assertNotContains(contact_page, "Federal agency") - - def test_application_form_section_skipping(self): - """Can skip forward and back in sections""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = "federal" - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_page = type_result.follow() - - # Now on federal type page, click back to the organization type - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - new_page = federal_page.click(str(self.TITLES["organization_type"]), index=0) - - # Should be a link to the organization_federal page - self.assertGreater( - len(new_page.html.find_all("a", href="/request/organization_federal/")), - 0, - ) - - def test_application_form_nonfederal(self): - """Non-federal organizations don't have to provide their federal agency.""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - contact_page = type_result.follow() - org_contact_form = contact_page.forms[0] - - self.assertNotIn("federal_agency", org_contact_form.fields) - - # minimal fields that must be filled out - org_contact_form["organization_contact-organization_name"] = "Testorg" - org_contact_form["organization_contact-address_line1"] = "address 1" - org_contact_form["organization_contact-city"] = "NYC" - org_contact_form["organization_contact-state_territory"] = "NY" - org_contact_form["organization_contact-zipcode"] = "10002" - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - contact_result = org_contact_form.submit() - - # the post request should return a redirect to the - # about your organization page if it was successful. - self.assertEqual(contact_result.status_code, 302) - self.assertEqual(contact_result["Location"], "/request/about_your_organization/") - - def test_application_about_your_organization_special(self): - """Special districts have to answer an additional question.""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.SPECIAL_DISTRICT - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_page.forms[0].submit() - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - contact_page = type_result.follow() - - self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION]) - - def test_yes_no_form_inits_blank_for_new_application(self): - """On the Other Contacts page, the yes/no form gets initialized with nothing selected for - new applications""" - other_contacts_page = self.app.get(reverse("application:other_contacts")) - other_contacts_form = other_contacts_page.forms[0] - self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, None) - - def test_yes_no_form_inits_yes_for_application_with_other_contacts(self): - """On the Other Contacts page, the yes/no form gets initialized with YES selected if the - application has other contacts""" - # Application has other contacts by default - application = completed_application(user=self.user) - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True") - - def test_yes_no_form_inits_no_for_application_with_no_other_contacts_rationale(self): - """On the Other Contacts page, the yes/no form gets initialized with NO selected if the - application has no other contacts""" - # Application has other contacts by default - application = completed_application(user=self.user, has_other_contacts=False) - application.no_other_contacts_rationale = "Hello!" - application.save() - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False") - - def test_submitting_other_contacts_deletes_no_other_contacts_rationale(self): - """When a user submits the Other Contacts form with other contacts selected, the application's - no other contacts rationale gets deleted""" - # Application has other contacts by default - application = completed_application(user=self.user, has_other_contacts=False) - application.no_other_contacts_rationale = "Hello!" - application.save() - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False") - - other_contacts_form["other_contacts-has_other_contacts"] = "True" - - other_contacts_form["other_contacts-0-first_name"] = "Testy" - other_contacts_form["other_contacts-0-middle_name"] = "" - other_contacts_form["other_contacts-0-last_name"] = "McTesterson" - other_contacts_form["other_contacts-0-title"] = "Lord" - other_contacts_form["other_contacts-0-email"] = "testy@abc.org" - other_contacts_form["other_contacts-0-phone"] = "(201) 555-0123" - - # Submit the now empty form - other_contacts_form.submit() - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database - application = DomainApplication.objects.get() - self.assertEqual( - application.other_contacts.count(), - 1, - ) - - self.assertEquals( - application.no_other_contacts_rationale, - None, - ) - - def test_submitting_no_other_contacts_rationale_deletes_other_contacts(self): - """When a user submits the Other Contacts form with no other contacts selected, the application's - other contacts get deleted for other contacts that exist and are not joined to other objects - """ - # Application has other contacts by default - application = completed_application(user=self.user) - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True") - - other_contacts_form["other_contacts-has_other_contacts"] = "False" - - other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!" - - # Submit the now empty form - other_contacts_form.submit() - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database - application = DomainApplication.objects.get() - self.assertEqual( - application.other_contacts.count(), - 0, - ) - - self.assertEquals( - application.no_other_contacts_rationale, - "Hello again!", - ) - - def test_submitting_no_other_contacts_rationale_removes_reference_other_contacts_when_joined(self): - """When a user submits the Other Contacts form with no other contacts selected, the application's - other contacts references get removed for other contacts that exist and are joined to other objects""" - # Populate the database with a domain application that - # has 1 "other contact" assigned to it - # We'll do it from scratch so we can reuse the other contact - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(555) 555 5555", - ) - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(555) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(555) 555 5557", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - submitter=you, - creator=self.user, - status="started", - ) - application.other_contacts.add(other) - - # Now let's join the other contact to another object - domain_info = DomainInformation.objects.create(creator=self.user) - domain_info.other_contacts.set([other]) - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True") - - other_contacts_form["other_contacts-has_other_contacts"] = "False" - - other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!" - - # Submit the now empty form - other_contacts_form.submit() - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - # Verify that the no_other_contacts_rationale we saved earlier is no longer associated with the application - application = DomainApplication.objects.get() - self.assertEqual( - application.other_contacts.count(), - 0, - ) - - # Verify that the 'other' contact object still exists - domain_info = DomainInformation.objects.get() - self.assertEqual( - domain_info.other_contacts.count(), - 1, - ) - self.assertEqual( - domain_info.other_contacts.all()[0].first_name, - "Testy2", - ) - - self.assertEquals( - application.no_other_contacts_rationale, - "Hello again!", - ) - - def test_if_yes_no_form_is_no_then_no_other_contacts_required(self): - """Applicants with no other contacts have to give a reason.""" - other_contacts_page = self.app.get(reverse("application:other_contacts")) - other_contacts_form = other_contacts_page.forms[0] - other_contacts_form["other_contacts-has_other_contacts"] = "False" - response = other_contacts_page.forms[0].submit() - - # The textarea for no other contacts returns this error message - # Assert that it is returned, ie the no other contacts form is required - self.assertContains(response, "Rationale for no other employees is required.") - - # The first name field for other contacts returns this error message - # Assert that it is not returned, ie the contacts form is not required - self.assertNotContains(response, "Enter the first name / given name of this contact.") - - def test_if_yes_no_form_is_yes_then_other_contacts_required(self): - """Applicants with other contacts do not have to give a reason.""" - other_contacts_page = self.app.get(reverse("application:other_contacts")) - other_contacts_form = other_contacts_page.forms[0] - other_contacts_form["other_contacts-has_other_contacts"] = "True" - response = other_contacts_page.forms[0].submit() - - # The textarea for no other contacts returns this error message - # Assert that it is not returned, ie the no other contacts form is not required - self.assertNotContains(response, "Rationale for no other employees is required.") - - # The first name field for other contacts returns this error message - # Assert that it is returned, ie the contacts form is required - self.assertContains(response, "Enter the first name / given name of this contact.") - - def test_delete_other_contact(self): - """Other contacts can be deleted after being saved to database. - - This formset uses the DJANGO DELETE widget. We'll test that by setting 2 contacts on an application, - loading the form and marking one contact up for deletion.""" - # Populate the database with a domain application that - # has 2 "other contact" assigned to it - # We'll do it from scratch so we can reuse the other contact - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(201) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(201) 555 5557", - ) - other2, _ = Contact.objects.get_or_create( - first_name="Testy3", - last_name="Tester3", - title="Another Tester", - email="testy3@town.com", - phone="(201) 555 5557", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - submitter=you, - creator=self.user, - status="started", - ) - application.other_contacts.add(other) - application.other_contacts.add(other2) - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - - # Minimal check to ensure the form is loaded with both other contacts - self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") - self.assertEqual(other_contacts_form["other_contacts-1-first_name"].value, "Testy3") - - # Mark the first dude for deletion - other_contacts_form.set("other_contacts-0-DELETE", "on") - - # Submit the form - other_contacts_form.submit() - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - # Verify that the first dude was deleted - application = DomainApplication.objects.get() - self.assertEqual(application.other_contacts.count(), 1) - self.assertEqual(application.other_contacts.first().first_name, "Testy3") - - def test_delete_other_contact_does_not_allow_zero_contacts(self): - """Delete Other Contact does not allow submission with zero contacts.""" - # Populate the database with a domain application that - # has 1 "other contact" assigned to it - # We'll do it from scratch so we can reuse the other contact - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(201) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(201) 555 5557", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - submitter=you, - creator=self.user, - status="started", - ) - application.other_contacts.add(other) - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") - - # Mark the first dude for deletion - other_contacts_form.set("other_contacts-0-DELETE", "on") - - # Submit the form - other_contacts_form.submit() - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - # Verify that the contact was not deleted - application = DomainApplication.objects.get() - self.assertEqual(application.other_contacts.count(), 1) - self.assertEqual(application.other_contacts.first().first_name, "Testy2") - - def test_delete_other_contact_sets_visible_empty_form_as_required_after_failed_submit(self): - """When you: - 1. add an empty contact, - 2. delete existing contacts, - 3. then submit, - The forms on page reload shows all the required fields and their errors.""" - - # Populate the database with a domain application that - # has 1 "other contact" assigned to it - # We'll do it from scratch so we can reuse the other contact - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(201) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(201) 555 5557", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - submitter=you, - creator=self.user, - status="started", - ) - application.other_contacts.add(other) - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") - - # Set total forms to 2 indicating an additional formset was added. - # Submit no data though for the second formset. - # Set the first formset to be deleted. - other_contacts_form["other_contacts-TOTAL_FORMS"] = "2" - other_contacts_form.set("other_contacts-0-DELETE", "on") - - response = other_contacts_form.submit() - - # Assert that the response presents errors to the user, including to - # Enter the first name ... - self.assertContains(response, "Enter the first name / given name of this contact.") - - def test_edit_other_contact_in_place(self): - """When you: - 1. edit an existing contact which is not joined to another model, - 2. then submit, - The application is linked to the existing contact, and the existing contact updated.""" - - # Populate the database with a domain application that - # has 1 "other contact" assigned to it - # We'll do it from scratch - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(201) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(201) 555 5557", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - submitter=you, - creator=self.user, - status="started", - ) - application.other_contacts.add(other) - - # other_contact_pk is the initial pk of the other contact. set it before update - # to be able to verify after update that the same contact object is in place - other_contact_pk = other.id - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") - - # update the first name of the contact - other_contacts_form["other_contacts-0-first_name"] = "Testy3" - - # Submit the updated form - other_contacts_form.submit() - - application.refresh_from_db() - - # assert that the Other Contact is updated "in place" - other_contact = application.other_contacts.all()[0] - self.assertEquals(other_contact_pk, other_contact.id) - self.assertEquals("Testy3", other_contact.first_name) - - def test_edit_other_contact_creates_new(self): - """When you: - 1. edit an existing contact which IS joined to another model, - 2. then submit, - The application is linked to a new contact, and the new contact is updated.""" - - # Populate the database with a domain application that - # has 1 "other contact" assigned to it, the other contact is also - # the authorizing official initially - # We'll do it from scratch - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(201) 555 5556", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - submitter=you, - creator=self.user, - status="started", - ) - application.other_contacts.add(ao) - - # other_contact_pk is the initial pk of the other contact. set it before update - # to be able to verify after update that the ao contact is still in place - # and not updated, and that the new contact has a new id - other_contact_pk = ao.id - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_page = self.app.get(reverse("application:other_contacts")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - other_contacts_form = other_contacts_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy") - - # update the first name of the contact - other_contacts_form["other_contacts-0-first_name"] = "Testy2" - - # Submit the updated form - other_contacts_form.submit() - - application.refresh_from_db() - - # assert that other contact info is updated, and that a new Contact - # is created for the other contact - other_contact = application.other_contacts.all()[0] - self.assertNotEquals(other_contact_pk, other_contact.id) - self.assertEquals("Testy2", other_contact.first_name) - # assert that the authorizing official is not updated - authorizing_official = application.authorizing_official - self.assertEquals("Testy", authorizing_official.first_name) - - def test_edit_authorizing_official_in_place(self): - """When you: - 1. edit an authorizing official which is not joined to another model, - 2. then submit, - The application is linked to the existing ao, and the ao updated.""" - - # Populate the database with a domain application that - # has an authorizing_official (ao) - # We'll do it from scratch - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - creator=self.user, - status="started", - ) - - # ao_pk is the initial pk of the Authorizing Official. set it before update - # to be able to verify after update that the same Contact object is in place - ao_pk = ao.id - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - ao_page = self.app.get(reverse("application:authorizing_official")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - ao_form = ao_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy") - - # update the first name of the contact - ao_form["authorizing_official-first_name"] = "Testy2" - - # Submit the updated form - ao_form.submit() - - application.refresh_from_db() - - # assert AO is updated "in place" - updated_ao = application.authorizing_official - self.assertEquals(ao_pk, updated_ao.id) - self.assertEquals("Testy2", updated_ao.first_name) - - def test_edit_authorizing_official_creates_new(self): - """When you: - 1. edit an existing authorizing official which IS joined to another model, - 2. then submit, - The application is linked to a new Contact, and the new Contact is updated.""" - - # Populate the database with a domain application that - # has authorizing official assigned to it, the authorizing offical is also - # an other contact initially - # We'll do it from scratch - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - creator=self.user, - status="started", - ) - application.other_contacts.add(ao) - - # ao_pk is the initial pk of the authorizing official. set it before update - # to be able to verify after update that the other contact is still in place - # and not updated, and that the new ao has a new id - ao_pk = ao.id - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - ao_page = self.app.get(reverse("application:authorizing_official")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - ao_form = ao_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy") - - # update the first name of the contact - ao_form["authorizing_official-first_name"] = "Testy2" - - # Submit the updated form - ao_form.submit() - - application.refresh_from_db() - - # assert that the other contact is not updated - other_contacts = application.other_contacts.all() - other_contact = other_contacts[0] - self.assertEquals(ao_pk, other_contact.id) - self.assertEquals("Testy", other_contact.first_name) - # assert that the authorizing official is updated - authorizing_official = application.authorizing_official - self.assertEquals("Testy2", authorizing_official.first_name) - - def test_edit_submitter_in_place(self): - """When you: - 1. edit a submitter (your contact) which is not joined to another model, - 2. then submit, - The application is linked to the existing submitter, and the submitter updated.""" - - # Populate the database with a domain application that - # has a submitter - # We'll do it from scratch - you, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - submitter=you, - creator=self.user, - status="started", - ) - - # submitter_pk is the initial pk of the submitter. set it before update - # to be able to verify after update that the same contact object is in place - submitter_pk = you.id - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - your_contact_page = self.app.get(reverse("application:your_contact")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - your_contact_form = your_contact_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy") - - # update the first name of the contact - your_contact_form["your_contact-first_name"] = "Testy2" - - # Submit the updated form - your_contact_form.submit() - - application.refresh_from_db() - - updated_submitter = application.submitter - self.assertEquals(submitter_pk, updated_submitter.id) - self.assertEquals("Testy2", updated_submitter.first_name) - - def test_edit_submitter_creates_new(self): - """When you: - 1. edit an existing your contact which IS joined to another model, - 2. then submit, - The application is linked to a new Contact, and the new Contact is updated.""" - - # Populate the database with a domain application that - # has submitter assigned to it, the submitter is also - # an other contact initially - # We'll do it from scratch - submitter, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(201) 555 5555", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - submitter=submitter, - creator=self.user, - status="started", - ) - application.other_contacts.add(submitter) - - # submitter_pk is the initial pk of the your contact. set it before update - # to be able to verify after update that the other contact is still in place - # and not updated, and that the new submitter has a new id - submitter_pk = submitter.id - - # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - your_contact_page = self.app.get(reverse("application:your_contact")) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - your_contact_form = your_contact_page.forms[0] - - # Minimal check to ensure the form is loaded - self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy") - - # update the first name of the contact - your_contact_form["your_contact-first_name"] = "Testy2" - - # Submit the updated form - your_contact_form.submit() - - application.refresh_from_db() - - # assert that the other contact is not updated - other_contacts = application.other_contacts.all() - other_contact = other_contacts[0] - self.assertEquals(submitter_pk, other_contact.id) - self.assertEquals("Testy", other_contact.first_name) - # assert that the submitter is updated - submitter = application.submitter - self.assertEquals("Testy2", submitter.first_name) - - def test_application_about_your_organiztion_interstate(self): - """Special districts have to answer an additional question.""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - contact_page = type_result.follow() - - self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION]) - - def test_application_tribal_government(self): - """Tribal organizations have to answer an additional question.""" - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.TRIBAL - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - # the tribal government page comes immediately afterwards - self.assertIn("/tribal_government", type_result.headers["Location"]) - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - tribal_government_page = type_result.follow() - - # and the step is on the sidebar list. - self.assertContains(tribal_government_page, self.TITLES[Step.TRIBAL_GOVERNMENT]) - - def test_application_ao_dynamic_text(self): - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - # ---- TYPE PAGE ---- - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = "federal" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - - # ---- FEDERAL BRANCH PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_page = type_result.follow() - federal_form = federal_page.forms[0] - federal_form["organization_federal-federal_type"] = "executive" - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_result = federal_form.submit() - - # ---- ORG CONTACT PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - org_contact_page = federal_result.follow() - org_contact_form = org_contact_page.forms[0] - # federal agency so we have to fill in federal_agency - org_contact_form["organization_contact-federal_agency"] = "General Services Administration" - org_contact_form["organization_contact-organization_name"] = "Testorg" - org_contact_form["organization_contact-address_line1"] = "address 1" - org_contact_form["organization_contact-address_line2"] = "address 2" - org_contact_form["organization_contact-city"] = "NYC" - org_contact_form["organization_contact-state_territory"] = "NY" - org_contact_form["organization_contact-zipcode"] = "10002" - org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks" - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - org_contact_result = org_contact_form.submit() - - # ---- AO CONTACT PAGE ---- - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page = org_contact_result.follow() - self.assertContains(ao_page, "Executive branch federal agencies") - - # Go back to organization type page and change type - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page.click(str(self.TITLES["organization_type"]), index=0) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_form["organization_type-organization_type"] = "city" - type_result = type_form.submit() - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - election_page = type_result.follow() - - # Go back to AO page and test the dynamic text changed - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page = election_page.click(str(self.TITLES["authorizing_official"]), index=0) - self.assertContains(ao_page, "Domain requests from cities") - - def test_application_dotgov_domain_dynamic_text(self): - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - # ---- TYPE PAGE ---- - type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = "federal" - - # test next button - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_result = type_form.submit() - - # ---- FEDERAL BRANCH PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_page = type_result.follow() - federal_form = federal_page.forms[0] - federal_form["organization_federal-federal_type"] = "executive" - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - federal_result = federal_form.submit() - - # ---- ORG CONTACT PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - org_contact_page = federal_result.follow() - org_contact_form = org_contact_page.forms[0] - # federal agency so we have to fill in federal_agency - org_contact_form["organization_contact-federal_agency"] = "General Services Administration" - org_contact_form["organization_contact-organization_name"] = "Testorg" - org_contact_form["organization_contact-address_line1"] = "address 1" - org_contact_form["organization_contact-address_line2"] = "address 2" - org_contact_form["organization_contact-city"] = "NYC" - org_contact_form["organization_contact-state_territory"] = "NY" - org_contact_form["organization_contact-zipcode"] = "10002" - org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks" - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - org_contact_result = org_contact_form.submit() - - # ---- AO CONTACT PAGE ---- - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page = org_contact_result.follow() - - # ---- AUTHORIZING OFFICIAL PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page = org_contact_result.follow() - ao_form = ao_page.forms[0] - ao_form["authorizing_official-first_name"] = "Testy ATO" - ao_form["authorizing_official-last_name"] = "Tester ATO" - ao_form["authorizing_official-title"] = "Chief Tester" - ao_form["authorizing_official-email"] = "testy@town.com" - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_result = ao_form.submit() - - # ---- CURRENT SITES PAGE ---- - # Follow the redirect to the next form page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - current_sites_page = ao_result.follow() - current_sites_form = current_sites_page.forms[0] - current_sites_form["current_sites-0-website"] = "www.city.com" - - # test saving the page - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - current_sites_result = current_sites_form.submit() - - # ---- DOTGOV DOMAIN PAGE ---- - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - dotgov_page = current_sites_result.follow() - - self.assertContains(dotgov_page, "medicare.gov") - - # Go back to organization type page and change type - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - dotgov_page.click(str(self.TITLES["organization_type"]), index=0) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_form["organization_type-organization_type"] = "city" - type_result = type_form.submit() - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - election_page = type_result.follow() - - # Go back to dotgov domain page to test the dynamic text changed - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - dotgov_page = election_page.click(str(self.TITLES["dotgov_domain"]), index=0) - self.assertContains(dotgov_page, "CityofEudoraKS.gov") - self.assertNotContains(dotgov_page, "medicare.gov") - - def test_application_formsets(self): - """Users are able to add more than one of some fields.""" - current_sites_page = self.app.get(reverse("application:current_sites")) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - # fill in the form field - current_sites_form = current_sites_page.forms[0] - self.assertIn("current_sites-0-website", current_sites_form.fields) - self.assertNotIn("current_sites-1-website", current_sites_form.fields) - current_sites_form["current_sites-0-website"] = "https://example.com" - - # click "Add another" - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - current_sites_result = current_sites_form.submit("submit_button", value="save") - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - current_sites_form = current_sites_result.follow().forms[0] - - # verify that there are two form fields - value = current_sites_form["current_sites-0-website"].value - self.assertEqual(value, "https://example.com") - self.assertIn("current_sites-1-website", current_sites_form.fields) - # and it is correctly referenced in the ManyToOne relationship - application = DomainApplication.objects.get() # there's only one - self.assertEqual( - application.current_websites.filter(website="https://example.com").count(), - 1, - ) - - @skip("WIP") - def test_application_edit_restore(self): - """ - Test that a previously saved application is available at the /edit endpoint. - """ - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(555) 555 5555", - ) - domain, _ = Domain.objects.get_or_create(name="city.gov") - alt, _ = Website.objects.get_or_create(website="city1.gov") - current, _ = Website.objects.get_or_create(website="city.com") - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(555) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(555) 555 5557", - ) - application, _ = DomainApplication.objects.get_or_create( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - anything_else="No", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - requested_domain=domain, - submitter=you, - creator=self.user, - ) - application.other_contacts.add(other) - application.current_websites.add(current) - application.alternative_domains.add(alt) - - # prime the form by visiting /edit - url = reverse("edit-application", kwargs={"id": application.pk}) - response = self.client.get(url) - - # TODO: this is a sketch of each page in the wizard which needs to be tested - # Django does not have tools sufficient for real end to end integration testing - # (for example, USWDS moves radio buttons off screen and replaces them with - # CSS styled "fakes" -- Django cannot determine if those are visually correct) - # -- the best that can/should be done here is to ensure the correct values - # are being passed to the templating engine - - url = reverse("application:organization_type") - response = self.client.get(url, follow=True) - self.assertContains(response, "") - # choices = response.context['wizard']['form']['organization_type'].subwidgets - # radio = [ x for x in choices if x.data["value"] == "federal" ][0] - # checked = radio.data["selected"] - # self.assertTrue(checked) - - # url = reverse("application:organization_federal") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:organization_contact") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:authorizing_official") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:current_sites") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:dotgov_domain") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:purpose") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:your_contact") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:other_contacts") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:other_contacts") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:security_email") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:anything_else") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - # url = reverse("application:requirements") - # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # page = self.app.get(url) - # self.assertNotContains(page, "VALUE") - - def test_long_org_name_in_application(self): - """ - Make sure the long name is displaying in the application form, - org step - """ - intro_page = self.app.get(reverse("application:")) - # django-webtest does not handle cookie-based sessions well because it keeps - # resetting the session key on each new request, thus destroying the concept - # of a "session". We are going to do it manually, saving the session ID here - # and then setting the cookie on each request. - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - intro_form = intro_page.forms[0] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - intro_result = intro_form.submit() - - # follow first redirect - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - type_page = intro_result.follow() - - self.assertContains(type_page, "Federal: an agency of the U.S. government") - - def test_submit_modal_no_domain_text_fallback(self): - """When user clicks on submit your domain request and the requested domain - is null (possible through url direct access to the review page), present - fallback copy in the modal's header. - - NOTE: This may be a moot point if we implement a more solid pattern in the - future, like not a submit action at all on the review page.""" - - review_page = self.app.get(reverse("application:review")) - self.assertContains(review_page, "toggle-submit-domain-request") - self.assertContains(review_page, "You are about to submit an incomplete request") - - -class TestWithDomainPermissions(TestWithUser): - def setUp(self): - super().setUp() - self.domain, _ = Domain.objects.get_or_create(name="igorville.gov") - self.domain_with_ip, _ = Domain.objects.get_or_create(name="nameserverwithip.gov") - self.domain_just_nameserver, _ = Domain.objects.get_or_create(name="justnameserver.com") - self.domain_no_information, _ = Domain.objects.get_or_create(name="noinformation.gov") - self.domain_on_hold, _ = Domain.objects.get_or_create( - name="on-hold.gov", - state=Domain.State.ON_HOLD, - expiration_date=timezone.make_aware( - datetime.combine(date.today() + timedelta(days=1), datetime.min.time()) - ), - ) - self.domain_deleted, _ = Domain.objects.get_or_create( - name="deleted.gov", - state=Domain.State.DELETED, - expiration_date=timezone.make_aware( - datetime.combine(date.today() + timedelta(days=1), datetime.min.time()) - ), - ) - - self.domain_dsdata, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov") - self.domain_multdsdata, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov") - # We could simply use domain (igorville) but this will be more readable in tests - # that inherit this setUp - self.domain_dnssec_none, _ = Domain.objects.get_or_create(name="dnssec-none.gov") - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dsdata) - DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_multdsdata) - DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dnssec_none) - DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_with_ip) - DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_just_nameserver) - DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_on_hold) - DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_deleted) - - self.role, _ = UserDomainRole.objects.get_or_create( - user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER - ) - - UserDomainRole.objects.get_or_create( - user=self.user, domain=self.domain_dsdata, role=UserDomainRole.Roles.MANAGER - ) - UserDomainRole.objects.get_or_create( - user=self.user, - domain=self.domain_multdsdata, - role=UserDomainRole.Roles.MANAGER, - ) - UserDomainRole.objects.get_or_create( - user=self.user, - domain=self.domain_dnssec_none, - role=UserDomainRole.Roles.MANAGER, - ) - UserDomainRole.objects.get_or_create( - user=self.user, - domain=self.domain_with_ip, - role=UserDomainRole.Roles.MANAGER, - ) - UserDomainRole.objects.get_or_create( - user=self.user, - domain=self.domain_just_nameserver, - role=UserDomainRole.Roles.MANAGER, - ) - UserDomainRole.objects.get_or_create( - user=self.user, domain=self.domain_on_hold, role=UserDomainRole.Roles.MANAGER - ) - UserDomainRole.objects.get_or_create( - user=self.user, domain=self.domain_deleted, role=UserDomainRole.Roles.MANAGER - ) - - def tearDown(self): - try: - UserDomainRole.objects.all().delete() - if hasattr(self.domain, "contacts"): - self.domain.contacts.all().delete() - DomainApplication.objects.all().delete() - DomainInformation.objects.all().delete() - PublicContact.objects.all().delete() - HostIP.objects.all().delete() - Host.objects.all().delete() - Domain.objects.all().delete() - UserDomainRole.objects.all().delete() - except ValueError: # pass if already deleted - pass - super().tearDown() - - -class TestDomainPermissions(TestWithDomainPermissions): - def test_not_logged_in(self): - """Not logged in gets a redirect to Login.""" - for view_name in [ - "domain", - "domain-users", - "domain-users-add", - "domain-dns-nameservers", - "domain-org-name-address", - "domain-authorizing-official", - "domain-your-contact-information", - "domain-security-email", - ]: - with self.subTest(view_name=view_name): - response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id})) - self.assertEqual(response.status_code, 302) - - def test_no_domain_role(self): - """Logged in but no role gets 403 Forbidden.""" - self.client.force_login(self.user) - self.role.delete() # user no longer has a role on this domain - - for view_name in [ - "domain", - "domain-users", - "domain-users-add", - "domain-dns-nameservers", - "domain-org-name-address", - "domain-authorizing-official", - "domain-your-contact-information", - "domain-security-email", - ]: - with self.subTest(view_name=view_name): - with less_console_noise(): - response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id})) - self.assertEqual(response.status_code, 403) - - def test_domain_pages_blocked_for_on_hold_and_deleted(self): - """Test that the domain pages are blocked for on hold and deleted domains""" - - self.client.force_login(self.user) - for view_name in [ - "domain-users", - "domain-users-add", - "domain-dns", - "domain-dns-nameservers", - "domain-dns-dnssec", - "domain-dns-dnssec-dsdata", - "domain-org-name-address", - "domain-authorizing-official", - "domain-your-contact-information", - "domain-security-email", - ]: - for domain in [ - self.domain_on_hold, - self.domain_deleted, - ]: - with self.subTest(view_name=view_name, domain=domain): - with less_console_noise(): - response = self.client.get(reverse(view_name, kwargs={"pk": domain.id})) - self.assertEqual(response.status_code, 403) - - -class TestDomainOverview(TestWithDomainPermissions, WebTest): - def setUp(self): - super().setUp() - self.app.set_user(self.user.username) - self.client.force_login(self.user) - - -class TestDomainDetail(TestDomainOverview): - @skip("Assertion broke for no reason, why? Need to fix") - def test_domain_detail_link_works(self): - home_page = self.app.get("/") - logger.info(f"This is the value of home_page: {home_page}") - self.assertContains(home_page, "igorville.gov") - # click the "Edit" link - detail_page = home_page.click("Manage", index=0) - self.assertContains(detail_page, "igorville.gov") - self.assertContains(detail_page, "Status") - - def test_unknown_domain_does_not_show_as_expired_on_homepage(self): - """An UNKNOWN domain does not show as expired on the homepage. - It shows as 'DNS needed'""" - # At the time of this test's writing, there are 6 UNKNOWN domains inherited - # from constructors. Let's reset. - Domain.objects.all().delete() - UserDomainRole.objects.all().delete() - self.domain, _ = Domain.objects.get_or_create(name="igorville.gov") - home_page = self.app.get("/") - self.assertNotContains(home_page, "igorville.gov") - self.role, _ = UserDomainRole.objects.get_or_create( - user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER - ) - home_page = self.app.get("/") - self.assertContains(home_page, "igorville.gov") - igorville = Domain.objects.get(name="igorville.gov") - self.assertEquals(igorville.state, Domain.State.UNKNOWN) - self.assertNotContains(home_page, "Expired") - self.assertContains(home_page, "DNS needed") - - def test_unknown_domain_does_not_show_as_expired_on_detail_page(self): - """An UNKNOWN domain does not show as expired on the detail page. - It shows as 'DNS needed'""" - # At the time of this test's writing, there are 6 UNKNOWN domains inherited - # from constructors. Let's reset. - Domain.objects.all().delete() - UserDomainRole.objects.all().delete() - - self.domain, _ = Domain.objects.get_or_create(name="igorville.gov") - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - self.role, _ = UserDomainRole.objects.get_or_create( - user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER - ) - - home_page = self.app.get("/") - self.assertContains(home_page, "igorville.gov") - igorville = Domain.objects.get(name="igorville.gov") - self.assertEquals(igorville.state, Domain.State.UNKNOWN) - detail_page = home_page.click("Manage", index=0) - self.assertNotContains(detail_page, "Expired") - - self.assertContains(detail_page, "DNS needed") - - def test_domain_detail_blocked_for_ineligible_user(self): - """We could easily duplicate this test for all domain management - views, but a single url test should be solid enough since all domain - management pages share the same permissions class""" - self.user.status = User.RESTRICTED - self.user.save() - home_page = self.app.get("/") - self.assertContains(home_page, "igorville.gov") - with less_console_noise(): - response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id})) - self.assertEqual(response.status_code, 403) - - def test_domain_detail_allowed_for_on_hold(self): - """Test that the domain overview page displays for on hold domain""" - home_page = self.app.get("/") - self.assertContains(home_page, "on-hold.gov") - - # View domain overview page - detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_on_hold.id})) - self.assertNotContains(detail_page, "Edit") - - def test_domain_detail_see_just_nameserver(self): - home_page = self.app.get("/") - self.assertContains(home_page, "justnameserver.com") - - # View nameserver on Domain Overview page - detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_just_nameserver.id})) - - self.assertContains(detail_page, "justnameserver.com") - self.assertContains(detail_page, "ns1.justnameserver.com") - self.assertContains(detail_page, "ns2.justnameserver.com") - - def test_domain_detail_see_nameserver_and_ip(self): - home_page = self.app.get("/") - self.assertContains(home_page, "nameserverwithip.gov") - - # View nameserver on Domain Overview page - detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_with_ip.id})) - - self.assertContains(detail_page, "nameserverwithip.gov") - - self.assertContains(detail_page, "ns1.nameserverwithip.gov") - self.assertContains(detail_page, "ns2.nameserverwithip.gov") - self.assertContains(detail_page, "ns3.nameserverwithip.gov") - # Splitting IP addresses bc there is odd whitespace and can't strip text - self.assertContains(detail_page, "(1.2.3.4,") - self.assertContains(detail_page, "2.3.4.5)") - - def test_domain_detail_with_no_information_or_application(self): - """Test that domain management page returns 200 and displays error - when no domain information or domain application exist""" - # have to use staff user for this test - staff_user = create_user() - # staff_user.save() - self.client.force_login(staff_user) - - # need to set the analyst_action and analyst_action_location - # in the session to emulate user clicking Manage Domain - # in the admin interface - session = self.client.session - session["analyst_action"] = "foo" - session["analyst_action_location"] = self.domain_no_information.id - session.save() - - detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_no_information.id})) - - self.assertContains(detail_page, "noinformation.gov") - self.assertContains(detail_page, "Domain missing domain information") - - -class TestDomainManagers(TestDomainOverview): - def tearDown(self): - """Ensure that the user has its original permissions""" - super().tearDown() - self.user.is_staff = False - self.user.save() - User.objects.all().delete() - - def test_domain_managers(self): - response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id})) - self.assertContains(response, "Domain managers") - - def test_domain_managers_add_link(self): - """Button to get to user add page works.""" - management_page = self.app.get(reverse("domain-users", kwargs={"pk": self.domain.id})) - add_page = management_page.click("Add a domain manager") - self.assertContains(add_page, "Add a domain manager") - - def test_domain_user_add(self): - response = self.client.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - self.assertContains(response, "Add a domain manager") - - def test_domain_user_delete(self): - """Tests if deleting a domain manager works""" - - # Add additional users - dummy_user_1 = User.objects.create( - username="macncheese", - email="cheese@igorville.com", - ) - dummy_user_2 = User.objects.create( - username="pastapizza", - email="pasta@igorville.com", - ) - - role_1 = UserDomainRole.objects.create(user=dummy_user_1, domain=self.domain, role=UserDomainRole.Roles.MANAGER) - role_2 = UserDomainRole.objects.create(user=dummy_user_2, domain=self.domain, role=UserDomainRole.Roles.MANAGER) - - response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id})) - - # Make sure we're on the right page - self.assertContains(response, "Domain managers") - - # Make sure the desired user exists - self.assertContains(response, "cheese@igorville.com") - - # Delete dummy_user_1 - response = self.client.post( - reverse("domain-user-delete", kwargs={"pk": self.domain.id, "user_pk": dummy_user_1.id}), follow=True - ) - - # Grab the displayed messages - messages = list(response.context["messages"]) - self.assertEqual(len(messages), 1) - - # Ensure the error we recieve is in line with what we expect - message = messages[0] - self.assertEqual(message.message, "Removed cheese@igorville.com as a manager for this domain.") - self.assertEqual(message.tags, "success") - - # Check that role_1 deleted in the DB after the post - deleted_user_exists = UserDomainRole.objects.filter(id=role_1.id).exists() - self.assertFalse(deleted_user_exists) - - # Ensure that the current user wasn't deleted - current_user_exists = UserDomainRole.objects.filter(user=self.user.id, domain=self.domain).exists() - self.assertTrue(current_user_exists) - - # Ensure that the other userdomainrole was not deleted - role_2_exists = UserDomainRole.objects.filter(id=role_2.id).exists() - self.assertTrue(role_2_exists) - - def test_domain_user_delete_denied_if_no_permission(self): - """Deleting a domain manager is denied if the user has no permission to do so""" - - # Create a domain object - vip_domain = Domain.objects.create(name="freeman.gov") - - # Add users - dummy_user_1 = User.objects.create( - username="bagel", - email="bagel@igorville.com", - ) - dummy_user_2 = User.objects.create( - username="pastapizza", - email="pasta@igorville.com", - ) - - role_1 = UserDomainRole.objects.create(user=dummy_user_1, domain=vip_domain, role=UserDomainRole.Roles.MANAGER) - role_2 = UserDomainRole.objects.create(user=dummy_user_2, domain=vip_domain, role=UserDomainRole.Roles.MANAGER) - - response = self.client.get(reverse("domain-users", kwargs={"pk": vip_domain.id})) - - # Make sure that we can't access the domain manager page normally - self.assertEqual(response.status_code, 403) - - # Try to delete dummy_user_1 - response = self.client.post( - reverse("domain-user-delete", kwargs={"pk": vip_domain.id, "user_pk": dummy_user_1.id}), follow=True - ) - - # Ensure that we are denied access - self.assertEqual(response.status_code, 403) - - # Ensure that the user wasn't deleted - role_1_exists = UserDomainRole.objects.filter(id=role_1.id).exists() - self.assertTrue(role_1_exists) - - # Ensure that the other userdomainrole was not deleted - role_2_exists = UserDomainRole.objects.filter(id=role_2.id).exists() - self.assertTrue(role_2_exists) - - # Make sure that the current user wasn't deleted for some reason - current_user_exists = UserDomainRole.objects.filter(user=dummy_user_1.id, domain=vip_domain.id).exists() - self.assertTrue(current_user_exists) - - def test_domain_user_delete_denied_if_last_man_standing(self): - """Deleting a domain manager is denied if the user is the only manager""" - - # Create a domain object - vip_domain = Domain.objects.create(name="olive-oil.gov") - - # Add the requesting user as the only manager on the domain - UserDomainRole.objects.create(user=self.user, domain=vip_domain, role=UserDomainRole.Roles.MANAGER) - - response = self.client.get(reverse("domain-users", kwargs={"pk": vip_domain.id})) - - # Make sure that we can still access the domain manager page normally - self.assertContains(response, "Domain managers") - - # Make sure that the logged in user exists - self.assertContains(response, "info@example.com") - - # Try to delete the current user - response = self.client.post( - reverse("domain-user-delete", kwargs={"pk": vip_domain.id, "user_pk": self.user.id}), follow=True - ) - - # Ensure that we are denied access - self.assertEqual(response.status_code, 403) - - # Make sure that the current user wasn't deleted - current_user_exists = UserDomainRole.objects.filter(user=self.user.id, domain=vip_domain.id).exists() - self.assertTrue(current_user_exists) - - def test_domain_user_delete_self_redirects_home(self): - """Tests if deleting yourself redirects to home""" - # Add additional users - dummy_user_1 = User.objects.create( - username="macncheese", - email="cheese@igorville.com", - ) - dummy_user_2 = User.objects.create( - username="pastapizza", - email="pasta@igorville.com", - ) - - role_1 = UserDomainRole.objects.create(user=dummy_user_1, domain=self.domain, role=UserDomainRole.Roles.MANAGER) - role_2 = UserDomainRole.objects.create(user=dummy_user_2, domain=self.domain, role=UserDomainRole.Roles.MANAGER) - - response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id})) - - # Make sure we're on the right page - self.assertContains(response, "Domain managers") - - # Make sure the desired user exists - self.assertContains(response, "info@example.com") - - # Make sure more than one UserDomainRole exists on this object - self.assertContains(response, "cheese@igorville.com") - - # Delete the current user - response = self.client.post( - reverse("domain-user-delete", kwargs={"pk": self.domain.id, "user_pk": self.user.id}), follow=True - ) - - # Check if we've been redirected to the home page - self.assertContains(response, "Manage your domains") - - # Grab the displayed messages - messages = list(response.context["messages"]) - self.assertEqual(len(messages), 1) - - # Ensure the error we recieve is in line with what we expect - message = messages[0] - self.assertEqual(message.message, "You are no longer managing the domain igorville.gov.") - self.assertEqual(message.tags, "success") - - # Ensure that the current user was deleted - current_user_exists = UserDomainRole.objects.filter(user=self.user.id, domain=self.domain).exists() - self.assertFalse(current_user_exists) - - # Ensure that the other userdomainroles are not deleted - role_1_exists = UserDomainRole.objects.filter(id=role_1.id).exists() - self.assertTrue(role_1_exists) - - role_2_exists = UserDomainRole.objects.filter(id=role_2.id).exists() - self.assertTrue(role_2_exists) - - @boto3_mocking.patching - def test_domain_user_add_form(self): - """Adding an existing user works.""" - other_user, _ = get_user_model().objects.get_or_create(email="mayor@igorville.gov") - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - add_page.form["email"] = "mayor@igorville.gov" - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - mock_client = MockSESClient() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - success_result = add_page.form.submit() - - self.assertEqual(success_result.status_code, 302) - self.assertEqual( - success_result["Location"], - reverse("domain-users", kwargs={"pk": self.domain.id}), - ) - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - success_page = success_result.follow() - self.assertContains(success_page, "mayor@igorville.gov") - - @boto3_mocking.patching - def test_domain_invitation_created(self): - """Add user on a nonexistent email creates an invitation. - - Adding a non-existent user sends an email as a side-effect, so mock - out the boto3 SES email sending here. - """ - # make sure there is no user with this email - email_address = "mayor@igorville.gov" - User.objects.filter(email=email_address).delete() - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - mock_client = MockSESClient() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - success_result = add_page.form.submit() - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - success_page = success_result.follow() - - self.assertContains(success_page, email_address) - self.assertContains(success_page, "Cancel") # link to cancel invitation - self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists()) - - @boto3_mocking.patching - def test_domain_invitation_created_for_caps_email(self): - """Add user on a nonexistent email with CAPS creates an invitation to lowercase email. - - Adding a non-existent user sends an email as a side-effect, so mock - out the boto3 SES email sending here. - """ - # make sure there is no user with this email - email_address = "mayor@igorville.gov" - caps_email_address = "MAYOR@igorville.gov" - User.objects.filter(email=email_address).delete() - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = caps_email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - mock_client = MockSESClient() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - success_result = add_page.form.submit() - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - success_page = success_result.follow() - - self.assertContains(success_page, email_address) - self.assertContains(success_page, "Cancel") # link to cancel invitation - self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists()) - - @boto3_mocking.patching - def test_domain_invitation_email_sent(self): - """Inviting a non-existent user sends them an email.""" - # make sure there is no user with this email - email_address = "mayor@igorville.gov" - User.objects.filter(email=email_address).delete() - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - mock_client = MagicMock() - mock_client_instance = mock_client.return_value - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - add_page.form.submit() - - # check the mock instance to see if `send_email` was called right - mock_client_instance.send_email.assert_called_once_with( - FromEmailAddress=settings.DEFAULT_FROM_EMAIL, - Destination={"ToAddresses": [email_address]}, - Content=ANY, - ) - - @boto3_mocking.patching - def test_domain_invitation_email_has_email_as_requestor_non_existent(self): - """Inviting a non existent user sends them an email, with email as the name.""" - # make sure there is no user with this email - email_address = "mayor@igorville.gov" - User.objects.filter(email=email_address).delete() - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - mock_client = MagicMock() - mock_client_instance = mock_client.return_value - - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - add_page.form.submit() - - # check the mock instance to see if `send_email` was called right - mock_client_instance.send_email.assert_called_once_with( - FromEmailAddress=settings.DEFAULT_FROM_EMAIL, - Destination={"ToAddresses": [email_address]}, - Content=ANY, - ) - - # Check the arguments passed to send_email method - _, kwargs = mock_client_instance.send_email.call_args - - # Extract the email content, and check that the message is as we expect - email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] - self.assertIn("info@example.com", email_content) - - # Check that the requestors first/last name do not exist - self.assertNotIn("First", email_content) - self.assertNotIn("Last", email_content) - self.assertNotIn("First Last", email_content) - - @boto3_mocking.patching - def test_domain_invitation_email_has_email_as_requestor(self): - """Inviting a user sends them an email, with email as the name.""" - # Create a fake user object - email_address = "mayor@igorville.gov" - User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com") - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - mock_client = MagicMock() - mock_client_instance = mock_client.return_value - - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - add_page.form.submit() - - # check the mock instance to see if `send_email` was called right - mock_client_instance.send_email.assert_called_once_with( - FromEmailAddress=settings.DEFAULT_FROM_EMAIL, - Destination={"ToAddresses": [email_address]}, - Content=ANY, - ) - - # Check the arguments passed to send_email method - _, kwargs = mock_client_instance.send_email.call_args - - # Extract the email content, and check that the message is as we expect - email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] - self.assertIn("info@example.com", email_content) - - # Check that the requestors first/last name do not exist - self.assertNotIn("First", email_content) - self.assertNotIn("Last", email_content) - self.assertNotIn("First Last", email_content) - - @boto3_mocking.patching - def test_domain_invitation_email_has_email_as_requestor_staff(self): - """Inviting a user sends them an email, with email as the name.""" - # Create a fake user object - email_address = "mayor@igorville.gov" - User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com") - - # Make sure the user is staff - self.user.is_staff = True - self.user.save() - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - mock_client = MagicMock() - mock_client_instance = mock_client.return_value - - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - add_page.form.submit() - - # check the mock instance to see if `send_email` was called right - mock_client_instance.send_email.assert_called_once_with( - FromEmailAddress=settings.DEFAULT_FROM_EMAIL, - Destination={"ToAddresses": [email_address]}, - Content=ANY, - ) - - # Check the arguments passed to send_email method - _, kwargs = mock_client_instance.send_email.call_args - - # Extract the email content, and check that the message is as we expect - email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] - self.assertIn("help@get.gov", email_content) - - # Check that the requestors first/last name do not exist - self.assertNotIn("First", email_content) - self.assertNotIn("Last", email_content) - self.assertNotIn("First Last", email_content) - - @boto3_mocking.patching - def test_domain_invitation_email_displays_error_non_existent(self): - """Inviting a non existent user sends them an email, with email as the name.""" - # make sure there is no user with this email - email_address = "mayor@igorville.gov" - User.objects.filter(email=email_address).delete() - - # Give the user who is sending the email an invalid email address - self.user.email = "" - self.user.save() - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - mock_client = MagicMock() - mock_error_message = MagicMock() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with patch("django.contrib.messages.error") as mock_error_message: - with less_console_noise(): - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - add_page.form.submit().follow() - - expected_message_content = "Can't send invitation email. No email is associated with your account." - - # Grab the message content - returned_error_message = mock_error_message.call_args[0][1] - - # Check that the message content is what we expect - self.assertEqual(expected_message_content, returned_error_message) - - @boto3_mocking.patching - def test_domain_invitation_email_displays_error(self): - """When the requesting user has no email, an error is displayed""" - # make sure there is no user with this email - # Create a fake user object - email_address = "mayor@igorville.gov" - User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com") - - # Give the user who is sending the email an invalid email address - self.user.email = "" - self.user.save() - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - mock_client = MagicMock() - - mock_error_message = MagicMock() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with patch("django.contrib.messages.error") as mock_error_message: - with less_console_noise(): - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - add_page.form.submit().follow() - - expected_message_content = "Can't send invitation email. No email is associated with your account." - - # Grab the message content - returned_error_message = mock_error_message.call_args[0][1] - - # Check that the message content is what we expect - self.assertEqual(expected_message_content, returned_error_message) - - def test_domain_invitation_cancel(self): - """Posting to the delete view deletes an invitation.""" - email_address = "mayor@igorville.gov" - invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address) - mock_client = MockSESClient() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id})) - mock_client.EMAILS_SENT.clear() - with self.assertRaises(DomainInvitation.DoesNotExist): - DomainInvitation.objects.get(id=invitation.id) - - def test_domain_invitation_cancel_no_permissions(self): - """Posting to the delete view as a different user should fail.""" - email_address = "mayor@igorville.gov" - invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address) - - other_user = User() - other_user.save() - self.client.force_login(other_user) - mock_client = MagicMock() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): # permission denied makes console errors - result = self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id})) - - self.assertEqual(result.status_code, 403) - - @boto3_mocking.patching - def test_domain_invitation_flow(self): - """Send an invitation to a new user, log in and load the dashboard.""" - email_address = "mayor@igorville.gov" - User.objects.filter(email=email_address).delete() - - add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) - - self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) - - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - add_page.form["email"] = email_address - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - - mock_client = MagicMock() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - add_page.form.submit() - - # user was invited, create them - new_user = User.objects.create(username=email_address, email=email_address) - # log them in to `self.app` - self.app.set_user(new_user.username) - # and manually call the on each login callback - new_user.on_each_login() - - # Now load the home page and make sure our domain appears there - home_page = self.app.get(reverse("home")) - self.assertContains(home_page, self.domain.name) - - -class TestDomainNameservers(TestDomainOverview): - def test_domain_nameservers(self): - """Can load domain's nameservers page.""" - page = self.client.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - self.assertContains(page, "DNS name servers") - - def test_domain_nameservers_form_submit_one_nameserver(self): - """Nameserver form submitted with one nameserver throws error. - - Uses self.app WebTest because we need to interact with forms. - """ - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form with only one nameserver, should error - # regarding required fields - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the required field. form requires a minimum of 2 name servers - self.assertContains( - result, - "At least two name servers are required.", - count=2, - status_code=200, - ) - - def test_domain_nameservers_form_submit_subdomain_missing_ip(self): - """Nameserver form catches missing ip error on subdomain. - - Uses self.app WebTest because we need to interact with forms. - """ - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form without two hosts, both subdomains, - # only one has ips - nameservers_page.form["form-1-server"] = "ns2.igorville.gov" - - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the required field. subdomain missing an ip - self.assertContains( - result, - str(NameserverError(code=NameserverErrorCodes.MISSING_IP)), - count=2, - status_code=200, - ) - - def test_domain_nameservers_form_submit_missing_host(self): - """Nameserver form catches error when host is missing. - - Uses self.app WebTest because we need to interact with forms. - """ - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form without two hosts, both subdomains, - # only one has ips - nameservers_page.form["form-1-ip"] = "127.0.0.1" - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the required field. nameserver has ip but missing host - self.assertContains( - result, - str(NameserverError(code=NameserverErrorCodes.MISSING_HOST)), - count=2, - status_code=200, - ) - - def test_domain_nameservers_form_submit_duplicate_host(self): - """Nameserver form catches error when host is duplicated. - - Uses self.app WebTest because we need to interact with forms. - """ - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form with duplicate host names of fake.host.com - nameservers_page.form["form-0-ip"] = "" - nameservers_page.form["form-1-server"] = "fake.host.com" - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the required field. remove duplicate entry - self.assertContains( - result, - str(NameserverError(code=NameserverErrorCodes.DUPLICATE_HOST)), - count=2, - status_code=200, - ) - - def test_domain_nameservers_form_submit_whitespace(self): - """Nameserver form removes whitespace from ip. - - Uses self.app WebTest because we need to interact with forms. - """ - nameserver1 = "ns1.igorville.gov" - nameserver2 = "ns2.igorville.gov" - valid_ip = "1.1. 1.1" - # initial nameservers page has one server with two ips - # have to throw an error in order to test that the whitespace has been stripped from ip - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form without one host and an ip with whitespace - nameservers_page.form["form-0-server"] = nameserver1 - nameservers_page.form["form-1-ip"] = valid_ip - nameservers_page.form["form-1-server"] = nameserver2 - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an ip address which has been stripped of whitespace, - # response should be a 302 to success page - self.assertEqual(result.status_code, 302) - self.assertEqual( - result["Location"], - reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}), - ) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - page = result.follow() - # in the event of a generic nameserver error from registry error, there will be a 302 - # with an error message displayed, so need to follow 302 and test for success message - self.assertContains(page, "The name servers for this domain have been updated") - - def test_domain_nameservers_form_submit_glue_record_not_allowed(self): - """Nameserver form catches error when IP is present - but host not subdomain. - - Uses self.app WebTest because we need to interact with forms. - """ - nameserver1 = "ns1.igorville.gov" - nameserver2 = "ns2.igorville.com" - valid_ip = "127.0.0.1" - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form without two hosts, both subdomains, - # only one has ips - nameservers_page.form["form-0-server"] = nameserver1 - nameservers_page.form["form-1-server"] = nameserver2 - nameservers_page.form["form-1-ip"] = valid_ip - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the required field. nameserver has ip but missing host - self.assertContains( - result, - str(NameserverError(code=NameserverErrorCodes.GLUE_RECORD_NOT_ALLOWED)), - count=2, - status_code=200, - ) - - def test_domain_nameservers_form_submit_invalid_ip(self): - """Nameserver form catches invalid IP on submission. - - Uses self.app WebTest because we need to interact with forms. - """ - nameserver = "ns2.igorville.gov" - invalid_ip = "123" - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form without two hosts, both subdomains, - # only one has ips - nameservers_page.form["form-1-server"] = nameserver - nameservers_page.form["form-1-ip"] = invalid_ip - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the required field. nameserver has ip but missing host - self.assertContains( - result, - str(NameserverError(code=NameserverErrorCodes.INVALID_IP, nameserver=nameserver)), - count=2, - status_code=200, - ) - - def test_domain_nameservers_form_submit_invalid_host(self): - """Nameserver form catches invalid host on submission. - - Uses self.app WebTest because we need to interact with forms. - """ - nameserver = "invalid-nameserver.gov" - valid_ip = "123.2.45.111" - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form without two hosts, both subdomains, - # only one has ips - nameservers_page.form["form-1-server"] = nameserver - nameservers_page.form["form-1-ip"] = valid_ip - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the required field. nameserver has invalid host - self.assertContains( - result, - str(NameserverError(code=NameserverErrorCodes.INVALID_HOST, nameserver=nameserver)), - count=2, - status_code=200, - ) - - def test_domain_nameservers_form_submits_successfully(self): - """Nameserver form submits successfully with valid input. - - Uses self.app WebTest because we need to interact with forms. - """ - nameserver1 = "ns1.igorville.gov" - nameserver2 = "ns2.igorville.gov" - valid_ip = "127.0.0.1" - # initial nameservers page has one server with two ips - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # attempt to submit the form without two hosts, both subdomains, - # only one has ips - nameservers_page.form["form-0-server"] = nameserver1 - nameservers_page.form["form-1-server"] = nameserver2 - nameservers_page.form["form-1-ip"] = valid_ip - with less_console_noise(): # swallow log warning message - result = nameservers_page.form.submit() - # form submission was a successful post, response should be a 302 - self.assertEqual(result.status_code, 302) - self.assertEqual( - result["Location"], - reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}), - ) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - page = result.follow() - self.assertContains(page, "The name servers for this domain have been updated") - - def test_domain_nameservers_form_invalid(self): - """Nameserver form does not submit with invalid data. - - Uses self.app WebTest because we need to interact with forms. - """ - nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # first two nameservers are required, so if we empty one out we should - # get a form error - nameservers_page.form["form-0-server"] = "" - with less_console_noise(): # swallow logged warning message - result = nameservers_page.form.submit() - # form submission was a post with an error, response should be a 200 - # error text appears four times, twice at the top of the page, - # once around each required field. - self.assertContains( - result, - "At least two name servers are required.", - count=4, - status_code=200, - ) - - -class TestDomainAuthorizingOfficial(TestDomainOverview): - def test_domain_authorizing_official(self): - """Can load domain's authorizing official page.""" - page = self.client.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) - # once on the sidebar, once in the title - self.assertContains(page, "Authorizing official", count=2) - - def test_domain_authorizing_official_content(self): - """Authorizing official information appears on the page.""" - self.domain_information.authorizing_official = Contact(first_name="Testy") - self.domain_information.authorizing_official.save() - self.domain_information.save() - page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) - self.assertContains(page, "Testy") - - def test_domain_edit_authorizing_official_in_place(self): - """When editing an authorizing official for domain information and AO is not - joined to any other objects""" - self.domain_information.authorizing_official = Contact( - first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov" - ) - self.domain_information.authorizing_official.save() - self.domain_information.save() - ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_form = ao_page.forms[0] - self.assertEqual(ao_form["first_name"].value, "Testy") - ao_form["first_name"] = "Testy2" - # ao_pk is the initial pk of the authorizing official. set it before update - # to be able to verify after update that the same contact object is in place - ao_pk = self.domain_information.authorizing_official.id - ao_form.submit() - - # refresh domain information - self.domain_information.refresh_from_db() - self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name) - self.assertEqual(ao_pk, self.domain_information.authorizing_official.id) - - def test_domain_edit_authorizing_official_creates_new(self): - """When editing an authorizing official for domain information and AO IS - joined to another object""" - # set AO and Other Contact to the same Contact object - self.domain_information.authorizing_official = Contact( - first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov" - ) - self.domain_information.authorizing_official.save() - self.domain_information.save() - self.domain_information.other_contacts.add(self.domain_information.authorizing_official) - self.domain_information.save() - # load the Authorizing Official in the web form - ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_form = ao_page.forms[0] - # verify the first name is "Testy" and then change it to "Testy2" - self.assertEqual(ao_form["first_name"].value, "Testy") - ao_form["first_name"] = "Testy2" - # ao_pk is the initial pk of the authorizing official. set it before update - # to be able to verify after update that the same contact object is in place - ao_pk = self.domain_information.authorizing_official.id - ao_form.submit() - - # refresh domain information - self.domain_information.refresh_from_db() - # assert that AO information is updated, and that the AO is a new Contact - self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name) - self.assertNotEqual(ao_pk, self.domain_information.authorizing_official.id) - # assert that the Other Contact information is not updated and that the Other Contact - # is the original Contact object - other_contact = self.domain_information.other_contacts.all()[0] - self.assertEqual("Testy", other_contact.first_name) - self.assertEqual(ao_pk, other_contact.id) - - -class TestDomainOrganization(TestDomainOverview): - def test_domain_org_name_address(self): - """Can load domain's org name and mailing address page.""" - page = self.client.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id})) - # once on the sidebar, once in the page title, once as H1 - self.assertContains(page, "Organization name and mailing address", count=3) - - def test_domain_org_name_address_content(self): - """Org name and address information appears on the page.""" - self.domain_information.organization_name = "Town of Igorville" - self.domain_information.save() - page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id})) - self.assertContains(page, "Town of Igorville") - - def test_domain_org_name_address_form(self): - """Submitting changes works on the org name address page.""" - self.domain_information.organization_name = "Town of Igorville" - self.domain_information.save() - org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - - org_name_page.form["organization_name"] = "Not igorville" - org_name_page.form["city"] = "Faketown" - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - success_result_page = org_name_page.form.submit() - self.assertEqual(success_result_page.status_code, 200) - - self.assertContains(success_result_page, "Not igorville") - self.assertContains(success_result_page, "Faketown") - - -class TestDomainContactInformation(TestDomainOverview): - def test_domain_your_contact_information(self): - """Can load domain's your contact information page.""" - page = self.client.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id})) - self.assertContains(page, "Your contact information") - - def test_domain_your_contact_information_content(self): - """Logged-in user's contact information appears on the page.""" - self.user.contact.first_name = "Testy" - self.user.contact.save() - page = self.app.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id})) - self.assertContains(page, "Testy") - - -class TestDomainSecurityEmail(TestDomainOverview): - def test_domain_security_email_existing_security_contact(self): - """Can load domain's security email page.""" - self.mockSendPatch = patch("registrar.models.domain.registry.send") - self.mockedSendFunction = self.mockSendPatch.start() - self.mockedSendFunction.side_effect = self.mockSend - - domain_contact, _ = Domain.objects.get_or_create(name="freeman.gov") - # Add current user to this domain - _ = UserDomainRole(user=self.user, domain=domain_contact, role="admin").save() - page = self.client.get(reverse("domain-security-email", kwargs={"pk": domain_contact.id})) - - # Loads correctly - self.assertContains(page, "Security email") - self.assertContains(page, "security@mail.gov") - self.mockSendPatch.stop() - - def test_domain_security_email_no_security_contact(self): - """Loads a domain with no defined security email. - We should not show the default.""" - self.mockSendPatch = patch("registrar.models.domain.registry.send") - self.mockedSendFunction = self.mockSendPatch.start() - self.mockedSendFunction.side_effect = self.mockSend - - page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id})) - - # Loads correctly - self.assertContains(page, "Security email") - self.assertNotContains(page, "dotgov@cisa.dhs.gov") - self.mockSendPatch.stop() - - def test_domain_security_email(self): - """Can load domain's security email page.""" - page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id})) - self.assertContains(page, "Security email") - - def test_domain_security_email_form(self): - """Adding a security email works. - Uses self.app WebTest because we need to interact with forms. - """ - security_email_page = self.app.get(reverse("domain-security-email", kwargs={"pk": self.domain.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - security_email_page.form["security_email"] = "mayor@igorville.gov" - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - mock_client = MagicMock() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): # swallow log warning message - result = security_email_page.form.submit() - self.assertEqual(result.status_code, 302) - self.assertEqual( - result["Location"], - reverse("domain-security-email", kwargs={"pk": self.domain.id}), - ) - - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - success_page = result.follow() - self.assertContains(success_page, "The security email for this domain has been updated") - - def test_security_email_form_messages(self): - """ - Test against the success and error messages that are defined in the view - """ - p = "adminpass" - self.client.login(username="superuser", password=p) - - form_data_registry_error = { - "security_email": "test@failCreate.gov", - } - - form_data_contact_error = { - "security_email": "test@contactError.gov", - } - - form_data_success = { - "security_email": "test@something.gov", - } - - test_cases = [ - ( - "RegistryError", - form_data_registry_error, - str(GenericError(code=GenericErrorCodes.CANNOT_CONTACT_REGISTRY)), - ), - ( - "ContactError", - form_data_contact_error, - str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)), - ), - ( - "RegistrySuccess", - form_data_success, - "The security email for this domain has been updated.", - ), - # Add more test cases with different scenarios here - ] - - for test_name, data, expected_message in test_cases: - response = self.client.post( - reverse("domain-security-email", kwargs={"pk": self.domain.id}), - data=data, - follow=True, - ) - - # Check the response status code, content, or any other relevant assertions - self.assertEqual(response.status_code, 200) - - # Check if the expected message tag is set - if test_name == "RegistryError" or test_name == "ContactError": - message_tag = "error" - elif test_name == "RegistrySuccess": - message_tag = "success" - else: - # Handle other cases if needed - message_tag = "info" # Change to the appropriate default - - # Check the message tag - messages = list(response.context["messages"]) - self.assertEqual(len(messages), 1) - message = messages[0] - self.assertEqual(message.tags, message_tag) - self.assertEqual(message.message.strip(), expected_message.strip()) - - def test_domain_overview_blocked_for_ineligible_user(self): - """We could easily duplicate this test for all domain management - views, but a single url test should be solid enough since all domain - management pages share the same permissions class""" - self.user.status = User.RESTRICTED - self.user.save() - home_page = self.app.get("/") - self.assertContains(home_page, "igorville.gov") - with less_console_noise(): - response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id})) - self.assertEqual(response.status_code, 403) - - -class TestDomainDNSSEC(TestDomainOverview): - - """MockEPPLib is already inherited.""" - - def test_dnssec_page_refreshes_enable_button(self): - """DNSSEC overview page loads when domain has no DNSSEC data - and shows a 'Enable DNSSEC' button.""" - - page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id})) - self.assertContains(page, "Enable DNSSEC") - - def test_dnssec_page_loads_with_data_in_domain(self): - """DNSSEC overview page loads when domain has DNSSEC data - and the template contains a button to disable DNSSEC.""" - - page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id})) - self.assertContains(page, "Disable DNSSEC") - - # Prepare the data for the POST request - post_data = { - "disable_dnssec": "Disable DNSSEC", - } - updated_page = self.client.post( - reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}), - post_data, - follow=True, - ) - - self.assertEqual(updated_page.status_code, 200) - - self.assertContains(updated_page, "Enable DNSSEC") - - def test_ds_form_loads_with_no_domain_data(self): - """DNSSEC Add DS data page loads when there is no - domain DNSSEC data and shows a button to Add new record""" - - page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id})) - self.assertContains(page, "You have no DS data added") - self.assertContains(page, "Add new record") - - def test_ds_form_loads_with_ds_data(self): - """DNSSEC Add DS data page loads when there is - domain DNSSEC DS data and shows the data""" - - page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - self.assertContains(page, "DS data record 1") - - def test_ds_data_form_modal(self): - """When user clicks on save, a modal pops up.""" - add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - # Assert that a hidden trigger for the modal does not exist. - # This hidden trigger will pop on the page when certain condition are met: - # 1) Initial form contained DS data, 2) All data is deleted and form is - # submitted. - self.assertNotContains(add_data_page, "Trigger Disable DNSSEC Modal") - # Simulate a delete all data - form_data = {} - response = self.client.post( - reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}), - data=form_data, - ) - self.assertEqual(response.status_code, 200) # Adjust status code as needed - # Now check to see whether the JS trigger for the modal is present on the page - self.assertContains(response, "Trigger Disable DNSSEC Modal") - - def test_ds_data_form_submits(self): - """DS data form submits successfully - - Uses self.app WebTest because we need to interact with forms. - """ - add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - with less_console_noise(): # swallow log warning message - result = add_data_page.forms[0].submit() - # form submission was a post, response should be a redirect - self.assertEqual(result.status_code, 302) - self.assertEqual( - result["Location"], - reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}), - ) - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - page = result.follow() - self.assertContains(page, "The DS data records for this domain have been updated.") - - def test_ds_data_form_invalid(self): - """DS data form errors with invalid data (missing required fields) - - Uses self.app WebTest because we need to interact with forms. - """ - add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # all four form fields are required, so will test with each blank - add_data_page.forms[0]["form-0-key_tag"] = "" - add_data_page.forms[0]["form-0-algorithm"] = "" - add_data_page.forms[0]["form-0-digest_type"] = "" - add_data_page.forms[0]["form-0-digest"] = "" - with less_console_noise(): # swallow logged warning message - result = add_data_page.forms[0].submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the field. - self.assertContains(result, "Key tag is required", count=2, status_code=200) - self.assertContains(result, "Algorithm is required", count=2, status_code=200) - self.assertContains(result, "Digest type is required", count=2, status_code=200) - self.assertContains(result, "Digest is required", count=2, status_code=200) - - def test_ds_data_form_invalid_keytag(self): - """DS data form errors with invalid data (key tag too large) - - Uses self.app WebTest because we need to interact with forms. - """ - add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # first two nameservers are required, so if we empty one out we should - # get a form error - add_data_page.forms[0]["form-0-key_tag"] = "65536" # > 65535 - add_data_page.forms[0]["form-0-algorithm"] = "" - add_data_page.forms[0]["form-0-digest_type"] = "" - add_data_page.forms[0]["form-0-digest"] = "" - with less_console_noise(): # swallow logged warning message - result = add_data_page.forms[0].submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the field. - self.assertContains( - result, str(DsDataError(code=DsDataErrorCodes.INVALID_KEYTAG_SIZE)), count=2, status_code=200 - ) - - def test_ds_data_form_invalid_digest_chars(self): - """DS data form errors with invalid data (digest contains non hexadecimal chars) - - Uses self.app WebTest because we need to interact with forms. - """ - add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # first two nameservers are required, so if we empty one out we should - # get a form error - add_data_page.forms[0]["form-0-key_tag"] = "1234" - add_data_page.forms[0]["form-0-algorithm"] = "3" - add_data_page.forms[0]["form-0-digest_type"] = "1" - add_data_page.forms[0]["form-0-digest"] = "GG1234" - with less_console_noise(): # swallow logged warning message - result = add_data_page.forms[0].submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the field. - self.assertContains( - result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_CHARS)), count=2, status_code=200 - ) - - def test_ds_data_form_invalid_digest_sha1(self): - """DS data form errors with invalid data (digest is invalid sha-1) - - Uses self.app WebTest because we need to interact with forms. - """ - add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # first two nameservers are required, so if we empty one out we should - # get a form error - add_data_page.forms[0]["form-0-key_tag"] = "1234" - add_data_page.forms[0]["form-0-algorithm"] = "3" - add_data_page.forms[0]["form-0-digest_type"] = "1" # SHA-1 - add_data_page.forms[0]["form-0-digest"] = "A123" - with less_console_noise(): # swallow logged warning message - result = add_data_page.forms[0].submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the field. - self.assertContains( - result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA1)), count=2, status_code=200 - ) - - def test_ds_data_form_invalid_digest_sha256(self): - """DS data form errors with invalid data (digest is invalid sha-256) - - Uses self.app WebTest because we need to interact with forms. - """ - add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) - session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - # first two nameservers are required, so if we empty one out we should - # get a form error - add_data_page.forms[0]["form-0-key_tag"] = "1234" - add_data_page.forms[0]["form-0-algorithm"] = "3" - add_data_page.forms[0]["form-0-digest_type"] = "2" # SHA-256 - add_data_page.forms[0]["form-0-digest"] = "GG1234" - with less_console_noise(): # swallow logged warning message - result = add_data_page.forms[0].submit() - # form submission was a post with an error, response should be a 200 - # error text appears twice, once at the top of the page, once around - # the field. - self.assertContains( - result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA256)), count=2, status_code=200 - ) - - -class TestApplicationStatus(TestWithUser, WebTest): - def setUp(self): - super().setUp() - self.app.set_user(self.user.username) - self.client.force_login(self.user) - - def test_application_status(self): - """Checking application status page""" - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) - application.save() - - home_page = self.app.get("/") - self.assertContains(home_page, "city.gov") - # click the "Manage" link - detail_page = home_page.click("Manage", index=0) - self.assertContains(detail_page, "city.gov") - self.assertContains(detail_page, "city1.gov") - self.assertContains(detail_page, "Chief Tester") - self.assertContains(detail_page, "testy@town.com") - self.assertContains(detail_page, "Admin Tester") - self.assertContains(detail_page, "Status:") - - def test_application_status_with_ineligible_user(self): - """Checking application status page whith a blocked user. - The user should still have access to view.""" - self.user.status = "ineligible" - self.user.save() - - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) - application.save() - - home_page = self.app.get("/") - self.assertContains(home_page, "city.gov") - # click the "Manage" link - detail_page = home_page.click("Manage", index=0) - self.assertContains(detail_page, "city.gov") - self.assertContains(detail_page, "Chief Tester") - self.assertContains(detail_page, "testy@town.com") - self.assertContains(detail_page, "Admin Tester") - self.assertContains(detail_page, "Status:") - - def test_application_withdraw(self): - """Checking application status page""" - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) - application.save() - - home_page = self.app.get("/") - self.assertContains(home_page, "city.gov") - # click the "Manage" link - detail_page = home_page.click("Manage", index=0) - self.assertContains(detail_page, "city.gov") - self.assertContains(detail_page, "city1.gov") - self.assertContains(detail_page, "Chief Tester") - self.assertContains(detail_page, "testy@town.com") - self.assertContains(detail_page, "Admin Tester") - self.assertContains(detail_page, "Status:") - # click the "Withdraw request" button - mock_client = MockSESClient() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - with less_console_noise(): - withdraw_page = detail_page.click("Withdraw request") - self.assertContains(withdraw_page, "Withdraw request for") - home_page = withdraw_page.click("Withdraw request") - # confirm that it has redirected, and the status has been updated to withdrawn - self.assertRedirects( - home_page, - "/", - status_code=302, - target_status_code=200, - fetch_redirect_response=True, - ) - home_page = self.app.get("/") - self.assertContains(home_page, "Withdrawn") - - def test_application_withdraw_no_permissions(self): - """Can't withdraw applications as a restricted user.""" - self.user.status = User.RESTRICTED - self.user.save() - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) - application.save() - - home_page = self.app.get("/") - self.assertContains(home_page, "city.gov") - # click the "Manage" link - detail_page = home_page.click("Manage", index=0) - self.assertContains(detail_page, "city.gov") - self.assertContains(detail_page, "city1.gov") - self.assertContains(detail_page, "Chief Tester") - self.assertContains(detail_page, "testy@town.com") - self.assertContains(detail_page, "Admin Tester") - self.assertContains(detail_page, "Status:") - # Restricted user trying to withdraw results in 403 error - with less_console_noise(): - for url_name in [ - "application-withdraw-confirmation", - "application-withdrawn", - ]: - with self.subTest(url_name=url_name): - page = self.client.get(reverse(url_name, kwargs={"pk": application.pk})) - self.assertEqual(page.status_code, 403) - - def test_application_status_no_permissions(self): - """Can't access applications without being the creator.""" - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) - other_user = User() - other_user.save() - application.creator = other_user - application.save() - - # PermissionDeniedErrors make lots of noise in test output - with less_console_noise(): - for url_name in [ - "application-status", - "application-withdraw-confirmation", - "application-withdrawn", - ]: - with self.subTest(url_name=url_name): - page = self.client.get(reverse(url_name, kwargs={"pk": application.pk})) - self.assertEqual(page.status_code, 403) - - def test_approved_application_not_in_active_requests(self): - """An approved application is not shown in the Active - Requests table on home.html.""" - application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED, user=self.user) - application.save() - - home_page = self.app.get("/") - # This works in our test environment because creating - # an approved application here does not generate a - # domain object, so we do not expect to see 'city.gov' - # in either the Domains or Requests tables. - self.assertNotContains(home_page, "city.gov") diff --git a/src/registrar/tests/test_views_application.py b/src/registrar/tests/test_views_application.py new file mode 100644 index 000000000..cdeacaf27 --- /dev/null +++ b/src/registrar/tests/test_views_application.py @@ -0,0 +1,2199 @@ +from unittest import skip + +from django.conf import settings +from django.urls import reverse + +from .common import MockSESClient, completed_application # type: ignore +from django_webtest import WebTest # type: ignore +import boto3_mocking # type: ignore + +from registrar.models import ( + DomainApplication, + Domain, + DomainInformation, + Contact, + User, + Website, +) +from registrar.views.application import ApplicationWizard, Step + +from .common import less_console_noise +from .test_views import TestWithUser + +import logging + +logger = logging.getLogger(__name__) + + +class DomainApplicationTests(TestWithUser, WebTest): + + """Webtests for domain application to test filling and submitting.""" + + # Doesn't work with CSRF checking + # hypothesis is that CSRF_USE_SESSIONS is incompatible with WebTest + csrf_checks = False + + def setUp(self): + super().setUp() + self.app.set_user(self.user.username) + self.TITLES = ApplicationWizard.TITLES + + def test_application_form_intro_acknowledgement(self): + """Tests that user is presented with intro acknowledgement page""" + intro_page = self.app.get(reverse("application:")) + self.assertContains(intro_page, "You’re about to start your .gov domain request") + + def test_application_form_intro_is_skipped_when_edit_access(self): + """Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'""" + completed_application(status=DomainApplication.ApplicationStatus.STARTED, user=self.user) + home_page = self.app.get("/") + self.assertContains(home_page, "city.gov") + # click the "Edit" link + detail_page = home_page.click("Edit", index=0) + # Check that the response is a redirect + self.assertEqual(detail_page.status_code, 302) + # You can access the 'Location' header to get the redirect URL + redirect_url = detail_page.url + self.assertEqual(redirect_url, "/request/organization_type/") + + def test_application_form_empty_submit(self): + """Tests empty submit on the first page after the acknowledgement page""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + # submitting should get back the same page if the required field is empty + result = type_page.forms[0].submit() + self.assertIn("What kind of U.S.-based government organization do you represent?", result) + + def test_application_multiple_applications_exist(self): + """Test that an info message appears when user has multiple applications already""" + # create and submit an application + application = completed_application(user=self.user) + mock_client = MockSESClient() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + application.submit() + application.save() + + # now, attempt to create another one + with less_console_noise(): + intro_page = self.app.get(reverse("application:")) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + self.assertContains(type_page, "You cannot submit this request yet") + + @boto3_mocking.patching + def test_application_form_submission(self): + """ + Can fill out the entire form and submit. + As we add additional form pages, we need to include them here to make + this test work. + + This test also looks for the long organization name on the summary page. + + This also tests for the presence of a modal trigger and the dynamic test + in the modal header on the submit page. + """ + num_pages_tested = 0 + # elections, type_of_work, tribal_government + SKIPPED_PAGES = 3 + num_pages = len(self.TITLES) - SKIPPED_PAGES + + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + # ---- TYPE PAGE ---- + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = "federal" + # test next button and validate data + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + # should see results in db + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.organization_type, "federal") + # the post request should return a redirect to the next form in + # the application + self.assertEqual(type_result.status_code, 302) + self.assertEqual(type_result["Location"], "/request/organization_federal/") + num_pages_tested += 1 + + # ---- FEDERAL BRANCH PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + federal_page = type_result.follow() + federal_form = federal_page.forms[0] + federal_form["organization_federal-federal_type"] = "executive" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_result = federal_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.federal_type, "executive") + # the post request should return a redirect to the next form in + # the application + self.assertEqual(federal_result.status_code, 302) + self.assertEqual(federal_result["Location"], "/request/organization_contact/") + num_pages_tested += 1 + + # ---- ORG CONTACT PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + org_contact_page = federal_result.follow() + org_contact_form = org_contact_page.forms[0] + # federal agency so we have to fill in federal_agency + org_contact_form["organization_contact-federal_agency"] = "General Services Administration" + org_contact_form["organization_contact-organization_name"] = "Testorg" + org_contact_form["organization_contact-address_line1"] = "address 1" + org_contact_form["organization_contact-address_line2"] = "address 2" + org_contact_form["organization_contact-city"] = "NYC" + org_contact_form["organization_contact-state_territory"] = "NY" + org_contact_form["organization_contact-zipcode"] = "10002" + org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + org_contact_result = org_contact_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.organization_name, "Testorg") + self.assertEqual(application.address_line1, "address 1") + self.assertEqual(application.address_line2, "address 2") + self.assertEqual(application.city, "NYC") + self.assertEqual(application.state_territory, "NY") + self.assertEqual(application.zipcode, "10002") + self.assertEqual(application.urbanization, "URB Royal Oaks") + # the post request should return a redirect to the next form in + # the application + self.assertEqual(org_contact_result.status_code, 302) + self.assertEqual(org_contact_result["Location"], "/request/authorizing_official/") + num_pages_tested += 1 + + # ---- AUTHORIZING OFFICIAL PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_page = org_contact_result.follow() + ao_form = ao_page.forms[0] + ao_form["authorizing_official-first_name"] = "Testy ATO" + ao_form["authorizing_official-last_name"] = "Tester ATO" + ao_form["authorizing_official-title"] = "Chief Tester" + ao_form["authorizing_official-email"] = "testy@town.com" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_result = ao_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.authorizing_official.first_name, "Testy ATO") + self.assertEqual(application.authorizing_official.last_name, "Tester ATO") + self.assertEqual(application.authorizing_official.title, "Chief Tester") + self.assertEqual(application.authorizing_official.email, "testy@town.com") + # the post request should return a redirect to the next form in + # the application + self.assertEqual(ao_result.status_code, 302) + self.assertEqual(ao_result["Location"], "/request/current_sites/") + num_pages_tested += 1 + + # ---- CURRENT SITES PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + current_sites_page = ao_result.follow() + current_sites_form = current_sites_page.forms[0] + current_sites_form["current_sites-0-website"] = "www.city.com" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + current_sites_result = current_sites_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual( + application.current_websites.filter(website="http://www.city.com").count(), + 1, + ) + # the post request should return a redirect to the next form in + # the application + self.assertEqual(current_sites_result.status_code, 302) + self.assertEqual(current_sites_result["Location"], "/request/dotgov_domain/") + num_pages_tested += 1 + + # ---- DOTGOV DOMAIN PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + dotgov_page = current_sites_result.follow() + dotgov_form = dotgov_page.forms[0] + dotgov_form["dotgov_domain-requested_domain"] = "city" + dotgov_form["dotgov_domain-0-alternative_domain"] = "city1" + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + dotgov_result = dotgov_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.requested_domain.name, "city.gov") + self.assertEqual(application.alternative_domains.filter(website="city1.gov").count(), 1) + # the post request should return a redirect to the next form in + # the application + self.assertEqual(dotgov_result.status_code, 302) + self.assertEqual(dotgov_result["Location"], "/request/purpose/") + num_pages_tested += 1 + + # ---- PURPOSE PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + purpose_page = dotgov_result.follow() + purpose_form = purpose_page.forms[0] + purpose_form["purpose-purpose"] = "For all kinds of things." + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + purpose_result = purpose_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.purpose, "For all kinds of things.") + # the post request should return a redirect to the next form in + # the application + self.assertEqual(purpose_result.status_code, 302) + self.assertEqual(purpose_result["Location"], "/request/your_contact/") + num_pages_tested += 1 + + # ---- YOUR CONTACT INFO PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + your_contact_page = purpose_result.follow() + your_contact_form = your_contact_page.forms[0] + + your_contact_form["your_contact-first_name"] = "Testy you" + your_contact_form["your_contact-last_name"] = "Tester you" + your_contact_form["your_contact-title"] = "Admin Tester" + your_contact_form["your_contact-email"] = "testy-admin@town.com" + your_contact_form["your_contact-phone"] = "(201) 555 5556" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + your_contact_result = your_contact_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.submitter.first_name, "Testy you") + self.assertEqual(application.submitter.last_name, "Tester you") + self.assertEqual(application.submitter.title, "Admin Tester") + self.assertEqual(application.submitter.email, "testy-admin@town.com") + self.assertEqual(application.submitter.phone, "(201) 555 5556") + # the post request should return a redirect to the next form in + # the application + self.assertEqual(your_contact_result.status_code, 302) + self.assertEqual(your_contact_result["Location"], "/request/other_contacts/") + num_pages_tested += 1 + + # ---- OTHER CONTACTS PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + other_contacts_page = your_contact_result.follow() + + # This page has 3 forms in 1. + # Let's set the yes/no radios to enable the other contacts fieldsets + other_contacts_form = other_contacts_page.forms[0] + + other_contacts_form["other_contacts-has_other_contacts"] = "True" + + other_contacts_form["other_contacts-0-first_name"] = "Testy2" + other_contacts_form["other_contacts-0-last_name"] = "Tester2" + other_contacts_form["other_contacts-0-title"] = "Another Tester" + other_contacts_form["other_contacts-0-email"] = "testy2@town.com" + other_contacts_form["other_contacts-0-phone"] = "(201) 555 5557" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + other_contacts_result = other_contacts_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual( + application.other_contacts.filter( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(201) 555 5557", + ).count(), + 1, + ) + # the post request should return a redirect to the next form in + # the application + self.assertEqual(other_contacts_result.status_code, 302) + self.assertEqual(other_contacts_result["Location"], "/request/anything_else/") + num_pages_tested += 1 + + # ---- ANYTHING ELSE PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + anything_else_page = other_contacts_result.follow() + anything_else_form = anything_else_page.forms[0] + + anything_else_form["anything_else-anything_else"] = "Nothing else." + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + anything_else_result = anything_else_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.anything_else, "Nothing else.") + # the post request should return a redirect to the next form in + # the application + self.assertEqual(anything_else_result.status_code, 302) + self.assertEqual(anything_else_result["Location"], "/request/requirements/") + num_pages_tested += 1 + + # ---- REQUIREMENTS PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + requirements_page = anything_else_result.follow() + requirements_form = requirements_page.forms[0] + + requirements_form["requirements-is_policy_acknowledged"] = True + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + requirements_result = requirements_form.submit() + # validate that data from this step are being saved + application = DomainApplication.objects.get() # there's only one + self.assertEqual(application.is_policy_acknowledged, True) + # the post request should return a redirect to the next form in + # the application + self.assertEqual(requirements_result.status_code, 302) + self.assertEqual(requirements_result["Location"], "/request/review/") + num_pages_tested += 1 + + # ---- REVIEW AND FINSIHED PAGES ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + review_page = requirements_result.follow() + review_form = review_page.forms[0] + + # Review page contains all the previously entered data + # Let's make sure the long org name is displayed + self.assertContains(review_page, "Federal") + self.assertContains(review_page, "Executive") + self.assertContains(review_page, "Testorg") + self.assertContains(review_page, "address 1") + self.assertContains(review_page, "address 2") + self.assertContains(review_page, "NYC") + self.assertContains(review_page, "NY") + self.assertContains(review_page, "10002") + self.assertContains(review_page, "URB Royal Oaks") + self.assertContains(review_page, "Testy ATO") + self.assertContains(review_page, "Tester ATO") + self.assertContains(review_page, "Chief Tester") + self.assertContains(review_page, "testy@town.com") + self.assertContains(review_page, "city.com") + self.assertContains(review_page, "city.gov") + self.assertContains(review_page, "city1.gov") + self.assertContains(review_page, "For all kinds of things.") + self.assertContains(review_page, "Testy you") + self.assertContains(review_page, "Tester you") + self.assertContains(review_page, "Admin Tester") + self.assertContains(review_page, "testy-admin@town.com") + self.assertContains(review_page, "(201) 555-5556") + self.assertContains(review_page, "Testy2") + self.assertContains(review_page, "Tester2") + self.assertContains(review_page, "Another Tester") + self.assertContains(review_page, "testy2@town.com") + self.assertContains(review_page, "(201) 555-5557") + self.assertContains(review_page, "Nothing else.") + + # We can't test the modal itself as it relies on JS for init and triggering, + # but we can test for the existence of its trigger: + self.assertContains(review_page, "toggle-submit-domain-request") + # And the existence of the modal's data parked and ready for the js init. + # The next assert also tests for the passed requested domain context from + # the view > application_form > modal + self.assertContains(review_page, "You are about to submit a domain request for city.gov") + + # final submission results in a redirect to the "finished" URL + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + with less_console_noise(): + review_result = review_form.submit() + + self.assertEqual(review_result.status_code, 302) + self.assertEqual(review_result["Location"], "/request/finished/") + num_pages_tested += 1 + + # following this redirect is a GET request, so include the cookie + # here too. + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + with less_console_noise(): + final_result = review_result.follow() + self.assertContains(final_result, "Thanks for your domain request!") + + # check that any new pages are added to this test + self.assertEqual(num_pages, num_pages_tested) + + # This is the start of a test to check an existing application, it currently + # does not work and results in errors as noted in: + # https://github.com/cisagov/getgov/pull/728 + @skip("WIP") + def test_application_form_started_allsteps(self): + num_pages_tested = 0 + # elections, type_of_work, tribal_government + SKIPPED_PAGES = 3 + DASHBOARD_PAGE = 1 + num_pages = len(self.TITLES) - SKIPPED_PAGES + DASHBOARD_PAGE + + application = completed_application(user=self.user) + application.save() + home_page = self.app.get("/") + self.assertContains(home_page, "city.gov") + self.assertContains(home_page, "Started") + num_pages_tested += 1 + + # TODO: For some reason this click results in a new application being generated + # This appraoch is an alternatie to using get as is being done below + # + # type_page = home_page.click("Edit") + + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + url = reverse("edit-application", kwargs={"id": application.pk}) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + # TODO: The following line results in a django error on middleware + response = self.client.get(url, follow=True) + self.assertContains(response, "Type of organization") + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # TODO: Step through the remaining pages + + self.assertEqual(num_pages, num_pages_tested) + + def test_application_form_conditional_federal(self): + """Federal branch question is shown for federal organizations.""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + # ---- TYPE PAGE ---- + + # the conditional step titles shouldn't appear initially + self.assertNotContains(type_page, self.TITLES["organization_federal"]) + self.assertNotContains(type_page, self.TITLES["organization_election"]) + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = "federal" + + # set the session ID before .submit() + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + + # the post request should return a redirect to the federal branch + # question + self.assertEqual(type_result.status_code, 302) + self.assertEqual(type_result["Location"], "/request/organization_federal/") + + # and the step label should appear in the sidebar of the resulting page + # but the step label for the elections page should not appear + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_page = type_result.follow() + self.assertContains(federal_page, self.TITLES["organization_federal"]) + self.assertNotContains(federal_page, self.TITLES["organization_election"]) + + # continuing on in the flow we need to see top-level agency on the + # contact page + federal_page.forms[0]["organization_federal-federal_type"] = "executive" + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_result = federal_page.forms[0].submit() + # the post request should return a redirect to the contact + # question + self.assertEqual(federal_result.status_code, 302) + self.assertEqual(federal_result["Location"], "/request/organization_contact/") + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + contact_page = federal_result.follow() + self.assertContains(contact_page, "Federal agency") + + def test_application_form_conditional_elections(self): + """Election question is shown for other organizations.""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + # ---- TYPE PAGE ---- + + # the conditional step titles shouldn't appear initially + self.assertNotContains(type_page, self.TITLES["organization_federal"]) + self.assertNotContains(type_page, self.TITLES["organization_election"]) + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = "county" + + # set the session ID before .submit() + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + + # the post request should return a redirect to the elections question + self.assertEqual(type_result.status_code, 302) + self.assertEqual(type_result["Location"], "/request/organization_election/") + + # and the step label should appear in the sidebar of the resulting page + # but the step label for the elections page should not appear + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + election_page = type_result.follow() + self.assertContains(election_page, self.TITLES["organization_election"]) + self.assertNotContains(election_page, self.TITLES["organization_federal"]) + + # continuing on in the flow we need to NOT see top-level agency on the + # contact page + election_page.forms[0]["organization_election-is_election_board"] = "True" + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + election_result = election_page.forms[0].submit() + # the post request should return a redirect to the contact + # question + self.assertEqual(election_result.status_code, 302) + self.assertEqual(election_result["Location"], "/request/organization_contact/") + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + contact_page = election_result.follow() + self.assertNotContains(contact_page, "Federal agency") + + def test_application_form_section_skipping(self): + """Can skip forward and back in sections""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = "federal" + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_page = type_result.follow() + + # Now on federal type page, click back to the organization type + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + new_page = federal_page.click(str(self.TITLES["organization_type"]), index=0) + + # Should be a link to the organization_federal page + self.assertGreater( + len(new_page.html.find_all("a", href="/request/organization_federal/")), + 0, + ) + + def test_application_form_nonfederal(self): + """Non-federal organizations don't have to provide their federal agency.""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + contact_page = type_result.follow() + org_contact_form = contact_page.forms[0] + + self.assertNotIn("federal_agency", org_contact_form.fields) + + # minimal fields that must be filled out + org_contact_form["organization_contact-organization_name"] = "Testorg" + org_contact_form["organization_contact-address_line1"] = "address 1" + org_contact_form["organization_contact-city"] = "NYC" + org_contact_form["organization_contact-state_territory"] = "NY" + org_contact_form["organization_contact-zipcode"] = "10002" + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + contact_result = org_contact_form.submit() + + # the post request should return a redirect to the + # about your organization page if it was successful. + self.assertEqual(contact_result.status_code, 302) + self.assertEqual(contact_result["Location"], "/request/about_your_organization/") + + def test_application_about_your_organization_special(self): + """Special districts have to answer an additional question.""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.SPECIAL_DISTRICT + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_page.forms[0].submit() + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + contact_page = type_result.follow() + + self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION]) + + def test_yes_no_form_inits_blank_for_new_application(self): + """On the Other Contacts page, the yes/no form gets initialized with nothing selected for + new applications""" + other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_form = other_contacts_page.forms[0] + self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, None) + + def test_yes_no_form_inits_yes_for_application_with_other_contacts(self): + """On the Other Contacts page, the yes/no form gets initialized with YES selected if the + application has other contacts""" + # Application has other contacts by default + application = completed_application(user=self.user) + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True") + + def test_yes_no_form_inits_no_for_application_with_no_other_contacts_rationale(self): + """On the Other Contacts page, the yes/no form gets initialized with NO selected if the + application has no other contacts""" + # Application has other contacts by default + application = completed_application(user=self.user, has_other_contacts=False) + application.no_other_contacts_rationale = "Hello!" + application.save() + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False") + + def test_submitting_other_contacts_deletes_no_other_contacts_rationale(self): + """When a user submits the Other Contacts form with other contacts selected, the application's + no other contacts rationale gets deleted""" + # Application has other contacts by default + application = completed_application(user=self.user, has_other_contacts=False) + application.no_other_contacts_rationale = "Hello!" + application.save() + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "False") + + other_contacts_form["other_contacts-has_other_contacts"] = "True" + + other_contacts_form["other_contacts-0-first_name"] = "Testy" + other_contacts_form["other_contacts-0-middle_name"] = "" + other_contacts_form["other_contacts-0-last_name"] = "McTesterson" + other_contacts_form["other_contacts-0-title"] = "Lord" + other_contacts_form["other_contacts-0-email"] = "testy@abc.org" + other_contacts_form["other_contacts-0-phone"] = "(201) 555-0123" + + # Submit the now empty form + other_contacts_form.submit() + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database + application = DomainApplication.objects.get() + self.assertEqual( + application.other_contacts.count(), + 1, + ) + + self.assertEquals( + application.no_other_contacts_rationale, + None, + ) + + def test_submitting_no_other_contacts_rationale_deletes_other_contacts(self): + """When a user submits the Other Contacts form with no other contacts selected, the application's + other contacts get deleted for other contacts that exist and are not joined to other objects + """ + # Application has other contacts by default + application = completed_application(user=self.user) + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True") + + other_contacts_form["other_contacts-has_other_contacts"] = "False" + + other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!" + + # Submit the now empty form + other_contacts_form.submit() + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database + application = DomainApplication.objects.get() + self.assertEqual( + application.other_contacts.count(), + 0, + ) + + self.assertEquals( + application.no_other_contacts_rationale, + "Hello again!", + ) + + def test_submitting_no_other_contacts_rationale_removes_reference_other_contacts_when_joined(self): + """When a user submits the Other Contacts form with no other contacts selected, the application's + other contacts references get removed for other contacts that exist and are joined to other objects""" + # Populate the database with a domain application that + # has 1 "other contact" assigned to it + # We'll do it from scratch so we can reuse the other contact + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(555) 555 5555", + ) + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(555) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(555) 555 5557", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + submitter=you, + creator=self.user, + status="started", + ) + application.other_contacts.add(other) + + # Now let's join the other contact to another object + domain_info = DomainInformation.objects.create(creator=self.user) + domain_info.other_contacts.set([other]) + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True") + + other_contacts_form["other_contacts-has_other_contacts"] = "False" + + other_contacts_form["other_contacts-no_other_contacts_rationale"] = "Hello again!" + + # Submit the now empty form + other_contacts_form.submit() + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + # Verify that the no_other_contacts_rationale we saved earlier is no longer associated with the application + application = DomainApplication.objects.get() + self.assertEqual( + application.other_contacts.count(), + 0, + ) + + # Verify that the 'other' contact object still exists + domain_info = DomainInformation.objects.get() + self.assertEqual( + domain_info.other_contacts.count(), + 1, + ) + self.assertEqual( + domain_info.other_contacts.all()[0].first_name, + "Testy2", + ) + + self.assertEquals( + application.no_other_contacts_rationale, + "Hello again!", + ) + + def test_if_yes_no_form_is_no_then_no_other_contacts_required(self): + """Applicants with no other contacts have to give a reason.""" + other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_form = other_contacts_page.forms[0] + other_contacts_form["other_contacts-has_other_contacts"] = "False" + response = other_contacts_page.forms[0].submit() + + # The textarea for no other contacts returns this error message + # Assert that it is returned, ie the no other contacts form is required + self.assertContains(response, "Rationale for no other employees is required.") + + # The first name field for other contacts returns this error message + # Assert that it is not returned, ie the contacts form is not required + self.assertNotContains(response, "Enter the first name / given name of this contact.") + + def test_if_yes_no_form_is_yes_then_other_contacts_required(self): + """Applicants with other contacts do not have to give a reason.""" + other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_form = other_contacts_page.forms[0] + other_contacts_form["other_contacts-has_other_contacts"] = "True" + response = other_contacts_page.forms[0].submit() + + # The textarea for no other contacts returns this error message + # Assert that it is not returned, ie the no other contacts form is not required + self.assertNotContains(response, "Rationale for no other employees is required.") + + # The first name field for other contacts returns this error message + # Assert that it is returned, ie the contacts form is required + self.assertContains(response, "Enter the first name / given name of this contact.") + + def test_delete_other_contact(self): + """Other contacts can be deleted after being saved to database. + + This formset uses the DJANGO DELETE widget. We'll test that by setting 2 contacts on an application, + loading the form and marking one contact up for deletion.""" + # Populate the database with a domain application that + # has 2 "other contact" assigned to it + # We'll do it from scratch so we can reuse the other contact + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(201) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(201) 555 5557", + ) + other2, _ = Contact.objects.get_or_create( + first_name="Testy3", + last_name="Tester3", + title="Another Tester", + email="testy3@town.com", + phone="(201) 555 5557", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + submitter=you, + creator=self.user, + status="started", + ) + application.other_contacts.add(other) + application.other_contacts.add(other2) + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + + # Minimal check to ensure the form is loaded with both other contacts + self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") + self.assertEqual(other_contacts_form["other_contacts-1-first_name"].value, "Testy3") + + # Mark the first dude for deletion + other_contacts_form.set("other_contacts-0-DELETE", "on") + + # Submit the form + other_contacts_form.submit() + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + # Verify that the first dude was deleted + application = DomainApplication.objects.get() + self.assertEqual(application.other_contacts.count(), 1) + self.assertEqual(application.other_contacts.first().first_name, "Testy3") + + def test_delete_other_contact_does_not_allow_zero_contacts(self): + """Delete Other Contact does not allow submission with zero contacts.""" + # Populate the database with a domain application that + # has 1 "other contact" assigned to it + # We'll do it from scratch so we can reuse the other contact + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(201) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(201) 555 5557", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + submitter=you, + creator=self.user, + status="started", + ) + application.other_contacts.add(other) + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") + + # Mark the first dude for deletion + other_contacts_form.set("other_contacts-0-DELETE", "on") + + # Submit the form + other_contacts_form.submit() + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + # Verify that the contact was not deleted + application = DomainApplication.objects.get() + self.assertEqual(application.other_contacts.count(), 1) + self.assertEqual(application.other_contacts.first().first_name, "Testy2") + + def test_delete_other_contact_sets_visible_empty_form_as_required_after_failed_submit(self): + """When you: + 1. add an empty contact, + 2. delete existing contacts, + 3. then submit, + The forms on page reload shows all the required fields and their errors.""" + + # Populate the database with a domain application that + # has 1 "other contact" assigned to it + # We'll do it from scratch so we can reuse the other contact + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(201) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(201) 555 5557", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + submitter=you, + creator=self.user, + status="started", + ) + application.other_contacts.add(other) + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") + + # Set total forms to 2 indicating an additional formset was added. + # Submit no data though for the second formset. + # Set the first formset to be deleted. + other_contacts_form["other_contacts-TOTAL_FORMS"] = "2" + other_contacts_form.set("other_contacts-0-DELETE", "on") + + response = other_contacts_form.submit() + + # Assert that the response presents errors to the user, including to + # Enter the first name ... + self.assertContains(response, "Enter the first name / given name of this contact.") + + def test_edit_other_contact_in_place(self): + """When you: + 1. edit an existing contact which is not joined to another model, + 2. then submit, + The application is linked to the existing contact, and the existing contact updated.""" + + # Populate the database with a domain application that + # has 1 "other contact" assigned to it + # We'll do it from scratch + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(201) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(201) 555 5557", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + submitter=you, + creator=self.user, + status="started", + ) + application.other_contacts.add(other) + + # other_contact_pk is the initial pk of the other contact. set it before update + # to be able to verify after update that the same contact object is in place + other_contact_pk = other.id + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy2") + + # update the first name of the contact + other_contacts_form["other_contacts-0-first_name"] = "Testy3" + + # Submit the updated form + other_contacts_form.submit() + + application.refresh_from_db() + + # assert that the Other Contact is updated "in place" + other_contact = application.other_contacts.all()[0] + self.assertEquals(other_contact_pk, other_contact.id) + self.assertEquals("Testy3", other_contact.first_name) + + def test_edit_other_contact_creates_new(self): + """When you: + 1. edit an existing contact which IS joined to another model, + 2. then submit, + The application is linked to a new contact, and the new contact is updated.""" + + # Populate the database with a domain application that + # has 1 "other contact" assigned to it, the other contact is also + # the authorizing official initially + # We'll do it from scratch + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(201) 555 5556", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + submitter=you, + creator=self.user, + status="started", + ) + application.other_contacts.add(ao) + + # other_contact_pk is the initial pk of the other contact. set it before update + # to be able to verify after update that the ao contact is still in place + # and not updated, and that the new contact has a new id + other_contact_pk = ao.id + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_page = self.app.get(reverse("application:other_contacts")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + other_contacts_form = other_contacts_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(other_contacts_form["other_contacts-0-first_name"].value, "Testy") + + # update the first name of the contact + other_contacts_form["other_contacts-0-first_name"] = "Testy2" + + # Submit the updated form + other_contacts_form.submit() + + application.refresh_from_db() + + # assert that other contact info is updated, and that a new Contact + # is created for the other contact + other_contact = application.other_contacts.all()[0] + self.assertNotEquals(other_contact_pk, other_contact.id) + self.assertEquals("Testy2", other_contact.first_name) + # assert that the authorizing official is not updated + authorizing_official = application.authorizing_official + self.assertEquals("Testy", authorizing_official.first_name) + + def test_edit_authorizing_official_in_place(self): + """When you: + 1. edit an authorizing official which is not joined to another model, + 2. then submit, + The application is linked to the existing ao, and the ao updated.""" + + # Populate the database with a domain application that + # has an authorizing_official (ao) + # We'll do it from scratch + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + creator=self.user, + status="started", + ) + + # ao_pk is the initial pk of the Authorizing Official. set it before update + # to be able to verify after update that the same Contact object is in place + ao_pk = ao.id + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + ao_page = self.app.get(reverse("application:authorizing_official")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + ao_form = ao_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy") + + # update the first name of the contact + ao_form["authorizing_official-first_name"] = "Testy2" + + # Submit the updated form + ao_form.submit() + + application.refresh_from_db() + + # assert AO is updated "in place" + updated_ao = application.authorizing_official + self.assertEquals(ao_pk, updated_ao.id) + self.assertEquals("Testy2", updated_ao.first_name) + + def test_edit_authorizing_official_creates_new(self): + """When you: + 1. edit an existing authorizing official which IS joined to another model, + 2. then submit, + The application is linked to a new Contact, and the new Contact is updated.""" + + # Populate the database with a domain application that + # has authorizing official assigned to it, the authorizing offical is also + # an other contact initially + # We'll do it from scratch + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + creator=self.user, + status="started", + ) + application.other_contacts.add(ao) + + # ao_pk is the initial pk of the authorizing official. set it before update + # to be able to verify after update that the other contact is still in place + # and not updated, and that the new ao has a new id + ao_pk = ao.id + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + ao_page = self.app.get(reverse("application:authorizing_official")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + ao_form = ao_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(ao_form["authorizing_official-first_name"].value, "Testy") + + # update the first name of the contact + ao_form["authorizing_official-first_name"] = "Testy2" + + # Submit the updated form + ao_form.submit() + + application.refresh_from_db() + + # assert that the other contact is not updated + other_contacts = application.other_contacts.all() + other_contact = other_contacts[0] + self.assertEquals(ao_pk, other_contact.id) + self.assertEquals("Testy", other_contact.first_name) + # assert that the authorizing official is updated + authorizing_official = application.authorizing_official + self.assertEquals("Testy2", authorizing_official.first_name) + + def test_edit_submitter_in_place(self): + """When you: + 1. edit a submitter (your contact) which is not joined to another model, + 2. then submit, + The application is linked to the existing submitter, and the submitter updated.""" + + # Populate the database with a domain application that + # has a submitter + # We'll do it from scratch + you, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + submitter=you, + creator=self.user, + status="started", + ) + + # submitter_pk is the initial pk of the submitter. set it before update + # to be able to verify after update that the same contact object is in place + submitter_pk = you.id + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + your_contact_page = self.app.get(reverse("application:your_contact")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + your_contact_form = your_contact_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy") + + # update the first name of the contact + your_contact_form["your_contact-first_name"] = "Testy2" + + # Submit the updated form + your_contact_form.submit() + + application.refresh_from_db() + + updated_submitter = application.submitter + self.assertEquals(submitter_pk, updated_submitter.id) + self.assertEquals("Testy2", updated_submitter.first_name) + + def test_edit_submitter_creates_new(self): + """When you: + 1. edit an existing your contact which IS joined to another model, + 2. then submit, + The application is linked to a new Contact, and the new Contact is updated.""" + + # Populate the database with a domain application that + # has submitter assigned to it, the submitter is also + # an other contact initially + # We'll do it from scratch + submitter, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(201) 555 5555", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + submitter=submitter, + creator=self.user, + status="started", + ) + application.other_contacts.add(submitter) + + # submitter_pk is the initial pk of the your contact. set it before update + # to be able to verify after update that the other contact is still in place + # and not updated, and that the new submitter has a new id + submitter_pk = submitter.id + + # prime the form by visiting /edit + self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + your_contact_page = self.app.get(reverse("application:your_contact")) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + your_contact_form = your_contact_page.forms[0] + + # Minimal check to ensure the form is loaded + self.assertEqual(your_contact_form["your_contact-first_name"].value, "Testy") + + # update the first name of the contact + your_contact_form["your_contact-first_name"] = "Testy2" + + # Submit the updated form + your_contact_form.submit() + + application.refresh_from_db() + + # assert that the other contact is not updated + other_contacts = application.other_contacts.all() + other_contact = other_contacts[0] + self.assertEquals(submitter_pk, other_contact.id) + self.assertEquals("Testy", other_contact.first_name) + # assert that the submitter is updated + submitter = application.submitter + self.assertEquals("Testy2", submitter.first_name) + + def test_application_about_your_organiztion_interstate(self): + """Special districts have to answer an additional question.""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + contact_page = type_result.follow() + + self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION]) + + def test_application_tribal_government(self): + """Tribal organizations have to answer an additional question.""" + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.TRIBAL + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + # the tribal government page comes immediately afterwards + self.assertIn("/tribal_government", type_result.headers["Location"]) + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + tribal_government_page = type_result.follow() + + # and the step is on the sidebar list. + self.assertContains(tribal_government_page, self.TITLES[Step.TRIBAL_GOVERNMENT]) + + def test_application_ao_dynamic_text(self): + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + # ---- TYPE PAGE ---- + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = "federal" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + + # ---- FEDERAL BRANCH PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_page = type_result.follow() + federal_form = federal_page.forms[0] + federal_form["organization_federal-federal_type"] = "executive" + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_result = federal_form.submit() + + # ---- ORG CONTACT PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + org_contact_page = federal_result.follow() + org_contact_form = org_contact_page.forms[0] + # federal agency so we have to fill in federal_agency + org_contact_form["organization_contact-federal_agency"] = "General Services Administration" + org_contact_form["organization_contact-organization_name"] = "Testorg" + org_contact_form["organization_contact-address_line1"] = "address 1" + org_contact_form["organization_contact-address_line2"] = "address 2" + org_contact_form["organization_contact-city"] = "NYC" + org_contact_form["organization_contact-state_territory"] = "NY" + org_contact_form["organization_contact-zipcode"] = "10002" + org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks" + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + org_contact_result = org_contact_form.submit() + + # ---- AO CONTACT PAGE ---- + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_page = org_contact_result.follow() + self.assertContains(ao_page, "Executive branch federal agencies") + + # Go back to organization type page and change type + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_page.click(str(self.TITLES["organization_type"]), index=0) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_form["organization_type-organization_type"] = "city" + type_result = type_form.submit() + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + election_page = type_result.follow() + + # Go back to AO page and test the dynamic text changed + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_page = election_page.click(str(self.TITLES["authorizing_official"]), index=0) + self.assertContains(ao_page, "Domain requests from cities") + + def test_application_dotgov_domain_dynamic_text(self): + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + # ---- TYPE PAGE ---- + type_form = type_page.forms[0] + type_form["organization_type-organization_type"] = "federal" + + # test next button + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_result = type_form.submit() + + # ---- FEDERAL BRANCH PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_page = type_result.follow() + federal_form = federal_page.forms[0] + federal_form["organization_federal-federal_type"] = "executive" + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + federal_result = federal_form.submit() + + # ---- ORG CONTACT PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + org_contact_page = federal_result.follow() + org_contact_form = org_contact_page.forms[0] + # federal agency so we have to fill in federal_agency + org_contact_form["organization_contact-federal_agency"] = "General Services Administration" + org_contact_form["organization_contact-organization_name"] = "Testorg" + org_contact_form["organization_contact-address_line1"] = "address 1" + org_contact_form["organization_contact-address_line2"] = "address 2" + org_contact_form["organization_contact-city"] = "NYC" + org_contact_form["organization_contact-state_territory"] = "NY" + org_contact_form["organization_contact-zipcode"] = "10002" + org_contact_form["organization_contact-urbanization"] = "URB Royal Oaks" + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + org_contact_result = org_contact_form.submit() + + # ---- AO CONTACT PAGE ---- + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_page = org_contact_result.follow() + + # ---- AUTHORIZING OFFICIAL PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_page = org_contact_result.follow() + ao_form = ao_page.forms[0] + ao_form["authorizing_official-first_name"] = "Testy ATO" + ao_form["authorizing_official-last_name"] = "Tester ATO" + ao_form["authorizing_official-title"] = "Chief Tester" + ao_form["authorizing_official-email"] = "testy@town.com" + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_result = ao_form.submit() + + # ---- CURRENT SITES PAGE ---- + # Follow the redirect to the next form page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + current_sites_page = ao_result.follow() + current_sites_form = current_sites_page.forms[0] + current_sites_form["current_sites-0-website"] = "www.city.com" + + # test saving the page + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + current_sites_result = current_sites_form.submit() + + # ---- DOTGOV DOMAIN PAGE ---- + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + dotgov_page = current_sites_result.follow() + + self.assertContains(dotgov_page, "medicare.gov") + + # Go back to organization type page and change type + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + dotgov_page.click(str(self.TITLES["organization_type"]), index=0) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_form["organization_type-organization_type"] = "city" + type_result = type_form.submit() + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + election_page = type_result.follow() + + # Go back to dotgov domain page to test the dynamic text changed + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + dotgov_page = election_page.click(str(self.TITLES["dotgov_domain"]), index=0) + self.assertContains(dotgov_page, "CityofEudoraKS.gov") + self.assertNotContains(dotgov_page, "medicare.gov") + + def test_application_formsets(self): + """Users are able to add more than one of some fields.""" + current_sites_page = self.app.get(reverse("application:current_sites")) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + # fill in the form field + current_sites_form = current_sites_page.forms[0] + self.assertIn("current_sites-0-website", current_sites_form.fields) + self.assertNotIn("current_sites-1-website", current_sites_form.fields) + current_sites_form["current_sites-0-website"] = "https://example.com" + + # click "Add another" + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + current_sites_result = current_sites_form.submit("submit_button", value="save") + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + current_sites_form = current_sites_result.follow().forms[0] + + # verify that there are two form fields + value = current_sites_form["current_sites-0-website"].value + self.assertEqual(value, "https://example.com") + self.assertIn("current_sites-1-website", current_sites_form.fields) + # and it is correctly referenced in the ManyToOne relationship + application = DomainApplication.objects.get() # there's only one + self.assertEqual( + application.current_websites.filter(website="https://example.com").count(), + 1, + ) + + @skip("WIP") + def test_application_edit_restore(self): + """ + Test that a previously saved application is available at the /edit endpoint. + """ + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(555) 555 5555", + ) + domain, _ = Domain.objects.get_or_create(name="city.gov") + alt, _ = Website.objects.get_or_create(website="city1.gov") + current, _ = Website.objects.get_or_create(website="city.com") + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(555) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(555) 555 5557", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + requested_domain=domain, + submitter=you, + creator=self.user, + ) + application.other_contacts.add(other) + application.current_websites.add(current) + application.alternative_domains.add(alt) + + # prime the form by visiting /edit + url = reverse("edit-application", kwargs={"id": application.pk}) + response = self.client.get(url) + + # TODO: this is a sketch of each page in the wizard which needs to be tested + # Django does not have tools sufficient for real end to end integration testing + # (for example, USWDS moves radio buttons off screen and replaces them with + # CSS styled "fakes" -- Django cannot determine if those are visually correct) + # -- the best that can/should be done here is to ensure the correct values + # are being passed to the templating engine + + url = reverse("application:organization_type") + response = self.client.get(url, follow=True) + self.assertContains(response, "") + # choices = response.context['wizard']['form']['organization_type'].subwidgets + # radio = [ x for x in choices if x.data["value"] == "federal" ][0] + # checked = radio.data["selected"] + # self.assertTrue(checked) + + # url = reverse("application:organization_federal") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:organization_contact") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:authorizing_official") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:current_sites") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:dotgov_domain") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:purpose") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:your_contact") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:other_contacts") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:other_contacts") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:security_email") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:anything_else") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + # url = reverse("application:requirements") + # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # page = self.app.get(url) + # self.assertNotContains(page, "VALUE") + + def test_long_org_name_in_application(self): + """ + Make sure the long name is displaying in the application form, + org step + """ + intro_page = self.app.get(reverse("application:")) + # django-webtest does not handle cookie-based sessions well because it keeps + # resetting the session key on each new request, thus destroying the concept + # of a "session". We are going to do it manually, saving the session ID here + # and then setting the cookie on each request. + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + intro_form = intro_page.forms[0] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + intro_result = intro_form.submit() + + # follow first redirect + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + type_page = intro_result.follow() + + self.assertContains(type_page, "Federal: an agency of the U.S. government") + + def test_submit_modal_no_domain_text_fallback(self): + """When user clicks on submit your domain request and the requested domain + is null (possible through url direct access to the review page), present + fallback copy in the modal's header. + + NOTE: This may be a moot point if we implement a more solid pattern in the + future, like not a submit action at all on the review page.""" + + review_page = self.app.get(reverse("application:review")) + self.assertContains(review_page, "toggle-submit-domain-request") + self.assertContains(review_page, "You are about to submit an incomplete request") + + +class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): + def setUp(self): + super().setUp() + self.app.set_user(self.user.username) + self.client.force_login(self.user) + + def test_application_status(self): + """Checking application status page""" + application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application.save() + + home_page = self.app.get("/") + self.assertContains(home_page, "city.gov") + # click the "Manage" link + detail_page = home_page.click("Manage", index=0) + self.assertContains(detail_page, "city.gov") + self.assertContains(detail_page, "city1.gov") + self.assertContains(detail_page, "Chief Tester") + self.assertContains(detail_page, "testy@town.com") + self.assertContains(detail_page, "Admin Tester") + self.assertContains(detail_page, "Status:") + + def test_application_status_with_ineligible_user(self): + """Checking application status page whith a blocked user. + The user should still have access to view.""" + self.user.status = "ineligible" + self.user.save() + + application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application.save() + + home_page = self.app.get("/") + self.assertContains(home_page, "city.gov") + # click the "Manage" link + detail_page = home_page.click("Manage", index=0) + self.assertContains(detail_page, "city.gov") + self.assertContains(detail_page, "Chief Tester") + self.assertContains(detail_page, "testy@town.com") + self.assertContains(detail_page, "Admin Tester") + self.assertContains(detail_page, "Status:") + + def test_application_withdraw(self): + """Checking application status page""" + application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application.save() + + home_page = self.app.get("/") + self.assertContains(home_page, "city.gov") + # click the "Manage" link + detail_page = home_page.click("Manage", index=0) + self.assertContains(detail_page, "city.gov") + self.assertContains(detail_page, "city1.gov") + self.assertContains(detail_page, "Chief Tester") + self.assertContains(detail_page, "testy@town.com") + self.assertContains(detail_page, "Admin Tester") + self.assertContains(detail_page, "Status:") + # click the "Withdraw request" button + mock_client = MockSESClient() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + withdraw_page = detail_page.click("Withdraw request") + self.assertContains(withdraw_page, "Withdraw request for") + home_page = withdraw_page.click("Withdraw request") + # confirm that it has redirected, and the status has been updated to withdrawn + self.assertRedirects( + home_page, + "/", + status_code=302, + target_status_code=200, + fetch_redirect_response=True, + ) + home_page = self.app.get("/") + self.assertContains(home_page, "Withdrawn") + + def test_application_withdraw_no_permissions(self): + """Can't withdraw applications as a restricted user.""" + self.user.status = User.RESTRICTED + self.user.save() + application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application.save() + + home_page = self.app.get("/") + self.assertContains(home_page, "city.gov") + # click the "Manage" link + detail_page = home_page.click("Manage", index=0) + self.assertContains(detail_page, "city.gov") + self.assertContains(detail_page, "city1.gov") + self.assertContains(detail_page, "Chief Tester") + self.assertContains(detail_page, "testy@town.com") + self.assertContains(detail_page, "Admin Tester") + self.assertContains(detail_page, "Status:") + # Restricted user trying to withdraw results in 403 error + with less_console_noise(): + for url_name in [ + "application-withdraw-confirmation", + "application-withdrawn", + ]: + with self.subTest(url_name=url_name): + page = self.client.get(reverse(url_name, kwargs={"pk": application.pk})) + self.assertEqual(page.status_code, 403) + + def test_application_status_no_permissions(self): + """Can't access applications without being the creator.""" + application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + other_user = User() + other_user.save() + application.creator = other_user + application.save() + + # PermissionDeniedErrors make lots of noise in test output + with less_console_noise(): + for url_name in [ + "application-status", + "application-withdraw-confirmation", + "application-withdrawn", + ]: + with self.subTest(url_name=url_name): + page = self.client.get(reverse(url_name, kwargs={"pk": application.pk})) + self.assertEqual(page.status_code, 403) + + def test_approved_application_not_in_active_requests(self): + """An approved application is not shown in the Active + Requests table on home.html.""" + application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED, user=self.user) + application.save() + + home_page = self.app.get("/") + # This works in our test environment because creating + # an approved application here does not generate a + # domain object, so we do not expect to see 'city.gov' + # in either the Domains or Requests tables. + self.assertNotContains(home_page, "city.gov") diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py new file mode 100644 index 000000000..df035b13e --- /dev/null +++ b/src/registrar/tests/test_views_domain.py @@ -0,0 +1,1611 @@ +from unittest import skip +from unittest.mock import MagicMock, ANY, patch + +from django.conf import settings +from django.urls import reverse +from django.contrib.auth import get_user_model + +from .common import MockSESClient, create_user # type: ignore +from django_webtest import WebTest # type: ignore +import boto3_mocking # type: ignore + +from registrar.utility.errors import ( + NameserverError, + NameserverErrorCodes, + SecurityEmailError, + SecurityEmailErrorCodes, + GenericError, + GenericErrorCodes, + DsDataError, + DsDataErrorCodes, +) + +from registrar.models import ( + DomainApplication, + Domain, + DomainInformation, + DomainInvitation, + Contact, + PublicContact, + Host, + HostIP, + UserDomainRole, + User, +) +from datetime import date, datetime, timedelta +from django.utils import timezone + +from .common import less_console_noise +from .test_views import TestWithUser + +import logging + +logger = logging.getLogger(__name__) + + +class TestWithDomainPermissions(TestWithUser): + def setUp(self): + super().setUp() + self.domain, _ = Domain.objects.get_or_create(name="igorville.gov") + self.domain_with_ip, _ = Domain.objects.get_or_create(name="nameserverwithip.gov") + self.domain_just_nameserver, _ = Domain.objects.get_or_create(name="justnameserver.com") + self.domain_no_information, _ = Domain.objects.get_or_create(name="noinformation.gov") + self.domain_on_hold, _ = Domain.objects.get_or_create( + name="on-hold.gov", + state=Domain.State.ON_HOLD, + expiration_date=timezone.make_aware( + datetime.combine(date.today() + timedelta(days=1), datetime.min.time()) + ), + ) + self.domain_deleted, _ = Domain.objects.get_or_create( + name="deleted.gov", + state=Domain.State.DELETED, + expiration_date=timezone.make_aware( + datetime.combine(date.today() + timedelta(days=1), datetime.min.time()) + ), + ) + + self.domain_dsdata, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov") + self.domain_multdsdata, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov") + # We could simply use domain (igorville) but this will be more readable in tests + # that inherit this setUp + self.domain_dnssec_none, _ = Domain.objects.get_or_create(name="dnssec-none.gov") + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dsdata) + DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_multdsdata) + DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dnssec_none) + DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_with_ip) + DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_just_nameserver) + DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_on_hold) + DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_deleted) + + self.role, _ = UserDomainRole.objects.get_or_create( + user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER + ) + + UserDomainRole.objects.get_or_create( + user=self.user, domain=self.domain_dsdata, role=UserDomainRole.Roles.MANAGER + ) + UserDomainRole.objects.get_or_create( + user=self.user, + domain=self.domain_multdsdata, + role=UserDomainRole.Roles.MANAGER, + ) + UserDomainRole.objects.get_or_create( + user=self.user, + domain=self.domain_dnssec_none, + role=UserDomainRole.Roles.MANAGER, + ) + UserDomainRole.objects.get_or_create( + user=self.user, + domain=self.domain_with_ip, + role=UserDomainRole.Roles.MANAGER, + ) + UserDomainRole.objects.get_or_create( + user=self.user, + domain=self.domain_just_nameserver, + role=UserDomainRole.Roles.MANAGER, + ) + UserDomainRole.objects.get_or_create( + user=self.user, domain=self.domain_on_hold, role=UserDomainRole.Roles.MANAGER + ) + UserDomainRole.objects.get_or_create( + user=self.user, domain=self.domain_deleted, role=UserDomainRole.Roles.MANAGER + ) + + def tearDown(self): + try: + UserDomainRole.objects.all().delete() + if hasattr(self.domain, "contacts"): + self.domain.contacts.all().delete() + DomainApplication.objects.all().delete() + DomainInformation.objects.all().delete() + PublicContact.objects.all().delete() + HostIP.objects.all().delete() + Host.objects.all().delete() + Domain.objects.all().delete() + UserDomainRole.objects.all().delete() + except ValueError: # pass if already deleted + pass + super().tearDown() + + +class TestDomainPermissions(TestWithDomainPermissions): + def test_not_logged_in(self): + """Not logged in gets a redirect to Login.""" + for view_name in [ + "domain", + "domain-users", + "domain-users-add", + "domain-dns-nameservers", + "domain-org-name-address", + "domain-authorizing-official", + "domain-your-contact-information", + "domain-security-email", + ]: + with self.subTest(view_name=view_name): + response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id})) + self.assertEqual(response.status_code, 302) + + def test_no_domain_role(self): + """Logged in but no role gets 403 Forbidden.""" + self.client.force_login(self.user) + self.role.delete() # user no longer has a role on this domain + + for view_name in [ + "domain", + "domain-users", + "domain-users-add", + "domain-dns-nameservers", + "domain-org-name-address", + "domain-authorizing-official", + "domain-your-contact-information", + "domain-security-email", + ]: + with self.subTest(view_name=view_name): + with less_console_noise(): + response = self.client.get(reverse(view_name, kwargs={"pk": self.domain.id})) + self.assertEqual(response.status_code, 403) + + def test_domain_pages_blocked_for_on_hold_and_deleted(self): + """Test that the domain pages are blocked for on hold and deleted domains""" + + self.client.force_login(self.user) + for view_name in [ + "domain-users", + "domain-users-add", + "domain-dns", + "domain-dns-nameservers", + "domain-dns-dnssec", + "domain-dns-dnssec-dsdata", + "domain-org-name-address", + "domain-authorizing-official", + "domain-your-contact-information", + "domain-security-email", + ]: + for domain in [ + self.domain_on_hold, + self.domain_deleted, + ]: + with self.subTest(view_name=view_name, domain=domain): + with less_console_noise(): + response = self.client.get(reverse(view_name, kwargs={"pk": domain.id})) + self.assertEqual(response.status_code, 403) + + +class TestDomainOverview(TestWithDomainPermissions, WebTest): + def setUp(self): + super().setUp() + self.app.set_user(self.user.username) + self.client.force_login(self.user) + + +class TestDomainDetail(TestDomainOverview): + @skip("Assertion broke for no reason, why? Need to fix") + def test_domain_detail_link_works(self): + home_page = self.app.get("/") + logger.info(f"This is the value of home_page: {home_page}") + self.assertContains(home_page, "igorville.gov") + # click the "Edit" link + detail_page = home_page.click("Manage", index=0) + self.assertContains(detail_page, "igorville.gov") + self.assertContains(detail_page, "Status") + + def test_unknown_domain_does_not_show_as_expired_on_homepage(self): + """An UNKNOWN domain does not show as expired on the homepage. + It shows as 'DNS needed'""" + # At the time of this test's writing, there are 6 UNKNOWN domains inherited + # from constructors. Let's reset. + Domain.objects.all().delete() + UserDomainRole.objects.all().delete() + self.domain, _ = Domain.objects.get_or_create(name="igorville.gov") + home_page = self.app.get("/") + self.assertNotContains(home_page, "igorville.gov") + self.role, _ = UserDomainRole.objects.get_or_create( + user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER + ) + home_page = self.app.get("/") + self.assertContains(home_page, "igorville.gov") + igorville = Domain.objects.get(name="igorville.gov") + self.assertEquals(igorville.state, Domain.State.UNKNOWN) + self.assertNotContains(home_page, "Expired") + self.assertContains(home_page, "DNS needed") + + def test_unknown_domain_does_not_show_as_expired_on_detail_page(self): + """An UNKNOWN domain does not show as expired on the detail page. + It shows as 'DNS needed'""" + # At the time of this test's writing, there are 6 UNKNOWN domains inherited + # from constructors. Let's reset. + Domain.objects.all().delete() + UserDomainRole.objects.all().delete() + + self.domain, _ = Domain.objects.get_or_create(name="igorville.gov") + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + self.role, _ = UserDomainRole.objects.get_or_create( + user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER + ) + + home_page = self.app.get("/") + self.assertContains(home_page, "igorville.gov") + igorville = Domain.objects.get(name="igorville.gov") + self.assertEquals(igorville.state, Domain.State.UNKNOWN) + detail_page = home_page.click("Manage", index=0) + self.assertNotContains(detail_page, "Expired") + + self.assertContains(detail_page, "DNS needed") + + def test_domain_detail_blocked_for_ineligible_user(self): + """We could easily duplicate this test for all domain management + views, but a single url test should be solid enough since all domain + management pages share the same permissions class""" + self.user.status = User.RESTRICTED + self.user.save() + home_page = self.app.get("/") + self.assertContains(home_page, "igorville.gov") + with less_console_noise(): + response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id})) + self.assertEqual(response.status_code, 403) + + def test_domain_detail_allowed_for_on_hold(self): + """Test that the domain overview page displays for on hold domain""" + home_page = self.app.get("/") + self.assertContains(home_page, "on-hold.gov") + + # View domain overview page + detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_on_hold.id})) + self.assertNotContains(detail_page, "Edit") + + def test_domain_detail_see_just_nameserver(self): + home_page = self.app.get("/") + self.assertContains(home_page, "justnameserver.com") + + # View nameserver on Domain Overview page + detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_just_nameserver.id})) + + self.assertContains(detail_page, "justnameserver.com") + self.assertContains(detail_page, "ns1.justnameserver.com") + self.assertContains(detail_page, "ns2.justnameserver.com") + + def test_domain_detail_see_nameserver_and_ip(self): + home_page = self.app.get("/") + self.assertContains(home_page, "nameserverwithip.gov") + + # View nameserver on Domain Overview page + detail_page = self.app.get(reverse("domain", kwargs={"pk": self.domain_with_ip.id})) + + self.assertContains(detail_page, "nameserverwithip.gov") + + self.assertContains(detail_page, "ns1.nameserverwithip.gov") + self.assertContains(detail_page, "ns2.nameserverwithip.gov") + self.assertContains(detail_page, "ns3.nameserverwithip.gov") + # Splitting IP addresses bc there is odd whitespace and can't strip text + self.assertContains(detail_page, "(1.2.3.4,") + self.assertContains(detail_page, "2.3.4.5)") + + def test_domain_detail_with_no_information_or_application(self): + """Test that domain management page returns 200 and displays error + when no domain information or domain application exist""" + # have to use staff user for this test + staff_user = create_user() + # staff_user.save() + self.client.force_login(staff_user) + + # need to set the analyst_action and analyst_action_location + # in the session to emulate user clicking Manage Domain + # in the admin interface + session = self.client.session + session["analyst_action"] = "foo" + session["analyst_action_location"] = self.domain_no_information.id + session.save() + + detail_page = self.client.get(reverse("domain", kwargs={"pk": self.domain_no_information.id})) + + self.assertContains(detail_page, "noinformation.gov") + self.assertContains(detail_page, "Domain missing domain information") + + +class TestDomainManagers(TestDomainOverview): + def tearDown(self): + """Ensure that the user has its original permissions""" + super().tearDown() + self.user.is_staff = False + self.user.save() + User.objects.all().delete() + + def test_domain_managers(self): + response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id})) + self.assertContains(response, "Domain managers") + + def test_domain_managers_add_link(self): + """Button to get to user add page works.""" + management_page = self.app.get(reverse("domain-users", kwargs={"pk": self.domain.id})) + add_page = management_page.click("Add a domain manager") + self.assertContains(add_page, "Add a domain manager") + + def test_domain_user_add(self): + response = self.client.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + self.assertContains(response, "Add a domain manager") + + def test_domain_user_delete(self): + """Tests if deleting a domain manager works""" + + # Add additional users + dummy_user_1 = User.objects.create( + username="macncheese", + email="cheese@igorville.com", + ) + dummy_user_2 = User.objects.create( + username="pastapizza", + email="pasta@igorville.com", + ) + + role_1 = UserDomainRole.objects.create(user=dummy_user_1, domain=self.domain, role=UserDomainRole.Roles.MANAGER) + role_2 = UserDomainRole.objects.create(user=dummy_user_2, domain=self.domain, role=UserDomainRole.Roles.MANAGER) + + response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id})) + + # Make sure we're on the right page + self.assertContains(response, "Domain managers") + + # Make sure the desired user exists + self.assertContains(response, "cheese@igorville.com") + + # Delete dummy_user_1 + response = self.client.post( + reverse("domain-user-delete", kwargs={"pk": self.domain.id, "user_pk": dummy_user_1.id}), follow=True + ) + + # Grab the displayed messages + messages = list(response.context["messages"]) + self.assertEqual(len(messages), 1) + + # Ensure the error we recieve is in line with what we expect + message = messages[0] + self.assertEqual(message.message, "Removed cheese@igorville.com as a manager for this domain.") + self.assertEqual(message.tags, "success") + + # Check that role_1 deleted in the DB after the post + deleted_user_exists = UserDomainRole.objects.filter(id=role_1.id).exists() + self.assertFalse(deleted_user_exists) + + # Ensure that the current user wasn't deleted + current_user_exists = UserDomainRole.objects.filter(user=self.user.id, domain=self.domain).exists() + self.assertTrue(current_user_exists) + + # Ensure that the other userdomainrole was not deleted + role_2_exists = UserDomainRole.objects.filter(id=role_2.id).exists() + self.assertTrue(role_2_exists) + + def test_domain_user_delete_denied_if_no_permission(self): + """Deleting a domain manager is denied if the user has no permission to do so""" + + # Create a domain object + vip_domain = Domain.objects.create(name="freeman.gov") + + # Add users + dummy_user_1 = User.objects.create( + username="bagel", + email="bagel@igorville.com", + ) + dummy_user_2 = User.objects.create( + username="pastapizza", + email="pasta@igorville.com", + ) + + role_1 = UserDomainRole.objects.create(user=dummy_user_1, domain=vip_domain, role=UserDomainRole.Roles.MANAGER) + role_2 = UserDomainRole.objects.create(user=dummy_user_2, domain=vip_domain, role=UserDomainRole.Roles.MANAGER) + + response = self.client.get(reverse("domain-users", kwargs={"pk": vip_domain.id})) + + # Make sure that we can't access the domain manager page normally + self.assertEqual(response.status_code, 403) + + # Try to delete dummy_user_1 + response = self.client.post( + reverse("domain-user-delete", kwargs={"pk": vip_domain.id, "user_pk": dummy_user_1.id}), follow=True + ) + + # Ensure that we are denied access + self.assertEqual(response.status_code, 403) + + # Ensure that the user wasn't deleted + role_1_exists = UserDomainRole.objects.filter(id=role_1.id).exists() + self.assertTrue(role_1_exists) + + # Ensure that the other userdomainrole was not deleted + role_2_exists = UserDomainRole.objects.filter(id=role_2.id).exists() + self.assertTrue(role_2_exists) + + # Make sure that the current user wasn't deleted for some reason + current_user_exists = UserDomainRole.objects.filter(user=dummy_user_1.id, domain=vip_domain.id).exists() + self.assertTrue(current_user_exists) + + def test_domain_user_delete_denied_if_last_man_standing(self): + """Deleting a domain manager is denied if the user is the only manager""" + + # Create a domain object + vip_domain = Domain.objects.create(name="olive-oil.gov") + + # Add the requesting user as the only manager on the domain + UserDomainRole.objects.create(user=self.user, domain=vip_domain, role=UserDomainRole.Roles.MANAGER) + + response = self.client.get(reverse("domain-users", kwargs={"pk": vip_domain.id})) + + # Make sure that we can still access the domain manager page normally + self.assertContains(response, "Domain managers") + + # Make sure that the logged in user exists + self.assertContains(response, "info@example.com") + + # Try to delete the current user + response = self.client.post( + reverse("domain-user-delete", kwargs={"pk": vip_domain.id, "user_pk": self.user.id}), follow=True + ) + + # Ensure that we are denied access + self.assertEqual(response.status_code, 403) + + # Make sure that the current user wasn't deleted + current_user_exists = UserDomainRole.objects.filter(user=self.user.id, domain=vip_domain.id).exists() + self.assertTrue(current_user_exists) + + def test_domain_user_delete_self_redirects_home(self): + """Tests if deleting yourself redirects to home""" + # Add additional users + dummy_user_1 = User.objects.create( + username="macncheese", + email="cheese@igorville.com", + ) + dummy_user_2 = User.objects.create( + username="pastapizza", + email="pasta@igorville.com", + ) + + role_1 = UserDomainRole.objects.create(user=dummy_user_1, domain=self.domain, role=UserDomainRole.Roles.MANAGER) + role_2 = UserDomainRole.objects.create(user=dummy_user_2, domain=self.domain, role=UserDomainRole.Roles.MANAGER) + + response = self.client.get(reverse("domain-users", kwargs={"pk": self.domain.id})) + + # Make sure we're on the right page + self.assertContains(response, "Domain managers") + + # Make sure the desired user exists + self.assertContains(response, "info@example.com") + + # Make sure more than one UserDomainRole exists on this object + self.assertContains(response, "cheese@igorville.com") + + # Delete the current user + response = self.client.post( + reverse("domain-user-delete", kwargs={"pk": self.domain.id, "user_pk": self.user.id}), follow=True + ) + + # Check if we've been redirected to the home page + self.assertContains(response, "Manage your domains") + + # Grab the displayed messages + messages = list(response.context["messages"]) + self.assertEqual(len(messages), 1) + + # Ensure the error we recieve is in line with what we expect + message = messages[0] + self.assertEqual(message.message, "You are no longer managing the domain igorville.gov.") + self.assertEqual(message.tags, "success") + + # Ensure that the current user was deleted + current_user_exists = UserDomainRole.objects.filter(user=self.user.id, domain=self.domain).exists() + self.assertFalse(current_user_exists) + + # Ensure that the other userdomainroles are not deleted + role_1_exists = UserDomainRole.objects.filter(id=role_1.id).exists() + self.assertTrue(role_1_exists) + + role_2_exists = UserDomainRole.objects.filter(id=role_2.id).exists() + self.assertTrue(role_2_exists) + + @boto3_mocking.patching + def test_domain_user_add_form(self): + """Adding an existing user works.""" + other_user, _ = get_user_model().objects.get_or_create(email="mayor@igorville.gov") + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + add_page.form["email"] = "mayor@igorville.gov" + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + mock_client = MockSESClient() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + success_result = add_page.form.submit() + + self.assertEqual(success_result.status_code, 302) + self.assertEqual( + success_result["Location"], + reverse("domain-users", kwargs={"pk": self.domain.id}), + ) + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + success_page = success_result.follow() + self.assertContains(success_page, "mayor@igorville.gov") + + @boto3_mocking.patching + def test_domain_invitation_created(self): + """Add user on a nonexistent email creates an invitation. + + Adding a non-existent user sends an email as a side-effect, so mock + out the boto3 SES email sending here. + """ + # make sure there is no user with this email + email_address = "mayor@igorville.gov" + User.objects.filter(email=email_address).delete() + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + mock_client = MockSESClient() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + success_result = add_page.form.submit() + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + success_page = success_result.follow() + + self.assertContains(success_page, email_address) + self.assertContains(success_page, "Cancel") # link to cancel invitation + self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists()) + + @boto3_mocking.patching + def test_domain_invitation_created_for_caps_email(self): + """Add user on a nonexistent email with CAPS creates an invitation to lowercase email. + + Adding a non-existent user sends an email as a side-effect, so mock + out the boto3 SES email sending here. + """ + # make sure there is no user with this email + email_address = "mayor@igorville.gov" + caps_email_address = "MAYOR@igorville.gov" + User.objects.filter(email=email_address).delete() + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = caps_email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + mock_client = MockSESClient() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + success_result = add_page.form.submit() + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + success_page = success_result.follow() + + self.assertContains(success_page, email_address) + self.assertContains(success_page, "Cancel") # link to cancel invitation + self.assertTrue(DomainInvitation.objects.filter(email=email_address).exists()) + + @boto3_mocking.patching + def test_domain_invitation_email_sent(self): + """Inviting a non-existent user sends them an email.""" + # make sure there is no user with this email + email_address = "mayor@igorville.gov" + User.objects.filter(email=email_address).delete() + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + add_page.form.submit() + + # check the mock instance to see if `send_email` was called right + mock_client_instance.send_email.assert_called_once_with( + FromEmailAddress=settings.DEFAULT_FROM_EMAIL, + Destination={"ToAddresses": [email_address]}, + Content=ANY, + ) + + @boto3_mocking.patching + def test_domain_invitation_email_has_email_as_requestor_non_existent(self): + """Inviting a non existent user sends them an email, with email as the name.""" + # make sure there is no user with this email + email_address = "mayor@igorville.gov" + User.objects.filter(email=email_address).delete() + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + add_page.form.submit() + + # check the mock instance to see if `send_email` was called right + mock_client_instance.send_email.assert_called_once_with( + FromEmailAddress=settings.DEFAULT_FROM_EMAIL, + Destination={"ToAddresses": [email_address]}, + Content=ANY, + ) + + # Check the arguments passed to send_email method + _, kwargs = mock_client_instance.send_email.call_args + + # Extract the email content, and check that the message is as we expect + email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] + self.assertIn("info@example.com", email_content) + + # Check that the requestors first/last name do not exist + self.assertNotIn("First", email_content) + self.assertNotIn("Last", email_content) + self.assertNotIn("First Last", email_content) + + @boto3_mocking.patching + def test_domain_invitation_email_has_email_as_requestor(self): + """Inviting a user sends them an email, with email as the name.""" + # Create a fake user object + email_address = "mayor@igorville.gov" + User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com") + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + add_page.form.submit() + + # check the mock instance to see if `send_email` was called right + mock_client_instance.send_email.assert_called_once_with( + FromEmailAddress=settings.DEFAULT_FROM_EMAIL, + Destination={"ToAddresses": [email_address]}, + Content=ANY, + ) + + # Check the arguments passed to send_email method + _, kwargs = mock_client_instance.send_email.call_args + + # Extract the email content, and check that the message is as we expect + email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] + self.assertIn("info@example.com", email_content) + + # Check that the requestors first/last name do not exist + self.assertNotIn("First", email_content) + self.assertNotIn("Last", email_content) + self.assertNotIn("First Last", email_content) + + @boto3_mocking.patching + def test_domain_invitation_email_has_email_as_requestor_staff(self): + """Inviting a user sends them an email, with email as the name.""" + # Create a fake user object + email_address = "mayor@igorville.gov" + User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com") + + # Make sure the user is staff + self.user.is_staff = True + self.user.save() + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + add_page.form.submit() + + # check the mock instance to see if `send_email` was called right + mock_client_instance.send_email.assert_called_once_with( + FromEmailAddress=settings.DEFAULT_FROM_EMAIL, + Destination={"ToAddresses": [email_address]}, + Content=ANY, + ) + + # Check the arguments passed to send_email method + _, kwargs = mock_client_instance.send_email.call_args + + # Extract the email content, and check that the message is as we expect + email_content = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] + self.assertIn("help@get.gov", email_content) + + # Check that the requestors first/last name do not exist + self.assertNotIn("First", email_content) + self.assertNotIn("Last", email_content) + self.assertNotIn("First Last", email_content) + + @boto3_mocking.patching + def test_domain_invitation_email_displays_error_non_existent(self): + """Inviting a non existent user sends them an email, with email as the name.""" + # make sure there is no user with this email + email_address = "mayor@igorville.gov" + User.objects.filter(email=email_address).delete() + + # Give the user who is sending the email an invalid email address + self.user.email = "" + self.user.save() + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + mock_client = MagicMock() + mock_error_message = MagicMock() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with patch("django.contrib.messages.error") as mock_error_message: + with less_console_noise(): + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + add_page.form.submit().follow() + + expected_message_content = "Can't send invitation email. No email is associated with your account." + + # Grab the message content + returned_error_message = mock_error_message.call_args[0][1] + + # Check that the message content is what we expect + self.assertEqual(expected_message_content, returned_error_message) + + @boto3_mocking.patching + def test_domain_invitation_email_displays_error(self): + """When the requesting user has no email, an error is displayed""" + # make sure there is no user with this email + # Create a fake user object + email_address = "mayor@igorville.gov" + User.objects.get_or_create(email=email_address, username="fakeuser@fakeymail.com") + + # Give the user who is sending the email an invalid email address + self.user.email = "" + self.user.save() + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + mock_client = MagicMock() + + mock_error_message = MagicMock() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with patch("django.contrib.messages.error") as mock_error_message: + with less_console_noise(): + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + add_page.form.submit().follow() + + expected_message_content = "Can't send invitation email. No email is associated with your account." + + # Grab the message content + returned_error_message = mock_error_message.call_args[0][1] + + # Check that the message content is what we expect + self.assertEqual(expected_message_content, returned_error_message) + + def test_domain_invitation_cancel(self): + """Posting to the delete view deletes an invitation.""" + email_address = "mayor@igorville.gov" + invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address) + mock_client = MockSESClient() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id})) + mock_client.EMAILS_SENT.clear() + with self.assertRaises(DomainInvitation.DoesNotExist): + DomainInvitation.objects.get(id=invitation.id) + + def test_domain_invitation_cancel_no_permissions(self): + """Posting to the delete view as a different user should fail.""" + email_address = "mayor@igorville.gov" + invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address) + + other_user = User() + other_user.save() + self.client.force_login(other_user) + mock_client = MagicMock() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): # permission denied makes console errors + result = self.client.post(reverse("invitation-delete", kwargs={"pk": invitation.id})) + + self.assertEqual(result.status_code, 403) + + @boto3_mocking.patching + def test_domain_invitation_flow(self): + """Send an invitation to a new user, log in and load the dashboard.""" + email_address = "mayor@igorville.gov" + User.objects.filter(email=email_address).delete() + + add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) + + self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain) + + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + add_page.form["email"] = email_address + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + + mock_client = MagicMock() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): + add_page.form.submit() + + # user was invited, create them + new_user = User.objects.create(username=email_address, email=email_address) + # log them in to `self.app` + self.app.set_user(new_user.username) + # and manually call the on each login callback + new_user.on_each_login() + + # Now load the home page and make sure our domain appears there + home_page = self.app.get(reverse("home")) + self.assertContains(home_page, self.domain.name) + + +class TestDomainNameservers(TestDomainOverview): + def test_domain_nameservers(self): + """Can load domain's nameservers page.""" + page = self.client.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + self.assertContains(page, "DNS name servers") + + def test_domain_nameservers_form_submit_one_nameserver(self): + """Nameserver form submitted with one nameserver throws error. + + Uses self.app WebTest because we need to interact with forms. + """ + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form with only one nameserver, should error + # regarding required fields + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the required field. form requires a minimum of 2 name servers + self.assertContains( + result, + "At least two name servers are required.", + count=2, + status_code=200, + ) + + def test_domain_nameservers_form_submit_subdomain_missing_ip(self): + """Nameserver form catches missing ip error on subdomain. + + Uses self.app WebTest because we need to interact with forms. + """ + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form without two hosts, both subdomains, + # only one has ips + nameservers_page.form["form-1-server"] = "ns2.igorville.gov" + + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the required field. subdomain missing an ip + self.assertContains( + result, + str(NameserverError(code=NameserverErrorCodes.MISSING_IP)), + count=2, + status_code=200, + ) + + def test_domain_nameservers_form_submit_missing_host(self): + """Nameserver form catches error when host is missing. + + Uses self.app WebTest because we need to interact with forms. + """ + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form without two hosts, both subdomains, + # only one has ips + nameservers_page.form["form-1-ip"] = "127.0.0.1" + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the required field. nameserver has ip but missing host + self.assertContains( + result, + str(NameserverError(code=NameserverErrorCodes.MISSING_HOST)), + count=2, + status_code=200, + ) + + def test_domain_nameservers_form_submit_duplicate_host(self): + """Nameserver form catches error when host is duplicated. + + Uses self.app WebTest because we need to interact with forms. + """ + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form with duplicate host names of fake.host.com + nameservers_page.form["form-0-ip"] = "" + nameservers_page.form["form-1-server"] = "fake.host.com" + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the required field. remove duplicate entry + self.assertContains( + result, + str(NameserverError(code=NameserverErrorCodes.DUPLICATE_HOST)), + count=2, + status_code=200, + ) + + def test_domain_nameservers_form_submit_whitespace(self): + """Nameserver form removes whitespace from ip. + + Uses self.app WebTest because we need to interact with forms. + """ + nameserver1 = "ns1.igorville.gov" + nameserver2 = "ns2.igorville.gov" + valid_ip = "1.1. 1.1" + # initial nameservers page has one server with two ips + # have to throw an error in order to test that the whitespace has been stripped from ip + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form without one host and an ip with whitespace + nameservers_page.form["form-0-server"] = nameserver1 + nameservers_page.form["form-1-ip"] = valid_ip + nameservers_page.form["form-1-server"] = nameserver2 + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an ip address which has been stripped of whitespace, + # response should be a 302 to success page + self.assertEqual(result.status_code, 302) + self.assertEqual( + result["Location"], + reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}), + ) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + page = result.follow() + # in the event of a generic nameserver error from registry error, there will be a 302 + # with an error message displayed, so need to follow 302 and test for success message + self.assertContains(page, "The name servers for this domain have been updated") + + def test_domain_nameservers_form_submit_glue_record_not_allowed(self): + """Nameserver form catches error when IP is present + but host not subdomain. + + Uses self.app WebTest because we need to interact with forms. + """ + nameserver1 = "ns1.igorville.gov" + nameserver2 = "ns2.igorville.com" + valid_ip = "127.0.0.1" + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form without two hosts, both subdomains, + # only one has ips + nameservers_page.form["form-0-server"] = nameserver1 + nameservers_page.form["form-1-server"] = nameserver2 + nameservers_page.form["form-1-ip"] = valid_ip + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the required field. nameserver has ip but missing host + self.assertContains( + result, + str(NameserverError(code=NameserverErrorCodes.GLUE_RECORD_NOT_ALLOWED)), + count=2, + status_code=200, + ) + + def test_domain_nameservers_form_submit_invalid_ip(self): + """Nameserver form catches invalid IP on submission. + + Uses self.app WebTest because we need to interact with forms. + """ + nameserver = "ns2.igorville.gov" + invalid_ip = "123" + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form without two hosts, both subdomains, + # only one has ips + nameservers_page.form["form-1-server"] = nameserver + nameservers_page.form["form-1-ip"] = invalid_ip + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the required field. nameserver has ip but missing host + self.assertContains( + result, + str(NameserverError(code=NameserverErrorCodes.INVALID_IP, nameserver=nameserver)), + count=2, + status_code=200, + ) + + def test_domain_nameservers_form_submit_invalid_host(self): + """Nameserver form catches invalid host on submission. + + Uses self.app WebTest because we need to interact with forms. + """ + nameserver = "invalid-nameserver.gov" + valid_ip = "123.2.45.111" + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form without two hosts, both subdomains, + # only one has ips + nameservers_page.form["form-1-server"] = nameserver + nameservers_page.form["form-1-ip"] = valid_ip + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the required field. nameserver has invalid host + self.assertContains( + result, + str(NameserverError(code=NameserverErrorCodes.INVALID_HOST, nameserver=nameserver)), + count=2, + status_code=200, + ) + + def test_domain_nameservers_form_submits_successfully(self): + """Nameserver form submits successfully with valid input. + + Uses self.app WebTest because we need to interact with forms. + """ + nameserver1 = "ns1.igorville.gov" + nameserver2 = "ns2.igorville.gov" + valid_ip = "127.0.0.1" + # initial nameservers page has one server with two ips + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # attempt to submit the form without two hosts, both subdomains, + # only one has ips + nameservers_page.form["form-0-server"] = nameserver1 + nameservers_page.form["form-1-server"] = nameserver2 + nameservers_page.form["form-1-ip"] = valid_ip + with less_console_noise(): # swallow log warning message + result = nameservers_page.form.submit() + # form submission was a successful post, response should be a 302 + self.assertEqual(result.status_code, 302) + self.assertEqual( + result["Location"], + reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id}), + ) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + page = result.follow() + self.assertContains(page, "The name servers for this domain have been updated") + + def test_domain_nameservers_form_invalid(self): + """Nameserver form does not submit with invalid data. + + Uses self.app WebTest because we need to interact with forms. + """ + nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # first two nameservers are required, so if we empty one out we should + # get a form error + nameservers_page.form["form-0-server"] = "" + with less_console_noise(): # swallow logged warning message + result = nameservers_page.form.submit() + # form submission was a post with an error, response should be a 200 + # error text appears four times, twice at the top of the page, + # once around each required field. + self.assertContains( + result, + "At least two name servers are required.", + count=4, + status_code=200, + ) + + +class TestDomainAuthorizingOfficial(TestDomainOverview): + def test_domain_authorizing_official(self): + """Can load domain's authorizing official page.""" + page = self.client.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) + # once on the sidebar, once in the title + self.assertContains(page, "Authorizing official", count=2) + + def test_domain_authorizing_official_content(self): + """Authorizing official information appears on the page.""" + self.domain_information.authorizing_official = Contact(first_name="Testy") + self.domain_information.authorizing_official.save() + self.domain_information.save() + page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) + self.assertContains(page, "Testy") + + def test_domain_edit_authorizing_official_in_place(self): + """When editing an authorizing official for domain information and AO is not + joined to any other objects""" + self.domain_information.authorizing_official = Contact( + first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov" + ) + self.domain_information.authorizing_official.save() + self.domain_information.save() + ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_form = ao_page.forms[0] + self.assertEqual(ao_form["first_name"].value, "Testy") + ao_form["first_name"] = "Testy2" + # ao_pk is the initial pk of the authorizing official. set it before update + # to be able to verify after update that the same contact object is in place + ao_pk = self.domain_information.authorizing_official.id + ao_form.submit() + + # refresh domain information + self.domain_information.refresh_from_db() + self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name) + self.assertEqual(ao_pk, self.domain_information.authorizing_official.id) + + def test_domain_edit_authorizing_official_creates_new(self): + """When editing an authorizing official for domain information and AO IS + joined to another object""" + # set AO and Other Contact to the same Contact object + self.domain_information.authorizing_official = Contact( + first_name="Testy", last_name="Tester", title="CIO", email="nobody@igorville.gov" + ) + self.domain_information.authorizing_official.save() + self.domain_information.save() + self.domain_information.other_contacts.add(self.domain_information.authorizing_official) + self.domain_information.save() + # load the Authorizing Official in the web form + ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + ao_form = ao_page.forms[0] + # verify the first name is "Testy" and then change it to "Testy2" + self.assertEqual(ao_form["first_name"].value, "Testy") + ao_form["first_name"] = "Testy2" + # ao_pk is the initial pk of the authorizing official. set it before update + # to be able to verify after update that the same contact object is in place + ao_pk = self.domain_information.authorizing_official.id + ao_form.submit() + + # refresh domain information + self.domain_information.refresh_from_db() + # assert that AO information is updated, and that the AO is a new Contact + self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name) + self.assertNotEqual(ao_pk, self.domain_information.authorizing_official.id) + # assert that the Other Contact information is not updated and that the Other Contact + # is the original Contact object + other_contact = self.domain_information.other_contacts.all()[0] + self.assertEqual("Testy", other_contact.first_name) + self.assertEqual(ao_pk, other_contact.id) + + +class TestDomainOrganization(TestDomainOverview): + def test_domain_org_name_address(self): + """Can load domain's org name and mailing address page.""" + page = self.client.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id})) + # once on the sidebar, once in the page title, once as H1 + self.assertContains(page, "Organization name and mailing address", count=3) + + def test_domain_org_name_address_content(self): + """Org name and address information appears on the page.""" + self.domain_information.organization_name = "Town of Igorville" + self.domain_information.save() + page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id})) + self.assertContains(page, "Town of Igorville") + + def test_domain_org_name_address_form(self): + """Submitting changes works on the org name address page.""" + self.domain_information.organization_name = "Town of Igorville" + self.domain_information.save() + org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + + org_name_page.form["organization_name"] = "Not igorville" + org_name_page.form["city"] = "Faketown" + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + success_result_page = org_name_page.form.submit() + self.assertEqual(success_result_page.status_code, 200) + + self.assertContains(success_result_page, "Not igorville") + self.assertContains(success_result_page, "Faketown") + + +class TestDomainContactInformation(TestDomainOverview): + def test_domain_your_contact_information(self): + """Can load domain's your contact information page.""" + page = self.client.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id})) + self.assertContains(page, "Your contact information") + + def test_domain_your_contact_information_content(self): + """Logged-in user's contact information appears on the page.""" + self.user.contact.first_name = "Testy" + self.user.contact.save() + page = self.app.get(reverse("domain-your-contact-information", kwargs={"pk": self.domain.id})) + self.assertContains(page, "Testy") + + +class TestDomainSecurityEmail(TestDomainOverview): + def test_domain_security_email_existing_security_contact(self): + """Can load domain's security email page.""" + self.mockSendPatch = patch("registrar.models.domain.registry.send") + self.mockedSendFunction = self.mockSendPatch.start() + self.mockedSendFunction.side_effect = self.mockSend + + domain_contact, _ = Domain.objects.get_or_create(name="freeman.gov") + # Add current user to this domain + _ = UserDomainRole(user=self.user, domain=domain_contact, role="admin").save() + page = self.client.get(reverse("domain-security-email", kwargs={"pk": domain_contact.id})) + + # Loads correctly + self.assertContains(page, "Security email") + self.assertContains(page, "security@mail.gov") + self.mockSendPatch.stop() + + def test_domain_security_email_no_security_contact(self): + """Loads a domain with no defined security email. + We should not show the default.""" + self.mockSendPatch = patch("registrar.models.domain.registry.send") + self.mockedSendFunction = self.mockSendPatch.start() + self.mockedSendFunction.side_effect = self.mockSend + + page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id})) + + # Loads correctly + self.assertContains(page, "Security email") + self.assertNotContains(page, "dotgov@cisa.dhs.gov") + self.mockSendPatch.stop() + + def test_domain_security_email(self): + """Can load domain's security email page.""" + page = self.client.get(reverse("domain-security-email", kwargs={"pk": self.domain.id})) + self.assertContains(page, "Security email") + + def test_domain_security_email_form(self): + """Adding a security email works. + Uses self.app WebTest because we need to interact with forms. + """ + security_email_page = self.app.get(reverse("domain-security-email", kwargs={"pk": self.domain.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + security_email_page.form["security_email"] = "mayor@igorville.gov" + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + mock_client = MagicMock() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + with less_console_noise(): # swallow log warning message + result = security_email_page.form.submit() + self.assertEqual(result.status_code, 302) + self.assertEqual( + result["Location"], + reverse("domain-security-email", kwargs={"pk": self.domain.id}), + ) + + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + success_page = result.follow() + self.assertContains(success_page, "The security email for this domain has been updated") + + def test_security_email_form_messages(self): + """ + Test against the success and error messages that are defined in the view + """ + p = "adminpass" + self.client.login(username="superuser", password=p) + + form_data_registry_error = { + "security_email": "test@failCreate.gov", + } + + form_data_contact_error = { + "security_email": "test@contactError.gov", + } + + form_data_success = { + "security_email": "test@something.gov", + } + + test_cases = [ + ( + "RegistryError", + form_data_registry_error, + str(GenericError(code=GenericErrorCodes.CANNOT_CONTACT_REGISTRY)), + ), + ( + "ContactError", + form_data_contact_error, + str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)), + ), + ( + "RegistrySuccess", + form_data_success, + "The security email for this domain has been updated.", + ), + # Add more test cases with different scenarios here + ] + + for test_name, data, expected_message in test_cases: + response = self.client.post( + reverse("domain-security-email", kwargs={"pk": self.domain.id}), + data=data, + follow=True, + ) + + # Check the response status code, content, or any other relevant assertions + self.assertEqual(response.status_code, 200) + + # Check if the expected message tag is set + if test_name == "RegistryError" or test_name == "ContactError": + message_tag = "error" + elif test_name == "RegistrySuccess": + message_tag = "success" + else: + # Handle other cases if needed + message_tag = "info" # Change to the appropriate default + + # Check the message tag + messages = list(response.context["messages"]) + self.assertEqual(len(messages), 1) + message = messages[0] + self.assertEqual(message.tags, message_tag) + self.assertEqual(message.message.strip(), expected_message.strip()) + + def test_domain_overview_blocked_for_ineligible_user(self): + """We could easily duplicate this test for all domain management + views, but a single url test should be solid enough since all domain + management pages share the same permissions class""" + self.user.status = User.RESTRICTED + self.user.save() + home_page = self.app.get("/") + self.assertContains(home_page, "igorville.gov") + with less_console_noise(): + response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id})) + self.assertEqual(response.status_code, 403) + + +class TestDomainDNSSEC(TestDomainOverview): + + """MockEPPLib is already inherited.""" + + def test_dnssec_page_refreshes_enable_button(self): + """DNSSEC overview page loads when domain has no DNSSEC data + and shows a 'Enable DNSSEC' button.""" + + page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id})) + self.assertContains(page, "Enable DNSSEC") + + def test_dnssec_page_loads_with_data_in_domain(self): + """DNSSEC overview page loads when domain has DNSSEC data + and the template contains a button to disable DNSSEC.""" + + page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id})) + self.assertContains(page, "Disable DNSSEC") + + # Prepare the data for the POST request + post_data = { + "disable_dnssec": "Disable DNSSEC", + } + updated_page = self.client.post( + reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}), + post_data, + follow=True, + ) + + self.assertEqual(updated_page.status_code, 200) + + self.assertContains(updated_page, "Enable DNSSEC") + + def test_ds_form_loads_with_no_domain_data(self): + """DNSSEC Add DS data page loads when there is no + domain DNSSEC data and shows a button to Add new record""" + + page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id})) + self.assertContains(page, "You have no DS data added") + self.assertContains(page, "Add new record") + + def test_ds_form_loads_with_ds_data(self): + """DNSSEC Add DS data page loads when there is + domain DNSSEC DS data and shows the data""" + + page = self.client.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + self.assertContains(page, "DS data record 1") + + def test_ds_data_form_modal(self): + """When user clicks on save, a modal pops up.""" + add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + # Assert that a hidden trigger for the modal does not exist. + # This hidden trigger will pop on the page when certain condition are met: + # 1) Initial form contained DS data, 2) All data is deleted and form is + # submitted. + self.assertNotContains(add_data_page, "Trigger Disable DNSSEC Modal") + # Simulate a delete all data + form_data = {} + response = self.client.post( + reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}), + data=form_data, + ) + self.assertEqual(response.status_code, 200) # Adjust status code as needed + # Now check to see whether the JS trigger for the modal is present on the page + self.assertContains(response, "Trigger Disable DNSSEC Modal") + + def test_ds_data_form_submits(self): + """DS data form submits successfully + + Uses self.app WebTest because we need to interact with forms. + """ + add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + with less_console_noise(): # swallow log warning message + result = add_data_page.forms[0].submit() + # form submission was a post, response should be a redirect + self.assertEqual(result.status_code, 302) + self.assertEqual( + result["Location"], + reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}), + ) + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + page = result.follow() + self.assertContains(page, "The DS data records for this domain have been updated.") + + def test_ds_data_form_invalid(self): + """DS data form errors with invalid data (missing required fields) + + Uses self.app WebTest because we need to interact with forms. + """ + add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # all four form fields are required, so will test with each blank + add_data_page.forms[0]["form-0-key_tag"] = "" + add_data_page.forms[0]["form-0-algorithm"] = "" + add_data_page.forms[0]["form-0-digest_type"] = "" + add_data_page.forms[0]["form-0-digest"] = "" + with less_console_noise(): # swallow logged warning message + result = add_data_page.forms[0].submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the field. + self.assertContains(result, "Key tag is required", count=2, status_code=200) + self.assertContains(result, "Algorithm is required", count=2, status_code=200) + self.assertContains(result, "Digest type is required", count=2, status_code=200) + self.assertContains(result, "Digest is required", count=2, status_code=200) + + def test_ds_data_form_invalid_keytag(self): + """DS data form errors with invalid data (key tag too large) + + Uses self.app WebTest because we need to interact with forms. + """ + add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # first two nameservers are required, so if we empty one out we should + # get a form error + add_data_page.forms[0]["form-0-key_tag"] = "65536" # > 65535 + add_data_page.forms[0]["form-0-algorithm"] = "" + add_data_page.forms[0]["form-0-digest_type"] = "" + add_data_page.forms[0]["form-0-digest"] = "" + with less_console_noise(): # swallow logged warning message + result = add_data_page.forms[0].submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the field. + self.assertContains( + result, str(DsDataError(code=DsDataErrorCodes.INVALID_KEYTAG_SIZE)), count=2, status_code=200 + ) + + def test_ds_data_form_invalid_digest_chars(self): + """DS data form errors with invalid data (digest contains non hexadecimal chars) + + Uses self.app WebTest because we need to interact with forms. + """ + add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # first two nameservers are required, so if we empty one out we should + # get a form error + add_data_page.forms[0]["form-0-key_tag"] = "1234" + add_data_page.forms[0]["form-0-algorithm"] = "3" + add_data_page.forms[0]["form-0-digest_type"] = "1" + add_data_page.forms[0]["form-0-digest"] = "GG1234" + with less_console_noise(): # swallow logged warning message + result = add_data_page.forms[0].submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the field. + self.assertContains( + result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_CHARS)), count=2, status_code=200 + ) + + def test_ds_data_form_invalid_digest_sha1(self): + """DS data form errors with invalid data (digest is invalid sha-1) + + Uses self.app WebTest because we need to interact with forms. + """ + add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # first two nameservers are required, so if we empty one out we should + # get a form error + add_data_page.forms[0]["form-0-key_tag"] = "1234" + add_data_page.forms[0]["form-0-algorithm"] = "3" + add_data_page.forms[0]["form-0-digest_type"] = "1" # SHA-1 + add_data_page.forms[0]["form-0-digest"] = "A123" + with less_console_noise(): # swallow logged warning message + result = add_data_page.forms[0].submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the field. + self.assertContains( + result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA1)), count=2, status_code=200 + ) + + def test_ds_data_form_invalid_digest_sha256(self): + """DS data form errors with invalid data (digest is invalid sha-256) + + Uses self.app WebTest because we need to interact with forms. + """ + add_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})) + session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] + self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) + # first two nameservers are required, so if we empty one out we should + # get a form error + add_data_page.forms[0]["form-0-key_tag"] = "1234" + add_data_page.forms[0]["form-0-algorithm"] = "3" + add_data_page.forms[0]["form-0-digest_type"] = "2" # SHA-256 + add_data_page.forms[0]["form-0-digest"] = "GG1234" + with less_console_noise(): # swallow logged warning message + result = add_data_page.forms[0].submit() + # form submission was a post with an error, response should be a 200 + # error text appears twice, once at the top of the page, once around + # the field. + self.assertContains( + result, str(DsDataError(code=DsDataErrorCodes.INVALID_DIGEST_SHA256)), count=2, status_code=200 + )