diff --git a/.vscode/settings.json b/.vscode/settings.json index f2d5e82c..e14ecea2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,8 @@ "cSpell.language": "en-GB", "cSpell.words": [ "dateutil", + "Dproject", + "Dsonar", "endcall", "endfor", "endset", @@ -20,8 +22,10 @@ "novalidate", "psycopg", "pyjwt", + "qualitygate", "relativedelta", "responseset", + "sonarsource", "stylesheet", "toplevel", "unsubmitted", diff --git a/lung_cancer_screening/core/jinja2/layout.jinja b/lung_cancer_screening/core/jinja2/layout.jinja index 2982402e..1fd97e6e 100644 --- a/lung_cancer_screening/core/jinja2/layout.jinja +++ b/lung_cancer_screening/core/jinja2/layout.jinja @@ -2,6 +2,8 @@ {% extends 'nhsuk/template.jinja' %} +{% from 'nhsuk/components/back-link/macro.jinja' import backLink %} + {% block head %} diff --git a/lung_cancer_screening/questions/forms/relatives_age_when_diagnosed_form.py b/lung_cancer_screening/questions/forms/relatives_age_when_diagnosed_form.py new file mode 100644 index 00000000..60d5be24 --- /dev/null +++ b/lung_cancer_screening/questions/forms/relatives_age_when_diagnosed_form.py @@ -0,0 +1,23 @@ +from django import forms + +from ...nhsuk_forms.choice_field import ChoiceField +from ..models.relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedResponse, RelativesAgeWhenDiagnosedValues + + +class RelativesAgeWhenDiagnosedForm(forms.ModelForm): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.fields["value"] = ChoiceField( + choices=RelativesAgeWhenDiagnosedValues.choices, + label="Were any of your relatives younger than 60 years old when they were diagnosed with lung cancer?", + widget=forms.RadioSelect, + error_messages={ + 'required': 'Select if your relatives were younger than 60 when they were diagnosed with lung cancer' + } + ) + + class Meta: + model = RelativesAgeWhenDiagnosedResponse + fields = ['value'] diff --git a/lung_cancer_screening/questions/jinja2/question_form.jinja b/lung_cancer_screening/questions/jinja2/question_form.jinja index c28e517b..9ad31a1d 100644 --- a/lung_cancer_screening/questions/jinja2/question_form.jinja +++ b/lung_cancer_screening/questions/jinja2/question_form.jinja @@ -1,7 +1,6 @@ {% extends 'layout.jinja' %} {% from 'nhsuk/components/button/macro.jinja' import button %} -{% from 'nhsuk/components/back-link/macro.jinja' import backLink %} {% if error %} {% set error_message = { "text": error } %} diff --git a/lung_cancer_screening/questions/jinja2/relative_age_when_diagnosed.jinja b/lung_cancer_screening/questions/jinja2/relative_age_when_diagnosed.jinja new file mode 100644 index 00000000..e1ff8bc4 --- /dev/null +++ b/lung_cancer_screening/questions/jinja2/relative_age_when_diagnosed.jinja @@ -0,0 +1,11 @@ +{% extends 'question_form.jinja' %} + +{% block prelude %} + +

If your relatives were under 60 when they were diagnosed

+ +

We ask about their age when they were diagnosed with lung cancer because it may impact your chances of developing lung cancer.

+ +

If you do not know or cannot remember, select ‘I do not know’.

+ +{% endblock prelude %} diff --git a/lung_cancer_screening/questions/jinja2/responses.jinja b/lung_cancer_screening/questions/jinja2/responses.jinja index 6c37468e..e141a2db 100644 --- a/lung_cancer_screening/questions/jinja2/responses.jinja +++ b/lung_cancer_screening/questions/jinja2/responses.jinja @@ -1,17 +1,6 @@ {% extends 'layout.jinja' %} -{% from 'nhsuk/components/button/macro.jinja' import button %} -{% from 'nhsuk/components/back-link/macro.jinja' import backLink %} -{% block beforeContent %} - -{% endblock beforeContent %} +{% from 'nhsuk/components/button/macro.jinja' import button %} {% block page_content %}
@@ -27,6 +16,9 @@
  • What is your ethnic background? {{ response_set.ethnicity }}
  • Have you ever worked in a job where you might have been exposed to asbestos? {{ response_set.asbestos_exposure }}
  • Have you ever been diagnosed with any of the following respiratory conditions? {{ response_set.respiratory_conditions }}
  • +
  • Have you ever been diagnosed with cancer? {{ response_set.cancer_diagnosis }}
  • +
  • Have any of your parents, siblings or children ever been diagnosed with lung cancer {{ response_set.family_history_lung_cancer }}
  • +
  • Were any of your relatives younger than 60 years old when they were diagnosed with lung cancer? {{ response_set.relatives_age_when_diagnosed }}
  • diff --git a/lung_cancer_screening/questions/migrations/0037_familyhistoryagewhendiagnosedresponse.py b/lung_cancer_screening/questions/migrations/0037_familyhistoryagewhendiagnosedresponse.py new file mode 100644 index 00000000..79d41feb --- /dev/null +++ b/lung_cancer_screening/questions/migrations/0037_familyhistoryagewhendiagnosedresponse.py @@ -0,0 +1,27 @@ +# Generated by Django 5.2.9 on 2026-01-05 12:20 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('questions', '0036_familyhistorylungcancerresponse'), + ] + + operations = [ + migrations.CreateModel( + name='FamilyHistoryAgeWhenDiagnosedResponse', + 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.CharField(choices=[('Y', 'Yes, they were younger than 60'), ('N', 'No, they were 60 or older'), ('U', 'I do not know')], max_length=1)), + ('response_set', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='family_history_age_when_diagnosed', to='questions.responseset')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/lung_cancer_screening/questions/migrations/0038_relativesagewhendiagnosedresponse_and_more.py b/lung_cancer_screening/questions/migrations/0038_relativesagewhendiagnosedresponse_and_more.py new file mode 100644 index 00000000..dfbf8c0a --- /dev/null +++ b/lung_cancer_screening/questions/migrations/0038_relativesagewhendiagnosedresponse_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 5.2.9 on 2026-01-05 15:23 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('questions', '0037_familyhistoryagewhendiagnosedresponse'), + ] + + operations = [ + migrations.CreateModel( + name='RelativesAgeWhenDiagnosedResponse', + 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.CharField(choices=[('Y', 'Yes, they were younger than 60'), ('N', 'No, they were 60 or older'), ('U', 'I do not know')], max_length=1)), + ('response_set', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='relatives_age_when_diagnosed', to='questions.responseset')), + ], + options={ + 'abstract': False, + }, + ), + migrations.DeleteModel( + name='FamilyHistoryAgeWhenDiagnosedResponse', + ), + ] diff --git a/lung_cancer_screening/questions/models/__init__.py b/lung_cancer_screening/questions/models/__init__.py index e5a1cd74..28ed939c 100644 --- a/lung_cancer_screening/questions/models/__init__.py +++ b/lung_cancer_screening/questions/models/__init__.py @@ -12,3 +12,4 @@ from .weight_response import WeightResponse # noqa: F401 from .cancer_diagnosis_response import CancerDiagnosisResponse # noqa: F401 from .family_history_lung_cancer_response import FamilyHistoryLungCancerResponse # noqa: F401 +from .relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedResponse # noqa: F401 diff --git a/lung_cancer_screening/questions/models/family_history_lung_cancer_response.py b/lung_cancer_screening/questions/models/family_history_lung_cancer_response.py index a61a0569..fb45d04b 100644 --- a/lung_cancer_screening/questions/models/family_history_lung_cancer_response.py +++ b/lung_cancer_screening/questions/models/family_history_lung_cancer_response.py @@ -5,8 +5,8 @@ class FamilyHistoryLungCancerValues(models.TextChoices): - YES = "Y", 'Yes' - NO = "N", 'No' + YES = "Y", "Yes" + NO = "N", "No" UNKNOWN = "U", "I do not know" class FamilyHistoryLungCancerResponse(BaseModel): diff --git a/lung_cancer_screening/questions/models/relatives_age_when_diagnosed_response.py b/lung_cancer_screening/questions/models/relatives_age_when_diagnosed_response.py new file mode 100644 index 00000000..8ea4df0b --- /dev/null +++ b/lung_cancer_screening/questions/models/relatives_age_when_diagnosed_response.py @@ -0,0 +1,14 @@ +from django.db import models + +from .base import BaseModel +from .response_set import ResponseSet + + +class RelativesAgeWhenDiagnosedValues(models.TextChoices): + YES = "Y", "Yes, they were younger than 60" + NO = "N", "No, they were 60 or older" + UNKNOWN = "U", "I do not know" + +class RelativesAgeWhenDiagnosedResponse(BaseModel): + response_set = models.OneToOneField(ResponseSet, on_delete=models.CASCADE, related_name='relatives_age_when_diagnosed') + value = models.CharField(max_length=1, choices=RelativesAgeWhenDiagnosedValues.choices) diff --git a/lung_cancer_screening/questions/presenters/response_set_presenter.py b/lung_cancer_screening/questions/presenters/response_set_presenter.py index c4c0e2b4..139353e3 100644 --- a/lung_cancer_screening/questions/presenters/response_set_presenter.py +++ b/lung_cancer_screening/questions/presenters/response_set_presenter.py @@ -85,10 +85,17 @@ def cancer_diagnosis(self): @property def family_history_lung_cancer(self): - if not hasattr(self.response_set, 'family_history_lung_cancer_response'): + if not hasattr(self.response_set, 'family_history_lung_cancer'): return None - return self.response_set.family_history_lung_cancer_response.get_value_display() + return self.response_set.family_history_lung_cancer.get_value_display() + + @property + def relatives_age_when_diagnosed(self): + if not hasattr(self.response_set, 'relatives_age_when_diagnosed'): + return None + + return self.response_set.relatives_age_when_diagnosed.get_value_display() @property def respiratory_conditions(self): diff --git a/lung_cancer_screening/questions/tests/factories/relatives_age_when_diagnosed_response_factory.py b/lung_cancer_screening/questions/tests/factories/relatives_age_when_diagnosed_response_factory.py new file mode 100644 index 00000000..7e0298af --- /dev/null +++ b/lung_cancer_screening/questions/tests/factories/relatives_age_when_diagnosed_response_factory.py @@ -0,0 +1,12 @@ +import factory + +from .response_set_factory import ResponseSetFactory +from ...models.relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedResponse, RelativesAgeWhenDiagnosedValues + + +class RelativesAgeWhenDiagnosedResponseFactory(factory.django.DjangoModelFactory): + class Meta: + model = RelativesAgeWhenDiagnosedResponse + + response_set = factory.SubFactory(ResponseSetFactory) + value = factory.Iterator(RelativesAgeWhenDiagnosedValues) diff --git a/lung_cancer_screening/questions/tests/unit/forms/test_relatives_age_when_diagnosed_form.py b/lung_cancer_screening/questions/tests/unit/forms/test_relatives_age_when_diagnosed_form.py new file mode 100644 index 00000000..68c4fabd --- /dev/null +++ b/lung_cancer_screening/questions/tests/unit/forms/test_relatives_age_when_diagnosed_form.py @@ -0,0 +1,54 @@ +from django.test import TestCase, tag + +from ...factories.response_set_factory import ResponseSetFactory +from ....models.relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedResponse, RelativesAgeWhenDiagnosedValues +from ....forms.relatives_age_when_diagnosed_form import RelativesAgeWhenDiagnosedForm + +@tag("FamilyHistoryLungCancer") +class TestRelativesLungCancerForm(TestCase): + def setUp(self): + self.response_set = ResponseSetFactory() + self.response = RelativesAgeWhenDiagnosedResponse.objects.create( + response_set=self.response_set, + value=RelativesAgeWhenDiagnosedValues.NO + ) + + + def test_is_valid_with_a_valid_value(self): + form = RelativesAgeWhenDiagnosedForm( + instance=self.response, + data={ + "value": RelativesAgeWhenDiagnosedValues.NO + } + ) + self.assertTrue(form.is_valid()) + self.assertEqual( + form.cleaned_data["value"], + RelativesAgeWhenDiagnosedValues.NO + ) + + def test_is_invalid_with_an_invalid_value(self): + form = RelativesAgeWhenDiagnosedForm( + instance=self.response, + data={ + "value": "invalid" + } + ) + self.assertFalse(form.is_valid()) + self.assertEqual( + form.errors["value"], + ["Select a valid choice. invalid is not one of the available choices."] + ) + + def test_is_invalid_when_no_option_is_selected(self): + form = RelativesAgeWhenDiagnosedForm( + instance=self.response, + data={ + "value": None + } + ) + self.assertFalse(form.is_valid()) + self.assertEqual( + form.errors["value"], + ["Select if your relatives were younger than 60 when they were diagnosed with lung cancer"] + ) diff --git a/lung_cancer_screening/questions/tests/unit/models/test_relatives_age_when_diagnosed_response.py b/lung_cancer_screening/questions/tests/unit/models/test_relatives_age_when_diagnosed_response.py new file mode 100644 index 00000000..9f0ddfc2 --- /dev/null +++ b/lung_cancer_screening/questions/tests/unit/models/test_relatives_age_when_diagnosed_response.py @@ -0,0 +1,34 @@ +from django.test import TestCase, tag + +from ...factories.response_set_factory import ResponseSetFactory +from ...factories.relatives_age_when_diagnosed_response_factory import RelativesAgeWhenDiagnosedResponseFactory, RelativesAgeWhenDiagnosedValues + +from ....models.relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedResponse + +@tag("FamilyHistoryLungCancer") +class TestRelativesAgeWhenDiagnosedResponse(TestCase): + def setUp(self): + self.response_set = ResponseSetFactory() + + def test_has_a_valid_factory(self): + model = RelativesAgeWhenDiagnosedResponseFactory.build(response_set=self.response_set) + model.full_clean() + + + def test_has_response_set_as_foreign_key(self): + response_set = ResponseSetFactory() + response = RelativesAgeWhenDiagnosedResponse.objects.create( + response_set=response_set, + value=RelativesAgeWhenDiagnosedValues.NO + ) + + self.assertEqual(response.response_set, response_set) + + def test_has_value_as_string(self): + response_set = ResponseSetFactory() + response = RelativesAgeWhenDiagnosedResponse.objects.create( + response_set=response_set, + value=RelativesAgeWhenDiagnosedValues.NO + ) + + self.assertIsInstance(response.value, str) diff --git a/lung_cancer_screening/questions/tests/unit/presenters/test_response_set_presenter.py b/lung_cancer_screening/questions/tests/unit/presenters/test_response_set_presenter.py index 97e2ce78..9521a5a4 100644 --- a/lung_cancer_screening/questions/tests/unit/presenters/test_response_set_presenter.py +++ b/lung_cancer_screening/questions/tests/unit/presenters/test_response_set_presenter.py @@ -11,11 +11,17 @@ from ...factories.asbestos_exposure_response_factory import AsbestosExposureResponseFactory from ...factories.respiratory_conditions_response_factory import RespiratoryConditionsResponseFactory from ...factories.cancer_diagnosis_response_factory import CancerDiagnosisResponseFactory +from ...factories.family_history_lung_cancer_response_factory import FamilyHistoryLungCancerResponseFactory +from ...factories.relatives_age_when_diagnosed_response_factory import RelativesAgeWhenDiagnosedResponseFactory from ....models.have_you_ever_smoked_response import HaveYouEverSmokedValues from ....models.sex_at_birth_response import SexAtBirthValues from ....models.gender_response import GenderValues from ....models.ethnicity_response import EthnicityValues +from ....models.family_history_lung_cancer_response import FamilyHistoryLungCancerValues +from ....models.relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedValues + + from ....models.respiratory_conditions_response import RespiratoryConditionValues from ....presenters.response_set_presenter import ResponseSetPresenter @@ -178,3 +184,30 @@ def test_cancer_diagnosis_with_value(self): ) presenter = ResponseSetPresenter(self.response_set) self.assertEqual(presenter.cancer_diagnosis, "Yes") + + def test_family_history_lung_cancer_with_no_value(self): + presenter = ResponseSetPresenter(self.response_set) + self.assertEqual(presenter.family_history_lung_cancer, None) + + def test_family_history_lung_cancer_with_value(self): + FamilyHistoryLungCancerResponseFactory( + response_set=self.response_set, + value=FamilyHistoryLungCancerValues.YES + ) + + presenter = ResponseSetPresenter(self.response_set) + + self.assertEqual(presenter.family_history_lung_cancer, FamilyHistoryLungCancerValues.YES.label) + + def test_relative_age_when_diagnosed_with_no_value(self): + presenter = ResponseSetPresenter(self.response_set) + self.assertEqual(presenter.relatives_age_when_diagnosed, None) + + + def test_relative_age_when_diagnosed_with_value(self): + RelativesAgeWhenDiagnosedResponseFactory( + response_set=self.response_set, + value=RelativesAgeWhenDiagnosedValues.YES + ) + presenter = ResponseSetPresenter(self.response_set) + self.assertEqual(presenter.relatives_age_when_diagnosed, RelativesAgeWhenDiagnosedValues.YES.label) diff --git a/lung_cancer_screening/questions/tests/unit/views/test_relatives_age_when_diagnosed.py b/lung_cancer_screening/questions/tests/unit/views/test_relatives_age_when_diagnosed.py new file mode 100644 index 00000000..9a27ebd6 --- /dev/null +++ b/lung_cancer_screening/questions/tests/unit/views/test_relatives_age_when_diagnosed.py @@ -0,0 +1,154 @@ +from django.test import TestCase, tag +from django.urls import reverse +from dateutil.relativedelta import relativedelta +from django.utils import timezone + +from lung_cancer_screening.questions.models.relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedValues +from lung_cancer_screening.questions.tests.factories.family_history_lung_cancer_response_factory import FamilyHistoryLungCancerResponseFactory +from lung_cancer_screening.questions.tests.factories.response_set_factory import ResponseSetFactory +from ....models.family_history_lung_cancer_response import FamilyHistoryLungCancerValues + +from .helpers.authentication import login_user + + +@tag("FamilyHistoryLungCancer") +class TestGetRelativesAgeWhenDiagnosed(TestCase): + def setUp(self): + self.user = login_user(self.client) + + def test_get_redirects_if_the_user_is_not_logged_in(self): + self.client.logout() + + response = self.client.get( + reverse("questions:relatives_age_when_diagnosed") + ) + + self.assertRedirects( + response, + "/oidc/authenticate/?next=/relatives-age-when-diagnosed", + fetch_redirect_response=False + ) + + def test_get_redirects_when_submitted_response_set_exists_within_last_year( + self + ): + self.user.responseset_set.create( + submitted_at=timezone.now() - relativedelta(days=364) + ) + + response = self.client.get( + reverse("questions:relatives_age_when_diagnosed") + ) + + self.assertRedirects(response, reverse("questions:start")) + + def test_get_responds_successfully(self): + FamilyHistoryLungCancerResponseFactory( + response_set=ResponseSetFactory.create(user=self.user), + value=FamilyHistoryLungCancerValues.YES + ) + + response = self.client.get( + reverse("questions:relatives_age_when_diagnosed") + ) + self.assertEqual(response.status_code, 200) + + def test_get_responds_redirect_for_no_family_history(self): + FamilyHistoryLungCancerResponseFactory( + response_set=ResponseSetFactory.create(user=self.user), + value=FamilyHistoryLungCancerValues.NO + ) + + response = self.client.get( + reverse("questions:relatives_age_when_diagnosed") + ) + + self.assertRedirects( + response, + reverse("questions:family_history_lung_cancer"), + fetch_redirect_response=False + ) + + +class TestPostRelativesAgeWhenDiagnosed(TestCase): + def setUp(self): + self.user = login_user(self.client) + + self.valid_params = {"value": RelativesAgeWhenDiagnosedValues.NO} + + def test_post_redirects_if_the_user_is_not_logged_in(self): + self.client.logout() + + response = self.client.post( + reverse("questions:relatives_age_when_diagnosed"), + self.valid_params + ) + + self.assertRedirects( + response, + "/oidc/authenticate/?next=/relatives-age-when-diagnosed", + fetch_redirect_response=False + ) + + def test_post_creates_unsubmitted_response_set_when_no_response_set_exists( + self + ): + self.client.post( + reverse("questions:relatives_age_when_diagnosed") + ) + + response_set = self.user.responseset_set.first() + self.assertEqual(self.user.responseset_set.count(), 1) + self.assertEqual(response_set.submitted_at, None) + self.assertEqual(response_set.user, self.user) + + def test_post_updates_unsubmitted_response_set_when_one_exists(self): + response_set = self.user.responseset_set.create() + + self.client.post( + reverse("questions:relatives_age_when_diagnosed") + ) + + response_set.refresh_from_db() + self.assertEqual(self.user.responseset_set.count(), 1) + self.assertEqual(response_set.submitted_at, None) + self.assertEqual(response_set.user, self.user) + + def test_post_creates_new_unsubmitted_response_set_when_submitted_exists_over_year_ago( + self + ): + self.user.responseset_set.create( + submitted_at=timezone.now() - relativedelta(years=1) + ) + + self.client.post( + reverse("questions:relatives_age_when_diagnosed") + ) + + self.assertEqual(self.user.responseset_set.count(), 2) + self.assertEqual(self.user.responseset_set.unsubmitted().count(), 1) + + response_set = self.user.responseset_set.last() + self.assertEqual(response_set.submitted_at, None) + self.assertEqual(response_set.user, self.user) + + def test_post_redirects_when_submitted_response_set_exists_within_last_year( + self + ): + self.user.responseset_set.create( + submitted_at=timezone.now() - relativedelta(days=364) + ) + + response = self.client.post( + reverse("questions:relatives_age_when_diagnosed") + ) + + self.assertRedirects(response, reverse("questions:start")) + + def test_post_redirects_to_responses_path(self): + response = self.client.post( + reverse("questions:relatives_age_when_diagnosed"), + self.valid_params + ) + + self.assertRedirects(response, reverse("questions:responses")) diff --git a/lung_cancer_screening/questions/views/family_history_lung_cancer.py b/lung_cancer_screening/questions/views/family_history_lung_cancer.py index 6565d481..727deb60 100644 --- a/lung_cancer_screening/questions/views/family_history_lung_cancer.py +++ b/lung_cancer_screening/questions/views/family_history_lung_cancer.py @@ -29,8 +29,6 @@ def post(self, request): response.value = form.cleaned_data["value"] response.save() - print(response.value) - if response.value == FamilyHistoryLungCancerValues.YES: return redirect(reverse("questions:relatives_age_when_diagnosed")) else: diff --git a/lung_cancer_screening/questions/views/relatives_age_when_diagnosed.py b/lung_cancer_screening/questions/views/relatives_age_when_diagnosed.py index dff49bb1..2181194f 100644 --- a/lung_cancer_screening/questions/views/relatives_age_when_diagnosed.py +++ b/lung_cancer_screening/questions/views/relatives_age_when_diagnosed.py @@ -5,20 +5,46 @@ from .mixins.ensure_response_set import EnsureResponseSet - +from ..forms.relatives_age_when_diagnosed_form import RelativesAgeWhenDiagnosedForm +from ..models.relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedResponse +from ..models.family_history_lung_cancer_response import FamilyHistoryLungCancerValues class RelativesAgeWhenDiagnosedView(LoginRequiredMixin, EnsureResponseSet, View): def get(self, request): - return render_template(request) + response, _ = RelativesAgeWhenDiagnosedResponse.objects.get_or_build( + response_set=request.response_set + ) + + if hasattr(request.response_set, 'family_history_lung_cancer') and request.response_set.family_history_lung_cancer.value == FamilyHistoryLungCancerValues.YES: + return render_template(request, RelativesAgeWhenDiagnosedForm(instance=response)) + else: + return redirect(reverse("questions:family_history_lung_cancer")) def post(self, request): - return redirect(reverse("questions:responses")) + response, _ = RelativesAgeWhenDiagnosedResponse.objects.get_or_build( + response_set=request.response_set + ) + + form = RelativesAgeWhenDiagnosedForm( + instance=response, + data=request.POST + ) + + if form.is_valid(): + response.value = form.cleaned_data["value"] + response.save() + + return redirect(reverse("questions:responses")) + + else: + return render_template(request, form, 422) -def render_template(request, status=200): +def render_template(request, form, status=200): return render( request, - "question_form.jinja", + "relative_age_when_diagnosed.jinja", { + "form": form, "back_link_url": reverse("questions:family_history_lung_cancer") }, status=status diff --git a/lung_cancer_screening/questions/views/responses.py b/lung_cancer_screening/questions/views/responses.py index 0dae7796..18789ef1 100644 --- a/lung_cancer_screening/questions/views/responses.py +++ b/lung_cancer_screening/questions/views/responses.py @@ -13,7 +13,10 @@ def get(self, request): return render( request, "responses.jinja", - { "response_set": ResponseSetPresenter(request.response_set) } + { + "response_set": ResponseSetPresenter(request.response_set), + "back_link_url": reverse("questions:relatives_age_when_diagnosed") + } ) def post(self, request): diff --git a/scripts/tests/accessibility.sh b/scripts/tests/accessibility.sh index 397ae6b9..8e0bcfd8 100755 --- a/scripts/tests/accessibility.sh +++ b/scripts/tests/accessibility.sh @@ -1 +1,3 @@ +echo Running Accessibility Tests + docker compose run --rm --remove-orphans web poetry run python manage.py test --settings=lung_cancer_screening.settings_test --tag=accessibility diff --git a/scripts/tests/ui.sh b/scripts/tests/ui.sh index 7eb0e1aa..79a71a06 100755 --- a/scripts/tests/ui.sh +++ b/scripts/tests/ui.sh @@ -1,3 +1,4 @@ +echo Running UI Tests if [[ -n "${TAG:-}" ]]; then TAG="--tags=$TAG" diff --git a/scripts/tests/unit.sh b/scripts/tests/unit.sh index bfba2d60..dd098be3 100755 --- a/scripts/tests/unit.sh +++ b/scripts/tests/unit.sh @@ -1,5 +1,7 @@ #!/bin/bash +echo Running Unit Tests + set -euo pipefail cd "$(git rev-parse --show-toplevel)" diff --git a/tests/features/questionnaire.feature b/tests/features/questionnaire.feature index d9d8c910..95a76fc5 100644 --- a/tests/features/questionnaire.feature +++ b/tests/features/questionnaire.feature @@ -44,9 +44,12 @@ Feature: Questionnaire When I fill in and submit my cancer diagnosis with "No" Then I am on "/family-history-lung-cancer" And I see a back link to "/cancer-diagnosis" - When I fill in and submit my family history lung cancer with "No" - Then I am on "/responses" + When I fill in and submit my family history lung cancer with "Yes" + 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 "/responses" + And I see a back link to "/relatives-age-when-diagnosed" And I see responses "Have you ever smoked? Yes, I used to smoke" And I see responses "What is your date of birth?" with a date 55 years ago And I see responses "What is your height? 5 feet 7 inches" @@ -56,3 +59,6 @@ Feature: Questionnaire And I see responses "What is your ethnic background? White" And I see responses "Have you ever worked in a job where you might have been exposed to asbestos? No" And I see responses "Have you ever been diagnosed with any of the following respiratory conditions? Pneumonia and Emphysema" + And I see responses "Have you ever been diagnosed with cancer? No" + And I see responses "Have any of your parents, siblings or children ever been diagnosed with lung cancer Yes" + And I see responses "Were any of your relatives younger than 60 years old when they were diagnosed with lung cancer? Yes, they were younger than 60" diff --git a/tests/features/steps/form_steps.py b/tests/features/steps/form_steps.py index cfa6d730..6ffdc265 100644 --- a/tests/features/steps/form_steps.py +++ b/tests/features/steps/form_steps.py @@ -84,6 +84,11 @@ def when_i_fill_in_and_submit_my_cancer_diagnosis(context, family_history_lung_c context.page.get_by_label(family_history_lung_cancer, exact=True).check() when_i_submit_the_form(context) +@when(u'I fill in and submit my relatives age when diagnosed with "{relatives_age_when_diagnosed}"') +def when_i_fill_in_and_submit_my_cancer_diagnosis(context, relatives_age_when_diagnosed): + context.page.get_by_label(relatives_age_when_diagnosed, exact=True).check() + when_i_submit_the_form(context) + @when('I submit the form') def when_i_submit_the_form(context): context.page.click("text=Continue") diff --git a/tests/features/validation_errors.feature b/tests/features/validation_errors.feature index 83343ea9..4516c480 100644 --- a/tests/features/validation_errors.feature +++ b/tests/features/validation_errors.feature @@ -123,3 +123,30 @@ Feature: Validation errors When I fill in and submit my respiratory conditions with "Bronchitis" and "No, I have not had any of these respiratory conditions" Then I am on "/respiratory-conditions" And I see a form error "Select if you have had any respiratory conditions, or select 'No, I have not had any of these respiratory conditions'" + + Scenario: Respiratory conditions form errors + Given I am logged in + And I have started the questionnaire + When I go to "/cancer-diagnosis" + And I submit the form + Then I am on "/cancer-diagnosis" + And I see a form error "Select if you have been diagnosed with cancer" + + Scenario: Respiratory conditions form errors + Given I am logged in + And I have started the questionnaire + When I go to "/family-history-lung-cancer" + And I submit the form + Then I am on "/family-history-lung-cancer" + And I see a form error "Select if any of your parents, siblings or children have had a diagnosis of lung cancer" + + Scenario: Respiratory conditions form errors + Given I am logged in + And I have started the questionnaire + When I go to "/relatives-age-when-diagnosed" + Then I am on "/family-history-lung-cancer" + When I fill in and submit my family history lung cancer with "Yes" + Then I am on "/relatives-age-when-diagnosed" + When I submit the form + Then I am on "/relatives-age-when-diagnosed" + And I see a form error "Select if your relatives were younger than 60 when they were diagnosed with lung cancer"