Display federal and election questions conditionally

This commit is contained in:
Neil Martinsen-Burrell 2022-11-23 13:25:11 -06:00
parent e746cb2adc
commit 3fe00d1980
No known key found for this signature in database
GPG key ID: 6A3C818CC10D0184
4 changed files with 125 additions and 50 deletions

View file

@ -10,12 +10,14 @@ from django.urls import include, path
from django.views.generic import RedirectView from django.views.generic import RedirectView
from registrar.views import health, index, profile, whoami from registrar.views import health, index, profile, whoami
from registrar.forms import ApplicationWizard from registrar.forms import ApplicationWizard, WIZARD_CONDITIONS
from api.views import available from api.views import available
APPLICATION_URL_NAME = "application_step" APPLICATION_URL_NAME = "application_step"
application_wizard = ApplicationWizard.as_view( application_wizard = ApplicationWizard.as_view(
url_name=APPLICATION_URL_NAME, done_step_name="finished" url_name=APPLICATION_URL_NAME,
done_step_name="finished",
condition_dict=WIZARD_CONDITIONS,
) )
urlpatterns = [ urlpatterns = [

View file

@ -1,4 +1,4 @@
from .edit_profile import EditProfileForm from .edit_profile import EditProfileForm
from .application_wizard import ApplicationWizard from .application_wizard import ApplicationWizard, WIZARD_CONDITIONS
__all__ = ["EditProfileForm", "ApplicationWizard"] __all__ = ["EditProfileForm", "ApplicationWizard", "WIZARD_CONDITIONS"]

View file

@ -1,5 +1,7 @@
"""Forms Wizard for creating a new domain application.""" """Forms Wizard for creating a new domain application."""
from __future__ import annotations # allows forward references in annotations
import logging import logging
from django import forms from django import forms
@ -52,19 +54,6 @@ class OrganizationTypeForm(RegistrarForm):
], ],
widget=forms.RadioSelect, widget=forms.RadioSelect,
) )
federal_type = forms.ChoiceField(
required=False,
choices=DomainApplication.BRANCH_CHOICES,
widget=forms.RadioSelect,
)
is_election_board = forms.ChoiceField(
required=False,
choices=[
("Yes", "Yes"),
("No", "No"),
],
widget=forms.RadioSelect(attrs={"class": "usa-radio__input"}),
)
class OrganizationFederalForm(RegistrarForm): class OrganizationFederalForm(RegistrarForm):
@ -82,7 +71,8 @@ class OrganizationElectionForm(RegistrarForm):
(True, "Yes"), (True, "Yes"),
(False, "No"), (False, "No"),
], ],
) ),
required=False
) )
@ -297,6 +287,41 @@ TITLES = {
} }
def _get_organization_type(wizard: ApplicationWizard) -> Union[str, None]:
"""Extract the answer to the organization type question from the wizard."""
# using the step data from the storage is a workaround for this
# bug in django-formtools version 2.4
# https://github.com/jazzband/django-formtools/issues/220
type_data = wizard.storage.get_step_data("organization_type")
if type_data:
return type_data.get("organization_type-organization_type")
return None
def show_organization_federal(wizard: ApplicationWizard) -> Bool:
"""Show this step if the answer to the first question was "federal"."""
return _get_organization_type(wizard) == "Federal"
def show_organization_election(wizard: ApplicationWizard) -> Bool:
"""Show this step if the answer to the first question implies it.
This shows for answers that aren't "Federal" or "Interstate".
"""
type_answer = _get_organization_type(wizard)
if type_answer and type_answer not in ("Federal", "Interstate"):
return True
return False
# We can use a dictionary with step names and callables that return booleans
# to show or hide particular steps based on the state of the process.
WIZARD_CONDITIONS = {
"organization_federal": show_organization_federal,
"organization_election": show_organization_election,
}
class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView): class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView):
"""Multi-page form ("wizard") for new domain applications. """Multi-page form ("wizard") for new domain applications.
@ -330,13 +355,17 @@ class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView):
organization_type_data = form_dict["organization_type"].cleaned_data organization_type_data = form_dict["organization_type"].cleaned_data
application.organization_type = organization_type_data["organization_type"] application.organization_type = organization_type_data["organization_type"]
# federal branch information # federal branch information may not exist
federal_branch_data = form_dict["organization_federal"].cleaned_data federal_branch_data = form_dict.get("organization_federal")
application.federal_branch = federal_branch_data["federal_type"] if federal_branch_data is not None:
federal_branch_data = federal_branch_data.cleaned_data
application.federal_branch = federal_branch_data["federal_type"]
# election board information # election board information may not exist.
election_board_data = form_dict["organization_election"].cleaned_data election_board_data = form_dict.get("organization_election")
application.is_election_office = election_board_data["is_election_board"] if election_board_data is not None:
election_board_data = election_board_data.cleaned_data
application.is_election_office = election_board_data["is_election_board"]
# contact information # contact information
contact_data = form_dict["organization_contact"].cleaned_data contact_data = form_dict["organization_contact"].cleaned_data

