From 24f0c3dc09ed5bc8ef64cc204734a0efe9e1d05f Mon Sep 17 00:00:00 2001 From: Laurence de Bruxelles Date: Wed, 20 May 2026 12:18:40 +0300 Subject: [PATCH 1/3] Remove unneeded translation This translation was just repeating back its input, so wasn't needed. --- app/presenters/route_summary_card_data_presenter.rb | 2 +- config/locales/en.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/presenters/route_summary_card_data_presenter.rb b/app/presenters/route_summary_card_data_presenter.rb index 65ffff8c4..0c6655756 100644 --- a/app/presenters/route_summary_card_data_presenter.rb +++ b/app/presenters/route_summary_card_data_presenter.rb @@ -91,7 +91,7 @@ def conditional_route_card(routing_condition, route_number) { key: { text: I18n.t("page_route_card.if_answer_is") }, html_attributes: { id: check_id(routing_condition), class: check_value_error ? "govuk-summary-list__row--error" : "" }, - value: { text: safe_join([check_value_error, I18n.t("page_route_card.conditional_answer_value", answer_value: routing_condition.answer_value)]) }, + value: { text: safe_join([check_value_error, routing_condition.answer_value]) }, }, { key: { text: I18n.t("page_route_card.take_the_person_to") }, diff --git a/config/locales/en.yml b/config/locales/en.yml index f89af602b..9adcaf193 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1466,7 +1466,6 @@ en: unconditional_skip_to_end_text: Go to the end of the form page_route_card: any_other_answer: Route for any other answer - conditional_answer_value: "%{answer_value}" continue_to: Continue to delete: Delete delete_route: Delete all routes From 089f9fae67e969a47de5cbdf028ee89bea34cbef Mon Sep 17 00:00:00 2001 From: Laurence de Bruxelles Date: Wed, 20 May 2026 09:47:53 +0300 Subject: [PATCH 2/3] Add constant to represent none of the above answer in condition record --- app/components/page_list_component/view.rb | 4 ++-- app/input_objects/pages/conditions_input.rb | 2 +- app/models/condition.rb | 4 +++- app/services/routes/build_service.rb | 2 +- app/services/step_summary_card_service.rb | 2 +- spec/input_objects/pages/conditions_input_spec.rb | 2 +- spec/models/condition_spec.rb | 2 +- spec/services/step_summary_card_service_spec.rb | 2 +- 8 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/components/page_list_component/view.rb b/app/components/page_list_component/view.rb index 2e59977a6..102669960 100644 --- a/app/components/page_list_component/view.rb +++ b/app/components/page_list_component/view.rb @@ -53,7 +53,7 @@ def condition_check_page_text(condition) def answer_value_text_for_condition(condition) if condition.answer_value.present? - answer_value = condition.answer_value == :none_of_the_above.to_s ? I18n.t("page_conditions.none_of_the_above") : condition.answer_value + answer_value = condition.answer_value == Condition::NONE_OF_THE_ABOVE ? I18n.t("page_conditions.none_of_the_above") : condition.answer_value I18n.t("page_conditions.condition_answer_value_text", answer_value:) else I18n.t("page_conditions.condition_answer_value_text_with_errors") @@ -62,7 +62,7 @@ def answer_value_text_for_condition(condition) def answer_value_text_for_condition2(condition) if condition.answer_value.present? - answer_value = condition.answer_value == :none_of_the_above.to_s ? I18n.t("page_conditions.none_of_the_above") : condition.answer_value + answer_value = condition.answer_value == Condition::NONE_OF_THE_ABOVE ? I18n.t("page_conditions.none_of_the_above") : condition.answer_value I18n.t("page_conditions.condition_answer_value_text2", answer_value:) else I18n.t("page_conditions.condition_answer_value_text_with_errors") diff --git a/app/input_objects/pages/conditions_input.rb b/app/input_objects/pages/conditions_input.rb index 1c1487c23..0c6de0b56 100644 --- a/app/input_objects/pages/conditions_input.rb +++ b/app/input_objects/pages/conditions_input.rb @@ -41,7 +41,7 @@ def update_condition def routing_answer_options options = page.answer_settings.selection_options.map { |option| OpenStruct.new(value: option[:name], label: option[:name]) } - options << OpenStruct.new(value: :none_of_the_above.to_s, label: I18n.t("page_conditions.none_of_the_above")) if page.is_optional + options << OpenStruct.new(value: Condition::NONE_OF_THE_ABOVE, label: I18n.t("page_conditions.none_of_the_above")) if page.is_optional options end diff --git a/app/models/condition.rb b/app/models/condition.rb index 2d704b535..db7062fe8 100644 --- a/app/models/condition.rb +++ b/app/models/condition.rb @@ -2,6 +2,8 @@ class Condition < ApplicationRecord include ConditionMethods extend Mobility + NONE_OF_THE_ABOVE = :none_of_the_above.to_s + belongs_to :routing_page, class_name: "Page" belongs_to :check_page, class_name: "Page", optional: true belongs_to :goto_page, class_name: "Page", optional: true @@ -52,7 +54,7 @@ def warning_answer_doesnt_exist return nil if has_precondition? && answer_value.nil? answer_options = check_page&.answer_settings&.dig("selection_options")&.pluck("name") - return nil if answer_options.blank? || answer_options.include?(answer_value) || answer_value == :none_of_the_above.to_s && check_page.is_optional? + return nil if answer_options.blank? || answer_options.include?(answer_value) || answer_value == NONE_OF_THE_ABOVE && check_page.is_optional? DataStruct.new(name: "answer_value_doesnt_exist") end diff --git a/app/services/routes/build_service.rb b/app/services/routes/build_service.rb index 80cc03bab..7fcad7477 100644 --- a/app/services/routes/build_service.rb +++ b/app/services/routes/build_service.rb @@ -3,7 +3,7 @@ # based on the pages and conditions. class Routes::BuildService END_OF_FORM_OPTION = [I18n.t("page_conditions.end_of_form"), Forms::RouteInput::END_OF_FORM_VALUE].freeze - NONE_OF_THE_ABOVE_OPTION = DataStruct.new(value: :none_of_the_above.to_s, name: I18n.t("page_conditions.none_of_the_above")) + NONE_OF_THE_ABOVE_OPTION = DataStruct.new(value: Condition::NONE_OF_THE_ABOVE, name: I18n.t("page_conditions.none_of_the_above")) attr_reader :form diff --git a/app/services/step_summary_card_service.rb b/app/services/step_summary_card_service.rb index cd033f27d..35ff02cf1 100644 --- a/app/services/step_summary_card_service.rb +++ b/app/services/step_summary_card_service.rb @@ -267,7 +267,7 @@ def print_route(condition) end def format_answer_value(answer_value) - answer_value = I18n.t("page_conditions.none_of_the_above") if answer_value == "none_of_the_above" + answer_value = I18n.t("page_conditions.none_of_the_above") if answer_value == Condition::NONE_OF_THE_ABOVE ActionController::Base.helpers.sanitize(answer_value) end diff --git a/spec/input_objects/pages/conditions_input_spec.rb b/spec/input_objects/pages/conditions_input_spec.rb index c23c46d62..2ede88c25 100644 --- a/spec/input_objects/pages/conditions_input_spec.rb +++ b/spec/input_objects/pages/conditions_input_spec.rb @@ -142,7 +142,7 @@ expect(result).to eq([ OpenStruct.new(value: "Option 1", label: "Option 1"), OpenStruct.new(value: "Option 2", label: "Option 2"), - OpenStruct.new(value: :none_of_the_above.to_s, + OpenStruct.new(value: Condition::NONE_OF_THE_ABOVE, label: I18n.t("page_conditions.none_of_the_above")), ]) end diff --git a/spec/models/condition_spec.rb b/spec/models/condition_spec.rb index b05a32ae2..5dea83422 100644 --- a/spec/models/condition_spec.rb +++ b/spec/models/condition_spec.rb @@ -306,7 +306,7 @@ end context "when answer_value is 'None of the above" do - let(:condition) { create :condition, routing_page_id: check_page.id, check_page_id: check_page.id, goto_page_id: goto_page.id, answer_value: :none_of_the_above.to_s } + let(:condition) { create :condition, routing_page_id: check_page.id, check_page_id: check_page.id, goto_page_id: goto_page.id, answer_value: Condition::NONE_OF_THE_ABOVE } let(:check_page) { create :page, :with_selection_settings, form:, is_optional: } context "and routing page has 'None of the above' as an option" do diff --git a/spec/services/step_summary_card_service_spec.rb b/spec/services/step_summary_card_service_spec.rb index 5249a2dc1..53d3a7b29 100644 --- a/spec/services/step_summary_card_service_spec.rb +++ b/spec/services/step_summary_card_service_spec.rb @@ -309,7 +309,7 @@ before do page.update!(is_optional: true) - create :condition, routing_page_id: page.id, check_page_id: page.id, goto_page_id: goto_page.id, answer_value: "none_of_the_above" + create :condition, routing_page_id: page.id, check_page_id: page.id, goto_page_id: goto_page.id, answer_value: Condition::NONE_OF_THE_ABOVE page.reload form.reload.make_live! From f1aaa7c13b688147eb96ed6415f514be335c6cb5 Mon Sep 17 00:00:00 2001 From: Laurence de Bruxelles Date: Wed, 20 May 2026 09:22:34 +0300 Subject: [PATCH 3/3] Fix routing content when condition is for none of the above answer --- .../route_summary_card_data_presenter.rb | 8 ++++- app/views/pages/conditions/delete.html.erb | 2 +- app/views/pages/secondary_skip/_form.html.erb | 2 +- config/locales/en.yml | 3 ++ .../route_summary_card_data_presenter_spec.rb | 13 +++++++++ .../pages/conditions/delete.html.erb_spec.rb | 17 +++++++++++ .../pages/secondary_skip/new.html.erb_spec.rb | 29 +++++++++++++++++++ 7 files changed, 71 insertions(+), 3 deletions(-) diff --git a/app/presenters/route_summary_card_data_presenter.rb b/app/presenters/route_summary_card_data_presenter.rb index 0c6655756..2c3226912 100644 --- a/app/presenters/route_summary_card_data_presenter.rb +++ b/app/presenters/route_summary_card_data_presenter.rb @@ -74,6 +74,12 @@ def conditional_route_card(routing_condition, route_number) goto_question_name(routing_condition.goto_page_id) end + answer_value_text = if routing_condition.answer_value == Condition::NONE_OF_THE_ABOVE + I18n.t("page_route_card.none_of_the_above") + else + routing_condition.answer_value + end + check_value_error = format_error(I18n.t("page_route_card.errors.answer_value_doesnt_exist")) if routing_condition.validation_errors.any? { |error| error.name == "answer_value_doesnt_exist" } goto_page_next_error = format_error(I18n.t("page_route_card.errors.cannot_route_to_next_page")) if routing_condition.validation_errors.any? { |error| error.name == "cannot_route_to_next_page" } goto_page_before_error = format_error(I18n.t("page_route_card.errors.cannot_have_goto_page_before_routing_page", question_number: question_number(routing_condition.check_page_id))) if routing_condition.validation_errors.any? { |error| error.name == "cannot_have_goto_page_before_routing_page" } @@ -91,7 +97,7 @@ def conditional_route_card(routing_condition, route_number) { key: { text: I18n.t("page_route_card.if_answer_is") }, html_attributes: { id: check_id(routing_condition), class: check_value_error ? "govuk-summary-list__row--error" : "" }, - value: { text: safe_join([check_value_error, routing_condition.answer_value]) }, + value: { text: safe_join([check_value_error, answer_value_text]) }, }, { key: { text: I18n.t("page_route_card.take_the_person_to") }, diff --git a/app/views/pages/conditions/delete.html.erb b/app/views/pages/conditions/delete.html.erb index 789adb640..aecc9c607 100644 --- a/app/views/pages/conditions/delete.html.erb +++ b/app/views/pages/conditions/delete.html.erb @@ -28,7 +28,7 @@ end; summary_list.with_row do |row| row.with_key(text: t(".answered_as_key")) - row.with_value { delete_condition_input.answer_value } + row.with_value { delete_condition_input.answer_value == Condition::NONE_OF_THE_ABOVE ? t(".none_of_the_above") : delete_condition_input.answer_value } end; summary_list.with_row do |row| row.with_key(text: t(".skip_to_key")) diff --git a/app/views/pages/secondary_skip/_form.html.erb b/app/views/pages/secondary_skip/_form.html.erb index 440f4bcb7..ebb81b3da 100644 --- a/app/views/pages/secondary_skip/_form.html.erb +++ b/app/views/pages/secondary_skip/_form.html.erb @@ -16,7 +16,7 @@ <%= govuk_summary_list(actions: false) do |summary_list| summary_list.with_row(classes: "govuk-summary-list__row--no-border") do |row| row.with_key { t("secondary_skip.new.primary_route_answer_key") } - row.with_value { secondary_skip_input.answer_value } + row.with_value { secondary_skip_input.answer_value == Condition::NONE_OF_THE_ABOVE ? t("secondary_skip.none_of_the_above") : secondary_skip_input.answer_value } end; summary_list.with_row do |row| row.with_key { t("secondary_skip.new.primary_route_continue_key") } diff --git a/config/locales/en.yml b/config/locales/en.yml index 9adcaf193..e3159d7fe 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1479,6 +1479,7 @@ en: cannot_route_to_next_page_secondary_skip: The route for any other answer is not skipping any questions - edit or delete this route goto_page_invalid: Edit this route to select the question or page you want to take the person to, or delete the route if_answer_is: If the answer is + none_of_the_above: None of the above question_name_long: "%{question_number}. %{question_text}" question_name_short: Question %{question_number} route_title: Route %{route_number} @@ -1618,6 +1619,7 @@ en: any_other_answer_warning: If you delete this route, the route for any other answer will also be deleted delete_condition_legend: Are you sure you want to delete this route? exit_page_warning: If you delete this route, the exit page it goes to will also be deleted + none_of_the_above: None of the above skip_to_key: skip the person to edit: back_link: Back to question %{question_number}’s routes @@ -2012,6 +2014,7 @@ en:

