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