diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/nipple_change.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/nipple_change.jinja
index e5b6616eb..79d1065a4 100644
--- a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/nipple_change.jinja
+++ b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/nipple_change.jinja
@@ -3,6 +3,12 @@
{% from "nhsuk/components/fieldset/macro.jinja" import fieldset %}
{% block form %}
+ {% if heading_description %}
+
+ {% endif %}
+
{% do form.symptom_sub_type.add_conditional_html('NIPPLE_CHANGE_OTHER', form.symptom_sub_type_details.as_field_group()) %}
{% do form.when_started.add_divider_after("OVER_THREE_YEARS", "or") %}
diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/other.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/other.jinja
index c4e781c46..bd68cd981 100644
--- a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/other.jinja
+++ b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/other.jinja
@@ -32,6 +32,8 @@
{{ form.investigated.as_field_group() }}
+ {{ form.highlight_to_readers.as_field_group() }}
+
{{ form.additional_information.as_field_group() }}
diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/skin_change.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/skin_change.jinja
index 9f8c9d502..526696de9 100644
--- a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/skin_change.jinja
+++ b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/forms/skin_change.jinja
@@ -3,6 +3,12 @@
{% from "nhsuk/components/fieldset/macro.jinja" import fieldset %}
{% block form %}
+ {% if heading_description %}
+
+
{{ heading_description }}
+
+ {% endif %}
+
{% include "mammograms/medical_information/symptoms/forms/inline_area_radios.jinja" %}
{% do form.symptom_sub_type.add_conditional_html('SKIN_CHANGE_OTHER', form.symptom_sub_type_details.as_field_group()) %}
diff --git a/manage_breast_screening/mammograms/presenters/symptom_presenter.py b/manage_breast_screening/mammograms/presenters/symptom_presenter.py
index 4ac80c590..0db9e1d9a 100644
--- a/manage_breast_screening/mammograms/presenters/symptom_presenter.py
+++ b/manage_breast_screening/mammograms/presenters/symptom_presenter.py
@@ -1,5 +1,5 @@
from django.urls import reverse
-from django.utils.html import escape
+from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe
from manage_breast_screening.core.template_helpers import (
@@ -139,8 +139,17 @@ def build_summary_list_row(self, include_actions=True):
]
)
+ if self._symptom.highlight_to_readers:
+ key = {
+ "html": format_html(
+ '{}
Highlight to image readers',
+ self._symptom.symptom_type.name,
+ )
+ }
+ else:
+ key = {"text": self._symptom.symptom_type.name}
result = {
- "key": {"text": self._symptom.symptom_type.name},
+ "key": key,
"value": {"html": html},
}
diff --git a/manage_breast_screening/mammograms/tests/forms/test_symptom_forms.py b/manage_breast_screening/mammograms/tests/forms/test_symptom_forms.py
index 71a228e02..8f7d2f462 100644
--- a/manage_breast_screening/mammograms/tests/forms/test_symptom_forms.py
+++ b/manage_breast_screening/mammograms/tests/forms/test_symptom_forms.py
@@ -19,6 +19,7 @@
)
from manage_breast_screening.nhsuk_forms.choices import YesNo
from manage_breast_screening.participants.models.symptom import (
+ HighlightToReaderChoices,
NippleChangeChoices,
SkinChangeChoices,
SymptomAreas,
@@ -588,6 +589,7 @@ def test_valid_form(self):
"symptom_sub_type": SkinChangeChoices.COLOUR_CHANGE,
"when_started": RelativeDateChoices.LESS_THAN_THREE_MONTHS,
"investigated": YesNo.NO,
+ "highlight_to_readers": HighlightToReaderChoices.YES,
}
)
)
@@ -603,6 +605,9 @@ def test_missing_required_fields(self):
"symptom_sub_type_details": ["Enter a description of the symptom"],
"investigated": ["Select whether the symptom has been investigated or not"],
"area": ["Select the location of the symptom"],
+ "highlight_to_readers": [
+ "Select whether this symptom should be highlighted to image readers"
+ ],
}
def test_missing_conditionally_required_fields(self):
@@ -614,6 +619,7 @@ def test_missing_conditionally_required_fields(self):
"symptom_sub_type_details": "abc symptom",
"when_started": RelativeDateChoices.SINCE_A_SPECIFIC_DATE,
"investigated": YesNo.YES,
+ "highlight_to_readers": HighlightToReaderChoices.YES,
}
)
)
@@ -641,6 +647,7 @@ def test_valid_form_with_conditionally_required_fields(self):
"specific_date_0": "2",
"specific_date_1": "2025",
"investigation_details": "def",
+ "highlight_to_readers": HighlightToReaderChoices.YES,
}
)
)
@@ -658,6 +665,7 @@ def test_valid_form(self):
"area_description_left_breast": "uoq",
"when_started": RelativeDateChoices.LESS_THAN_THREE_MONTHS,
"investigated": YesNo.NO,
+ "highlight_to_readers": HighlightToReaderChoices.YES,
}
)
)
@@ -672,6 +680,9 @@ def test_missing_required_fields(self):
"when_started": ["Select how long the symptom has existed"],
"investigated": ["Select whether the symptom has been investigated or not"],
"area": ["Select the location of the pain"],
+ "highlight_to_readers": [
+ "Select whether this symptom should be highlighted to image readers"
+ ],
}
def test_missing_conditionally_required_fields(self):
@@ -683,6 +694,7 @@ def test_missing_conditionally_required_fields(self):
"when_started": RelativeDateChoices.SINCE_A_SPECIFIC_DATE,
"investigated": YesNo.YES,
"recently_resolved": True,
+ "highlight_to_readers": HighlightToReaderChoices.YES,
}
)
)
@@ -712,6 +724,7 @@ def test_valid_form_with_conditionally_required_fields(self):
"investigation_details": "def",
"recently_resolved": True,
"when_resolved": "3 months ago",
+ "highlight_to_readers": HighlightToReaderChoices.YES,
}
)
)
diff --git a/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py b/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py
index 0dce526cc..e0b2a12ed 100644
--- a/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py
+++ b/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py
@@ -51,6 +51,23 @@ def test_formats_symptoms_summary_list(self):
area=SymptomAreas.BOTH_BREASTS,
)
+ symptom3 = SymptomFactory.create(
+ other=True,
+ appointment=appointment,
+ when_started=RelativeDateChoices.LESS_THAN_THREE_MONTHS,
+ area=SymptomAreas.RIGHT_BREAST,
+ symptom_sub_type_details="abc",
+ )
+
+ symptom4 = SymptomFactory.create(
+ other=True,
+ appointment=appointment,
+ when_started=RelativeDateChoices.LESS_THAN_THREE_MONTHS,
+ area=SymptomAreas.LEFT_BREAST,
+ highlight_to_readers=False,
+ symptom_sub_type_details="xyz",
+ )
+
presenter = MedicalInformationPresenter(appointment)
assert presenter.symptom_rows == [
@@ -66,12 +83,46 @@ def test_formats_symptoms_summary_list(self):
],
},
"key": {
- "text": "Lump",
+ "html": 'Lump
Highlight to image readers',
},
"value": {
"html": "Left breast
Not sure
Symptom is intermittent
Stopped: resolved date
Not investigated
Additional information: abc",
},
},
+ {
+ "actions": {
+ "items": [
+ {
+ "text": "Change",
+ "classes": "nhsuk-link--no-visited-state",
+ "visuallyHiddenText": "other",
+ "href": f"/mammograms/{appointment.id}/record-medical-information/other/{symptom3.id}/",
+ },
+ ],
+ },
+ "key": {
+ "html": 'Other
Highlight to image readers'
+ },
+ "value": {
+ "html": "Description: abc
Right breast
Less than 3 months ago
Not investigated"
+ },
+ },
+ {
+ "actions": {
+ "items": [
+ {
+ "text": "Change",
+ "classes": "nhsuk-link--no-visited-state",
+ "visuallyHiddenText": "other",
+ "href": f"/mammograms/{appointment.id}/record-medical-information/other/{symptom4.id}/",
+ }
+ ]
+ },
+ "key": {"text": "Other"},
+ "value": {
+ "html": "Description: xyz
Left breast
Less than 3 months ago
Not investigated"
+ },
+ },
{
"actions": {
"items": [
@@ -84,7 +135,7 @@ def test_formats_symptoms_summary_list(self):
],
},
"key": {
- "text": "Swelling or shape change",
+ "html": 'Swelling or shape change
Highlight to image readers',
},
"value": {
"html": "Both breasts
Less than 3 months ago
Not investigated",
diff --git a/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py b/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py
index 85a61aad7..46fde1eff 100644
--- a/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py
+++ b/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py
@@ -135,7 +135,7 @@ def test_formats_intermittent_stopped_and_additional_information(self):
assert presenter.intermittent_line == "Symptom is intermittent"
assert presenter.additional_information_line == "Additional information: abc"
- def test_formats_for_summary_list(self):
+ def test_formats_lump_for_summary_list(self):
symptom = SymptomFactory.create(
lump=True,
when_started=RelativeDateChoices.NOT_SURE,
@@ -159,13 +159,48 @@ def test_formats_for_summary_list(self):
],
},
"key": {
- "text": "Lump",
+ "html": 'Lump
Highlight to image readers',
},
"value": {
"html": "Left breast
Not sure
Symptom is intermittent
Stopped: resolved date
Not investigated
Additional information: abc",
},
}
+ @pytest.mark.parametrize("highlight_to_readers", [True, False])
+ def test_formats_other_for_summary_list(self, highlight_to_readers):
+ symptom = SymptomFactory.create(
+ breast_pain=True,
+ when_started=RelativeDateChoices.LESS_THAN_THREE_MONTHS,
+ area=SymptomAreas.LEFT_BREAST,
+ highlight_to_readers=highlight_to_readers,
+ )
+
+ presenter = SymptomPresenter(symptom)
+
+ if highlight_to_readers:
+ expected_key = {
+ "html": 'Breast pain
Highlight to image readers',
+ }
+ else:
+ expected_key = {"text": "Breast pain"}
+
+ assert presenter.summary_list_row == {
+ "actions": {
+ "items": [
+ {
+ "text": "Change",
+ "classes": "nhsuk-link--no-visited-state",
+ "visuallyHiddenText": "breast pain",
+ "href": f"/mammograms/{symptom.appointment_id}/record-medical-information/breast-pain/{symptom.id}/",
+ }
+ ]
+ },
+ "key": expected_key,
+ "value": {
+ "html": "Left breast
Less than 3 months ago
Not investigated"
+ },
+ }
+
def test_delete_message_html(self):
lump = SymptomFactory.create(lump=True)
presenter = SymptomPresenter(lump)
diff --git a/manage_breast_screening/mammograms/tests/views/test_symptom_views.py b/manage_breast_screening/mammograms/tests/views/test_symptom_views.py
index e6ed3608e..9a5f43942 100644
--- a/manage_breast_screening/mammograms/tests/views/test_symptom_views.py
+++ b/manage_breast_screening/mammograms/tests/views/test_symptom_views.py
@@ -5,6 +5,7 @@
from manage_breast_screening.nhsuk_forms.choices import YesNo
from manage_breast_screening.participants.models.symptom import (
+ HighlightToReaderChoices,
NippleChangeChoices,
RelativeDateChoices,
SkinChangeChoices,
@@ -34,6 +35,10 @@ def test_renders_response(
)
)
assert response.status_code == 200
+ assert (
+ "Lumps are a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+ in response.content.decode()
+ )
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, confirmed_identity_appointment
@@ -112,6 +117,10 @@ def test_renders_response(self, clinical_user_client, lump):
)
)
assert response.status_code == 200
+ assert (
+ "Lumps are a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+ in response.content.decode()
+ )
def test_non_existant_or_deleted_symptom_id_is_a_404(
self, clinical_user_client, confirmed_identity_appointment
@@ -232,6 +241,10 @@ def test_renders_response(
)
)
assert response.status_code == 200
+ assert (
+ "Skin change is a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+ in response.content.decode()
+ )
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, confirmed_identity_appointment
@@ -277,6 +290,10 @@ def test_renders_response(self, clinical_user_client, colour_change):
)
)
assert response.status_code == 200
+ assert (
+ "Skin change is a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+ in response.content.decode()
+ )
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, colour_change
@@ -318,6 +335,10 @@ def test_renders_response(
)
)
assert response.status_code == 200
+ assert (
+ "Nipple change is a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+ in response.content.decode()
+ )
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, confirmed_identity_appointment
@@ -359,6 +380,10 @@ def test_renders_response(self, clinical_user_client, inversion):
)
)
assert response.status_code == 200
+ assert (
+ "Nipple change is a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+ in response.content.decode()
+ )
def test_valid_post_redirects_to_appointment(self, clinical_user_client, inversion):
response = clinical_user_client.http.post(
@@ -395,6 +420,13 @@ def test_renders_response(
)
assert response.status_code == 200
+ content = response.content.decode()
+ assert (
+ "Information recorded here will be highlighted during image reading."
+ not in content
+ )
+ assert "Highlight this symptom to readers?" in content
+
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, confirmed_identity_appointment
):
@@ -409,6 +441,7 @@ def test_valid_post_redirects_to_appointment(
"symptom_sub_type_details": "abc",
"when_started": RelativeDateChoices.LESS_THAN_THREE_MONTHS.value,
"investigated": YesNo.NO.value,
+ "highlight_to_readers": HighlightToReaderChoices.YES.value,
},
)
assertRedirects(
@@ -440,6 +473,13 @@ def test_renders_response(self, clinical_user_client, other_symptom):
)
assert response.status_code == 200
+ content = response.content.decode()
+ assert (
+ "Information recorded here will be highlighted during image reading."
+ not in content
+ )
+ assert "Highlight this symptom to readers?" in content
+
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, other_symptom
):
@@ -457,6 +497,7 @@ def test_valid_post_redirects_to_appointment(
"symptom_sub_type_details": "abc",
"when_started": RelativeDateChoices.LESS_THAN_THREE_MONTHS.value,
"investigated": YesNo.NO.value,
+ "highlight_to_readers": HighlightToReaderChoices.YES.value,
},
)
assertRedirects(
@@ -481,6 +522,13 @@ def test_renders_response(
)
assert response.status_code == 200
+ content = response.content.decode()
+ assert (
+ "Information recorded here will be highlighted during image reading."
+ not in content
+ )
+ assert "Highlight this symptom to readers?" in content
+
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, confirmed_identity_appointment
):
@@ -494,6 +542,7 @@ def test_valid_post_redirects_to_appointment(
"area_description_right_breast": "uiq",
"when_started": RelativeDateChoices.LESS_THAN_THREE_MONTHS.value,
"investigated": YesNo.NO.value,
+ "highlight_to_readers": HighlightToReaderChoices.YES.value,
},
)
assertRedirects(
@@ -526,6 +575,13 @@ def test_renders_response(self, clinical_user_client, breast_pain):
)
assert response.status_code == 200
+ content = response.content.decode()
+ assert (
+ "Information recorded here will be highlighted during image reading."
+ not in content
+ )
+ assert "Highlight this symptom to readers?" in content
+
def test_valid_post_redirects_to_appointment(
self, clinical_user_client, breast_pain
):
@@ -542,6 +598,7 @@ def test_valid_post_redirects_to_appointment(
"area_description_right_breast": "uiq",
"when_started": RelativeDateChoices.LESS_THAN_THREE_MONTHS.value,
"investigated": YesNo.NO.value,
+ "highlight_to_readers": HighlightToReaderChoices.YES.value,
},
)
assertRedirects(
diff --git a/manage_breast_screening/mammograms/views/symptom_views.py b/manage_breast_screening/mammograms/views/symptom_views.py
index 3e69aa461..711ea9983 100644
--- a/manage_breast_screening/mammograms/views/symptom_views.py
+++ b/manage_breast_screening/mammograms/views/symptom_views.py
@@ -48,7 +48,7 @@ def get_back_link_params(self):
}
def get_context_data(self, **kwargs):
- context = super().get_context_data()
+ context = super().get_context_data(**kwargs)
participant = self.appointment.participant
@@ -58,11 +58,18 @@ def get_context_data(self, **kwargs):
"caption": participant.full_name,
"heading": f"Details of the {self.symptom_type_name.lower()}",
"page_title": f"Details of the {self.symptom_type_name.lower()}",
+ "heading_description": self._get_heading_description(),
},
)
return context
+ def _get_heading_description(self):
+ suffix = " a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+ if self.symptom_type_name == "lump":
+ return "Lumps are" + suffix
+ return f"{self.symptom_type_name.capitalize()} is" + suffix
+
class AddSymptomView(BaseSymptomFormView):
"""
@@ -137,13 +144,6 @@ class AddSymptomLumpView(AddSymptomView):
form_class = LumpForm
template_name = "mammograms/medical_information/symptoms/forms/simple_symptom.jinja"
- def get_context_data(self, **kwargs):
- context = super().get_context_data(**kwargs)
- context["heading_description"] = (
- "Lumps are a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
- )
- return context
-
class AddSymptomSwellingOrShapeChangeView(AddSymptomView):
"""
@@ -212,13 +212,6 @@ class UpdateSymptomLumpView(UpdateSymptomView):
def extra_filters(self):
return {"symptom_type_id": SymptomType.LUMP}
- def get_context_data(self, **kwargs):
- context = super().get_context_data(**kwargs)
- context["heading_description"] = (
- "Record whether the lump is in the left breast, right breast or both."
- )
- return context
-
class UpdateSymptomSwellingOrShapeChangeView(UpdateSymptomView):
"""
diff --git a/manage_breast_screening/participants/migrations/0068_symptom_highlight_to_readers.py b/manage_breast_screening/participants/migrations/0068_symptom_highlight_to_readers.py
new file mode 100644
index 000000000..28872ee37
--- /dev/null
+++ b/manage_breast_screening/participants/migrations/0068_symptom_highlight_to_readers.py
@@ -0,0 +1,18 @@
+# Generated by Django 6.0.4 on 2026-04-28 11:49
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('participants', '0001_squashed_0067_participantreportedmammogram_created_by_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='symptom',
+ name='highlight_to_readers',
+ field=models.BooleanField(default=True),
+ ),
+ ]
diff --git a/manage_breast_screening/participants/migrations/max_migration.txt b/manage_breast_screening/participants/migrations/max_migration.txt
index bb7026a49..8cf7e2d60 100644
--- a/manage_breast_screening/participants/migrations/max_migration.txt
+++ b/manage_breast_screening/participants/migrations/max_migration.txt
@@ -1 +1 @@
-0001_squashed_0067_participantreportedmammogram_created_by_and_more
+0068_symptom_highlight_to_readers
diff --git a/manage_breast_screening/participants/models/symptom.py b/manage_breast_screening/participants/models/symptom.py
index d69a0b732..937dae35a 100644
--- a/manage_breast_screening/participants/models/symptom.py
+++ b/manage_breast_screening/participants/models/symptom.py
@@ -58,6 +58,11 @@ class RelativeDateChoices(models.TextChoices):
NOT_SURE = "NOT_SURE", "Not sure"
+class HighlightToReaderChoices(models.TextChoices):
+ YES = "YES", "Yes, highlight to image readers"
+ NO = "NO", "No, just record information"
+
+
class Symptom(BaseModel):
symptom_type = models.ForeignKey(SymptomType, on_delete=models.PROTECT)
symptom_sub_type = models.ForeignKey(
@@ -89,6 +94,8 @@ class Symptom(BaseModel):
recently_resolved = models.BooleanField(null=False, default=False)
when_resolved = models.CharField(blank=True, null=False)
+ highlight_to_readers = models.BooleanField(null=False, default=True)
+
additional_information = models.CharField(blank=True, null=False)
@property
diff --git a/manage_breast_screening/participants/tests/factories.py b/manage_breast_screening/participants/tests/factories.py
index 7783182e7..fb222e85b 100644
--- a/manage_breast_screening/participants/tests/factories.py
+++ b/manage_breast_screening/participants/tests/factories.py
@@ -292,6 +292,7 @@ class Meta:
intermittent = False
investigated = False
recently_resolved = False
+ highlight_to_readers = True
appointment = SubFactory(AppointmentFactory)
area_description = LazyAttribute(
lambda o: "" if o.area == models.SymptomAreas.BOTH_BREASTS else "abc"
@@ -329,6 +330,8 @@ class Params:
symptom_type_id=models.SymptomType.OTHER, symptom_sub_type_details="abc"
)
+ breast_pain = Trait(symptom_type_id=models.SymptomType.BREAST_PAIN)
+
class HormoneReplacementTherapyFactory(DjangoModelFactory):
class Meta:
diff --git a/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py b/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py
index 6aae12aa2..8cf414855 100644
--- a/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py
+++ b/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py
@@ -173,7 +173,7 @@ def then_i_am_back_on_the_medical_information_page(self):
def and_the_lump_on_the_right_breast_is_listed(self):
key = self.page.locator(
- ".nhsuk-summary-list__key", has=self.page.get_by_text("Lump", exact=True)
+ ".nhsuk-summary-list__key", has=self.page.get_by_text("Lump")
)
row = self.page.locator(".nhsuk-summary-list__row").filter(has=key)
expect(row).to_contain_text("Right breast")
@@ -181,7 +181,7 @@ def and_the_lump_on_the_right_breast_is_listed(self):
def when_i_click_on_change(self):
key = self.page.locator(
".nhsuk-summary-list__key",
- has=self.page.get_by_text("Swelling or shape change", exact=True),
+ has=self.page.get_by_text("Swelling or shape change"),
)
row = self.page.locator(".nhsuk-summary-list__row").filter(has=key)
row.locator(".nhsuk-summary-list__actions").get_by_text(
@@ -194,7 +194,7 @@ def then_less_than_three_months_should_be_selected(self):
def and_i_see_three_months_to_a_year(self):
key = self.page.locator(
".nhsuk-summary-list__key",
- has=self.page.get_by_text("Swelling or shape change", exact=True),
+ has=self.page.get_by_text("Swelling or shape change"),
)
row = self.page.locator(".nhsuk-summary-list__row").filter(has=key)
expect(row).to_contain_text("3 months to a year")
@@ -207,7 +207,7 @@ def and_i_confirm_i_want_to_delete_the_symptom(self):
def and_the_lump_is_no_longer_listed(self):
locator = self.page.locator(
- ".nhsuk-summary-list__key", has=self.page.get_by_text("Lump", exact=True)
+ ".nhsuk-summary-list__key", has=self.page.get_by_text("Lump")
)
expect(locator).not_to_be_attached()
From addf2444daae0d194cd87755eb4dfc120f7087aa Mon Sep 17 00:00:00 2001
From: Steve Webber <198724792+swebberuk@users.noreply.github.com>
Date: Thu, 30 Apr 2026 16:40:51 +0100
Subject: [PATCH 2/3] Only set heading_description for symptoms that use it
---
.../mammograms/views/symptom_views.py | 62 ++++++++++++++++---
1 file changed, 53 insertions(+), 9 deletions(-)
diff --git a/manage_breast_screening/mammograms/views/symptom_views.py b/manage_breast_screening/mammograms/views/symptom_views.py
index 711ea9983..f9a7ed23c 100644
--- a/manage_breast_screening/mammograms/views/symptom_views.py
+++ b/manage_breast_screening/mammograms/views/symptom_views.py
@@ -22,6 +22,9 @@
)
from .mixins import InProgressAppointmentMixin, MedicalInformationMixin
+HEADING_DESCRIPTION_KEY = "heading_description"
+HEADING_DESCRIPTION_SUFFIX = " a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
+
class BaseSymptomFormView(InProgressAppointmentMixin, FormView):
"""
@@ -58,18 +61,11 @@ def get_context_data(self, **kwargs):
"caption": participant.full_name,
"heading": f"Details of the {self.symptom_type_name.lower()}",
"page_title": f"Details of the {self.symptom_type_name.lower()}",
- "heading_description": self._get_heading_description(),
},
)
return context
- def _get_heading_description(self):
- suffix = " a recognised symptom of breast cancer. Information recorded here will be highlighted during image reading."
- if self.symptom_type_name == "lump":
- return "Lumps are" + suffix
- return f"{self.symptom_type_name.capitalize()} is" + suffix
-
class AddSymptomView(BaseSymptomFormView):
"""
@@ -144,6 +140,11 @@ class AddSymptomLumpView(AddSymptomView):
form_class = LumpForm
template_name = "mammograms/medical_information/symptoms/forms/simple_symptom.jinja"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = "Lumps are" + HEADING_DESCRIPTION_SUFFIX
+ return context
+
class AddSymptomSwellingOrShapeChangeView(AddSymptomView):
"""
@@ -154,6 +155,13 @@ class AddSymptomSwellingOrShapeChangeView(AddSymptomView):
form_class = SwellingOrShapeChangeForm
template_name = "mammograms/medical_information/symptoms/forms/simple_symptom.jinja"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = (
+ "Swelling or shape change is" + HEADING_DESCRIPTION_SUFFIX
+ )
+ return context
+
class AddSymptomSkinChangeView(AddSymptomView):
"""
@@ -164,6 +172,11 @@ class AddSymptomSkinChangeView(AddSymptomView):
form_class = SkinChangeForm
template_name = "mammograms/medical_information/symptoms/forms/skin_change.jinja"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = "Skin change is" + HEADING_DESCRIPTION_SUFFIX
+ return context
+
class AddSymptomNippleChangeView(AddSymptomView):
"""
@@ -174,6 +187,13 @@ class AddSymptomNippleChangeView(AddSymptomView):
form_class = NippleChangeForm
template_name = "mammograms/medical_information/symptoms/forms/nipple_change.jinja"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = (
+ "Nipple change is" + HEADING_DESCRIPTION_SUFFIX
+ )
+ return context
+
class AddOtherSymptomView(AddSymptomView):
"""
@@ -185,7 +205,7 @@ class AddOtherSymptomView(AddSymptomView):
template_name = "mammograms/medical_information/symptoms/forms/other.jinja"
def get_context_data(self, **kwargs):
- context = super().get_context_data()
+ context = super().get_context_data(**kwargs)
context["heading"] = "Symptom details"
return context
@@ -212,6 +232,11 @@ class UpdateSymptomLumpView(UpdateSymptomView):
def extra_filters(self):
return {"symptom_type_id": SymptomType.LUMP}
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = "Lumps are" + HEADING_DESCRIPTION_SUFFIX
+ return context
+
class UpdateSymptomSwellingOrShapeChangeView(UpdateSymptomView):
"""
@@ -225,6 +250,13 @@ class UpdateSymptomSwellingOrShapeChangeView(UpdateSymptomView):
def extra_filters(self):
return {"symptom_type_id": SymptomType.SWELLING_OR_SHAPE_CHANGE}
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = (
+ "Swelling or shape change is" + HEADING_DESCRIPTION_SUFFIX
+ )
+ return context
+
class UpdateSymptomSkinChangeView(UpdateSymptomView):
"""
@@ -238,6 +270,11 @@ class UpdateSymptomSkinChangeView(UpdateSymptomView):
def extra_filters(self):
return {"symptom_type_id": SymptomType.SKIN_CHANGE}
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = "Skin change is" + HEADING_DESCRIPTION_SUFFIX
+ return context
+
class UpdateSymptomNippleChangeView(UpdateSymptomView):
"""
@@ -251,6 +288,13 @@ class UpdateSymptomNippleChangeView(UpdateSymptomView):
def extra_filters(self):
return {"symptom_type_id": SymptomType.NIPPLE_CHANGE}
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context[HEADING_DESCRIPTION_KEY] = (
+ "Nipple change is" + HEADING_DESCRIPTION_SUFFIX
+ )
+ return context
+
class UpdateOtherSymptomView(UpdateSymptomView):
"""
@@ -265,7 +309,7 @@ def extra_filters(self):
return {"symptom_type_id": SymptomType.OTHER}
def get_context_data(self, **kwargs):
- context = super().get_context_data()
+ context = super().get_context_data(**kwargs)
context["heading"] = "Symptom details"
return context
From e19314620990fe49de206e4c749615611c638c41 Mon Sep 17 00:00:00 2001
From: Steve Webber <198724792+swebberuk@users.noreply.github.com>
Date: Fri, 1 May 2026 13:23:14 +0100
Subject: [PATCH 3/3] Add symptoms_summary for displaying symptoms
Adds 'Highlight to readers' tag if required
---
.../medical_information/section_cards.jinja | 22 ++++++++++--
.../symptoms/confirm_delete_lump.jinja | 7 ++--
.../presenters/symptom_presenter.py | 16 +++------
.../test_medical_information_presenter.py | 34 +++++++------------
.../presenters/test_symptom_presenter.py | 23 ++++---------
5 files changed, 43 insertions(+), 59 deletions(-)
diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/section_cards.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/section_cards.jinja
index 59f567617..d76814abc 100644
--- a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/section_cards.jinja
+++ b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/section_cards.jinja
@@ -97,9 +97,7 @@
{% set symptom_rows = presented_medical_info.read_only_symptom_rows if read_only else presented_medical_info.symptom_rows %}
Any problems or symptoms, including lumps, swelling, rashes or nipple changes
{% if symptom_rows %}
- {{ summaryList({
- "rows": symptom_rows
- }) }}
+ {{ symptoms_summary(symptom_rows) }}
{% else %}
{% set insetHtml %}
No symptoms have been recorded for this participant.
@@ -244,3 +242,21 @@
]
}) }}
{% endmacro %}
+
+{% macro symptoms_summary(symptom_rows, classes='') %}
+ {% set rows = [] %}
+ {% for row in symptom_rows %}
+ {% set key_html %}
+ {{ row.symptom_name }}
+ {% if row.highlight_to_readers %}
+
Highlight to image readers
+ {% endif %}
+ {% endset %}
+ {% set _ = rows.append({
+ "key": {"html": key_html},
+ "value": {"html": row.html},
+ "actions": row.actions if row.actions else {"items": []}
+ }) %}
+ {% endfor %}
+ {{ summaryList({"rows": rows, "classes": classes}) }}
+{% endmacro %}
diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/confirm_delete_lump.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/confirm_delete_lump.jinja
index 80a1d0bd1..1222afbb2 100644
--- a/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/confirm_delete_lump.jinja
+++ b/manage_breast_screening/mammograms/jinja2/mammograms/medical_information/symptoms/confirm_delete_lump.jinja
@@ -1,12 +1,9 @@
{% extends "layout-confirmation.jinja" %}
-{% from 'nhsuk/components/summary-list/macro.jinja' import summaryList %}
+{% from "mammograms/medical_information/section_cards.jinja" import symptoms_summary %}
{% from 'nhsuk/components/inset-text/macro.jinja' import insetText %}
{% block details %}
- {{ summaryList({
- "rows": [summary_list_row],
- "classes": "nhsuk-summary-list--no-border"
- }) }}
+ {{ symptoms_summary([summary_list_row], classes="nhsuk-summary-list--no-border") }}
{% set insetTextHtml %}
This action is final and cannot be undone.
diff --git a/manage_breast_screening/mammograms/presenters/symptom_presenter.py b/manage_breast_screening/mammograms/presenters/symptom_presenter.py
index 0db9e1d9a..404df87ef 100644
--- a/manage_breast_screening/mammograms/presenters/symptom_presenter.py
+++ b/manage_breast_screening/mammograms/presenters/symptom_presenter.py
@@ -1,5 +1,5 @@
from django.urls import reverse
-from django.utils.html import escape, format_html
+from django.utils.html import escape
from django.utils.safestring import mark_safe
from manage_breast_screening.core.template_helpers import (
@@ -139,18 +139,10 @@ def build_summary_list_row(self, include_actions=True):
]
)
- if self._symptom.highlight_to_readers:
- key = {
- "html": format_html(
- '{}
Highlight to image readers',
- self._symptom.symptom_type.name,
- )
- }
- else:
- key = {"text": self._symptom.symptom_type.name}
result = {
- "key": key,
- "value": {"html": html},
+ "symptom_name": self._symptom.symptom_type.name,
+ "highlight_to_readers": self._symptom.highlight_to_readers,
+ "html": html,
}
if include_actions:
diff --git a/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py b/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py
index e0b2a12ed..289a88bd9 100644
--- a/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py
+++ b/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py
@@ -82,12 +82,9 @@ def test_formats_symptoms_summary_list(self):
},
],
},
- "key": {
- "html": 'Lump
Highlight to image readers',
- },
- "value": {
- "html": "Left breast
Not sure
Symptom is intermittent
Stopped: resolved date
Not investigated
Additional information: abc",
- },
+ "symptom_name": "Lump",
+ "highlight_to_readers": True,
+ "html": "Left breast
Not sure
Symptom is intermittent
Stopped: resolved date
Not investigated
Additional information: abc",
},
{
"actions": {
@@ -100,12 +97,9 @@ def test_formats_symptoms_summary_list(self):
},
],
},
- "key": {
- "html": 'Other
Highlight to image readers'
- },
- "value": {
- "html": "Description: abc
Right breast
Less than 3 months ago
Not investigated"
- },
+ "symptom_name": "Other",
+ "highlight_to_readers": True,
+ "html": "Description: abc
Right breast
Less than 3 months ago
Not investigated",
},
{
"actions": {
@@ -118,10 +112,9 @@ def test_formats_symptoms_summary_list(self):
}
]
},
- "key": {"text": "Other"},
- "value": {
- "html": "Description: xyz
Left breast
Less than 3 months ago
Not investigated"
- },
+ "symptom_name": "Other",
+ "highlight_to_readers": False,
+ "html": "Description: xyz
Left breast
Less than 3 months ago
Not investigated",
},
{
"actions": {
@@ -134,12 +127,9 @@ def test_formats_symptoms_summary_list(self):
},
],
},
- "key": {
- "html": 'Swelling or shape change
Highlight to image readers',
- },
- "value": {
- "html": "Both breasts
Less than 3 months ago
Not investigated",
- },
+ "symptom_name": "Swelling or shape change",
+ "highlight_to_readers": True,
+ "html": "Both breasts
Less than 3 months ago
Not investigated",
},
]
diff --git a/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py b/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py
index 46fde1eff..aa61b9e4b 100644
--- a/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py
+++ b/manage_breast_screening/mammograms/tests/presenters/test_symptom_presenter.py
@@ -158,12 +158,9 @@ def test_formats_lump_for_summary_list(self):
},
],
},
- "key": {
- "html": 'Lump
Highlight to image readers',
- },
- "value": {
- "html": "Left breast
Not sure
Symptom is intermittent
Stopped: resolved date
Not investigated
Additional information: abc",
- },
+ "symptom_name": "Lump",
+ "highlight_to_readers": True,
+ "html": "Left breast
Not sure
Symptom is intermittent
Stopped: resolved date
Not investigated
Additional information: abc",
}
@pytest.mark.parametrize("highlight_to_readers", [True, False])
@@ -177,13 +174,6 @@ def test_formats_other_for_summary_list(self, highlight_to_readers):
presenter = SymptomPresenter(symptom)
- if highlight_to_readers:
- expected_key = {
- "html": 'Breast pain
Highlight to image readers',
- }
- else:
- expected_key = {"text": "Breast pain"}
-
assert presenter.summary_list_row == {
"actions": {
"items": [
@@ -195,10 +185,9 @@ def test_formats_other_for_summary_list(self, highlight_to_readers):
}
]
},
- "key": expected_key,
- "value": {
- "html": "Left breast
Less than 3 months ago
Not investigated"
- },
+ "symptom_name": "Breast pain",
+ "highlight_to_readers": highlight_to_readers,
+ "html": "Left breast
Less than 3 months ago
Not investigated",
}
def test_delete_message_html(self):