If you need to, you can make them skip one or more consecutive questions that only people on route %{route_number} need to answer.

primary_route_answer_key: If the answer is primary_route_continue_key: skip the person to + none_of_the_above: None of the above selection_none_of_the_above: preamble: If someone selects ‘None of the above’, we’ll show them a text box to enter their answer. preamble_more_than_30_options: If someone selects ‘None of the above’, we’ll show them a text box to enter their answer. If your list has over 30 options, we’ll show this text box on the next page of the form. diff --git a/spec/presenters/route_summary_card_data_presenter_spec.rb b/spec/presenters/route_summary_card_data_presenter_spec.rb index 4e7e737a8..0b125ed10 100644 --- a/spec/presenters/route_summary_card_data_presenter_spec.rb +++ b/spec/presenters/route_summary_card_data_presenter_spec.rb @@ -46,6 +46,19 @@ end end + context "when the condition is for the none of the above answer" do + before do + page.update!(is_optional: true) + create :condition, routing_page_id: page.id, check_page_id: page.id, goto_page_id: pages.last.id, answer_value: Condition::NONE_OF_THE_ABOVE + pages.each(&:reload) + end + + it "includes 'None of the above'" do + result = service.summary_card_data + expect(result[0][:rows][0][:value][:text]).to eq "None of the above" + end + end + context "when the condition has an exit page data" do let!(:condition) { create :condition, :with_exit_page, routing_page_id: page.id, check_page_id: page.id, answer_value: "Option 1" } diff --git a/spec/views/pages/conditions/delete.html.erb_spec.rb b/spec/views/pages/conditions/delete.html.erb_spec.rb index cf40cd3fd..4507de4ea 100644 --- a/spec/views/pages/conditions/delete.html.erb_spec.rb +++ b/spec/views/pages/conditions/delete.html.erb_spec.rb @@ -33,6 +33,23 @@ expect(rendered).to have_css(".govuk-summary-list__value", text: delete_condition_input.goto_page_question_text) end + context "when the condition is for a 'none of the above' answer" do + let(:condition) { create :condition, id: 1, routing_page_id: pages.first.id, check_page_id: pages.first.id, goto_page_id: pages.last.id, answer_value: Condition::NONE_OF_THE_ABOVE } + + let(:page) do + page = pages.first + page.update!(is_optional: true) + page + end + + it "contains the condition details" do + expect(rendered).to have_css(".govuk-summary-list__row") do |row| + row.has_css?(".govuk-summary-list__key", exact_text: "is answered as") && + row.has_css?(".govuk-summary-list__value", exact_text: "None of the above") + end + end + end + it "has a submit button" do expect(rendered).to have_css("button[type='submit'].govuk-button", text: I18n.t("save_and_continue")) end diff --git a/spec/views/pages/secondary_skip/new.html.erb_spec.rb b/spec/views/pages/secondary_skip/new.html.erb_spec.rb index bb47a1718..42aaa0943 100644 --- a/spec/views/pages/secondary_skip/new.html.erb_spec.rb +++ b/spec/views/pages/secondary_skip/new.html.erb_spec.rb @@ -40,4 +40,33 @@ expect(rendered).to have_selector("h1", text: "Question 1’s routes") expect(rendered).to have_selector("h1", text: I18n.t("page_titles.new_secondary_skip", route_index: 2)) end + + context "when the condition is for a 'none of the above' answer" do + let(:page) do + page = build( + :page, + :with_selection_settings, + id: 1, + position: 1, + answer_settings: DataStruct.new( + only_one_option: true, + selection_options: [ + OpenStruct.new(attributes: { name: "Option 1" }), + OpenStruct.new(attributes: { name: "Option 2" }), + ], + ), + ) + page.routing_conditions = [ + build(:condition, id: 1, routing_page: page, check_page: page, goto_page_id: 2, skip_to_end: false, answer_value: Condition::NONE_OF_THE_ABOVE), + ] + page + end + + it "has the correct answer value text" do + expect(rendered).to have_selector(".govuk-summary-list__row") do |row| + row.has_css?(".govuk-summary-list__key", exact_text: "If the answer is") && + row.has_css?(".govuk-summary-list__value", exact_text: "None of the above") + end + end + end end