Skip to content

Commit f8de6e2

Browse files
committed
PPHA-266: Add ethnicity question page
1 parent 54143dd commit f8de6e2

File tree

15 files changed

+324
-7
lines changed

15 files changed

+324
-7
lines changed

lung_cancer_screening/core/tests/acceptance/helpers/user_interaction_helpers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,11 @@ def fill_in_and_submit_gender(page, gender):
6868
page.get_by_label(gender, exact=True).check()
6969

7070
page.click("text=Continue")
71+
72+
def fill_in_and_submit_ethnicity(page, ethnicity):
73+
expect(page.locator("legend")).to_have_text(
74+
"What is your ethnic background?")
75+
76+
page.get_by_label(ethnicity, exact=True).check()
77+
78+
page.click("text=Continue")

lung_cancer_screening/core/tests/acceptance/test_cannot_change_answers_after_submission.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
fill_in_and_submit_date_of_birth,
1313
fill_in_and_submit_sex_at_birth,
1414
fill_in_and_submit_gender,
15+
fill_in_and_submit_ethnicity
1516
)
1617

1718
class TestQuestionnaire(StaticLiveServerTestCase):
@@ -44,6 +45,7 @@ def test_cannot_change_responses_once_checked_and_submitted(self):
4445
fill_in_and_submit_weight_metric(page, "25.4")
4546
fill_in_and_submit_sex_at_birth(page, "Male")
4647
fill_in_and_submit_gender(page, "Male")
48+
fill_in_and_submit_ethnicity(page, "White")
4749

4850
page.click("text=Submit")
4951

lung_cancer_screening/core/tests/acceptance/test_questionnaire.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
fill_in_and_submit_weight_metric,
1414
fill_in_and_submit_weight_imperial,
1515
fill_in_and_submit_sex_at_birth,
16-
fill_in_and_submit_gender
16+
fill_in_and_submit_gender,
17+
fill_in_and_submit_ethnicity
1718
)
1819

1920
from .helpers.assertion_helpers import expect_back_link_to_have_url
@@ -84,9 +85,14 @@ def test_full_questionnaire_user_journey(self):
8485
expect_back_link_to_have_url(page, "/sex-at-birth")
8586
fill_in_and_submit_gender(page, "Male")
8687

87-
expect(page).to_have_url(f"{self.live_server_url}/responses")
88+
expect(page).to_have_url(f"{self.live_server_url}/ethnicity")
8889
expect_back_link_to_have_url(page, "/gender")
8990

91+
fill_in_and_submit_ethnicity(page, "White")
92+
93+
expect(page).to_have_url(f"{self.live_server_url}/responses")
94+
expect_back_link_to_have_url(page, "/ethnicity")
95+
9096
responses = page.locator(".responses")
9197
expect(responses).to_contain_text("Have you ever smoked? Yes, I used to smoke regularly")
9298
expect(responses).to_contain_text(
@@ -95,6 +101,7 @@ def test_full_questionnaire_user_journey(self):
95101
expect(responses).to_contain_text(f"What is your weight? {weight_stone} stone {weight_pound} pound")
96102
expect(responses).to_contain_text("What was your sex at birth? Male")
97103
expect(responses).to_contain_text("Which of these best describes you? Male")
104+
expect(responses).to_contain_text("What is your ethnic background? White")
98105

99106
page.click("text=Submit")
100107

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from django import forms
2+
3+
from ...nhsuk_forms.typed_choice_field import TypedChoiceField
4+
from ..models.response_set import ResponseSet, EthnicityValues
5+
6+
class EthnicityForm(forms.ModelForm):
7+
8+
def __init__(self, *args, **kwargs):
9+
self.participant = kwargs.pop('participant')
10+
super().__init__(*args, **kwargs)
11+
self.instance.participant = self.participant
12+
13+
self.fields["ethnicity"] = TypedChoiceField(
14+
choices=EthnicityValues.choices,
15+
label="What is your ethnic background?",
16+
widget=forms.RadioSelect,
17+
label_classes="nhsuk-fieldset__legend--m",
18+
hint="Your ethnicity may impact your chances of developing lung cancer.",
19+
error_messages={
20+
'required': 'Select your ethnic background.'
21+
}
22+
)
23+
24+
class Meta:
25+
model = ResponseSet
26+
fields = ['ethnicity']
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{% extends 'layout.jinja' %}
2+
{% from 'nhsuk/components/button/macro.jinja' import button %}
3+
{% from 'nhsuk/components/back-link/macro.jinja' import backLink %}
4+
5+
{% block beforeContent %}
6+
{{
7+
backLink({
8+
"href": url("questions:gender"),
9+
"text": "Back"
10+
})
11+
}}
12+
{% endblock beforeContent %}
13+
14+
{% block page_content %}
15+
<div class="nhsuk-grid-row">
16+
<div class="nhsuk-grid-column-two-thirds">
17+
<form action="{{ request.path }}" method="POST">
18+
{{ csrf_input }}
19+
20+
{{ form }}
21+
22+
{{ button({
23+
"text": "Continue"
24+
}) }}
25+
</form>
26+
</div>
27+
</div>
28+
{% endblock %}

lung_cancer_screening/questions/jinja2/responses.jinja

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{% block beforeContent %}
66
{{
77
backLink({
8-
"href": url("questions:gender"),
8+
"href": url("questions:ethnicity"),
99
"text": "Back"
1010
})
1111
}}
@@ -22,6 +22,7 @@
2222
<li>What is your weight? {{ response_set.formatted_weight }}</li>
2323
<li>What was your sex at birth? {{ response_set.get_sex_at_birth_display() }}</li>
2424
<li>Which of these best describes you? {{ response_set.get_gender_display() }}</li>
25+
<li>What is your ethnic background? {{ response_set.get_ethnicity_display() }}</li>
2526
</ul>
2627

2728
<form action="{{ request.path }}" method="post">
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.2.7 on 2025-11-03 14:11
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('questions', '0014_responseset_gender'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='responseset',
15+
name='ethnicity',
16+
field=models.CharField(blank=True, choices=[('A', 'Asian or Asian British'), ('B', 'Black, African, Caribbean or Black British'), ('M', 'Mixed or multiple ethnic groups'), ('W', 'White'), ('O', 'Other ethnic group'), ('N', "I'd prefer not to say")], max_length=1, null=True),
17+
),
18+
migrations.AlterField(
19+
model_name='responseset',
20+
name='gender',
21+
field=models.CharField(blank=True, choices=[('F', 'Female'), ('M', 'Male'), ('N', 'Non-binary'), ('P', 'Prefer not to say'), ('G', 'How I describe myself may not match my GP record')], max_length=1, null=True),
22+
),
23+
]