View file

@ -6,6 +6,7 @@ from django.contrib.auth import get_user_model
from django_webtest import WebTest # type: ignore from django_webtest import WebTest # type: ignore
from registrar.models import DomainApplication from registrar.models import DomainApplication
from registrar.forms.application_wizard import TITLES
class TestViews(TestCase): class TestViews(TestCase):
@ -96,15 +97,6 @@ class FormTests(TestWithUser, WebTest):
result = page.form.submit() result = page.form.submit()
self.assertIn("What kind of government organization do you represent?", result) self.assertIn("What kind of government organization do you represent?", result)
def test_application_form_organization(self):
# 302 redirect to the first form
page = self.app.get(reverse("application")).follow()
form = page.form
form["organization_type-organization_type"] = "Federal"
result = page.form.submit().follow()
# Got the next form page
self.assertContains(result, "contact information")
def test_application_form_submission(self): def test_application_form_submission(self):
"""Can fill out the entire form and submit. """Can fill out the entire form and submit.
As we add additional form pages, we need to include them here to make As we add additional form pages, we need to include them here to make
@ -130,10 +122,10 @@ class FormTests(TestWithUser, WebTest):
self.assertEquals(type_result.status_code, 302) self.assertEquals(type_result.status_code, 302)
self.assertEquals(type_result["Location"], "/register/organization_federal/") self.assertEquals(type_result["Location"], "/register/organization_federal/")
# TODO: In the future this should be conditionally dispalyed based on org type
# ---- FEDERAL BRANCH PAGE ---- # ---- FEDERAL BRANCH PAGE ----
# Follow the redirect to the next form 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_page = type_result.follow()
federal_form = federal_page.form federal_form = federal_page.form
federal_form["organization_federal-federal_type"] = "Executive" federal_form["organization_federal-federal_type"] = "Executive"
@ -144,26 +136,12 @@ class FormTests(TestWithUser, WebTest):
self.assertEquals(federal_result.status_code, 302) self.assertEquals(federal_result.status_code, 302)
self.assertEquals( self.assertEquals(
federal_result["Location"], "/register/organization_election/" federal_result["Location"], "/register/organization_contact/"
)
# ---- ELECTION BOARD BRANCH PAGE ----
# Follow the redirect to the next form page
election_page = federal_result.follow()
election_form = election_page.form
election_form["organization_election-is_election_board"] = True
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
election_result = election_form.submit()
self.assertEquals(election_result.status_code, 302)
self.assertEquals(
election_result["Location"], "/register/organization_contact/"
) )
# ---- ORG CONTACT PAGE ---- # ---- ORG CONTACT PAGE ----
# Follow the redirect to the next form page # Follow the redirect to the next form page
org_contact_page = election_result.follow() org_contact_page = federal_result.follow()
org_contact_form = org_contact_page.form org_contact_form = org_contact_page.form
org_contact_form["organization_contact-organization_name"] = "Testorg" org_contact_form["organization_contact-organization_name"] = "Testorg"
org_contact_form["organization_contact-address_line1"] = "address 1" org_contact_form["organization_contact-address_line1"] = "address 1"
@ -322,3 +300,69 @@ class FormTests(TestWithUser, WebTest):
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
final_result = review_result.follow() final_result = review_result.follow()
self.assertContains(final_result, "Thank you for your domain request") self.assertContains(final_result, "Thank you for your domain request")
def test_application_form_conditional_federal(self):
"""Federal branch question is shown for federal organizations."""
type_page = self.app.get(reverse("application")).follow()
# 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]
# ---- TYPE PAGE ----
# the conditional step titles shouldn't appear initially
self.assertNotContains(type_page, TITLES["organization_federal"])
self.assertNotContains(type_page, TITLES["organization_election"])
type_form = type_page.form
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.assertEquals(type_result.status_code, 302)
self.assertEquals(type_result["Location"], "/register/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, TITLES["organization_federal"])
self.assertNotContains(federal_page, TITLES["organization_election"])
def test_application_form_conditional_elections(self):
"""Election question is shown for other organizations."""
type_page = self.app.get(reverse("application")).follow()
# 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]
# ---- TYPE PAGE ----
# the conditional step titles shouldn't appear initially
self.assertNotContains(type_page, TITLES["organization_federal"])
self.assertNotContains(type_page, TITLES["organization_election"])
type_form = type_page.form
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 federal branch
# question
self.assertEquals(type_result.status_code, 302)
self.assertEquals(type_result["Location"], "/register/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, TITLES["organization_election"])
self.assertNotContains(election_page, TITLES["organization_federal"])