Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions features/age_when_started_smoking.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@AgeWhenStartedSmoking
Feature: Age when started smoking
Scenario: The page is accessible
Given I am logged in
And I am 60 years old
When I go to "/age-when-started-smoking"
Then there are no accessibility violations

Scenario: Form errors
Given I am logged in
And I am 60 years old
When I go to "/age-when-started-smoking"
And I click "Continue"
Then I am on "/age-when-started-smoking"
And I see a form error "Enter your age when you started smoking"
When I fill in "How old were you when you started smoking?" as "0" and submit
Then I see a form error "The age you started smoking must be between 1 and your current age"
When I fill in "How old were you when you started smoking?" as "70" and submit
Then I see a form error "The age you started smoking must be the same as, or less than your current age"
And there are no accessibility violations

Scenario: Navigating backwards and forwards
Given I am logged in
And I am 60 years old
When I go to "/age-when-started-smoking"
Then I see a back link to "/relatives-age-when-diagnosed"
When I fill in "How old were you when you started smoking?" as "18" and submit
Then I am on "/check-your-answers"

Scenario: Checking responses and changing them
Given I am logged in
And I am 60 years old
When I go to "/age-when-started-smoking"
And I fill in "How old were you when you started smoking?" as "18" and submit
When I go to "/check-your-answers"
Then I see "18" as a response to "Age you started smoking" under "Smoking history"
And I see "/age-when-started-smoking?change=True" as a link to change "Age you started smoking" under "Smoking history"
When I click the link to change "Age you started smoking" under "Smoking History"
Then I am on "/age-when-started-smoking?change=True"
And I see "18" filled in for "How old were you when you started smoking?"
When I fill in "How old were you when you started smoking?" as "22" and submit
Then I am on "/check-your-answers"
And I see "22" as a response to "Age you started smoking" under "Smoking history"
4 changes: 2 additions & 2 deletions features/family_history_lung_cancer.feature
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ Feature: Family history of lung cancer page
Given I am logged in
When I go to "/family-history-lung-cancer"
Then I see a back link to "/cancer-diagnosis"
When I fill in and submit my asbestos exposure with "No"
Then I am on "/check-your-answers"
When I fill in and submit my family history lung cancer with "No"
Then I am on "/age-when-started-smoking"
When I click "Back"
When I fill in and submit my family history lung cancer with "Yes"
Then I am on "/relatives-age-when-diagnosed"
Expand Down
7 changes: 5 additions & 2 deletions features/questionnaire.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@AgeWhenStartedSmoking
Feature: Questionnaire
Scenario: Cannot change responses once submitted
Given I am logged in
Expand Down Expand Up @@ -40,7 +41,6 @@ Feature: Questionnaire
Then I am on "/education"
When I fill in and submit my education with "A-levels"


Then I am on "/respiratory-conditions"
When I fill in and submit my respiratory conditions with "Pneumonia" and "Emphysema"

Expand All @@ -56,8 +56,11 @@ Feature: Questionnaire
Then I am on "/relatives-age-when-diagnosed"
When I fill in and submit my relatives age when diagnosed with "Yes, they were younger than 60"

Then I am on "/age-when-started-smoking"
When I fill in "How old were you when you started smoking?" as "18" and submit

Then I am on "/check-your-answers"
And I see a back link to "/relatives-age-when-diagnosed"
And I see a back link to "/age-when-started-smoking"

And I see "Yes, I used to smoke" as a response to "Have you ever smoked tobacco?" under "Eligibility"
And I see a date 55 years ago as a response to "Date of birth" under "Eligibility"
Expand Down
2 changes: 1 addition & 1 deletion features/relatives_age_when_diagnosed.feature
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Feature: Relatives age when diagnosed page
Then I am on "/relatives-age-when-diagnosed"
And I see a back link to "/family-history-lung-cancer"
When I fill in and submit my relatives age when diagnosed with "Yes, they were younger than 60"
Then I am on "/check-your-answers"
Then I am on "/age-when-started-smoking"