lung_cancer_screening/questions/models/response_set.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ class GenderValues(models.TextChoices):
2525
PREFER_NOT_TO_SAY = "P", 'Prefer not to say'
2626
GP = "G", 'How I describe myself may not match my GP record'
2727

28+
class EthnicityValues(models.TextChoices):
29+
ASIAN = "A", "Asian or Asian British"
30+
BLACK = "B", "Black, African, Caribbean or Black British"
31+
MIXED = "M", "Mixed or multiple ethnic groups"
32+
WHITE = "W", "White"
33+
OTHER = "O", "Other ethnic group"
34+
PREFER_NOT_TO_SAY = "N", "I'd prefer not to say"
35+
2836
class ResponseSet(BaseModel):
2937
participant = models.ForeignKey(Participant, on_delete=models.CASCADE)
3038

@@ -80,6 +88,13 @@ class ResponseSet(BaseModel):
8088
blank=True
8189
)
8290

91+
ethnicity = models.CharField(
92+
max_length=1,
93+
choices=EthnicityValues.choices,
94+
null=True,
95+
blank=True
96+
)
97+
8398
submitted_at = models.DateTimeField(null=True, blank=True)
8499

85100
class Meta:
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from django.test import TestCase
2+
3+
from ....models.response_set import EthnicityValues
4+
from ....models.participant import Participant
5+
from ....forms.ethnicity_form import EthnicityForm
6+
7+
class TestEthnicityForm(TestCase):
8+
def setUp(self):
9+
self.participant = Participant.objects.create(unique_id="1234567890")
10+
11+
def test_is_valid_with_a_valid_value(self):
12+
form = EthnicityForm(
13+
participant=self.participant,
14+
data={
15+
'ethnicity': EthnicityValues.WHITE
16+
}
17+
)
18+
self.assertTrue(form.is_valid())
19+
self.assertEqual(
20+
form.cleaned_data['ethnicity'],
21+
EthnicityValues.WHITE
22+
)
23+
24+
def test_is_invalid_with_an_invalid_value(self):
25+
form = EthnicityForm(
26+
participant=self.participant,
27+
data={
28+
"ethnicity": "invalid"
29+
}
30+
)
31+
self.assertFalse(form.is_valid())
32+
self.assertEqual(
33+
form.errors["ethnicity"],
34+
["Select a valid choice. invalid is not one of the available choices."]
35+
)
36+
37+
def test_is_invalid_when_no_option_is_selected(self):
38+
form = EthnicityForm(
39+
participant=self.participant,
40+
data={
41+
"ethnicity": None
42+
}
43+
)
44+
self.assertFalse(form.is_valid())
45+
self.assertEqual(
46+
form.errors["ethnicity"],
47+
["Select your ethnic background."]
48+
)

lung_cancer_screening/questions/tests/unit/models/test_response_set.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from django.core.exceptions import ValidationError
77

8-
from ....models.response_set import ResponseSet, HaveYouEverSmokedValues, SexAtBirthValues, GenderValues
8+
from ....models.response_set import ResponseSet, HaveYouEverSmokedValues, SexAtBirthValues, GenderValues, EthnicityValues
99
from ....models.participant import Participant
1010

1111
class TestResponseSet(TestCase):
@@ -109,6 +109,15 @@ def test_has_gender_as_string(self):
109109
str
110110
)
111111

112+
def test_has_ethnicity_as_string(self):
113+
self.response_set.ethnicity = EthnicityValues.WHITE
114+
self.response_set.save()
115+
116+
self.assertIsInstance(
117+
self.response_set.ethnicity,
118+
str
119+
)
120+
112121
# VALIDATIONS
113122

114123
def test_is_invalid_if_another_unsubmitted_response_set_exists(self):
@@ -259,3 +268,22 @@ def test_is_invalid_if_gender_is_not_an_accepted_value(self):
259268
context.exception.messages[0],
260269
"Value 'X' is not a valid choice."
261270
)
271+
272+
def test_is_valid_if_ethnicity_is_null(self):
273+
self.response_set.ethnicity = None
274+
self.response_set.save()
275+
276+
self.assertIsNone(
277+
self.response_set.ethnicity
278+
)
279+
280+
def test_is_invalid_if_ethnicity_is_not_an_accepted_value(self):
281+
self.response_set.ethnicity = "X"
282+
283+
with self.assertRaises(ValidationError) as context:
284+
self.response_set.full_clean()
285+
286+
self.assertEqual(
287+
context.exception.messages[0],
288+
"Value 'X' is not a valid choice."
289+
)

0 commit comments

Comments
 (0)