Skip to content

Commit 8bcb602

Browse files
authored
Merge pull request #119 from NHSDigital/PPHA-263--Weight-imperial-page
Add weight unit switching in acceptance test
2 parents f5a745e + 0cbd350 commit 8bcb602

File tree

10 files changed

+239
-18
lines changed

10 files changed

+239
-18
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{% from 'nhsuk/components/input/macro.jinja' import input %}
2+
{% from 'nhsuk/components/error-message/macro.jinja' import errorMessage %}
3+
4+
{% if field.errors | length > 0 %}
5+
{% set error_message = field.errors | first %}
6+
{% endif %}
7+
{% set unbound_field = field.field %}
8+
{% set hint = unbound_field.hint %}
9+
{% set form_group_error_classes = ' nhsuk-form-group--error' if error_message else '' %}
10+
{% set field_error_classes = ' nhsuk-input--error' if error_message else '' %}
11+
12+
<div id="{{ field.html_name }}" class="multi-field-input nhsuk-form-group{{ form_group_error_classes }}">
13+
{% if error_message %}
14+
{{ errorMessage({
15+
"id": field.auto_id,
16+
"text": error_message
17+
}) }}
18+
{% endif %}
19+
20+
<div class="multi-field-input__item">
21+
{{ input({
22+
"label": {
23+
"text": "Stone",
24+
"classes": "nhsuk-fieldset__legend--m",
25+
"isPageHeading": false
26+
},
27+
"hint": {
28+
"text": unbound_field.hint
29+
} if unbound_field.hint,
30+
"id": field.auto_id + "_0",
31+
"name": field.html_name + "_0",
32+
"value": field.subwidgets.0.data.value,
33+
"classes": "nhsuk-input--width-2" + field_error_classes,
34+
"type": "number"
35+
}) }}
36+
</div>
37+
38+
<div class="multi-field-input__item">
39+
{{ input({
40+
"label": {
41+
"text": "Pounds",
42+
"classes": "nhsuk-fieldset__legend--m",
43+
"isPageHeading": false
44+
},
45+
"id": field.auto_id + "_1",
46+
"name": field.html_name + "_1",
47+
"value": field.subwidgets.1.data.value,
48+
"classes": "nhsuk-input--width-2" + field_error_classes,
49+
"type": "number"
50+
}) }}
51+
</div>
52+
</div>

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
@@ -44,3 +44,11 @@ def fill_in_and_submit_weight_metric(page, kilograms):
4444
page.get_by_label("Kilograms").fill(str(kilograms))
4545

4646
page.click("text=Continue")
47+
48+
def fill_in_and_submit_weight_imperial(page, stone, pounds):
49+
expect(page.locator("h1")).to_have_text("Enter your weight")
50+
51+
page.get_by_label("Stone").fill(str(stone))
52+
page.get_by_label("Pounds").fill(str(pounds))
53+
54+
page.click("text=Continue")

lung_cancer_screening/core/tests/acceptance/test_questionnaire.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
fill_in_and_submit_participant_id,
1111
fill_in_and_submit_smoking_eligibility,
1212
fill_in_and_submit_date_of_birth,
13-
fill_in_and_submit_weight_metric
13+
fill_in_and_submit_weight_metric,
14+
fill_in_and_submit_weight_imperial
1415
)
1516

1617
from .helpers.assertion_helpers import expect_back_link_to_have_url
@@ -38,8 +39,8 @@ def test_full_questionnaire_user_journey(self):
3839
feet = 5
3940
inches = 7
4041
weight_metric = 70
41-
# weight_stone = 5
42-
# weight_pound = 10
42+
weight_stone = 5
43+
weight_pound = 10
4344

4445
page = self.browser.new_page()
4546
page.goto(f"{self.live_server_url}/start")
@@ -75,16 +76,16 @@ def test_full_questionnaire_user_journey(self):
7576
fill_in_and_submit_weight_metric(page, weight_metric)
7677

7778
expect(page).to_have_url(f"{self.live_server_url}/responses")
78-
# page.click("text=Back")
79-
# page.click("text=Switch to imperial")
80-
# fill_in_and_submit_weight_imperial(page, weight_stone, weight_pound)
79+
page.click("text=Back")
80+
page.get_by_role("link", name="Switch to stone and pounds").click()
81+
fill_in_and_submit_weight_imperial(page, weight_stone, weight_pound)
82+
expect(page).to_have_url(f"{self.live_server_url}/responses")
8183
responses = page.locator(".responses")
8284
expect(responses).to_contain_text("Have you ever smoked? Yes, I used to smoke regularly")
8385
expect(responses).to_contain_text(
8486
age.strftime("What is your date of birth? %Y-%m-%d"))
8587
expect(responses).to_contain_text(f"What is your height? {feet} feet {inches} inches")
86-
expect(responses).to_contain_text(f"What is your weight? {weight_metric}kg")
87-
# expect(responses).to_contain_text(f"What is your weight? {weight_stone} stone {weight_pound} pound")
88+
expect(responses).to_contain_text(f"What is your weight? {weight_stone} stone {weight_pound} pound")
8889