Scenario: Redirecting if they have no family history of lung cancer
Given I am logged in
Expand Down
7 changes: 6 additions & 1 deletion features/steps/form_steps.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from behave import when
from behave import when, then
from datetime import datetime
from dateutil.relativedelta import relativedelta

Expand All @@ -9,6 +9,11 @@ def when_i_check_value_and_submit(context, value):
context.page.get_by_label(value, exact=True).check()
when_i_submit_the_form(context)

@when("I fill in \"{field}\" as \"{value}\" and submit")
def when_i_enter_value_and_submit(context, field, value):
context.page.get_by_label(field).fill(value)
when_i_submit_the_form(context)

@when("I take a screenshot")
@when("I take a screenshot {value}")
def screenshot(context, value=""):
Expand Down
7 changes: 7 additions & 0 deletions features/steps/participant_steps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from behave import given
from django.utils import timezone

from features.steps.form_steps import when_i_fill_in_and_submit_my_date_of_birth_as_x_years_ago
from features.steps.navigation_steps import given_i_go_to
from lung_cancer_screening.questions.tests.factories.response_set_factory import ResponseSetFactory


Expand All @@ -15,3 +17,8 @@ def given_i_have_already_submitted_my_responses(context):
def given_i_have_started_the_questionnaire(context):
context.page.goto(f'{context.live_server_url}/start')
context.page.click('text=Start')

@given("I am {years:d} years old")
def given_i_am_years_old(context, years):
given_i_go_to(context, '/date-of-birth')
when_i_fill_in_and_submit_my_date_of_birth_as_x_years_ago(context, years)
3 changes: 3 additions & 0 deletions lung_cancer_screening/nhsuk_forms/integer_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ def __init__(
*args,
hint=None,
label_classes=None,
label_is_page_heading=False,
classes=None,
**kwargs,
):
kwargs["template_name"] = "input.jinja"

self.suffix = kwargs.pop("suffix", None)
self.prefix = kwargs.pop("prefix", None)
self.hint = hint
self.classes = classes
self.label_classes = label_classes
self.label_is_page_heading = label_is_page_heading

super().__init__(*args, **kwargs)

Expand Down
6 changes: 4 additions & 2 deletions lung_cancer_screening/nhsuk_forms/jinja2/input.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
"label": {
"text": field.label,
"html": label_html if label_html,
"classes": unbound_field.label_classes if unbound_field.label_classes
"classes": unbound_field.label_classes if unbound_field.label_classes,
"isPageHeading": unbound_field.label_is_page_heading if unbound_field.label_is_page_heading
},
"hint": {
"text": unbound_field.hint
} if unbound_field.hint,
"suffix": unbound_field.suffix if unbound_field.suffix,
"prefix": unbound_field.prefix if unbound_field.prefix,
"id": field.auto_id,
"name": field.html_name,
"value": field.value() or "",
Expand All @@ -26,7 +28,7 @@
{% if field.errors %}
{% set error_params = {
"errorMessage": {
"text": field.errors | first
"html": field.errors | first
}
} %}
{% set input_params = dict(input_params, **error_params) %}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django import forms
from django.urls import reverse_lazy
from django.utils.html import format_html

from ...nhsuk_forms.integer_field import IntegerField
from ..models.age_when_started_smoking_response import AgeWhenStartedSmokingResponse

class AgeWhenStartedSmokingForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.fields["value"] = IntegerField(
label="How old were you when you started smoking?",
label_classes="nhsuk-fieldset__legend--l",
label_is_page_heading=True,
classes="nhsuk-input--width-2",
hint="Give an estimate if you are not sure",
prefix="Age",
error_messages={
"required": "Enter your age when you started smoking",
"invalid": "Enter your age when you started smoking",
"zero_entered":"The age you started smoking must be between 1 and your current age",
"age_started_smoking_greater_than_current_age":"The age you started smoking must be the same as, or less than your current age",
"no_date_of_birth" : format_html("<a href=\"{}\">Provide your date of birth</a> before answering this question", reverse_lazy("questions:date_of_birth"))
}
)

