From 484bb499e68a7c0dd8c10c3f98dc58313da545e9 Mon Sep 17 00:00:00 2001 From: Dushan <47317567+dushan-madetech@users.noreply.github.com> Date: Fri, 11 Mar 2022 09:41:18 +0000 Subject: [PATCH] CLDC-788 interruption screen net income soft validation (#372) * Set up failing test for new soft validation design * remove unneeded js controller * remove unneeded controller and spec * rename net income validation override column * spec form changes (to allow tests to run) * validation spec changes * replace all instances of override_net_income_validatiom * passing first test * Add to form and import styling * remove unneeded code from interruption screen view * Update test & code - failing last new expectation * Display 2 previous question answers in the informative text * extract displaying of the informative text into a helper * Add tests for helper * Remove some of the previous soft validations set up * fix some failing specs * Fix more tests * lint * Reset earnings question prefix and suffix to initial values instead of nil * make it route backwards on a no * test and linter fixes * refactor next_page * stryling * more changes * fix specs * update real form * design tweaks * delete commented out tests * content changes * content changes * changes to informative/hint text * More robust styles for interuption panel, use smart quotes * Rubocop Co-authored-by: Kat Co-authored-by: Paul Robert Lloyd Co-authored-by: baarkerlounger --- app/controllers/form_controller.rb | 4 +- .../soft_validations_controller.rb | 21 ------ app/helpers/interuption_screen_helper.rb | 16 ++++ app/models/case_log.rb | 4 + app/models/form.rb | 4 +- app/models/form/page.rb | 15 +--- app/models/form/question.rb | 2 + app/models/validations/soft_validations.rb | 32 -------- .../_interruption_screen_question.html.erb | 23 ++++++ .../_validation_override_question.html.erb | 15 ---- app/views/form/page.html.erb | 16 ++-- .../soft_validations_controller.js | 28 ------- app/webpacker/styles/_button.scss | 31 ++++++++ app/webpacker/styles/_panel.scss | 28 +++++++ app/webpacker/styles/application.scss | 2 + config/forms/2021_2022.json | 34 +++++---- config/locales/en.yml | 10 ++- config/routes.rb | 1 - ...e_net_income_validation_override_column.rb | 5 ++ db/schema.rb | 2 +- docs/api/DLUHC-CORE-Data.v1.json | 2 +- spec/factories/case_log.rb | 2 +- spec/features/form/check_answers_page_spec.rb | 4 +- spec/features/form/form_navigation_spec.rb | 1 + spec/features/form/page_routing_spec.rb | 2 +- spec/features/form/validations_spec.rb | 39 +++------- spec/fixtures/complete_case_log.json | 4 +- spec/fixtures/exports/case_logs.xml | 2 +- spec/fixtures/forms/2021_2022.json | 75 +++++++++++++++++-- spec/helpers/check_answers_helper_spec.rb | 3 +- .../helpers/interuption_screen_helper_spec.rb | 65 ++++++++++++++++ spec/models/case_log_spec.rb | 32 -------- spec/models/form/page_spec.rb | 14 ---- spec/models/form/subsection_spec.rb | 10 +-- spec/models/form_handler_spec.rb | 2 +- spec/models/form_spec.rb | 5 +- spec/requests/form_controller_spec.rb | 2 +- .../soft_validations_controller_spec.rb | 54 ------------- spec/views/form/page_view_spec.rb | 2 +- 39 files changed, 322 insertions(+), 291 deletions(-) delete mode 100644 app/controllers/soft_validations_controller.rb create mode 100644 app/helpers/interuption_screen_helper.rb create mode 100644 app/views/form/_interruption_screen_question.html.erb delete mode 100644 app/views/form/_validation_override_question.html.erb delete mode 100644 app/webpacker/controllers/soft_validations_controller.js create mode 100644 app/webpacker/styles/_button.scss create mode 100644 app/webpacker/styles/_panel.scss create mode 100644 db/migrate/20220228112732_rename_net_income_validation_override_column.rb create mode 100644 spec/helpers/interuption_screen_helper_spec.rb delete mode 100644 spec/requests/soft_validations_controller_spec.rb diff --git a/app/controllers/form_controller.rb b/app/controllers/form_controller.rb index 5c5b31483..95da341fc 100644 --- a/app/controllers/form_controller.rb +++ b/app/controllers/form_controller.rb @@ -7,7 +7,7 @@ class FormController < ApplicationController if @case_log @page = @case_log.form.get_page(params[:case_log][:page]) responses_for_page = responses_for_page(@page) - if @case_log.update(responses_for_page) && @case_log.has_no_unresolved_soft_errors? + if @case_log.update(responses_for_page) if @case_log.form.is_last_question?(@page, @case_log.form.subsection_for_page(@page), @case_log) redirect_to(case_logs_path) else @@ -54,7 +54,7 @@ class FormController < ApplicationController private def responses_for_page(page) - page.expected_responses.each_with_object({}) do |question, result| + page.questions.each_with_object({}) do |question, result| question_params = params["case_log"][question.id] if question.type == "date" day = params["case_log"]["#{question.id}(3i)"] diff --git a/app/controllers/soft_validations_controller.rb b/app/controllers/soft_validations_controller.rb deleted file mode 100644 index c294171ce..000000000 --- a/app/controllers/soft_validations_controller.rb +++ /dev/null @@ -1,21 +0,0 @@ -class SoftValidationsController < ApplicationController - before_action :authenticate_user! - - def show - @case_log = CaseLog.find(params[:case_log_id]) - page_id = request.env["PATH_INFO"].split("/")[-2] - page = @case_log.form.get_page(page_id) - if page_requires_soft_validation_override?(page) - errors = @case_log.soft_errors.values.first - render json: { show: true, label: errors.message, hint: errors.hint_text } - else - render json: { show: false } - end - end - -private - - def page_requires_soft_validation_override?(page) - @case_log.soft_errors.present? && @case_log.soft_errors.keys.first == page.soft_validations&.first&.id - end -end diff --git a/app/helpers/interuption_screen_helper.rb b/app/helpers/interuption_screen_helper.rb new file mode 100644 index 000000000..e189c4d88 --- /dev/null +++ b/app/helpers/interuption_screen_helper.rb @@ -0,0 +1,16 @@ +module InteruptionScreenHelper + def display_informative_text(informative_text, case_log) + translation_questions = informative_text["argument"].map { |x| case_log.form.get_question(x) } + begin + case translation_questions.count + when 2 + translation = I18n.t(informative_text["translation"], informative_text["argument"][0].to_sym => translation_questions[0].answer_label(case_log), informative_text["argument"][1].to_sym => translation_questions[1].answer_label(case_log)) + when 1 + translation = I18n.t(informative_text["translation"], informative_text["argument"][0].to_sym => translation_questions[0].answer_label(case_log)) + end + rescue StandardError + return "" + end + translation.to_s.html_safe + end +end diff --git a/app/models/case_log.rb b/app/models/case_log.rb index 13e65a5e1..39519b645 100644 --- a/app/models/case_log.rb +++ b/app/models/case_log.rb @@ -111,6 +111,10 @@ class CaseLog < ApplicationRecord incfreq == 2 end + def net_income_soft_validation_triggered? + net_income_in_soft_min_range? || net_income_in_soft_max_range? + end + def given_reasonable_preference? reasonpref == 1 end diff --git a/app/models/form.rb b/app/models/form.rb index 37e3627a3..e8e553fac 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -35,7 +35,9 @@ class Form def next_page(page, case_log) page_ids = subsection_for_page(page).pages.map(&:id) page_index = page_ids.index(page.id) - nxt_page = get_page(page_ids[page_index + 1]) + page_id = page.id.include?("value_check") && case_log[page.id] == 1 ? page_ids[page_index - 1] : page_ids[page_index + 1] + nxt_page = get_page(page_id) + return :check_answers if nxt_page.nil? return nxt_page.id if nxt_page.routed_to?(case_log) diff --git a/app/models/form/page.rb b/app/models/form/page.rb index ad8a4a8af..1a300f081 100644 --- a/app/models/form/page.rb +++ b/app/models/form/page.rb @@ -1,6 +1,6 @@ class Form::Page - attr_accessor :id, :header, :description, :questions, :soft_validations, - :depends_on, :subsection, :hide_subsection_label + attr_accessor :id, :header, :description, :questions, + :depends_on, :title_text, :informative_text, :subsection, :hide_subsection_label def initialize(id, hsh, subsection) @id = id @@ -8,19 +8,12 @@ class Form::Page @description = hsh["description"] @questions = hsh["questions"].map { |q_id, q| Form::Question.new(q_id, q, self) } @depends_on = hsh["depends_on"] + @title_text = hsh["title_text"] + @informative_text = hsh["informative_text"] @hide_subsection_label = hsh["hide_subsection_label"] - @soft_validations = hsh["soft_validations"]&.map { |sv_id, s| Form::Question.new(sv_id, s, self) } @subsection = subsection end - def expected_responses - questions + (soft_validations || []) - end - - def has_soft_validations? - soft_validations.present? - end - def routed_to?(case_log) return true unless depends_on || subsection.depends_on diff --git a/app/models/form/question.rb b/app/models/form/question.rb index 670ca9a3b..409200f49 100644 --- a/app/models/form/question.rb +++ b/app/models/form/question.rb @@ -229,6 +229,7 @@ private household_charge: [0], is_carehome: [1], rent_shortfall: [0], + net_income_value_check: [0], }.freeze RADIO_NO_VALUE = { @@ -253,6 +254,7 @@ private household_charge: [1], is_carehome: [0], rent_shortfall: [1], + net_income_value_check: [1], }.freeze RADIO_DONT_KNOW_VALUE = { diff --git a/app/models/validations/soft_validations.rb b/app/models/validations/soft_validations.rb index 650620658..dcf5404ba 100644 --- a/app/models/validations/soft_validations.rb +++ b/app/models/validations/soft_validations.rb @@ -13,38 +13,6 @@ module Validations::SoftValidations 10 => OpenStruct.new(soft_min: 47, soft_max: 730, hard_min: 10, hard_max: 1300), }.freeze - def has_no_unresolved_soft_errors? - soft_errors.empty? || soft_errors_overridden? - end - - def soft_errors - {}.merge(net_income_validations) - end - - def soft_errors_overridden? - public_send(soft_errors.keys.first) == 1 if soft_errors.present? - end - -private - - def net_income_validations - net_income_errors = {} - if net_income_in_soft_min_range? - net_income_errors["override_net_income_validation"] = OpenStruct.new( - message: I18n.t("soft_validations.net_income.in_soft_min_range.message"), - hint_text: I18n.t("soft_validations.net_income.hint_text", ecstat1:), - ) - elsif net_income_in_soft_max_range? - net_income_errors["override_net_income_validation"] = OpenStruct.new( - message: I18n.t("soft_validations.net_income.in_soft_max_range.message"), - hint_text: I18n.t("soft_validations.net_income.hint_text", ecstat1:), - ) - else - update_column(:override_net_income_validation, nil) - end - net_income_errors - end - def net_income_in_soft_max_range? return unless weekly_net_income && ecstat1 diff --git a/app/views/form/_interruption_screen_question.html.erb b/app/views/form/_interruption_screen_question.html.erb new file mode 100644 index 000000000..36c797064 --- /dev/null +++ b/app/views/form/_interruption_screen_question.html.erb @@ -0,0 +1,23 @@ +<%= govuk_panel( + title_text: title_text, + classes: 'app-panel--interruption', +) do %> + <%= display_informative_text(informative_text, case_log) %> + <%= f.govuk_radio_buttons_fieldset question.id.to_sym, + legend: { text: question.header }, + hint: { text: question.hint_text&.html_safe } do %> + <% question.answer_options.map do |key, options| %> + <% if key.starts_with?("divider") %> + <%= f.govuk_radio_divider %> + <% else %> + <%= f.govuk_radio_button question.id, + key, + label: { text: options['value'] }, + hint: { text: options['hint'] }, + **stimulus_html_attributes(question) + %> + <% end %> + <% end %> + <% end %> + <%= f.govuk_submit "Save and continue", accesskey: "s", class: "app-button--inverse govuk-!-margin-bottom-0" %> +<% end %> \ No newline at end of file diff --git a/app/views/form/_validation_override_question.html.erb b/app/views/form/_validation_override_question.html.erb deleted file mode 100644 index 73f513b6b..000000000 --- a/app/views/form/_validation_override_question.html.erb +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/app/views/form/page.html.erb b/app/views/form/page.html.erb index b3a11b5fb..78cbd1b96 100644 --- a/app/views/form/page.html.erb +++ b/app/views/form/page.html.erb @@ -16,7 +16,7 @@ <%= turbo_frame_tag "case_log_form", target: "_top" do %> <%= form_with model: @case_log, url: form_case_log_path(@case_log), method: "post" do |f| %>
-
+
> <% remove_other_page_errors(@case_log, @page) %> <%= f.govuk_error_summary %> @@ -38,19 +38,21 @@ <% if question.read_only? %>
<% end %> - <%= render partial: "form/#{question.type}_question", locals: { question: question, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, f: f, conditional: false } %> + <% if question.type == "interruption_screen" %> + <%= render partial: "form/#{question.type}_question", locals: { question: question, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, title_text: @page.title_text, informative_text: @page.informative_text, form: @form, f: f, conditional: false } %> + <% else %> + <%= render partial: "form/#{question.type}_question", locals: { question: question, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, f: f, conditional: false } %> + <% end %>
<% end %> - <% if @page.has_soft_validations? %> - <%= render partial: "form/validation_override_question", locals: { f: f, page: @page } %> - <% end %> - <%= f.hidden_field :page, value: @page.id %> <% if @case_log.form.is_last_question?(@page, @subsection, @case_log) %> <%= f.govuk_submit "Submit lettings log", accesskey: "s" %> <%else %> - <%= f.govuk_submit "Save and continue", accesskey: "s" %> + <% if !@page.id.include?("value_check") %> + <%= f.govuk_submit "Save and continue", accesskey: "s" %> + <% end %> <%end %>
diff --git a/app/webpacker/controllers/soft_validations_controller.js b/app/webpacker/controllers/soft_validations_controller.js deleted file mode 100644 index 8deeb4f5e..000000000 --- a/app/webpacker/controllers/soft_validations_controller.js +++ /dev/null @@ -1,28 +0,0 @@ -import { Controller } from "@hotwired/stimulus" - -export default class extends Controller { - static targets = [ "override" ] - - initialize() { - let url = window.location.href + "/soft-validations" - let div = this.overrideTarget - fetch(url, { headers: { accept: "application/json" } }) - .then(response => response.json()) - .then((response) => { - if(response["show"]){ - div.style.display = "block" - let innerHTML = div.innerHTML - innerHTML = innerHTML.replace("soft-validations-placeholder-message", response["label"]) - innerHTML = innerHTML.replace("soft-validations-placeholder-hint-text", response["hint"]) - div.innerHTML = innerHTML - } else { - div.style.display = "none" - let buttons = document.getElementsByName(`case_log[override_net_income_validation][]`) - Object.entries(buttons).map(([idx, button]) => { - button.checked = false - }) - } - } - ) - } -} diff --git a/app/webpacker/styles/_button.scss b/app/webpacker/styles/_button.scss new file mode 100644 index 000000000..7dade9268 --- /dev/null +++ b/app/webpacker/styles/_button.scss @@ -0,0 +1,31 @@ +$app-button-shadow-size: $govuk-border-width-form-element; +$app-button-inverse-background-colour: govuk-colour("white"); +$app-button-inverse-foreground-colour: $govuk-brand-colour; +$app-button-inverse-shadow-colour: govuk-shade($app-button-inverse-foreground-colour, 30%); +$app-button-inverse-hover-background-colour: govuk-tint($app-button-inverse-foreground-colour, 90%); + +.app-button--inverse, +.app-button--inverse:link, +.app-button--inverse:visited { + color: $app-button-inverse-foreground-colour; + background-color: $app-button-inverse-background-colour; + box-shadow: 0 $app-button-shadow-size 0 $app-button-inverse-shadow-colour; +} + +.app-button--inverse:hover { + color: $app-button-inverse-foreground-colour; + background-color: $app-button-inverse-hover-background-colour; +} + +.app-button--inverse:focus:not(:hover) { + color: $govuk-focus-text-colour; + background-color: $govuk-focus-colour; +} + +.app-button--inverse:active, +.app-button--inverse:focus { + border-color: $govuk-focus-colour; + color: $app-button-inverse-foreground-colour; + background-color: $app-button-inverse-hover-background-colour; + box-shadow: inset 0 0 0 2px $govuk-focus-colour; +} \ No newline at end of file diff --git a/app/webpacker/styles/_panel.scss b/app/webpacker/styles/_panel.scss new file mode 100644 index 000000000..2425e82e4 --- /dev/null +++ b/app/webpacker/styles/_panel.scss @@ -0,0 +1,28 @@ +.app-panel--interruption { + background-color: govuk-colour("blue"); + color: govuk-colour("white"); + text-align: left; + + p, + .govuk-body, + .govuk-label, + .govuk-fieldset__legend, + .govuk-hint { + color: govuk-colour("white"); + } + + a:not(:focus) { + color: inherit; + } + + *:last-child { + margin-bottom: 0; + } + + .govuk-radios__label::before, + & ::after { + color: govuk-colour("black"); + border-color: govuk-colour("black"); + background-color: govuk-colour("white"); + } +} diff --git a/app/webpacker/styles/application.scss b/app/webpacker/styles/application.scss index e27df7c18..6b1d9cc81 100644 --- a/app/webpacker/styles/application.scss +++ b/app/webpacker/styles/application.scss @@ -13,6 +13,7 @@ $govuk-global-styles: true; @import "~govuk-frontend/govuk/all"; @import "accessible-autocomplete"; +@import "button"; @import "figure"; @import "input"; @import "related-navigation"; @@ -21,6 +22,7 @@ $govuk-global-styles: true; @import "table-group"; @import "task-list"; @import "template"; +@import "panel"; // Turbo .turbo-progress-bar { diff --git a/config/forms/2021_2022.json b/config/forms/2021_2022.json index d09e960ba..c3b2c6d22 100644 --- a/config/forms/2021_2022.json +++ b/config/forms/2021_2022.json @@ -1575,15 +1575,6 @@ } } } - }, - "soft_validations": { - "override_net_income_validation": { - "check_answer_label": "Net income confirmed?", - "type": "validation_override", - "answer_options": { - "override_net_income_validation": "Yes" - } - } } }, "person_2_known": { @@ -4583,13 +4574,28 @@ }, "hidden_in_check_answers": true } + } + }, + "net_income_value_check": { + "depends_on": [{ "net_income_soft_validation_triggered?": true }], + "title_text": "Net income is outside the expected range based on the main tenant’s working situation", + "informative_text": { + "translation": "soft_validations.net_income.hint_text", + "argument": ["ecstat1", "earnings"] }, - "soft_validations": { - "override_net_income_validation": { - "check_answer_label": "Net income confirmed?", - "type": "validation_override", + "questions": { + "net_income_value_check": { + "check_answer_label": "Net income soft validation", + "hidden_in_check_answers": true, + "header": "Are you sure this is correct?", + "type": "interruption_screen", "answer_options": { - "override_net_income_validation": "Yes" + "0": { + "value":"Yes" + }, + "1": { + "value":"No" + } } } } diff --git a/config/locales/en.yml b/config/locales/en.yml index d12912794..0acb9b5b5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -90,8 +90,8 @@ en: reasonpref: not_homeless: "Answer cannot be ‘homeless or about to lose their home’ as you already told us the tenant was not homeless immediately prior to this letting" reasonable_preference_reason: - reason_required: "If reasonable preference is \"Yes\", a reason must be given" - reason_not_required: "If reasonable preference is \"No\", no reasons should be given" + reason_required: 'If reasonable preference is "Yes", a reason must be given' + reason_not_required: 'If reasonable preference is "No", no reasons should be given' underoccupation_benefitcap: dont_know_required: "must be don’t know if tenant’s main reason for leaving is don’t know" reservist: @@ -131,7 +131,6 @@ en: not_homeless: "Answer cannot be ‘no’ as you already told us the tenant was homeless or about to lose their home" previous_la_known: "Enter a local authority" - tenancy: length: fixed_term_not_required: "You must only answer the fixed term tenancy length question if the tenancy type is fixed term" @@ -145,7 +144,7 @@ en: soft_validations: net_income: - hint_text: "This is based on the tenant’s work situation: %{ecstat1}" + hint_text: "

You told us the main tenant’s working situation is: %{ecstat1}

The household income you have entered is %{earnings}

" in_soft_min_range: message: "Net income is lower than expected based on the main tenant’s working situation. Are you sure this is correct?" in_soft_max_range: @@ -160,3 +159,6 @@ en: code_has_been_sent: "Your security code has been sent." code_required: "Security code is required" code_incorrect: "Security code is incorrect" + + test: + one_argument: "This is based on the tenant’s work situation: %{ecstat1}" diff --git a/config/routes.rb b/config/routes.rb index c230a969c..2b6b4aa7d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,7 +60,6 @@ Rails.application.routes.draw do FormHandler.instance.forms.each do |_key, form| form.pages.map do |page| get page.id.to_s.dasherize, to: "form##{page.id}" - get "#{page.id.to_s.dasherize}/soft-validations", to: "soft_validations#show" if page.has_soft_validations? end form.subsections.map do |subsection| diff --git a/db/migrate/20220228112732_rename_net_income_validation_override_column.rb b/db/migrate/20220228112732_rename_net_income_validation_override_column.rb new file mode 100644 index 000000000..e323286ef --- /dev/null +++ b/db/migrate/20220228112732_rename_net_income_validation_override_column.rb @@ -0,0 +1,5 @@ +class RenameNetIncomeValidationOverrideColumn < ActiveRecord::Migration[7.0] + def change + rename_column :case_logs, :override_net_income_validation, :net_income_value_check + end +end diff --git a/db/schema.rb b/db/schema.rb index dbebd8bcc..c762b1a4e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -124,7 +124,7 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do t.integer "rp_hardship" t.integer "rp_dontknow" t.string "tenancyother" - t.integer "override_net_income_validation" + t.integer "net_income_value_check" t.string "property_owner_organisation" t.string "property_manager_organisation" t.string "sale_or_letting" diff --git a/docs/api/DLUHC-CORE-Data.v1.json b/docs/api/DLUHC-CORE-Data.v1.json index bb90d3fb4..6750069f6 100644 --- a/docs/api/DLUHC-CORE-Data.v1.json +++ b/docs/api/DLUHC-CORE-Data.v1.json @@ -386,7 +386,7 @@ "rp_hardship": 0, "rp_dontknow": 0, "discarded_at": "05/05/2020", - "override_net_income_validation": "", + "net_income_value_check": "", "property_owner_organisation": "", "property_manager_organisation": "", "rent_type": 0, diff --git a/spec/factories/case_log.rb b/spec/factories/case_log.rb index b5de2432e..a7d9eb49a 100644 --- a/spec/factories/case_log.rb +++ b/spec/factories/case_log.rb @@ -105,7 +105,7 @@ FactoryBot.define do rp_hardship { 0 } rp_dontknow { 0 } tenancyother { nil } - override_net_income_validation { nil } + net_income_value_check { nil } net_income_known { 1 } property_owner_organisation { "Test" } property_manager_organisation { "Test" } diff --git a/spec/features/form/check_answers_page_spec.rb b/spec/features/form/check_answers_page_spec.rb index 8808cc8db..ae093cd24 100644 --- a/spec/features/form/check_answers_page_spec.rb +++ b/spec/features/form/check_answers_page_spec.rb @@ -72,7 +72,7 @@ RSpec.describe "Form Check Answers Page" do # This way only the links in the table will get picked up it "has an answer link for questions missing an answer" do visit("/logs/#{empty_case_log.id}/#{subsection}/check-answers") - assert_selector "a", text: /Answer (?!the missing questions)/, count: 4 + assert_selector "a", text: /Answer (?!the missing questions)/, count: 5 assert_selector "a", text: "Change", count: 0 expect(page).to have_link("Answer", href: "/logs/#{empty_case_log.id}/person-1-age") end @@ -80,7 +80,7 @@ RSpec.describe "Form Check Answers Page" do it "has a change link for answered questions" do fill_in_number_question(empty_case_log.id, "age1", 28, "person-1-age") visit("/logs/#{empty_case_log.id}/#{subsection}/check-answers") - assert_selector "a", text: /Answer (?!the missing questions)/, count: 3 + assert_selector "a", text: /Answer (?!the missing questions)/, count: 4 assert_selector "a", text: "Change", count: 1 expect(page).to have_link("Change", href: "/logs/#{empty_case_log.id}/person-1-age") end diff --git a/spec/features/form/form_navigation_spec.rb b/spec/features/form/form_navigation_spec.rb index fa7a0f5cf..fd4f78b08 100644 --- a/spec/features/form/form_navigation_spec.rb +++ b/spec/features/form/form_navigation_spec.rb @@ -18,6 +18,7 @@ RSpec.describe "Form Navigation" do tenant_code: { type: "text", answer: "BZ737", path: "tenant-code" }, age1: { type: "numeric", answer: 25, path: "person-1-age" }, sex1: { type: "radio", answer: "Female", path: "person-1-gender" }, + ecstat1: { type: "radio", answer: 3, path: "person-1-working-situation" }, other_hhmemb: { type: "numeric", answer: 2, path: "household-number-of-other-members" }, } end diff --git a/spec/features/form/page_routing_spec.rb b/spec/features/form/page_routing_spec.rb index 829532831..28358e949 100644 --- a/spec/features/form/page_routing_spec.rb +++ b/spec/features/form/page_routing_spec.rb @@ -38,7 +38,7 @@ RSpec.describe "Form Page Routing" do visit("/logs/#{id}/person-1-gender") choose("case-log-sex1-f-field", allow_label_click: true) click_button("Save and continue") - expect(page).to have_current_path("/logs/#{id}/household-number-of-other-members") + expect(page).to have_current_path("/logs/#{id}/person-1-working-situation") visit("/logs/#{id}/conditional-question") choose("case-log-preg-occ-1-field", allow_label_click: true) click_button("Save and continue") diff --git a/spec/features/form/validations_spec.rb b/spec/features/form/validations_spec.rb index c08a8cf39..34f6fbfd5 100644 --- a/spec/features/form/validations_spec.rb +++ b/spec/features/form/validations_spec.rb @@ -124,49 +124,28 @@ RSpec.describe "validations" do let(:income_over_soft_limit) { 750 } let(:income_under_soft_limit) { 700 } - it "prompts the user to confirm the value is correct", js: true do + it "prompts the user to confirm the value is correct with an interruption screen" do visit("/logs/#{case_log.id}/net-income") fill_in("case-log-earnings-field", with: income_over_soft_limit) choose("case-log-incfreq-0-field", allow_label_click: true) click_button("Save and continue") - expect(page).to have_content("Are you sure this is correct?") - check("case-log-override-net-income-validation-override-net-income-validation-field", allow_label_click: true) + expect(page).to have_current_path("/logs/#{case_log.id}/net-income-value-check") + expect(page).to have_content("Net income is outside the expected range based on the main tenant’s working situation") + expect(page).to have_content("You told us the main tenant’s working situation is: Full-time – 30 hours or more") + expect(page).to have_content("The household income you have entered is £750.00 every week") + choose("case-log-net-income-value-check-0-field", allow_label_click: true) click_button("Save and continue") expect(page).to have_current_path("/logs/#{case_log.id}/net-income-uc-proportion") end - it "does not require confirming the value if the value is amended" do + it "returns the user to the previous question if they do not confirm the value as correct on the interruption screen" do visit("/logs/#{case_log.id}/net-income") fill_in("case-log-earnings-field", with: income_over_soft_limit) choose("case-log-incfreq-0-field", allow_label_click: true) click_button("Save and continue") - fill_in("case-log-earnings-field", with: income_under_soft_limit) + choose("case-log-net-income-value-check-1-field", allow_label_click: true) click_button("Save and continue") - expect(page).to have_current_path("/logs/#{case_log.id}/net-income-uc-proportion") - case_log.reload - expect(case_log.override_net_income_validation).to be_nil - end - - it "clears the confirmation question if the amount was amended and the page is returned to using the back button", js: true do - visit("/logs/#{case_log.id}/net-income") - fill_in("case-log-earnings-field", with: income_over_soft_limit) - choose("case-log-incfreq-0-field", allow_label_click: true) - click_button("Save and continue") - fill_in("case-log-earnings-field", with: income_under_soft_limit) - click_button("Save and continue") - click_link(text: "Back") - expect(page).to have_no_content("Are you sure this is correct?") - end - - it "does not clear the confirmation question if the page is returned to using the back button and the amount is still over the soft limit", js: true do - visit("/logs/#{case_log.id}/net-income") - fill_in("case-log-earnings-field", with: income_over_soft_limit) - choose("case-log-incfreq-0-field", allow_label_click: true) - click_button("Save and continue") - check("case-log-override-net-income-validation-override-net-income-validation-field", allow_label_click: true) - click_button("Save and continue") - click_link(text: "Back") - expect(page).to have_content("Are you sure this is correct?") + expect(page).to have_current_path("/logs/#{case_log.id}/net-income") end end end diff --git a/spec/fixtures/complete_case_log.json b/spec/fixtures/complete_case_log.json index ac13176e7..6f3bf98e9 100644 --- a/spec/fixtures/complete_case_log.json +++ b/spec/fixtures/complete_case_log.json @@ -118,7 +118,7 @@ "rp_hardship": 0, "rp_dontknow": 0, "discarded_at": "05/05/2020", - "override_net_income_validation": "", + "net_income_value_check": 0, "property_owner_organisation": "", "property_manager_organisation": "", "rent_type": 0, @@ -141,7 +141,7 @@ "has_benefits": 1, "household_charge": 1, "is_carehome": 1, - "chcharge": 6, + "chcharge": 6, "letting_in_sheltered_accommodation": 0, "declaration": 1, "referral": 1 diff --git a/spec/fixtures/exports/case_logs.xml b/spec/fixtures/exports/case_logs.xml index 249d52c4f..d89fd07b1 100644 --- a/spec/fixtures/exports/case_logs.xml +++ b/spec/fixtures/exports/case_logs.xml @@ -86,7 +86,7 @@ 0 0 - + Test Test diff --git a/spec/fixtures/forms/2021_2022.json b/spec/fixtures/forms/2021_2022.json index f7a232724..a943de777 100644 --- a/spec/fixtures/forms/2021_2022.json +++ b/spec/fixtures/forms/2021_2022.json @@ -64,6 +64,56 @@ } } }, + "person_1_working_situation": { + "header": "", + "description": "", + "questions": { + "ecstat1": { + "check_answer_label": "Lead tenant’s working situation", + "header": "Which of these best describes the lead tenant’s socks?", + "hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.", + "type": "radio", + "answer_options": { + "0": { + "value": "Part-time – Less than 30 hours" + }, + "1": { + "value": "Full-time – 30 hours or more" + }, + "2": { + "value": "Full-time student" + }, + "3": { + "value": "In government training into work, such as New Deal" + }, + "4": { + "value": "Jobseeker" + }, + "5": { + "value": "Not seeking work" + }, + "6": { + "value": "Unable to work because of long term sick or disability" + }, + "7": { + "value": "Retired" + }, + "8": { + "value": "Child under 16" + }, + "9": { + "value": "Other" + }, + "divider": { + "value": true + }, + "10": { + "value": "Tenant prefers not to say" + } + } + } + } + }, "household_number_of_other_members": { "questions": { "other_hhmemb": { @@ -485,13 +535,28 @@ } } } + } + }, + "net_income_value_check": { + "depends_on": [{ "net_income_soft_validation_triggered?": true }], + "title_text": "Net income is outside the expected range based on the main tenant’s working situation", + "informative_text": { + "translation": "soft_validations.net_income.hint_text", + "argument": ["ecstat1", "earnings"] }, - "soft_validations": { - "override_net_income_validation": { - "check_answer_label": "Net income confirmed?", - "type": "validation_override", + "questions": { + "net_income_value_check": { + "check_answer_label": "Net income soft validation", + "hidden_in_check_answers": true, + "header": "Are you sure this is correct?", + "type": "interruption_screen", "answer_options": { - "override_net_income_validation": "Yes" + "0": { + "value":"Yes" + }, + "1": { + "value":"No" + } } } } diff --git a/spec/helpers/check_answers_helper_spec.rb b/spec/helpers/check_answers_helper_spec.rb index 0d1a94d6d..ade2473c3 100644 --- a/spec/helpers/check_answers_helper_spec.rb +++ b/spec/helpers/check_answers_helper_spec.rb @@ -9,7 +9,7 @@ RSpec.describe CheckAnswersHelper do context "when a section hasn't been completed yet" do it "returns that you have unanswered questions" do expect(display_answered_questions_summary(subsection, case_log)) - .to match(/You have answered 2 of 5 questions./) + .to match(/You have answered 2 of 6 questions./) end end @@ -18,6 +18,7 @@ RSpec.describe CheckAnswersHelper do case_log.sex1 = "F" case_log.other_hhmemb = 0 case_log.propcode = "123" + case_log.ecstat1 = 200 expect(display_answered_questions_summary(subsection, case_log)) .to match(/You answered all the questions./) expect(display_answered_questions_summary(subsection, case_log)) diff --git a/spec/helpers/interuption_screen_helper_spec.rb b/spec/helpers/interuption_screen_helper_spec.rb new file mode 100644 index 000000000..3ad158857 --- /dev/null +++ b/spec/helpers/interuption_screen_helper_spec.rb @@ -0,0 +1,65 @@ +require "rails_helper" + +RSpec.describe InteruptionScreenHelper do + form_handler = FormHandler.instance + let(:form) { form_handler.get_form("test_form") } + let(:subsection) { form.get_subsection("household_characteristics") } + let(:user) { FactoryBot.create(:user) } + let(:case_log) do + FactoryBot.create( + :case_log, + :in_progress, + ecstat1: 1, + earnings: 750, + incfreq: 0, + owning_organisation: user.organisation, + managing_organisation: user.organisation, + ) + end + + describe "display_informative_text" do + context "when 2 out of 2 arguments are given" do + it "returns correct informative text" do + informative_text = { + "translation" => "soft_validations.net_income.hint_text", + "argument" => %w[ecstat1 earnings], + } + expect(display_informative_text(informative_text, case_log)) + .to eq("

You told us the main tenant’s working situation is: Full-time – 30 hours or more

The household income you have entered is £750.00 every week

") + end + end + + context "when 1 out of 1 arguments is given" do + it "returns correct informative text" do + informative_text = { + "translation" => "test.one_argument", + "argument" => %w[ecstat1], + } + expect(display_informative_text(informative_text, case_log)) + .to eq("This is based on the tenant’s work situation: Full-time – 30 hours or more") + end + end + end + + context "when 2 out of 1 arguments are given" do + it "returns correct informative text" do + informative_text = { + "translation" => "test.one_argument", + "argument" => %w[ecstat1 earnings], + } + expect(display_informative_text(informative_text, case_log)) + .to eq("This is based on the tenant’s work situation: Full-time – 30 hours or more") + end + end + + context "when 1 out of 2 arguments are given" do + it "returns an empty string" do + informative_text = { + "translation" => "soft_validations.net_income.hint_text", + "argument" => %w[ecstat1], + } + expect(display_informative_text(informative_text, case_log)) + .to eq("") + end + end +end diff --git a/spec/models/case_log_spec.rb b/spec/models/case_log_spec.rb index 44672f89d..567d7284d 100644 --- a/spec/models/case_log_spec.rb +++ b/spec/models/case_log_spec.rb @@ -42,38 +42,6 @@ RSpec.describe CaseLog do .to include(CaseLogValidator) end end - - context "when soft validations exist" do - context "with an income in upper soft range" do - let(:case_log) do - FactoryBot.create(:case_log, - ecstat1: 1, - earnings: 750, - incfreq: 0) - end - - it "updates soft errors" do - expect(case_log.has_no_unresolved_soft_errors?).to be false - expect(case_log.soft_errors["override_net_income_validation"].message) - .to match(I18n.t("soft_validations.net_income.in_soft_max_range.message")) - end - end - - context "with an income in lower soft validation range" do - let(:case_log) do - FactoryBot.create(:case_log, - ecstat1: 1, - earnings: 120, - incfreq: 0) - end - - it "updates soft errors" do - expect(case_log.has_no_unresolved_soft_errors?).to be false - expect(case_log.soft_errors["override_net_income_validation"].message) - .to match(I18n.t("soft_validations.net_income.in_soft_min_range.message")) - end - end - end end describe "#update" do diff --git a/spec/models/form/page_spec.rb b/spec/models/form/page_spec.rb index d5c1bc67d..1b8a5189b 100644 --- a/spec/models/form/page_spec.rb +++ b/spec/models/form/page_spec.rb @@ -31,20 +31,6 @@ RSpec.describe Form::Page, type: :model do expect(page.questions.map(&:id)).to eq(expected_questions) end - it "has soft validations" do - expected_soft_validations = %w[override_net_income_validation] - expect(page.soft_validations.map(&:id)).to eq(expected_soft_validations) - end - - it "has a soft_validation helper" do - expect(page.has_soft_validations?).to be true - end - - it "has expected form responses" do - expected_responses = %w[earnings incfreq override_net_income_validation] - expect(page.expected_responses.map(&:id)).to eq(expected_responses) - end - context "with a page having conditional questions" do let(:page_id) { "housing_benefit" } diff --git a/spec/models/form/subsection_spec.rb b/spec/models/form/subsection_spec.rb index 0f6b269d6..9d0620b8d 100644 --- a/spec/models/form/subsection_spec.rb +++ b/spec/models/form/subsection_spec.rb @@ -25,12 +25,12 @@ RSpec.describe Form::Subsection, type: :model do end it "has pages" do - expected_pages = %w[tenant_code person_1_age person_1_gender household_number_of_other_members propcode] + expected_pages = %w[tenant_code person_1_age person_1_gender person_1_working_situation household_number_of_other_members propcode] expect(sub_section.pages.map(&:id)).to eq(expected_pages) end it "has questions" do - expected_questions = %w[tenant_code age1 sex1 other_hhmemb relat2 age2 sex2 ecstat2 propcode] + expected_questions = %w[tenant_code age1 sex1 ecstat1 other_hhmemb relat2 age2 sex2 ecstat2 propcode] expect(sub_section.questions.map(&:id)).to eq(expected_questions) end @@ -58,9 +58,9 @@ RSpec.describe Form::Subsection, type: :model do end it "has question helpers for the number of applicable questions" do - expected_questions = %w[tenant_code age1 sex1 other_hhmemb propcode] + expected_questions = %w[tenant_code age1 sex1 ecstat1 other_hhmemb propcode] expect(sub_section.applicable_questions(case_log).map(&:id)).to eq(expected_questions) - expect(sub_section.applicable_questions_count(case_log)).to eq(5) + expect(sub_section.applicable_questions_count(case_log)).to eq(6) end it "has question helpers for the number of answered questions" do @@ -79,7 +79,7 @@ RSpec.describe Form::Subsection, type: :model do end it "has a question helpers for the unanswered questions" do - expected_questions = %w[sex1 other_hhmemb propcode] + expected_questions = %w[sex1 ecstat1 other_hhmemb propcode] expect(sub_section.unanswered_questions(case_log).map(&:id)).to eq(expected_questions) end end diff --git a/spec/models/form_handler_spec.rb b/spec/models/form_handler_spec.rb index 94a6e9f9f..507d2416c 100644 --- a/spec/models/form_handler_spec.rb +++ b/spec/models/form_handler_spec.rb @@ -17,7 +17,7 @@ RSpec.describe FormHandler do form_handler = described_class.instance form = form_handler.get_form(test_form_name) expect(form).to be_a(Form) - expect(form.pages.count).to eq(29) + expect(form.pages.count).to eq(31) end end diff --git a/spec/models/form_spec.rb b/spec/models/form_spec.rb index f8dc3afad..5cb699061 100644 --- a/spec/models/form_spec.rb +++ b/spec/models/form_spec.rb @@ -89,6 +89,7 @@ RSpec.describe Form, type: :model do case_log.tenant_code = "123" case_log.age1 = 35 case_log.sex1 = "Male" + case_log.ecstat1 = 0 case_log.other_hhmemb = 0 end @@ -131,7 +132,7 @@ RSpec.describe Form, type: :model do describe "invalidated_page_questions" do context "when dependencies are not met" do - let(:expected_invalid) { %w[la_known cbl conditional_question_no_second_question dependent_question layear declaration] } + let(:expected_invalid) { %w[la_known cbl conditional_question_no_second_question net_income_value_check dependent_question layear declaration] } it "returns an array of question keys whose pages conditions are not met" do expect(form.invalidated_page_questions(case_log).map(&:id).uniq).to eq(expected_invalid) @@ -139,7 +140,7 @@ RSpec.describe Form, type: :model do end context "with two pages having the same question and only one has dependencies met" do - let(:expected_invalid) { %w[la_known cbl conditional_question_no_second_question dependent_question layear declaration] } + let(:expected_invalid) { %w[la_known cbl conditional_question_no_second_question net_income_value_check dependent_question layear declaration] } it "returns an array of question keys whose pages conditions are not met" do case_log["preg_occ"] = "No" diff --git a/spec/requests/form_controller_spec.rb b/spec/requests/form_controller_spec.rb index 7eaf215b2..bed33d616 100644 --- a/spec/requests/form_controller_spec.rb +++ b/spec/requests/form_controller_spec.rb @@ -240,7 +240,7 @@ RSpec.describe FormController, type: :request do let(:page) { case_log.form.get_page("accessibility_requirements") } it "updates both question fields" do - allow(page).to receive(:expected_responses).and_return(questions_for_page) + allow(page).to receive(:questions).and_return(questions_for_page) post "/logs/#{case_log.id}/form", params: case_log_form_params case_log.reload diff --git a/spec/requests/soft_validations_controller_spec.rb b/spec/requests/soft_validations_controller_spec.rb deleted file mode 100644 index 07acf43af..000000000 --- a/spec/requests/soft_validations_controller_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require "rails_helper" - -RSpec.describe SoftValidationsController, type: :request do - let(:params) { { case_log_id: case_log.id } } - let(:url) { "/logs/#{case_log.id}/net-income/soft-validations" } - let(:user) { FactoryBot.create(:user) } - - context "when a user is not signed in" do - let(:case_log) { FactoryBot.create(:case_log, :in_progress) } - - describe "GET #show" do - it "redirects to the sign in page" do - get url, headers: headers, params: {} - expect(response).to redirect_to("/users/sign-in") - end - end - end - - context "when a user is signed in" do - before do - sign_in user - get url, params: {} - end - - describe "GET #show" do - context "when a soft validation is triggered" do - let(:case_log) { FactoryBot.create(:case_log, :soft_validations_triggered) } - - it "returns a success response" do - expect(response).to be_successful - end - - it "returns a json with the soft validation fields" do - json_response = JSON.parse(response.body) - expect(json_response["show"]).to eq(true) - expect(json_response["label"]).to match(/Are you sure this is correct?/) - end - end - - context "when no soft validation is triggered" do - let(:case_log) { FactoryBot.create(:case_log, :in_progress) } - - it "returns a success response" do - expect(response).to be_successful - end - - it "returns a json without the soft validation fields" do - json_response = JSON.parse(response.body) - expect(json_response["show"]).to eq(false) - end - end - end - end -end diff --git a/spec/views/form/page_view_spec.rb b/spec/views/form/page_view_spec.rb index 5f653dfa6..252416974 100644 --- a/spec/views/form/page_view_spec.rb +++ b/spec/views/form/page_view_spec.rb @@ -7,7 +7,7 @@ RSpec.describe "form/page" do let(:page) { form.get_page("net_income") } let(:question) { page.questions.find { |q| q.id == "earnings" } } let(:initial_page_attributes) { { description: nil, hide_subsection_label: nil } } - let(:initial_question_attributes) { { type: "numeric", answer_options: nil, prefix: nil, suffix: nil } } + let(:initial_question_attributes) { { type: "numeric", answer_options: nil, prefix: "£", suffix: " every week" } } let(:page_attributes) { {} } let(:question_attributes) { {} }