8990
page.click("text=Submit")
9091

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from django import forms
2+
3+
from lung_cancer_screening.core.form_fields import ImperialWeightField
4+
from ..models.response_set import ResponseSet
5+
6+
class ImperialWeightForm(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["weight_imperial"] = ImperialWeightField(
14+
label="Weight",
15+
required=True,
16+
require_all_fields=False,
17+
error_messages={
18+
'required': 'Enter your weight.',
19+
'incomplete': 'Enter your weight.'
20+
}
21+
)
22+
23+
def clean_weight_metric(self):
24+
return None
25+
26+
class Meta:
27+
model = ResponseSet
28+
fields = ['weight_imperial', 'weight_metric']

lung_cancer_screening/questions/jinja2/responses.jinja

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{% block beforeContent %}
66
{{
77
backLink({
8-
"href": url("questions:height"),
8+
"href": url("questions:weight"),
99
"text": "Back"
1010
})
1111
}}

lung_cancer_screening/questions/jinja2/weight.jinja

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
{% from 'nhsuk/components/back-link/macro.jinja' import backLink %}
44
{% from 'nhsuk/components/fieldset/macro.jinja' import fieldset %}
55

6+
{% set WEIGHT_UNIT = {
7+
'imperial': 'stone and pounds',
8+
'metric': 'kilograms'
9+
} %}
10+
611
{% block beforeContent %}
712
{{
813
backLink({
@@ -15,7 +20,12 @@
1520
{% block page_content %}
1621
<div class="nhsuk-grid-row">
1722
<div class="nhsuk-grid-column-two-thirds">
18-
<form action="{{request.path}}" method="POST" novalidate>
23+
{% if unit %}
24+
{% set action_url = request.path + '?unit=' + unit %}
25+
{% else %}
26+
{% set action_url = request.path %}
27+
{% endif %}
28+
<form action="{{ action_url }}" method="POST" novalidate>
1929
{{ csrf_input }}
2030
<h1 class="nhsuk-heading-l">Enter your weight</h1>
2131

@@ -30,8 +40,13 @@
3040
}
3141
}) %}
3242

33-
{{form.weight_metric.as_field_group()}}
43+
{% if unit == "imperial" %}
44+
{{ form.weight_imperial.as_field_group() }}
45+
{% else %}
46+
{{ form.weight_metric.as_field_group() }}
47+
{% endif %}
3448

49+
<p><a href="?unit={{ switch_to_unit }}">Switch to {{ WEIGHT_UNIT[switch_to_unit] }}</a></p>
3550
{% endcall %}
3651

3752
{{ button({
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 5.2.7 on 2025-10-27 12:36
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('questions', '0011_responseset_weight_metric_and_more'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='responseset',
16+
name='weight_imperial',
17+
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(56, message='Weight must be between 4 stone and 50 stone'), django.core.validators.MaxValueValidator(700, message='Weight must be between 4 stone and 50 stone')]),
18+
),
19+
migrations.AlterField(
20+
model_name='responseset',
21+
name='weight_metric',
22+
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(254, message='Weight must be between 25.4kg and 317.5kg'), django.core.validators.MaxValueValidator(3175, message='Weight must be between 25.4kg and 317.5kg')]),
23+
),
24+
]

lung_cancer_screening/questions/models/response_set.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,19 @@ class ResponseSet(BaseModel):
4141

4242
MIN_WEIGHT_METRIC = 254
4343
MAX_WEIGHT_METRIC = 3175
44+
MAX_WEIGHT_IMPERIAL = 700
45+
MIN_WEIGHT_IMPERIAL = 56
4446

4547
weight_metric = models.PositiveIntegerField(null=True, blank=True, validators=[
4648
MinValueValidator(MIN_WEIGHT_METRIC, message="Weight must be between 25.4kg and 317.5kg"),
4749
MaxValueValidator(MAX_WEIGHT_METRIC, message="Weight must be between 25.4kg and 317.5kg"),
4850
])
49-
51+
weight_imperial = models.PositiveIntegerField(null=True, blank=True, validators=[
52+
MinValueValidator(
53+
MIN_WEIGHT_IMPERIAL, message="Weight must be between 4 stone and 50 stone"),
54+
MaxValueValidator(
55+
MAX_WEIGHT_IMPERIAL, message="Weight must be between 4 stone and 50 stone"),
56+
])
5057
submitted_at = models.DateTimeField(null=True, blank=True)
5158