class Meta:
model = AgeWhenStartedSmokingResponse
fields = ["value"]
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def __init__(self, *args, **kwargs):
self.fields["metric"] = DecimalField(
decimal_places=1,
label="Centimetres",
classes="nhsuk-input--width-4",
classes="nhsuk-input--width-2",
error_messages={
'required': 'Enter your height',
"max_decimal_places": (
Expand Down
8 changes: 8 additions & 0 deletions lung_cancer_screening/questions/jinja2/responses.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
}) }}
</section>

<section>
<h2 class="nhsuk-heading-m">Smoking history</h2>

{{ summaryList({
"rows": response_set.smoking_history_responses_items()
}) }}
</section>

<form action="{{ request.path }}" method="post">
{{ csrf_input }}
{{ button({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 5.2.10 on 2026-01-15 08:59

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('questions', '0042_alter_educationresponse_value'),
]

operations = [
migrations.CreateModel(
name='AgeWhenStartedSmokingResponse',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('value', models.PositiveIntegerField()),
('response_set', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='age_when_started_smoking_response', to='questions.responseset')),
],
options={
'abstract': False,
},
),
]
1 change: 1 addition & 0 deletions lung_cancer_screening/questions/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .response_set import ResponseSet # noqa: F401
from .user import User # noqa: F401

from .age_when_started_smoking_response import AgeWhenStartedSmokingResponse # noqa: F401
from .asbestos_exposure_response import AsbestosExposureResponse # noqa: F401
from .cancer_diagnosis_response import CancerDiagnosisResponse # noqa: F401
from .check_need_appointment_response import CheckNeedAppointmentResponse # noqa: F401
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.db import models
from django.forms import ValidationError

from .base import BaseModel
from .response_set import ResponseSet

from django.core.validators import MinValueValidator

class AgeWhenStartedSmokingResponse(BaseModel):
response_set = models.OneToOneField(ResponseSet, on_delete=models.CASCADE, related_name="age_when_started_smoking_response")
value = models.PositiveIntegerField(validators=[
MinValueValidator(1, message="The age you started smoking must be between 1 and your current age")
]
)

def clean(self):
super().clean()
if hasattr(self.response_set, "date_of_birth_response") :
if (self.value and self.value > self.response_set.date_of_birth_response.age_in_years()):
raise ValidationError({
"value":ValidationError(
"age started smoking must be less than current age",
code="age_started_smoking_greater_than_current_age")
}
)
else:
raise ValidationError({
"value":ValidationError(
"date of birth not set",
code="no_date_of_birth")
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ def is_currently_in_age_range(self):
seventy_five_years_ago = date.today() - relativedelta(years=75)

return seventy_five_years_ago < self.value <= fifty_five_years_ago

def age_in_years(self):
today = date.today()
born = self.value
age = int(today.year - born.year - ((today.month, today.day) < (born.month, born.day)))
return age
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ def relatives_age_when_diagnosed(self):

return self.response_set.relatives_age_when_diagnosed.get_value_display()

@property
def age_when_started_smoking(self):
if not hasattr(self.response_set, 'age_when_started_smoking_response'):
return None

return str(self.response_set.age_when_started_smoking_response.value)

@property
def respiratory_conditions(self):
Expand Down Expand Up @@ -217,6 +223,15 @@ def family_history_responses_items(self):

return items

def smoking_history_responses_items(self):
return [
self._check_your_answer_item(
"Age you started smoking",
self.age_when_started_smoking,
"questions:age_when_started_smoking",
)
]


def is_complete(self):
return self.response_set.is_complete()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import factory

from ..factories.date_of_birth_response_factory import DateOfBirthResponseFactory

from .response_set_factory import ResponseSetFactory
from ...models.age_when_started_smoking_response import AgeWhenStartedSmokingResponse


class AgeWhenStartedSmokingResponseFactory(factory.django.DjangoModelFactory):
class Meta:
model = AgeWhenStartedSmokingResponse

response_set = factory.SubFactory(ResponseSetFactory)
value = factory.Faker('pyint', min_value=15, max_value=50)

# Create a DateOfBirthResponse linked to the same response_set
date_of_birth_response = factory.RelatedFactory(
DateOfBirthResponseFactory,
factory_related_name="value",
)
Loading