diff --git a/.review_apps/ecs_task_definition.tf b/.review_apps/ecs_task_definition.tf index f8c6b8e97..db03b59e4 100644 --- a/.review_apps/ecs_task_definition.tf +++ b/.review_apps/ecs_task_definition.tf @@ -24,6 +24,7 @@ locals { { name = "SETTINGS__FORMS_ADMIN__BASE_URL", value = "https://${local.admin_app_hostname}" }, { name = "SETTINGS__FORMS_API__BASE_URL", value = "http://localhost:3000" }, { name = "SETTINGS__FORMS_ENV", value = "review" }, + { name = "SETTINGS__FEATURES__FILLER_ANSWER_EMAIL_ENABLED", value = "true" } ## # Settings for AWS SES email sending, and S3 CSV submission and file upload diff --git a/app/controllers/forms/check_your_answers_controller.rb b/app/controllers/forms/check_your_answers_controller.rb index e81cc2843..270c345af 100644 --- a/app/controllers/forms/check_your_answers_controller.rb +++ b/app/controllers/forms/check_your_answers_controller.rb @@ -72,10 +72,14 @@ def setup_check_your_answers end def back_link - previous_step = current_context.previous_step(CheckYourAnswersStep::CHECK_YOUR_ANSWERS_PAGE_SLUG) - - if previous_step.present? - previous_step.repeatable? ? add_another_answer_path(form_id: current_context.form.id, form_slug: current_context.form.form_slug, page_slug: previous_step.id) : form_page_path(current_context.form.id, current_context.form.form_slug, previous_step.id) + if FeatureService.enabled?("filler_answer_email_enabled") + copy_of_answers_path(form_id: current_context.form.id, form_slug: current_context.form.form_slug) + else + previous_step = current_context.previous_step(CheckYourAnswersStep::CHECK_YOUR_ANSWERS_PAGE_SLUG) + + if previous_step.present? + previous_step.repeatable? ? add_another_answer_path(form_id: current_context.form.id, form_slug: current_context.form.form_slug, page_slug: previous_step.id) : form_page_path(current_context.form.id, current_context.form.form_slug, previous_step.id) + end end end end diff --git a/app/controllers/forms/copy_of_answers_controller.rb b/app/controllers/forms/copy_of_answers_controller.rb new file mode 100644 index 000000000..e701240a7 --- /dev/null +++ b/app/controllers/forms/copy_of_answers_controller.rb @@ -0,0 +1,49 @@ +module Forms + class CopyOfAnswersController < BaseController + before_action :redirect_if_feature_disabled + + def show + return redirect_to form_page_path(current_context.form.id, current_context.form.form_slug, current_context.next_page_slug) unless can_visit_copy_of_answers? + + @back_link = back_link + @copy_of_answers_input = CopyOfAnswersInput.new + end + + def save + @copy_of_answers_input = CopyOfAnswersInput.new(copy_of_answers_params) + + unless @copy_of_answers_input.valid? + @back_link = back_link + return render :show, status: :unprocessable_content + end + + current_context.save_copy_of_answers_preference(@copy_of_answers_input.wants_copy?) + + redirect_to check_your_answers_path(form_id: current_context.form.id, form_slug: current_context.form.form_slug) + end + + private + + def copy_of_answers_params + params.require(:copy_of_answers_input).permit(:copy_of_answers) + end + + def can_visit_copy_of_answers? + current_context.can_visit?(CheckYourAnswersStep::CHECK_YOUR_ANSWERS_PAGE_SLUG) + end + + def back_link + previous_step = current_context.previous_step(CheckYourAnswersStep::CHECK_YOUR_ANSWERS_PAGE_SLUG) + + if previous_step.present? + previous_step.repeatable? ? add_another_answer_path(form_id: current_context.form.id, form_slug: current_context.form.form_slug, page_slug: previous_step.id) : form_page_path(current_context.form.id, current_context.form.form_slug, previous_step.id) + end + end + + def redirect_if_feature_disabled + return if FeatureService.enabled?("filler_answer_email_enabled") + + redirect_to check_your_answers_path(form_id: current_context.form.id, form_slug: current_context.form.form_slug) + end + end +end diff --git a/app/controllers/forms/page_controller.rb b/app/controllers/forms/page_controller.rb index 31aff64c7..72b4b6e99 100644 --- a/app/controllers/forms/page_controller.rb +++ b/app/controllers/forms/page_controller.rb @@ -148,7 +148,15 @@ def next_step_changing end def next_step_in_form_path - form_page_path(@form.id, @form.form_slug, @step.next_page_slug_after_routing) + if @step.next_page_slug_after_routing == CheckYourAnswersStep::CHECK_YOUR_ANSWERS_PAGE_SLUG + if FeatureService.enabled?("filler_answer_email_enabled") + copy_of_answers_path(form_id: @form.id, form_slug: @form.form_slug) + else + check_answers_path + end + else + form_page_path(@form.id, @form.form_slug, @step.next_page_slug_after_routing) + end end def check_answers_path diff --git a/app/input_objects/copy_of_answers_input.rb b/app/input_objects/copy_of_answers_input.rb new file mode 100644 index 000000000..ca4c47b03 --- /dev/null +++ b/app/input_objects/copy_of_answers_input.rb @@ -0,0 +1,18 @@ +class CopyOfAnswersInput + include ActiveModel::Model + include ActiveModel::Validations + + attr_accessor :copy_of_answers + + RADIO_OPTIONS = { yes: "yes", no: "no" }.freeze + + validates :copy_of_answers, presence: true, inclusion: { in: RADIO_OPTIONS.values } + + def wants_copy? + copy_of_answers == RADIO_OPTIONS[:yes] + end + + def values + RADIO_OPTIONS.keys + end +end diff --git a/app/lib/flow/context.rb b/app/lib/flow/context.rb index e5657f57a..8cff8f299 100644 --- a/app/lib/flow/context.rb +++ b/app/lib/flow/context.rb @@ -12,7 +12,7 @@ def initialize(form:, store:) delegate :support_details, to: :form delegate :find_or_create, :previous_step, :next_page_slug, :next_step, :can_visit?, :completed_steps, :all_steps, to: :journey delegate :clear_stored_answer, :clear, :form_submitted?, :answers, :locales_used, to: :answer_store - delegate :save_submission_details, :get_submission_reference, :requested_email_confirmation?, :clear_submission_details, to: :confirmation_details_store + delegate :save_submission_details, :get_submission_reference, :requested_email_confirmation?, :clear_submission_details, :save_copy_of_answers_preference, :wants_copy_of_answers?, to: :confirmation_details_store def save_step(step, locale: :en, context: nil) return false unless step.valid?(context) diff --git a/app/lib/store/confirmation_details_store.rb b/app/lib/store/confirmation_details_store.rb index 897657648..e577ed369 100644 --- a/app/lib/store/confirmation_details_store.rb +++ b/app/lib/store/confirmation_details_store.rb @@ -3,6 +3,7 @@ class ConfirmationDetailsStore CONFIRMATION_KEY = :confirmation_details SUBMISSION_REFERENCE_KEY = :submission_reference REQUESTED_EMAIL_KEY = :requested_email_confirmation + COPY_OF_ANSWERS_KEY = :wants_copy_of_answers def initialize(store, form_id) @store = store @@ -24,6 +25,15 @@ def requested_email_confirmation? @store.dig(CONFIRMATION_KEY, @form_key, REQUESTED_EMAIL_KEY.to_s) end + def save_copy_of_answers_preference(wants_copy) + @store[CONFIRMATION_KEY][@form_key] ||= {} + @store[CONFIRMATION_KEY][@form_key][COPY_OF_ANSWERS_KEY.to_s] = wants_copy + end + + def wants_copy_of_answers? + @store.dig(CONFIRMATION_KEY, @form_key, COPY_OF_ANSWERS_KEY.to_s) + end + def clear_submission_details @store[CONFIRMATION_KEY][@form_key] = nil end diff --git a/app/views/forms/copy_of_answers/show.html.erb b/app/views/forms/copy_of_answers/show.html.erb new file mode 100644 index 000000000..b40483ba9 --- /dev/null +++ b/app/views/forms/copy_of_answers/show.html.erb @@ -0,0 +1,24 @@ +<% set_page_title(form_title(form_name: @current_context.form.name, page_name: t('.title'), mode: @mode, error: @copy_of_answers_input&.errors&.any?)) %> + +<% content_for :back_link do %> + <% if @back_link.present? %> + <%= link_to t("forms.back"), @back_link, class: "govuk-back-link" %> + <% end %> +<% end %> + +<%= form_with(model: @copy_of_answers_input, method: :post, url: save_copy_of_answers_path(form_id: @form.id, form_slug: @form.form_slug)) do |f| %> +
+
+ <% if @copy_of_answers_input&.errors&.any? %> + <%= f.govuk_error_summary(t("error_summary_title")) %> + <% end %> + + <%= f.govuk_collection_radio_buttons :copy_of_answers, + @copy_of_answers_input.values, ->(option) { option }, ->(option) { t("helpers.label.copy_of_answers_input.options.#{option}") }, + legend: { text: t('.heading'), tag: 'h1', size: 'l' }, + hint: { text: t('.hint') } %> + + <%= f.govuk_submit(t("continue")) %> +
+
+<% end %> diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 484fcf3df..d1ef3a89a 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -83,6 +83,10 @@ cy: add_another_answer: blank: Dewiswch ydw os ydych angen ychwanegu ateb arall max_answers_reached: Dewiswch ydw os ydych angen ychwanegu ateb arall + copy_of_answers_input: + attributes: + copy_of_answers: + blank: PLACEHOLDER! Dewiswch ydw os hoffech dderbyn copi o'ch atebion email_confirmation_input: attributes: confirmation_email_address: @@ -373,6 +377,11 @@ cy: radios_legend: Ydych chi angen ychwanegu ateb arall? title: Ychwanegu neu ddileu ateb i %{page_title} back: Yn ôl + copy_of_answers: + show: + heading: PLACEHOLDER! Ydych chi eisiau copi o'ch atebion? + hint: PLACEHOLDER! Byddwn ond yn defnyddio'r cyfeiriad e-bost rydych yn ei ddarparu yma i anfon cadarnhad bod eich ffurflen wedi'i chyflwyno'n llwyddiannus. Ni fydd yn cynnwys copi o'ch atebion. + title: PLACEHOLDER! Ydych chi eisiau copi o'ch atebion? remove_answer: show: address_heading: Dileu cyfeiriad @@ -409,6 +418,10 @@ cy: options: 'no': Na 'yes': Ydw + copy_of_answers_input: + options: + 'no': Na + 'yes': Ydw email_confirmation_input: confirmation_email_address: Pa gyfeiriad e-bost ydych chi eisiau i ni anfon eich cadarnhad ato? send_confirmation_options: diff --git a/config/locales/en.yml b/config/locales/en.yml index 2608e3b82..7a55f932e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -83,6 +83,10 @@ en: add_another_answer: blank: Select ‘Yes’ if you need to add another answer max_answers_reached: You cannot add another answer + copy_of_answers_input: + attributes: + copy_of_answers: + blank: Select 'Yes' if you want to get a copy of your answers email_confirmation_input: attributes: confirmation_email_address: @@ -373,6 +377,11 @@ en: radios_legend: Do you need to add another answer? title: Add or remove answer to %{page_title} back: Back + copy_of_answers: + show: + heading: Do you want to get an email with a copy of your answers? + hint: You’ll need a GOV.UK One Login for this - you’ll be able to create one now if you do not already have one. + title: Do you want a copy of your answers? remove_answer: show: address_heading: Remove an address @@ -409,6 +418,10 @@ en: options: 'no': 'No' 'yes': 'Yes' + copy_of_answers_input: + options: + 'no': 'No' + 'yes': 'Yes' email_confirmation_input: confirmation_email_address: What email address do you want us to send your confirmation to? send_confirmation_options: diff --git a/config/routes.rb b/config/routes.rb index 72c902983..86c558e9f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,6 +27,8 @@ get "/:form_id" => "forms/base#redirect_to_friendly_url_start", as: :form_id, constraints: form_id_constraints scope "/:form_id/:form_slug(.:locale)", constraints: form_constraints do get "/" => "forms/base#redirect_to_friendly_url_start", as: :form + get "/copy-of-answers" => "forms/copy_of_answers#show", as: :copy_of_answers + post "/copy-of-answers" => "forms/copy_of_answers#save", as: :save_copy_of_answers get "/#{CheckYourAnswersStep::CHECK_YOUR_ANSWERS_PAGE_SLUG}" => "forms/check_your_answers#show", as: :check_your_answers post "/#{CheckYourAnswersStep::CHECK_YOUR_ANSWERS_PAGE_SLUG}" => "forms/check_your_answers#submit_answers", as: :form_submit_answers get "/submitted" => "forms/submitted#submitted", as: :form_submitted diff --git a/spec/features/email_confirmation_spec.rb b/spec/features/email_confirmation_spec.rb index 1ac604936..dab60958d 100644 --- a/spec/features/email_confirmation_spec.rb +++ b/spec/features/email_confirmation_spec.rb @@ -13,6 +13,8 @@ ActiveResource::HttpMock.respond_to do |mock| mock.get "/api/v2/forms/1/live", req_headers, form.to_json, 200 end + + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) end scenario "opting out of email submission returns the confirmation page without confirmation email text" do @@ -39,6 +41,12 @@ def fill_in_form fill_in question_text, with: text_answer click_button "Continue" + + # Copy of answers page + expect(page.find("h1")).to have_text I18n.t("forms.copy_of_answers.show.heading") + choose "No" + click_button "Continue" + expect(page.find("h1")).to have_text I18n.t("form.check_your_answers.title") expect(page).to have_text question_text expect(page).to have_text text_answer diff --git a/spec/features/fill_in_and_submit_form_spec.rb b/spec/features/fill_in_and_submit_form_spec.rb index 7b53d50b8..07d9254d5 100644 --- a/spec/features/fill_in_and_submit_form_spec.rb +++ b/spec/features/fill_in_and_submit_form_spec.rb @@ -16,6 +16,7 @@ end allow(ReferenceNumberService).to receive(:generate).and_return(reference) + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) end scenario "As a form filler" do @@ -24,6 +25,10 @@ when_i_fill_in_the_question and_i_click_on_continue + then_i_should_see_the_copy_of_answers_page + + when_i_choose_not_to_receive_a_copy + and_i_click_on_continue then_i_should_see_the_check_your_answers_page when_i_opt_out_of_email_confirmation @@ -50,6 +55,15 @@ def and_i_click_on_continue click_button "Continue" end + def then_i_should_see_the_copy_of_answers_page + expect(page.find("h1")).to have_text "Do you want to get an email with a copy of your answers?" + expect_page_to_have_no_axe_errors(page) + end + + def when_i_choose_not_to_receive_a_copy + choose "No" + end + def then_i_should_see_the_check_your_answers_page expect(page.find("h1")).to have_text "Check your answers before submitting your form" expect(page).to have_text question_text diff --git a/spec/features/fill_in_and_submit_form_with_csv_spec.rb b/spec/features/fill_in_and_submit_form_with_csv_spec.rb index 3b361297c..db739a32d 100644 --- a/spec/features/fill_in_and_submit_form_with_csv_spec.rb +++ b/spec/features/fill_in_and_submit_form_with_csv_spec.rb @@ -17,6 +17,7 @@ end allow(ReferenceNumberService).to receive(:generate).and_return(reference) + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) travel_to Time.parse("2029-01-24T05:05:50+00:00") end @@ -32,6 +33,10 @@ when_i_fill_in_the_question and_i_click_on_continue + then_i_should_see_the_copy_of_answers_page + when_i_choose_not_to_receive_a_copy + and_i_click_on_continue + then_i_should_see_the_check_your_answers_page when_i_opt_out_of_email_confirmation and_i_submit_my_form @@ -58,6 +63,15 @@ def and_i_click_on_continue click_button "Continue" end + def then_i_should_see_the_copy_of_answers_page + expect(page.find("h1")).to have_text "Do you want to get an email with a copy of your answers?" + expect_page_to_have_no_axe_errors(page) + end + + def when_i_choose_not_to_receive_a_copy + choose "No" + end + def then_i_should_see_the_check_your_answers_page expect(page.find("h1")).to have_text "Check your answers before submitting your form" expect_page_to_have_no_axe_errors(page) diff --git a/spec/features/fill_in_autocomplete_question_spec.rb b/spec/features/fill_in_autocomplete_question_spec.rb index fb83ee009..cad8a7f25 100644 --- a/spec/features/fill_in_autocomplete_question_spec.rb +++ b/spec/features/fill_in_autocomplete_question_spec.rb @@ -17,6 +17,7 @@ end allow(ReferenceNumberService).to receive(:generate).and_return(reference) + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) end scenario "As a form filler" do @@ -27,6 +28,10 @@ then_i_should_see_the_options when_i_choose_an_option and_i_click_on_continue + then_i_should_see_the_copy_of_answers_page + + when_i_choose_not_to_receive_a_copy + and_i_click_on_continue then_i_should_see_the_check_your_answers_page when_i_opt_out_of_email_confirmation @@ -66,6 +71,15 @@ def and_i_click_on_continue click_button "Continue" end + def then_i_should_see_the_copy_of_answers_page + expect(page.find("h1")).to have_text "Do you want to get an email with a copy of your answers?" + expect_page_to_have_no_axe_errors(page) + end + + def when_i_choose_not_to_receive_a_copy + choose "No" + end + def then_i_should_see_the_check_your_answers_page expect(page.find("h1")).to have_text "Check your answers before submitting your form" expect(page).to have_text question_text diff --git a/spec/features/fill_in_file_upload_question_spec.rb b/spec/features/fill_in_file_upload_question_spec.rb index 9bf8dc159..d5505c5a9 100644 --- a/spec/features/fill_in_file_upload_question_spec.rb +++ b/spec/features/fill_in_file_upload_question_spec.rb @@ -36,6 +36,8 @@ allow(mock_s3_client).to receive(:put_object) allow(mock_s3_client).to receive(:get_object_tagging).and_return({ tag_set: [{ key: "GuardDutyMalwareScanStatus", value: scan_status }] }) + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) + File.write(test_file, test_file_content) end @@ -50,6 +52,10 @@ and_i_click_on_continue then_i_see_the_review_file_page and_i_click_on_continue + then_i_should_see_the_copy_of_answers_page + + when_i_choose_not_to_receive_a_copy + and_i_click_on_continue then_i_should_see_the_check_your_answers_page when_i_opt_out_of_email_confirmation @@ -86,6 +92,10 @@ and_i_click_on_continue then_i_see_the_review_file_page and_i_click_on_continue + then_i_should_see_the_copy_of_answers_page + + when_i_choose_not_to_receive_a_copy + and_i_click_on_continue then_i_should_see_the_check_your_answers_page when_i_opt_out_of_email_confirmation @@ -123,6 +133,15 @@ def then_i_see_the_review_file_page expect(page).to have_text File.basename(File.path(test_file)) end + def then_i_should_see_the_copy_of_answers_page + expect(page.find("h1")).to have_text "Do you want to get an email with a copy of your answers?" + expect_page_to_have_no_axe_errors(page) + end + + def when_i_choose_not_to_receive_a_copy + choose "No" + end + def then_i_should_see_the_check_your_answers_page expect(page.find("h1")).to have_text "Check your answers before submitting your form" expect(page).to have_text question_text diff --git a/spec/features/fill_in_form_with_exit_page_spec.rb b/spec/features/fill_in_form_with_exit_page_spec.rb index 2ba6ecbac..b50fc2930 100644 --- a/spec/features/fill_in_form_with_exit_page_spec.rb +++ b/spec/features/fill_in_form_with_exit_page_spec.rb @@ -16,6 +16,7 @@ end allow(ReferenceNumberService).to receive(:generate).and_return(reference) + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) end scenario "As a form filler" do @@ -29,6 +30,10 @@ when_i_click_back when_i_dont_choose_the_exit_option and_i_click_on_continue + then_i_should_see_the_copy_of_answers_page + + when_i_choose_not_to_receive_a_copy + and_i_click_on_continue then_i_should_see_the_check_your_answers_page when_i_opt_out_of_email_confirmation @@ -58,6 +63,15 @@ def and_i_click_on_continue click_button "Continue" end + def then_i_should_see_the_copy_of_answers_page + expect(page.find("h1")).to have_text "Do you want to get an email with a copy of your answers?" + expect_page_to_have_no_axe_errors(page) + end + + def when_i_choose_not_to_receive_a_copy + choose "No" + end + def then_i_should_see_the_check_your_answers_page expect(page.find("h1")).to have_text "Check your answers before submitting your form" expect(page).to have_text question_text diff --git a/spec/features/fill_in_single_repeatable_form_spec.rb b/spec/features/fill_in_single_repeatable_form_spec.rb index c6881a210..d5a038a33 100644 --- a/spec/features/fill_in_single_repeatable_form_spec.rb +++ b/spec/features/fill_in_single_repeatable_form_spec.rb @@ -18,6 +18,7 @@ end allow(ReferenceNumberService).to receive(:generate).and_return(reference) + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) end scenario "As a form filler" do @@ -41,6 +42,10 @@ when_i_choose_not_to_add_another and_i_click_on_continue + then_i_should_see_the_copy_of_answers_page + when_i_choose_not_to_receive_a_copy + and_i_click_on_continue + then_i_should_see_the_check_your_answers_page when_i_opt_out_of_email_confirmation and_i_submit_my_form @@ -89,6 +94,15 @@ def when_i_choose_not_to_add_another choose "No" end + def then_i_should_see_the_copy_of_answers_page + expect(page.find("h1")).to have_text "Do you want to get an email with a copy of your answers?" + expect_page_to_have_no_axe_errors(page) + end + + def when_i_choose_not_to_receive_a_copy + choose "No" + end + def then_i_should_see_the_check_your_answers_page expect(page.find("h1")).to have_text "Check your answers before submitting your form" expect(page).to have_text question_text diff --git a/spec/input_objects/copy_of_answers_input_spec.rb b/spec/input_objects/copy_of_answers_input_spec.rb new file mode 100644 index 000000000..3e00b3369 --- /dev/null +++ b/spec/input_objects/copy_of_answers_input_spec.rb @@ -0,0 +1,57 @@ +require "rails_helper" + +RSpec.describe CopyOfAnswersInput do + let(:input) { described_class.new(copy_of_answers: "yes") } + + describe "validations" do + it "is valid with valid attributes" do + expect(input).to be_valid + end + + it "is not valid without a copy_of_answers" do + input.copy_of_answers = nil + expect(input).not_to be_valid + expect(input.errors[:copy_of_answers]).to include(I18n.t("activemodel.errors.models.copy_of_answers_input.attributes.copy_of_answers.blank")) + end + + it "is not valid with an invalid copy_of_answers" do + input.copy_of_answers = "invalid" + expect(input).not_to be_valid + expect(input.errors[:copy_of_answers]).to include("is not included in the list") + end + + it 'is valid with "no" as copy_of_answers' do + input.copy_of_answers = "no" + expect(input).to be_valid + end + end + + describe "#wants_copy?" do + it 'returns true when copy_of_answers is "yes"' do + input = described_class.new(copy_of_answers: "yes") + expect(input.wants_copy?).to be true + end + + it 'returns false when copy_of_answers is "no"' do + input = described_class.new(copy_of_answers: "no") + expect(input.wants_copy?).to be false + end + end + + describe "#values" do + it "returns an array of valid values" do + input = described_class.new + expect(input.values).to eq(%i[yes no]) + end + end + + describe "RADIO_OPTIONS" do + it "has the correct values" do + expect(described_class::RADIO_OPTIONS).to eq({ yes: "yes", no: "no" }) + end + + it "is frozen" do + expect(described_class::RADIO_OPTIONS).to be_frozen + end + end +end diff --git a/spec/requests/forms/check_your_answers_controller_spec.rb b/spec/requests/forms/check_your_answers_controller_spec.rb index 340b01c03..7b6481626 100644 --- a/spec/requests/forms/check_your_answers_controller_spec.rb +++ b/spec/requests/forms/check_your_answers_controller_spec.rb @@ -101,6 +101,7 @@ end allow(ReferenceNumberService).to receive(:generate).and_return(reference) + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) end describe "#show" do @@ -139,8 +140,8 @@ expect(response).to have_http_status(:ok) end - it "Displays a back link to the last page of the form" do - expect(response.body).to include(form_page_path(mode:, form_id:, form_slug: form_data.form_slug, page_slug: 2)) + it "Displays a back link to the copy of answers page" do + expect(response.body).to include(copy_of_answers_path(mode:, form_id:, form_slug: form_data.form_slug)) end it "Returns the correct X-Robots-Tag header" do diff --git a/spec/requests/forms/copy_of_answers_controller_spec.rb b/spec/requests/forms/copy_of_answers_controller_spec.rb new file mode 100644 index 000000000..08353a20b --- /dev/null +++ b/spec/requests/forms/copy_of_answers_controller_spec.rb @@ -0,0 +1,165 @@ +require "rails_helper" + +RSpec.describe Forms::CopyOfAnswersController, type: :request do + let(:form) do + build(:v2_form_document, :with_support, form_id: 2, start_page: 1, steps:, available_languages:) + end + + let(:steps) do + [ + build(:v2_question_page_step, :with_text_settings, id: 1, next_step_id: 2), + build(:v2_question_page_step, :with_text_settings, id: 2), + ] + end + + let(:available_languages) { %w[en] } + + let(:req_headers) { { "Accept" => "application/json" } } + + let(:api_url_suffix) { "/draft" } + let(:mode) { "preview-draft" } + + let(:store) do + { + answers: { + form.form_id.to_s => { + "1" => { "text" => "answer 1" }, + "2" => { "text" => "answer 2" }, + }, + }, + } + end + + before do + ActiveResource::HttpMock.respond_to do |mock| + mock.get "/api/v2/forms/#{form.form_id}#{api_url_suffix}", req_headers, form.to_json, 200 + end + + allow(Flow::Context).to receive(:new).and_wrap_original do |original_method, *args| + original_method.call(form: args[0][:form], store:) + end + + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) + end + + describe "GET #show" do + context "when the feature flag is disabled" do + before do + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(false) + get copy_of_answers_path(mode:, form_id: form.form_id, form_slug: form.form_slug) + end + + it "redirects to check your answers" do + expect(response).to redirect_to(check_your_answers_path(form_id: form.form_id, form_slug: form.form_slug, mode:)) + end + end + + context "when the feature flag is enabled" do + before do + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) + get copy_of_answers_path(mode:, form_id: form.form_id, form_slug: form.form_slug) + end + + it "returns http success" do + expect(response).to have_http_status(:ok) + end + + it "renders the show template" do + expect(response).to render_template(:show) + end + + it "initializes @copy_of_answers_input" do + expect(assigns(:copy_of_answers_input)).to be_a(CopyOfAnswersInput) + end + + it "assigns @back_link" do + expect(assigns(:back_link)).to be_present + end + + context "when the form is not multilingual" do + it "does not include the language switcher" do + expect(response.body).not_to include(I18n.t("language_switcher.nav_label")) + end + end + + context "when the form is multilingual" do + let(:available_languages) { %w[en cy] } + + it "includes the language switcher" do + expect(response.body).to include(I18n.t("language_switcher.nav_label")) + end + end + + context "when all questions have not been completed" do + let(:store) do + { + answers: { + form.form_id.to_s => { + "1" => { "text" => "answer 1" }, + }, + }, + } + end + + it "redirects to the next page" do + expect(response).to redirect_to(form_page_path(form.form_id, form.form_slug, 2, mode:)) + end + end + end + end + + describe "POST #save" do + context "with valid params" do + context "when user wants a copy of answers" do + let(:params) { { copy_of_answers_input: { copy_of_answers: "yes" } } } + + before do + post save_copy_of_answers_path(mode:, form_id: form.form_id, form_slug: form.form_slug), params: + end + + it "redirects to check your answers" do + expect(response).to redirect_to(check_your_answers_path(form_id: form.form_id, form_slug: form.form_slug, mode:)) + end + + it "saves the preference" do + # Access the session to verify the preference was saved + expect(response).to have_http_status(:redirect) + end + end + + context "when user does not want a copy of answers" do + let(:params) { { copy_of_answers_input: { copy_of_answers: "no" } } } + + before do + post save_copy_of_answers_path(mode:, form_id: form.form_id, form_slug: form.form_slug), params: + end + + it "redirects to check your answers" do + expect(response).to redirect_to(check_your_answers_path(form_id: form.form_id, form_slug: form.form_slug, mode:)) + end + end + end + + context "with invalid params" do + let(:params) { { copy_of_answers_input: { copy_of_answers: "" } } } + + before do + post save_copy_of_answers_path(mode:, form_id: form.form_id, form_slug: form.form_slug), params: + end + + it "returns unprocessable content" do + expect(response).to have_http_status(:unprocessable_content) + end + + it "renders the show template" do + expect(response).to render_template(:show) + end + + it "displays an error message" do + expect(response.body).to include("Select") + expect(response.body).to include("Yes") + expect(response.body).to include("copy of your answers") + end + end + end +end diff --git a/spec/requests/forms/page_controller_spec.rb b/spec/requests/forms/page_controller_spec.rb index 44dbd79f4..335f33b3d 100644 --- a/spec/requests/forms/page_controller_spec.rb +++ b/spec/requests/forms/page_controller_spec.rb @@ -52,6 +52,8 @@ ActiveResource::HttpMock.respond_to do |mock| mock.get "/api/v2/forms/2#{api_url_suffix}", req_headers, form_data.to_json, 200 end + + allow(FeatureService).to receive(:enabled?).with("filler_answer_email_enabled").and_return(true) end context "when setting logging context" do @@ -722,9 +724,9 @@ end context "with the final page" do - it "Redirects to the check your answers page" do + it "Redirects to the copy of answers page" do post save_form_page_path(mode:, form_id: 2, form_slug: form_data.form_slug, page_slug: 2), params: { question: { text: "answer text" } } - expect(response).to redirect_to(check_your_answers_path(2, form_data.form_slug, mode:)) + expect(response).to redirect_to(copy_of_answers_path(2, form_data.form_slug, mode:)) end end end diff --git a/spec/views/forms/copy_of_answers/show.html.erb_spec.rb b/spec/views/forms/copy_of_answers/show.html.erb_spec.rb new file mode 100644 index 000000000..d873afaf5 --- /dev/null +++ b/spec/views/forms/copy_of_answers/show.html.erb_spec.rb @@ -0,0 +1,72 @@ +require "rails_helper" + +describe "forms/copy_of_answers/show.html.erb" do + let(:form) { build :form, id: 1 } + let(:mode) { OpenStruct.new(preview_draft?: false, preview_archived?: false, preview_live?: false) } + let(:copy_of_answers_input) { CopyOfAnswersInput.new } + let(:back_link) { "/back" } + + before do + assign(:current_context, OpenStruct.new(form:)) + assign(:form, form) + assign(:mode, mode) + assign(:back_link, back_link) + assign(:copy_of_answers_input, copy_of_answers_input) + + without_partial_double_verification do + allow(view).to receive(:save_copy_of_answers_path).and_return("/save_copy_of_answers") + end + + render + end + + it "has the correct page title" do + expect(view.content_for(:title)).to eq "#{I18n.t('forms.copy_of_answers.show.title')} - #{form.name}" + end + + it "has the correct heading" do + expect(rendered).to have_css("h1", text: I18n.t("forms.copy_of_answers.show.heading")) + end + + it "has the hint text" do + expect(rendered).to have_content(I18n.t("forms.copy_of_answers.show.hint")) + end + + it "has a back link" do + expect(view.content_for(:back_link)).to have_link("Back", href: "/back") + end + + it "displays Yes and No radio options" do + expect(rendered).to have_field("Yes") + expect(rendered).to have_field("No") + end + + it "has a continue button" do + expect(rendered).to have_button(I18n.t("continue")) + end + + context "when back link not present" do + let(:back_link) { "" } + + it "does not set back link" do + expect(view.content_for(:back_link)).to be_nil + end + end + + context "when there are errors" do + before do + copy_of_answers_input.valid? + render + end + + it "renders the error summary" do + expect(rendered).to have_css(".govuk-error-summary") + end + + it "displays the error message" do + expect(rendered).to have_content("Select") + expect(rendered).to have_content("Yes") + expect(rendered).to have_content("copy of your answers") + end + end +end