diff --git a/.ds.baseline b/.ds.baseline
index 8b09a97f4..4f2a73d8c 100644
--- a/.ds.baseline
+++ b/.ds.baseline
@@ -161,7 +161,7 @@
"filename": "app/config.py",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
- "line_number": 119,
+ "line_number": 124,
"is_secret": false
}
],
@@ -634,5 +634,5 @@
}
]
},
- "generated_at": "2025-07-31T17:38:47Z"
+ "generated_at": "2025-07-31T11:53:28Z"
}
diff --git a/app/assets/javascripts/activityChart.js b/app/assets/javascripts/activityChart.js
index e2add6117..4fa8922ec 100644
--- a/app/assets/javascripts/activityChart.js
+++ b/app/assets/javascripts/activityChart.js
@@ -316,9 +316,18 @@
return rowSender === currentUserName;
});
- userRows.slice(0, 5).forEach(row => {
- row.style.display = '';
- });
+ if (userRows.length > 0) {
+ userRows.slice(0, 5).forEach(row => {
+ row.style.display = '';
+ });
+ } else {
+ const emptyMessageRow = Array.from(allRows).find(row => {
+ return row.querySelector('.table-empty-message');
+ });
+ if (emptyMessageRow) {
+ emptyMessageRow.style.display = '';
+ }
+ }
} else {
tableHeading.textContent = 'Service activity';
diff --git a/app/assets/javascripts/listEntry.js b/app/assets/javascripts/listEntry.js
index a2c0df0a3..f18b0c94f 100644
--- a/app/assets/javascripts/listEntry.js
+++ b/app/assets/javascripts/listEntry.js
@@ -17,6 +17,7 @@
this.minEntries = 2;
this.listItemName = this.$wrapper.data('listItemName');
this.getSharedAttributes();
+ this.getOriginalClasses();
this.getValues();
this.maxEntries = this.entries.length;
@@ -28,17 +29,18 @@
ListEntry.prototype.renderEntry = function(data) {
return `
-
+
${data.listItemName} number ${data.number}.
${data.button ? `
-
+
Remove ${data.listItemName} number ${data.number}
` : ''}
@@ -46,11 +48,11 @@
`;
};
ListEntry.prototype.renderAddButton = function(data) {
- return `Add another ${data.listItemName} (${data.entriesLeft} remaining) `;
+ return `Add another ${data.listItemName} (${data.entriesLeft} remaining) `;
};
ListEntry.prototype.getSharedAttributes = function () {
var $inputs = this.$wrapper.find('input'),
- generatedAttributes = ['id', 'name', 'value'],
+ generatedAttributes = ['id', 'name', 'value', 'class'],
attributes = [],
attrIdx,
elmAttributes,
@@ -95,6 +97,20 @@
this.sharedAttributes = (attributes.length) ? getAttributesHTML(attributes) : '';
};
+ ListEntry.prototype.getOriginalClasses = function () {
+ var $firstInput = this.$wrapper.find('input').first();
+ if ($firstInput.length) {
+ var classList = $firstInput.attr('class');
+ if (classList) {
+ // Preserve any additional classes from the original input
+ this.additionalClasses = classList;
+ } else {
+ this.additionalClasses = '';
+ }
+ } else {
+ this.additionalClasses = '';
+ }
+ };
ListEntry.prototype.getValues = function () {
this.entries = [];
this.$wrapper.find('input').each(function (idx, elm) {
@@ -183,7 +199,8 @@
'name' : this.getId(entryNumber),
'value' : entry,
'listItemName' : this.listItemName,
- 'sharedAttributes': this.sharedAttributes
+ 'sharedAttributes': this.sharedAttributes,
+ 'classes': this.additionalClasses
};
if (entryNumber > 1) {
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index b3e8bc3f5..758030e2c 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -7,9 +7,6 @@ $(() => GOVUK.modules.start());
$(() => $('.error-message, .usa-error-message').eq(0).parent('label').next('input').trigger('focus'));
-$(() => $('.govuk-header__container').on('click', function() {
- $(this).css('border-color', '#005ea5');
-}));
// Applies our expanded focus style to the siblings of links when that link is wrapped in a heading.
//
diff --git a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss
index da85cb5ba..029aaa22f 100644
--- a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss
+++ b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss
@@ -1092,3 +1092,14 @@ nav.nav {
.selection-content .usa-form-group--nested li.usa-checkbox {
margin-top: 0;
}
+
+// Radio button and checkbox legends
+.usa-radio legend.usa-legend,
+.usa-checkbox legend.usa-legend,
+.api-key-radios legend.usa-legend,
+.login-auth-radios legend.usa-legend,
+.auth-type-radios legend.usa-legend,
+.notification-type-radios legend.usa-legend,
+.organizations-radios legend.usa-legend {
+ font-weight: 700;
+}
diff --git a/app/config.py b/app/config.py
index 58e162148..2e9bb45bf 100644
--- a/app/config.py
+++ b/app/config.py
@@ -16,7 +16,12 @@ class Config(object):
API_PUBLIC_WS_URL = getenv("API_PUBLIC_WS_URL", "localhost")
ADMIN_BASE_URL = getenv("ADMIN_BASE_URL", "http://localhost:6012")
- HEADER_COLOUR = "#81878b" # mix of dark-grey and mid-grey
+ HEADER_COLOUR = (
+ "#81878b" # mix of dark-grey and mid-grey
+ )
+ LOGO_CDN_DOMAIN = (
+ "static-logos.notifications.service.gov.uk" # TODO use our own CDN
+ )
ASSETS_DEBUG = False
diff --git a/app/templates/components/checkboxes.html b/app/templates/components/checkboxes.html
new file mode 100644
index 000000000..4ae3d720a
--- /dev/null
+++ b/app/templates/components/checkboxes.html
@@ -0,0 +1,20 @@
+{% from "components/select-input.html" import select, select_list, select_nested, select_wrapper, select_input %}
+
+{% macro checkboxes(field, hint=None, disable=[], option_hints={}, hide_legend=False) %}
+ {{ select(field, hint, disable, option_hints, hide_legend, input="checkbox") }}
+{% endmacro %}
+
+
+{% macro checkbox_list(options, child_map, disable=[], option_hints={}) %}
+ {{ select_list(options, child_map, disable, option_hints, input="checkbox") }}
+{% endmacro %}
+
+
+{% macro checkboxes_nested(field, child_map, hint=None, disable=[], option_hints={}, hide_legend=False) %}
+ {{ select_nested(field, child_map, hint, disable, option_hints, hide_legend, input="checkbox") }}
+{% endmacro %}
+
+
+{% macro checkbox(option, disable=[], option_hints={}, data_target=None, as_list_item=False) %}
+ {{ select_input(option, disable, option_hints, data_target, as_list_item, input="checkbox") }}
+{% endmacro %}
diff --git a/app/templates/components/list-entry.html b/app/templates/components/list-entry.html
index 1788c5210..5e8a7bcaa 100644
--- a/app/templates/components/list-entry.html
+++ b/app/templates/components/list-entry.html
@@ -36,9 +36,9 @@
{% set autocomplete = "" %}
{% endif %}
{% if entry.errors %}
- {% set label_classes = "usa-input--numbered__label usa-input--numbered__label--error" %}
+ {% set label_classes = "usa-label usa-label--error" %}
{% else %}
- {% set label_classes = "usa-input--numbered__label" %}
+ {% set label_classes = "usa-label" %}
{% endif %}
{% set field_name = field.name + "-" + loop.index|string %}
{{ entry(param_extensions={
@@ -48,7 +48,7 @@
"html": '' + item_name + ' number ' + loop.index|string + '.',
"classes": label_classes
},
- "classes": "usa-input--numbered ",
+ "classes": "usa-input",
"value": field.data[loop.index0],
"autocomplete": autocomplete
}) }}
diff --git a/app/templates/components/previous-next-navigation.html b/app/templates/components/previous-next-navigation.html
index 6b9c5c4ab..1c84f74a9 100644
--- a/app/templates/components/previous-next-navigation.html
+++ b/app/templates/components/previous-next-navigation.html
@@ -1,30 +1,30 @@
{% macro previous_next_navigation(previous_page, next_page) %}
{% if previous_page or next_page %}
-
-
diff --git a/app/templates/views/service-settings/data-retention/add.html b/app/templates/views/service-settings/data-retention/add.html
index bd20e5f7e..3c9499d69 100644
--- a/app/templates/views/service-settings/data-retention/add.html
+++ b/app/templates/views/service-settings/data-retention/add.html
@@ -3,6 +3,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
+{% from "components/radios.html" import radios %}
{% block service_page_title %}
Set data retention
@@ -16,7 +17,9 @@
{{ page_header('Set data retention') }}
{% call form_wrapper() %}
- {{ form.notification_type }}
+
+ {{ radios(form.notification_type) }}
+
{{ form.days_of_retention }}
{{ page_footer('Add') }}
{% endcall %}
diff --git a/app/templates/views/service-settings/link-service-to-organization.html b/app/templates/views/service-settings/link-service-to-organization.html
index 222c3951f..8d847a333 100644
--- a/app/templates/views/service-settings/link-service-to-organization.html
+++ b/app/templates/views/service-settings/link-service-to-organization.html
@@ -4,6 +4,7 @@
{% from "components/live-search.html" import live_search %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
+{% from "components/radios.html" import radios %}
{% set page_title = "Link service to organization" %}
@@ -26,7 +27,9 @@
) }}
{% call form_wrapper(data_force_focus=True) %}
{% if has_organizations %}
- {{ form.organizations }}
+
+ {{ radios(form.organizations) }}
+
{{ sticky_page_footer('Save') }}
{% else %}
No organizations
diff --git a/app/templates/views/set-up-your-profile.html b/app/templates/views/set-up-your-profile.html
index e131aff2f..9a0e11cfc 100644
--- a/app/templates/views/set-up-your-profile.html
+++ b/app/templates/views/set-up-your-profile.html
@@ -2,6 +2,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/select/macro.njk" import usaSelect -%}
+{% from "components/radios.html" import radios %}
{% block per_page_title %}
Set up your profile
@@ -68,7 +69,7 @@ Set up your profile
]
})
}}-->
- {{form.auth_type}}
+ {{ radios(form.auth_type) }}
{{ page_footer("Save") }}
{% endcall %}
diff --git a/app/templates/views/templates/_template_list.html b/app/templates/views/templates/_template_list.html
index 6fc0baeec..e29131473 100644
--- a/app/templates/views/templates/_template_list.html
+++ b/app/templates/views/templates/_template_list.html
@@ -1,3 +1,5 @@
+{% from "components/checkboxes.html" import checkboxes %}
+
{% macro format_item_name(name, separators=True) -%}
{%- if name is string -%}
{{- name -}}
diff --git a/app/templates/views/templates/set-sender.html b/app/templates/views/templates/set-sender.html
index 2bb9a4162..293b8e847 100644
--- a/app/templates/views/templates/set-sender.html
+++ b/app/templates/views/templates/set-sender.html
@@ -2,6 +2,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
+{% from "components/radios.html" import radios %}
{% block service_page_title %}
{{ sender_context.title }}
@@ -15,20 +16,11 @@
{% call form_wrapper() %}
- {{ form.sender(param_extensions={
- 'fieldset': {
- 'legend': {
- 'isPageHeading': True,
- 'text': sender_context.title
- }
- },
- 'classes': 'grid-col-9'
- }) }}
+ {{ radios(form.sender, legend_style='usa-legend--large', option_hints=option_hints) }}
{{ page_footer('Continue') }}
{% endcall %}
-
{% endblock %}
diff --git a/app/templates/views/templates/set-template-sender.html b/app/templates/views/templates/set-template-sender.html
index 289ff222f..49600a860 100644
--- a/app/templates/views/templates/set-template-sender.html
+++ b/app/templates/views/templates/set-template-sender.html
@@ -2,6 +2,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
+{% from "components/radios.html" import radios %}
{% set page_title = 'Set letter contact block' %}
@@ -17,19 +18,10 @@
{% call form_wrapper() %}
- {{ form.sender(param_extensions={
- 'fieldset': {
- 'legend': {
- 'isPageHeading': True,
- 'text': page_title
- }
- },
- 'classes': 'grid-col-9'
- }) }}
+ {{ radios(form.sender) }}
+
{% endcall %}
diff --git a/backstop_data/bitmaps_reference/backstop_test_API_Guest_List_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_API_Guest_List_0_document_0_desktop.png
new file mode 100644
index 000000000..baa9e2d02
Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_API_Guest_List_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_API_Keys_Create_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_API_Keys_Create_0_document_0_desktop.png
index 26cbd5605..13ae82a9a 100644
Binary files a/backstop_data/bitmaps_reference/backstop_test_API_Keys_Create_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_API_Keys_Create_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png
index d79bc4d54..c4154f252 100644
Binary files a/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_About_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Change_User_Auth_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Change_User_Auth_0_document_0_desktop.png
index b2e7c30fc..bb470a095 100644
Binary files a/backstop_data/bitmaps_reference/backstop_test_Change_User_Auth_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_Change_User_Auth_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Data_Retention_Add_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Data_Retention_Add_0_document_0_desktop.png
new file mode 100644
index 000000000..f8dea36d1
Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Data_Retention_Add_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Email_Not_Received_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Email_Not_Received_0_document_0_desktop.png
index d65b61da3..cb1d73de2 100644
Binary files a/backstop_data/bitmaps_reference/backstop_test_Email_Not_Received_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_Email_Not_Received_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Invite_User_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Invite_User_0_document_0_desktop.png
index f59850299..7107461be 100644
Binary files a/backstop_data/bitmaps_reference/backstop_test_Invite_User_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_Invite_User_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Link_Service_to_Organization_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Link_Service_to_Organization_0_document_0_desktop.png
new file mode 100644
index 000000000..73a73d913
Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Link_Service_to_Organization_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Notifygov_Sign_In_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Notifygov_Sign_In_0_document_0_desktop.png
index ddeb38cbe..6d970c703 100644
Binary files a/backstop_data/bitmaps_reference/backstop_test_Notifygov_Sign_In_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_Notifygov_Sign_In_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Platform_Admin_User_Auth_Type_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Platform_Admin_User_Auth_Type_0_document_0_desktop.png
new file mode 100644
index 000000000..bb470a095
Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Platform_Admin_User_Auth_Type_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Set_Template_Letter_Sender_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Set_Template_Letter_Sender_0_document_0_desktop.png
new file mode 100644
index 000000000..51af137ab
Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Set_Template_Letter_Sender_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Set_Template_Sender_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Set_Template_Sender_0_document_0_desktop.png
new file mode 100644
index 000000000..db45f0738
Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Set_Template_Sender_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Text_Not_Received_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Text_Not_Received_0_document_0_desktop.png
index a1207863f..aaa97b31c 100644
Binary files a/backstop_data/bitmaps_reference/backstop_test_Text_Not_Received_0_document_0_desktop.png and b/backstop_data/bitmaps_reference/backstop_test_Text_Not_Received_0_document_0_desktop.png differ
diff --git a/backstop_data/bitmaps_reference/backstop_test_Uploads_0_document_0_desktop.png b/backstop_data/bitmaps_reference/backstop_test_Uploads_0_document_0_desktop.png
new file mode 100644
index 000000000..004784ad6
Binary files /dev/null and b/backstop_data/bitmaps_reference/backstop_test_Uploads_0_document_0_desktop.png differ
diff --git a/gunicorn_config.py b/gunicorn_config.py
index 2643f78c9..65494fd14 100644
--- a/gunicorn_config.py
+++ b/gunicorn_config.py
@@ -2,8 +2,6 @@ import multiprocessing
import os
import sys
import traceback
-import logging
-from app.utils import hilite
import gunicorn
# Let gunicorn figure out the right number of workers
@@ -13,8 +11,6 @@ import gunicorn
workers = multiprocessing.cpu_count()
worker_class = "gevent"
-logging.basicConfig(level=logging.INFO)
-logging.info(hilite("Gunicorn timeout set to 240 seconds"))
timeout = 240
bind = "0.0.0.0:{}".format(os.getenv("PORT"))
disable_redirect_access_to_syslog = True
diff --git a/tests/app/main/views/test_api_integration.py b/tests/app/main/views/test_api_integration.py
index ecfb9a196..1bb371ab3 100644
--- a/tests/app/main/views/test_api_integration.py
+++ b/tests/app/main/views/test_api_integration.py
@@ -182,10 +182,14 @@ def test_should_show_create_api_key_page(
for index, option in enumerate(expected_options):
item = page.select(".usa-radio")[index]
if type(option) is tuple:
- assert normalize_spaces(item.select_one(".usa-label").text) == option[0]
- assert normalize_spaces(item.select_one(".usa-hint").text) == option[1]
+ label = item.select_one(".usa-radio__label")
+ hint = label.select_one(".usa-hint")
+ # Get the label text without the hint text
+ label_text = label.text.replace(hint.text, "").strip() if hint else label.text
+ assert normalize_spaces(label_text) == option[0]
+ assert normalize_spaces(hint.text) == option[1]
else:
- assert normalize_spaces(item.select_one(".usa-label").text) == option
+ assert normalize_spaces(item.select_one(".usa-radio__label").text) == option
def test_should_create_api_key_with_type_normal(
diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py
index 37e0ccbf4..406853bbc 100644
--- a/tests/app/main/views/test_send.py
+++ b/tests/app/main/views/test_send.py
@@ -144,11 +144,11 @@ def test_default_email_sender_is_checked_and_has_hint(
".set_sender", service_id=SERVICE_ONE_ID, template_id=fake_uuid
)
- assert page.select(".usa-radios input")[0].has_attr("checked")
+ assert page.select(".usa-radio input")[0].has_attr("checked")
assert (
- normalize_spaces(page.select_one(".usa-radios .usa-hint").text) == "(Default)"
+ normalize_spaces(page.select_one(".usa-radio .usa-hint").text) == "(Default)"
)
- assert not page.select(".usa-radios input")[1].has_attr("checked")
+ assert not page.select(".usa-radio input")[1].has_attr("checked")
def test_default_sms_sender_is_checked_and_has_hint(
@@ -161,11 +161,11 @@ def test_default_sms_sender_is_checked_and_has_hint(
".set_sender", service_id=SERVICE_ONE_ID, template_id=fake_uuid
)
- assert page.select(".usa-radios input")[0].has_attr("checked")
+ assert page.select(".usa-radio input")[0].has_attr("checked")
assert (
- normalize_spaces(page.select_one(".usa-radios .usa-hint").text) == "(Default)"
+ normalize_spaces(page.select_one(".usa-radio .usa-hint").text) == "(Default)"
)
- assert not page.select(".usa-radios input")[1].has_attr("checked")
+ assert not page.select(".usa-radio input")[1].has_attr("checked")
def test_default_sms_sender_is_checked_and_has_hint_when_there_are_no_inbound_numbers(
@@ -178,11 +178,11 @@ def test_default_sms_sender_is_checked_and_has_hint_when_there_are_no_inbound_nu
".set_sender", service_id=SERVICE_ONE_ID, template_id=fake_uuid
)
- assert page.select(".usa-radios input")[0].has_attr("checked")
+ assert page.select(".usa-radio input")[0].has_attr("checked")
assert (
- normalize_spaces(page.select_one(".usa-radios .usa-hint").text) == "(Default)"
+ normalize_spaces(page.select_one(".usa-radio .usa-hint").text) == "(Default)"
)
- assert not page.select(".usa-radios input")[1].has_attr("checked")
+ assert not page.select(".usa-radio input")[1].has_attr("checked")
def test_default_inbound_sender_is_checked_and_has_hint_with_default_and_receives_text(
@@ -196,13 +196,13 @@ def test_default_inbound_sender_is_checked_and_has_hint_with_default_and_receive
".set_sender", service_id=service_one["id"], template_id=fake_uuid
)
- assert page.select(".usa-radios input")[0].has_attr("checked")
+ assert page.select(".usa-radio input")[0].has_attr("checked")
assert (
- normalize_spaces(page.select_one(".usa-radios .usa-hint").text)
+ normalize_spaces(page.select_one(".usa-radio .usa-hint").text)
== "(Default and receives replies)"
)
- assert not page.select(".usa-radios input")[1].has_attr("checked")
- assert not page.select(".usa-radios input")[2].has_attr("checked")
+ assert not page.select(".usa-radio input")[1].has_attr("checked")
+ assert not page.select(".usa-radio input")[2].has_attr("checked")
def test_sms_sender_has_receives_replies_hint(
@@ -216,13 +216,13 @@ def test_sms_sender_has_receives_replies_hint(
".set_sender", service_id=service_one["id"], template_id=fake_uuid
)
- assert page.select(".usa-radios input")[0].has_attr("checked")
+ assert page.select(".usa-radio input")[0].has_attr("checked")
assert (
- normalize_spaces(page.select_one(".usa-radios .usa-hint").text)
+ normalize_spaces(page.select_one(".usa-radio .usa-hint").text)
== "(Default and receives replies)"
)
- assert not page.select(".usa-radios input")[1].has_attr("checked")
- assert not page.select(".usa-radios input")[2].has_attr("checked")
+ assert not page.select(".usa-radio input")[1].has_attr("checked")
+ assert not page.select(".usa-radio input")[2].has_attr("checked")
@pytest.mark.parametrize(
diff --git a/tests/javascripts/activityChart.test.js b/tests/javascripts/activityChart.test.js
index 3d0087ec1..89e924dc1 100644
--- a/tests/javascripts/activityChart.test.js
+++ b/tests/javascripts/activityChart.test.js
@@ -283,3 +283,58 @@ test('handleDropdownChange updates DOM for individual selection', () => {
window.fetchData.mockRestore();
});
+
+test('handleDropdownChange shows empty message when user has no jobs', () => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+
+
+ Other User
+ Another User
+ Different User
+
+ No batched job messages found (messages are kept for 7 days).
+
+
+
+
+
+ Service
+ Individual
+
+ `;
+
+ window.currentUserName = "Test User";
+
+ jest.spyOn(window, 'fetchData').mockImplementation(() => {});
+
+ const selectElement = document.getElementById('options');
+ selectElement.value = 'individual';
+ const event = { target: selectElement };
+
+ window.handleDropdownChange(event);
+
+ expect(document.getElementById('table-heading').textContent).toBe('My activity');
+ expect(document.getElementById('caption').textContent).toContain('Test User');
+
+ document.querySelectorAll('.sender-column').forEach(col => {
+ expect(col.style.display).toBe('none');
+ });
+
+ const emptyMessageRow = document.querySelector('.table-empty-message').closest('tr');
+ expect(emptyMessageRow.style.display).toBe('');
+
+ const allRows = Array.from(document.querySelectorAll('#activity-table tbody tr'));
+ const visibleRows = allRows.filter(row => row.style.display !== 'none');
+ expect(visibleRows.length).toBe(1);
+ expect(visibleRows[0].querySelector('.table-empty-message')).not.toBeNull();
+
+ window.fetchData.mockRestore();
+});
diff --git a/tests/javascripts/listEntry.test.js b/tests/javascripts/listEntry.test.js
index 5a4d47543..4bcc50e03 100644
--- a/tests/javascripts/listEntry.test.js
+++ b/tests/javascripts/listEntry.test.js
@@ -48,10 +48,10 @@ describe("List entry", () => {
result += `
`;
}
@@ -247,7 +247,7 @@ describe("List entry", () => {
triggerEvent(inputList.querySelectorAll('.input-list__button--remove')[0], 'click');
const newNums = Array.from(
- inputList.querySelectorAll('.govuk-input--numbered__label')
+ inputList.querySelectorAll('.usa-label')
)
.map((itemNum, idx) => {
return parseInt(itemNum.lastChild.nodeValue, 10);
@@ -350,4 +350,72 @@ describe("List entry", () => {
});
});
+
+ describe("getOriginalClasses functionality", () => {
+ test("Should handle inputs without any classes", () => {
+ // Create input without classes
+ document.body.innerHTML = `
+ `;
+
+ inputList = document.querySelector('.input-list');
+
+ // start module
+ window.GOVUK.modules.start();
+
+ // Check that it handles missing classes gracefully
+ const newInput = inputList.querySelector('.list-entry input');
+ expect(newInput).not.toBeNull();
+ });
+
+ test("Should handle empty input list", () => {
+ // Create div without any inputs
+ document.body.innerHTML = `
+
+
`;
+
+ inputList = document.querySelector('.input-list');
+
+ // This should not throw an error
+ expect(() => {
+ window.GOVUK.modules.start();
+ }).not.toThrow();
+ });
+ });
+
+ describe("getId functionality", () => {
+ test("Should generate IDs correctly with and without number parameter", () => {
+ // Set up a simpler structure to test ID generation
+ document.body.innerHTML = `
+ `;
+
+ inputList = document.querySelector('.input-list');
+
+ // start module
+ window.GOVUK.modules.start();
+
+ // After module starts, check that IDs are generated correctly
+ // The module will have regenerated the DOM
+ const inputs = inputList.querySelectorAll('input');
+
+ // Check that inputs have proper IDs with numbers
+ expect(inputs[0].id).toEqual("test-1");
+ expect(inputs[1].id).toEqual("test-2");
+
+ // The getId function is called internally during render
+ // We can verify it worked by checking the generated HTML structure
+ expect(inputList.innerHTML).toContain('id="test-1"');
+ expect(inputList.innerHTML).toContain('id="test-2"');
+ });
+ });
});
diff --git a/urls.js b/urls.js
index 54053bdd7..c53398bb9 100644
--- a/urls.js
+++ b/urls.js
@@ -14,6 +14,10 @@ const routes = {
{ label: 'Email Not Received', path: '/email-not-received' },
{ label: 'Text Not Received', path: '/text-not-received' },
{ label: 'Performance', path: '/performance' },
+ // Registration pages with radio buttons
+ // Note: /register returns 404, registration is handled through login.gov
+ // { label: 'Register', path: '/register' },
+ // { label: 'Register From Invite', path: '/register/from-invite/example-token' },
],
authenticated: [
@@ -67,16 +71,50 @@ const routes = {
label: 'Invite User',
path: '/services/829ac564-59e9-47c5-ad69-e91315641c31/users/invite',
},
- // Platform admin pages with checkboxes
{
label: 'Platform Admin Live Services',
path: '/platform-admin/live-services',
},
- // Organization pages
{
label: 'Add Organization',
path: '/organizations/add',
},
+ {
+ label: 'Uploads',
+ path: '/services/829ac564-59e9-47c5-ad69-e91315641c31/uploads',
+ },
+ {
+ label: 'API Guest List',
+ path: '/services/829ac564-59e9-47c5-ad69-e91315641c31/api/guest-list',
+ },
+ // User profile and auth pages with radio buttons
+ // Note: /set-up-your-profile requires special auth flow from login.gov
+ // {
+ // label: 'Set Up Your Profile',
+ // path: '/set-up-your-profile',
+ // },
+ {
+ label: 'Platform Admin User Auth Type',
+ path: '/users/6af522d0-2915-4e52-83a3-3690455a5fe6/change_auth',
+ },
+ // Service settings pages with radio buttons
+ {
+ label: 'Data Retention Add',
+ path: '/services/829ac564-59e9-47c5-ad69-e91315641c31/data-retention/add',
+ },
+ {
+ label: 'Link Service to Organization',
+ path: '/services/829ac564-59e9-47c5-ad69-e91315641c31/service-settings/link-service-to-organization',
+ },
+ // Template sender pages with radio buttons
+ {
+ label: 'Set Template Sender',
+ path: '/services/829ac564-59e9-47c5-ad69-e91315641c31/send/9c2b7a55-8785-4dc6-84d6-eb0e0615590d/set-sender',
+ },
+ {
+ label: 'Set Template Letter Sender',
+ path: '/services/829ac564-59e9-47c5-ad69-e91315641c31/templates/9c2b7a55-8785-4dc6-84d6-eb0e0615590d/set-template-sender',
+ },
],
// Using Notify section