diff --git a/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss b/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss index dbb4f4ef7..ff2614fb8 100644 --- a/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss +++ b/src/registrar/assets/sass/_theme/_uswds-theme-custom-styles.scss @@ -426,3 +426,9 @@ abbr[title] { border-bottom: none; text-decoration: none; } + +.usa-textarea { + @include at-media('tablet') { + height: units('mobile'); + } +} \ No newline at end of file diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index ce3ef6e9f..333c9c6b1 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -5,7 +5,7 @@ from typing import Callable from phonenumber_field.formfields import PhoneNumberField # type: ignore from django import forms -from django.core.validators import RegexValidator +from django.core.validators import RegexValidator, MaxLengthValidator from django.urls import reverse from django.utils.safestring import mark_safe @@ -315,6 +315,12 @@ class TypeOfWorkForm(RegistrarForm): # label has to end in a space to get the label_suffix to show label="What type of work does your organization do? ", widget=forms.Textarea(), + validators=[ + MaxLengthValidator( + 1000, + message="Response must be less than 1000 characters.", + ) + ], error_messages={"required": "Enter the type of work your organization does."}, ) @@ -327,6 +333,12 @@ class TypeOfWorkForm(RegistrarForm): " support your claims. " ), widget=forms.Textarea(), + validators=[ + MaxLengthValidator( + 1000, + message="Response must be less than 1000 characters.", + ) + ], error_messages={ "required": ( "Describe how your organization is independent of a state government." @@ -554,6 +566,12 @@ class PurposeForm(RegistrarForm): purpose = forms.CharField( label="Purpose", widget=forms.Textarea(), + validators=[ + MaxLengthValidator( + 1000, + message="Response must be less than 1000 characters.", + ) + ], error_messages={ "required": "Describe how you'll use the .gov domain you’re requesting." }, @@ -696,6 +714,12 @@ class AnythingElseForm(RegistrarForm): required=False, label="Anything else we should know?", widget=forms.Textarea(), + validators=[ + MaxLengthValidator( + 1000, + message="Response must be less than 1000 characters.", + ) + ], ) diff --git a/src/registrar/templates/application_anything_else.html b/src/registrar/templates/application_anything_else.html index 306b2fb0b..1c598db9a 100644 --- a/src/registrar/templates/application_anything_else.html +++ b/src/registrar/templates/application_anything_else.html @@ -11,7 +11,7 @@ {% block form_fields %} - {% with add_label_class="usa-sr-only" attr_maxlength=500 %} + {% with add_label_class="usa-sr-only" attr_maxlength=1000 %} {% input_with_errors forms.0.anything_else %} {% endwith %} {% endblock %} diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/application_purpose.html index 54a68998c..a28dc27b3 100644 --- a/src/registrar/templates/application_purpose.html +++ b/src/registrar/templates/application_purpose.html @@ -19,7 +19,7 @@ Read about activities that are prohibited on .gov dom {% block form_fields %} - {% with attr_maxlength=500 add_label_class="usa-sr-only" %} + {% with attr_maxlength=1000 add_label_class="usa-sr-only" %} {% input_with_errors forms.0.purpose %} {% endwith %} {% endblock %} diff --git a/src/registrar/templates/application_type_of_work.html b/src/registrar/templates/application_type_of_work.html index 1cacc1535..9ad58936f 100644 --- a/src/registrar/templates/application_type_of_work.html +++ b/src/registrar/templates/application_type_of_work.html @@ -3,7 +3,7 @@ {% block form_fields %} - {% with attr_maxlength=500 %} + {% with attr_maxlength=1000 %} {% input_with_errors forms.0.type_of_work %} {% input_with_errors forms.0.more_organization_information %} {% endwith %} diff --git a/src/registrar/tests/test_forms.py b/src/registrar/tests/test_forms.py index 53bed0b5a..94f985fab 100644 --- a/src/registrar/tests/test_forms.py +++ b/src/registrar/tests/test_forms.py @@ -11,6 +11,9 @@ from registrar.forms.application_wizard import ( OtherContactsForm, RequirementsForm, TribalGovernmentForm, + PurposeForm, + AnythingElseForm, + TypeOfWorkForm, ) @@ -85,6 +88,125 @@ class TestFormValidation(TestCase): ["Enter an email address in the required format, like name@example.com."], ) + def test_purpose_form_character_count_invalid(self): + """Response must be less than 1000 characters.""" + form = PurposeForm( + data={ + "purpose": "Bacon ipsum dolor amet fatback strip steak pastrami" + "shankle, drumstick doner chicken landjaeger turkey andouille." + "Buffalo biltong chuck pork chop tongue bresaola turkey. Doner" + "ground round strip steak, jowl tail chuck ribeye bacon" + "beef ribs swine filet ball tip pancetta strip steak sirloin" + "mignon ham spare ribs rump. Tail shank biltong beef ribs doner" + "buffalo swine bacon. Tongue cow picanha brisket bacon chuck" + "leberkas pork loin pork, drumstick capicola. Doner short loin" + "ground round fatback turducken chislic shoulder turducken" + "spare ribs, burgdoggen kielbasa kevin frankfurter ball tip" + "pancetta cupim. Turkey meatball andouille porchetta hamburger" + "pork chop corned beef. Brisket short ribs turducken, pork chop" + "chislic turkey ball pork chop leberkas rump, rump bacon, jowl" + "tip ham. Shankle salami tongue venison short ribs kielbasa" + "tri-tip ham hock swine hamburger. Flank meatball corned beef" + "cow sausage ball tip kielbasa ham hock. Ball tip cupim meatloaf" + "beef ribs rump jowl tenderloin swine sausage biltong" + "bacon rump tail boudin meatball boudin meatball boudin." + } + ) + self.assertEqual( + form.errors["purpose"], + ["Response must be less than 1000 characters."], + ) + + def test_anything_else_form_type_of_work_character_count_invalid(self): + """Response must be less than 1000 characters.""" + form = AnythingElseForm( + data={ + "anything_else": "Bacon ipsum dolor amet fatback strip steak pastrami" + "shankle, drumstick doner chicken landjaeger turkey andouille." + "Buffalo biltong chuck pork chop tongue bresaola turkey. Doner" + "ground round strip steak, jowl tail chuck ribeye bacon" + "beef ribs swine filet ball tip pancetta strip steak sirloin" + "mignon ham spare ribs rump. Tail shank biltong beef ribs doner" + "buffalo swine bacon. Tongue cow picanha brisket bacon chuck" + "leberkas pork loin pork, drumstick capicola. Doner short loin" + "ground round fatback turducken chislic shoulder turducken" + "spare ribs, burgdoggen kielbasa kevin frankfurter ball tip" + "pancetta cupim. Turkey meatball andouille porchetta hamburger" + "pork chop corned beef. Brisket short ribs turducken, pork chop" + "chislic turkey ball pork chop leberkas rump, rump bacon, jowl" + "tip ham. Shankle salami tongue venison short ribs kielbasa" + "tri-tip ham hock swine hamburger. Flank meatball corned beef" + "cow sausage ball tip kielbasa ham hock. Ball tip cupim meatloaf" + "beef ribs rump jowl tenderloin swine sausage biltong" + "bacon rump tail boudin meatball boudin meatball boudin." + } + ) + self.assertEqual( + form.errors["anything_else"], + ["Response must be less than 1000 characters."], + ) + + def test_anything_else_form_more_organization_information_character_count_invalid( + self, + ): + """Response must be less than 1000 characters.""" + form = TypeOfWorkForm( + data={ + "more_organization_information": "Bacon ipsum dolor amet fatback" + "shankle, drumstick doner chicken landjaeger turkey andouille." + "Buffalo biltong chuck pork chop tongue bresaola turkey. Doner" + "ground round strip steak, jowl tail chuck ribeye bacon" + "beef ribs swine filet ball tip pancetta strip steak sirloin" + "mignon ham spare ribs rump. Tail shank biltong beef ribs doner" + "buffalo swine bacon. Tongue cow picanha brisket bacon chuck" + "leberkas pork loin pork, drumstick capicola. Doner short loin" + "ground round fatback turducken chislic shoulder turducken" + "spare ribs, burgdoggen kielbasa kevin frankfurter ball tip" + "pancetta cupim. Turkey meatball andouille porchetta hamburger" + "pork chop corned beef. Brisket short ribs turducken, pork chop" + "chislic turkey ball pork chop leberkas rump, rump bacon, jowl" + "tip ham. Shankle salami tongue venison short ribs kielbasa" + "tri-tip ham hock swine hamburger. Flank meatball corned beef" + "cow sausage ball tip kielbasa ham hock. Ball tip cupim meatloaf" + "beef ribs rump jowl tenderloin swine sausage biltong" + "bacon rump tail boudin meatball boudin meatball boudin" + "strip steak pastrami." + } + ) + self.assertEqual( + form.errors["more_organization_information"], + ["Response must be less than 1000 characters."], + ) + + def test_anything_else_form_character_count_invalid(self): + """Response must be less than 1000 characters.""" + form = TypeOfWorkForm( + data={ + "type_of_work": "Bacon ipsum dolor amet fatback strip steak pastrami" + "shankle, drumstick doner chicken landjaeger turkey andouille." + "Buffalo biltong chuck pork chop tongue bresaola turkey. Doner" + "ground round strip steak, jowl tail chuck ribeye bacon" + "beef ribs swine filet ball tip pancetta strip steak sirloin" + "mignon ham spare ribs rump. Tail shank biltong beef ribs doner" + "buffalo swine bacon. Tongue cow picanha brisket bacon chuck" + "leberkas pork loin pork, drumstick capicola. Doner short loin" + "ground round fatback turducken chislic shoulder turducken" + "spare ribs, burgdoggen kielbasa kevin frankfurter ball tip" + "pancetta cupim. Turkey meatball andouille porchetta hamburger" + "pork chop corned beef. Brisket short ribs turducken, pork chop" + "chislic turkey ball pork chop leberkas rump, rump bacon, jowl" + "tip ham. Shankle salami tongue venison short ribs kielbasa" + "tri-tip ham hock swine hamburger. Flank meatball corned beef" + "cow sausage ball tip kielbasa ham hock. Ball tip cupim meatloaf" + "beef ribs rump jowl tenderloin swine sausage biltong" + "bacon rump tail boudin meatball boudin meatball boudin." + } + ) + self.assertEqual( + form.errors["type_of_work"], + ["Response must be less than 1000 characters."], + ) + def test_authorizing_official_phone_invalid(self): """Must be a valid phone number.""" form = AuthorizingOfficialForm(data={"phone": "boss@boss"})