5259
class Meta:
@@ -82,8 +89,8 @@ def formatted_height(self):
8289
def formatted_weight(self):
8390
if self.weight_metric:
8491
return f"{Decimal(self.weight_metric) / 10}kg"
85-
# elif self.height_imperial:
86-
# value = Decimal(self.weight_imperial)
87-
# return f"{value // 12} feet {value % 12} inches"
92+
elif self.weight_imperial:
93+
value = Decimal(self.weight_imperial)
94+
return f"{value // 14} stone {value % 14} pounds"
8895

8996

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from django.test import TestCase
2+
3+
from ....models.participant import Participant
4+
from ....forms.imperial_weight_form import ImperialWeightForm
5+
6+
class TestImperialWeightForm(TestCase):
7+
def setUp(self):
8+
self.participant = Participant.objects.create(unique_id="1234567890")
9+
self.response_set = self.participant.responseset_set.create(
10+
weight_metric=1704
11+
)
12+
13+
def test_is_valid_with_valid_input(self):
14+
form = ImperialWeightForm(
15+
participant=self.participant,
16+
instance=self.response_set,
17+
data={
18+
"weight_imperial_0": "5", # stone
19+
"weight_imperial_1": "9" # pounds
20+
}
21+
)
22+
23+
self.assertTrue(form.is_valid())
24+
25+
def test_converts_stone_and_pounds_to_kilograms_integer(self):
26+
form = ImperialWeightForm(
27+
participant=self.participant,
28+
instance=self.response_set,
29+
data={
30+
"weight_imperial_0": "5", # stone
31+
"weight_imperial_1": "9" # pounds
32+
}
33+
)
34+
35+
self.assertTrue(form.is_valid(), f"Form errors: {form.errors}")
36+
self.assertEqual(form.cleaned_data['weight_imperial'], 79)
37+
38+
def test_setting_weight_imperial_clears_weight_metric(self):
39+
form = ImperialWeightForm(
40+
instance=self.response_set,
41+
participant=self.participant,
42+
data={
43+
"weight_imperial_0": "5", # stone
44+
"weight_imperial_1": "9" # pounds
45+
}
46+
)
47+
form.save()
48+
self.assertEqual(self.response_set.weight_metric, None)
49+
50+
def test_is_invalid_with_missing_data(self):
51+
form = ImperialWeightForm(
52+
participant=self.participant,
53+
instance=self.response_set,
54+
data={
55+
"weight_imperial_0": "5",
56+
# missing pounds
57+
}
58+
)
59+
self.assertFalse(form.is_valid())
60+
self.assertEqual(
61+
form.errors["weight_imperial"],
62+
["Enter your weight."]
63+
)
64+
65+
def test_is_invalid_when_given_a_decimal_stone_value(self):
66+
form = ImperialWeightForm(
67+
participant=self.participant,
68+
instance=self.response_set,
69+
data={
70+
"weight_imperial_0": "5.2",
71+
"weight_imperial_1": "0"
72+
}
73+
)
74+
self.assertFalse(form.is_valid())
75+
self.assertEqual(
76+
form.errors["weight_imperial"],
77+
["Stone must be in whole numbers."]
78+
)

lung_cancer_screening/questions/views/weight.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
from django.shortcuts import render, redirect
22

33
from lung_cancer_screening.questions.forms.metric_weight_form import MetricWeightForm
4+
from lung_cancer_screening.questions.forms.imperial_weight_form import ImperialWeightForm
45
from .decorators.participant_decorators import require_participant
56

67
@require_participant
78
def weight(request):
9+
unit = request.GET.get('unit')
10+
form_klass = ImperialWeightForm if unit == "imperial" else MetricWeightForm
11+
812
if request.method == "POST":
9-
form=MetricWeightForm(
13+
form = form_klass(
1014
instance=request.participant.responseset_set.last(),
1115
data=request.POST,
1216
participant=request.participant
@@ -19,14 +23,18 @@ def weight(request):
1923
request,
2024
"weight.jinja",
2125
{
22-
"form": form
26+
"form": form,
27+
"unit": unit,
28+
"switch_to_unit": "metric" if unit == "imperial" else "imperial"
2329
},
2430
status=422
2531
)
2632
return render(
2733
request,
2834
"weight.jinja",
2935
{
30-
"form": MetricWeightForm(participant=request.participant)
36+
"form": form_klass(participant=request.participant),
37+
"unit": unit,
38+
"switch_to_unit": "metric" if unit == "imperial" else "imperial"
3139
}
3240
)

0 commit comments

Comments
 (0)