diff --git a/.codeclimate.yml b/.codeclimate.yml index 88d30880bd7..bb08cef8e3e 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -90,6 +90,7 @@ plugins: exclude_patterns: - 'db/schema.rb' - 'node_modules/' + - 'lib/proofer_mocks/' - 'lib/rspec/formatters/user_flow_formatter.rb' - 'lib/tasks/create_test_accounts.rb' - 'lib/user_flow_exporter.rb' diff --git a/app/assets/javascripts/i18n-strings.js.erb b/app/assets/javascripts/i18n-strings.js.erb index fd535a4ebe6..4a36792f633 100644 --- a/app/assets/javascripts/i18n-strings.js.erb +++ b/app/assets/javascripts/i18n-strings.js.erb @@ -12,7 +12,7 @@ window.LoginGov = window.LoginGov || {}; 'idv.errors.pattern_mismatch.personal_key', 'idv.errors.pattern_mismatch.ssn', 'idv.errors.pattern_mismatch.zipcode', - 'idv.modal.button.warning', + 'idv.failure.button.warning', 'instructions.password.strength.i', 'instructions.password.strength.ii', 'instructions.password.strength.iii', diff --git a/app/controllers/concerns/idv_failure_concern.rb b/app/controllers/concerns/idv_failure_concern.rb index b8e30cdb569..aedc9ff3dc3 100644 --- a/app/controllers/concerns/idv_failure_concern.rb +++ b/app/controllers/concerns/idv_failure_concern.rb @@ -1,37 +1,54 @@ module IdvFailureConcern extend ActiveSupport::Concern - # rubocop:disable Metrics/MethodLength - def render_failure - if step_attempts_exceeded? - @view_model = view_model(error: 'fail') - flash_message(type: :error) - elsif step.vendor_validator_job_failed? - @view_model = view_model(error: 'jobfail') - flash_message(type: :warning) - elsif form_valid_but_vendor_validation_failed? - @view_model = view_model(error: 'warning', timed_out: step.vendor_validation_timed_out?) - flash_message(type: :warning) - else - @view_model = view_model - end - end - # rubocop:enable Metrics/MethodLength - - def form_valid_but_vendor_validation_failed? - idv_form.valid? && !step.vendor_validation_passed? - end - - def flash_message(type:) - flash.now[type.to_sym] = @view_model.flash_message - end - - def view_model(error: nil, timed_out: nil) - view_model_class.new( - error: error, + def idv_step_failure_reason + return :fail if fail? + return :jobfail if jobfail? + return :timeout if timeout? + return :warning if warning? + end + + def render_idv_step_failure(step, reason) + return render_failure('shared/_failure', failure_presenter(step)) if reason == :fail + render_failure('idv/shared/verification_failure', warning_presenter(step, reason)) + end + + def render_failure(template, presenter) + render_full_width(template, locals: { presenter: presenter }) + end + + private + + def fail? + idv_attempter.exceeded? || step_attempts_exceeded? + end + + def jobfail? + step.vendor_validator_job_failed? + end + + def timeout? + !step.vendor_validation_passed? && step.vendor_validation_timed_out? + end + + def warning? + !step.vendor_validation_passed? && !step.vendor_validation_timed_out? + end + + def failure_presenter(step) + Idv::MaxAttemptsFailurePresenter.new( + decorated_session: decorated_session, + step_name: step, + view_context: view_context + ) + end + + def warning_presenter(step, reason) + Idv::WarningPresenter.new( + reason: reason, remaining_attempts: remaining_step_attempts, - idv_form: idv_form, - timed_out: timed_out + step_name: step, + view_context: view_context ) end end diff --git a/app/controllers/concerns/idv_session.rb b/app/controllers/concerns/idv_session.rb index 83450691aaa..c0d8abd1074 100644 --- a/app/controllers/concerns/idv_session.rb +++ b/app/controllers/concerns/idv_session.rb @@ -8,9 +8,8 @@ def confirm_idv_session_started def confirm_idv_attempts_allowed if idv_attempter.exceeded? - flash[:error] = t('idv.errors.hardfail') analytics.track_event(Analytics::IDV_MAX_ATTEMPTS_EXCEEDED, request_path: request.path) - redirect_to idv_fail_url + redirect_to failure_url(:fail) elsif idv_attempter.reset_attempts? idv_attempter.reset end diff --git a/app/controllers/concerns/idv_step_concern.rb b/app/controllers/concerns/idv_step_concern.rb index ea31f59a065..7a4a0231794 100644 --- a/app/controllers/concerns/idv_step_concern.rb +++ b/app/controllers/concerns/idv_step_concern.rb @@ -28,7 +28,6 @@ def confirm_step_allowed end def redirect_to_fail_url - flash[:max_attempts_exceeded] = true - redirect_to idv_fail_url + redirect_to failure_url(:fail) end end diff --git a/app/controllers/idv/jurisdiction_controller.rb b/app/controllers/idv/jurisdiction_controller.rb index 5eb733b6fb9..880f68aa2ec 100644 --- a/app/controllers/idv/jurisdiction_controller.rb +++ b/app/controllers/idv/jurisdiction_controller.rb @@ -5,7 +5,7 @@ class JurisdictionController < ApplicationController before_action :confirm_two_factor_authenticated before_action :confirm_idv_attempts_allowed before_action :confirm_idv_needed - before_action :set_jurisdiction_form, only: %i[new create] + before_action :set_jurisdiction_form, except: [:failure] def new analytics.track_event(Analytics::IDV_JURISDICTION_VISIT) @@ -22,12 +22,12 @@ def create # The only invalid result here is due to an unsupported jurisdiction # and if it is missing from the params, it will be stopped by # `strong_params`. - redirect_to idv_jurisdiction_fail_url(:unsupported_jurisdiction) + redirect_to failure_url(:unsupported_jurisdiction) end end - def show - presenter = JurisdictionFailurePresenter.new( + def failure + presenter = Idv::JurisdictionFailurePresenter.new( reason: params[:reason], jurisdiction: user_session[:idv_jurisdiction], view_context: view_context @@ -44,5 +44,9 @@ def jurisdiction_params def set_jurisdiction_form @jurisdiction_form ||= Idv::JurisdictionForm.new end + + def failure_url(reason) + idv_jurisdiction_failure_url(reason) + end end end diff --git a/app/controllers/idv/phone_controller.rb b/app/controllers/idv/phone_controller.rb index 21583bcad8f..1a6810dbf86 100644 --- a/app/controllers/idv/phone_controller.rb +++ b/app/controllers/idv/phone_controller.rb @@ -3,12 +3,14 @@ class PhoneController < ApplicationController include IdvStepConcern include IdvFailureConcern + attr_reader :idv_form + before_action :confirm_step_needed - before_action :confirm_step_allowed + before_action :confirm_step_allowed, except: [:failure] before_action :refresh_if_not_ready, only: [:show] + before_action :set_idv_form, except: [:failure] def new - @view_model = view_model analytics.track_event(Analytics::IDV_PHONE_RECORD_VISIT) end @@ -20,7 +22,6 @@ def create Idv::Job.submit(idv_session, [:address]) redirect_to idv_phone_result_url else - @view_model = view_model render :new end end @@ -30,12 +31,12 @@ def show analytics.track_event(Analytics::IDV_PHONE_CONFIRMATION_VENDOR, result.to_h) increment_step_attempts - if result.success? - redirect_to_next_step - else - render_failure - render :new - end + redirect_to_next_step and return if result.success? + redirect_to idv_phone_failure_url(idv_step_failure_reason) + end + + def failure + render_idv_step_failure(:phone, params[:reason].to_sym) end private @@ -64,10 +65,6 @@ def step ) end - def view_model_class - Idv::PhoneNew - end - def step_params params.require(:idv_phone_form).permit(:phone) end @@ -76,8 +73,12 @@ def confirm_step_needed redirect_to_next_step if idv_session.user_phone_confirmation == true end - def idv_form - @_idv_form ||= Idv::PhoneForm.new(idv_session.params, current_user) + def set_idv_form + @idv_form ||= Idv::PhoneForm.new(idv_session.params, current_user) + end + + def failure_url(reason) + idv_phone_failure_url(reason) end end end diff --git a/app/controllers/idv/sessions_controller.rb b/app/controllers/idv/sessions_controller.rb index d434f610094..a1c272411f7 100644 --- a/app/controllers/idv/sessions_controller.rb +++ b/app/controllers/idv/sessions_controller.rb @@ -4,8 +4,10 @@ class SessionsController < ApplicationController include IdvFailureConcern include PersonalKeyConcern + attr_reader :idv_form + before_action :confirm_two_factor_authenticated, except: [:destroy] - before_action :confirm_idv_attempts_allowed, except: %i[destroy success] + before_action :confirm_idv_attempts_allowed, except: %i[destroy success failure] before_action :confirm_idv_needed before_action :confirm_step_needed, except: %i[destroy success] before_action :initialize_idv_session, only: [:create] @@ -15,12 +17,13 @@ class SessionsController < ApplicationController def new user_session[:context] = 'idv' - @view_model = view_model - @view_model.selected_state = user_session[:idv_jurisdiction] + set_idv_form + @selected_state = user_session[:idv_jurisdiction] analytics.track_event(Analytics::IDV_BASIC_INFO_VISIT) end def create + set_idv_form result = idv_form.submit(profile_params) analytics.track_event(Analytics::IDV_BASIC_INFO_SUBMITTED_FORM, result.to_h) @@ -28,7 +31,7 @@ def create Idv::Job.submit(idv_session, %i[resolution state_id]) redirect_to idv_session_result_url else - process_failure + process_form_failure end end @@ -36,11 +39,14 @@ def show result = step.submit analytics.track_event(Analytics::IDV_BASIC_INFO_SUBMITTED_VENDOR, result.to_h) - if result.success? - process_success - else - process_failure - end + redirect_to idv_session_success_url and return if result.success? + redirect_to idv_session_failure_url(idv_step_failure_reason) + end + + def failure + reason = params[:reason].to_sym + render_dupe_ssn_failure and return if reason == :dupe_ssn + render_idv_step_failure(:sessions, reason) end def success; end @@ -71,31 +77,29 @@ def handle_idv_redirect redirect_to manage_personal_key_url end - def process_success - redirect_to idv_session_success_url + def process_form_failure + redirect_to idv_session_failure_url(:dupe_ssn) and return if idv_form.duplicate_ssn? + if (sp_name = decorated_session.sp_name) && idv_form.unsupported_jurisdiction? + idv_form.add_sp_unsupported_jurisdiction_error(sp_name) + end + render :new end - def process_failure - if idv_form.duplicate_ssn? - flash[:error] = t('idv.errors.duplicate_ssn') - redirect_to idv_session_dupe_url - else - render_failure - @view_model.unsupported_jurisdiction_error(decorated_session.sp_name) - render :new - end + def render_dupe_ssn_failure + presenter = Idv::SsnFailurePresenter.new(view_context: view_context) + render_failure('shared/_failure', presenter) end - def view_model_class - Idv::SessionsNew + def step_name + :sessions end def remaining_step_attempts Idv::Attempter.idv_max_attempts - current_user.idv_attempts end - def idv_form - @_idv_form ||= Idv::ProfileForm.new((idv_session.params || {}), current_user) + def set_idv_form + @idv_form ||= Idv::ProfileForm.new((idv_session.params || {}), current_user) end def initialize_idv_session @@ -107,5 +111,9 @@ def initialize_idv_session def profile_params params.require(:profile).permit(Idv::ProfileForm::PROFILE_ATTRIBUTES) end + + def failure_url(reason) + idv_session_failure_url(reason) + end end end diff --git a/app/controllers/idv_controller.rb b/app/controllers/idv_controller.rb index 2ac95f97270..a22bba6150c 100644 --- a/app/controllers/idv_controller.rb +++ b/app/controllers/idv_controller.rb @@ -26,7 +26,11 @@ def activated def cancel; end def fail - redirect_to idv_url unless ok_to_fail? + redirect_to idv_url and return unless idv_attempter.exceeded? + presenter = Idv::IdvFailurePresenter.new( + view_context: view_context + ) + render_full_width('shared/_failure', locals: { presenter: presenter }) end private @@ -40,8 +44,4 @@ def profile_needs_reactivation? def active_profile? current_user.active_profile.present? end - - def ok_to_fail? - idv_attempter.exceeded? || flash[:max_attempts_exceeded] - end end diff --git a/app/decorators/service_provider_session_decorator.rb b/app/decorators/service_provider_session_decorator.rb index 3cb8bfff2bd..32fc5c69ca0 100644 --- a/app/decorators/service_provider_session_decorator.rb +++ b/app/decorators/service_provider_session_decorator.rb @@ -78,10 +78,6 @@ def verification_method_choice I18n.t('idv.messages.select_verification_with_sp', sp_name: sp_name) end - def idv_hardfail4_partial - 'idv/hardfail4' - end - def requested_attributes sp_session[:requested_attributes].sort end @@ -111,11 +107,11 @@ def sp_alert? end def sp_alert_name - sp_alert? ? SP_ALERTS[sp_name][:i18n_name] : nil + SP_ALERTS.dig(sp_name, :i18n_name) end def sp_alert_learn_more - sp_alert? ? SP_ALERTS[sp_name][:learn_more] : nil + SP_ALERTS.dig(sp_name, :learn_more) end private diff --git a/app/decorators/session_decorator.rb b/app/decorators/session_decorator.rb index 923990c5a0d..8a9bf592b71 100644 --- a/app/decorators/session_decorator.rb +++ b/app/decorators/session_decorator.rb @@ -27,10 +27,6 @@ def verification_method_choice I18n.t('idv.messages.select_verification_without_sp') end - def idv_hardfail4_partial - 'idv/no_sp_hardfail' - end - def cancel_link_url view_context.root_url end diff --git a/app/forms/idv/profile_form.rb b/app/forms/idv/profile_form.rb index 64f171c39fc..634ec0905af 100644 --- a/app/forms/idv/profile_form.rb +++ b/app/forms/idv/profile_form.rb @@ -29,6 +29,15 @@ def submit(params) FormResponse.new(success: valid?, errors: errors.messages) end + def add_sp_unsupported_jurisdiction_error(sp_name) + error_message = [ + I18n.t('idv.errors.unsupported_jurisdiction'), + I18n.t('idv.errors.unsupported_jurisdiction_sp', sp_name: sp_name), + ].join(' ') + errors.delete(:state) + errors.add(:state, error_message) + end + private def consume_params(params) diff --git a/app/presenters/idv/attempt_failure_presenter.rb b/app/presenters/idv/attempt_failure_presenter.rb new file mode 100644 index 00000000000..17882fa257c --- /dev/null +++ b/app/presenters/idv/attempt_failure_presenter.rb @@ -0,0 +1,25 @@ +module Idv + class AttemptFailurePresenter < FailurePresenter + include ActionView::Helpers::TranslationHelper + + attr_reader :remaining_attempts, :step_name + + def initialize(remaining_attempts:, step_name:) + super(:warning) + @remaining_attempts = remaining_attempts + @step_name = step_name + end + + def title + t("idv.failure.#{step_name}.heading") + end + + def header + t("idv.failure.#{step_name}.heading") + end + + def description + t("idv.failure.#{step_name}.warning") + end + end +end diff --git a/app/presenters/idv/idv_failure_presenter.rb b/app/presenters/idv/idv_failure_presenter.rb new file mode 100644 index 00000000000..bae0cdc260d --- /dev/null +++ b/app/presenters/idv/idv_failure_presenter.rb @@ -0,0 +1,53 @@ +module Idv + class IdvFailurePresenter < FailurePresenter + attr_reader :view_context + + delegate :account_path, + :decorated_session, + :link_to, + :t, + to: :view_context + + def initialize(view_context:) + super(:locked) + @view_context = view_context + end + + def title + t('idv.titles.hardfail', app: APP_NAME) + end + + def header + t('idv.titles.hardfail', app: APP_NAME) + end + + def description + t('idv.messages.hardfail', hours: Figaro.env.idv_attempt_window_in_hours) + end + + def message + t('headings.lock_failure') + end + + def next_steps + [help_step, sp_step, profile_step].compact + end + + private + + def help_step + link_to t('idv.messages.help_center_html'), MarketingSite.help_url + end + + def sp_step + return unless (sp_name = decorated_session.sp_name) + link = link_to(sp_name, decorated_session.sp_return_url) + t('idv.messages.jurisdiction.sp_support', link: link) + end + + def profile_step + link = link_to(t('idv.messages.jurisdiction.profile_link'), account_path) + t('idv.messages.jurisdiction.profile', link: link) + end + end +end diff --git a/app/presenters/idv/jurisdiction_failure_presenter.rb b/app/presenters/idv/jurisdiction_failure_presenter.rb index db81973c6da..29e18bc0964 100644 --- a/app/presenters/idv/jurisdiction_failure_presenter.rb +++ b/app/presenters/idv/jurisdiction_failure_presenter.rb @@ -44,19 +44,19 @@ def i18n_args end def try_again_step - try_again_link = link_to(t('idv.messages.jurisdiction.try_again_link'), idv_jurisdiction_path) - t('idv.messages.jurisdiction.try_again', link: try_again_link) + link = link_to(t('idv.messages.jurisdiction.try_again_link'), idv_jurisdiction_path) + t('idv.messages.jurisdiction.try_again', link: link) end def sp_step return unless (sp_name = decorated_session.sp_name) - support_link = link_to(sp_name, decorated_session.sp_alert_learn_more) - t('idv.messages.jurisdiction.sp_support', link: support_link) + link = link_to(sp_name, decorated_session.sp_return_url) + t('idv.messages.jurisdiction.sp_support', link: link) end def profile_step - profile_link = link_to(t('idv.messages.jurisdiction.profile_link'), account_path) - t('idv.messages.jurisdiction.profile', link: profile_link) + link = link_to(t('idv.messages.jurisdiction.profile_link'), account_path) + t('idv.messages.jurisdiction.profile', link: link) end end end diff --git a/app/presenters/idv/max_attempts_failure_presenter.rb b/app/presenters/idv/max_attempts_failure_presenter.rb new file mode 100644 index 00000000000..33df16ab249 --- /dev/null +++ b/app/presenters/idv/max_attempts_failure_presenter.rb @@ -0,0 +1,59 @@ +module Idv + class MaxAttemptsFailurePresenter < FailurePresenter + attr_reader :decorated_session, :step_name, :view_context + + delegate :account_path, + :idv_session_path, + :link_to, + :t, + to: :view_context + + def initialize(decorated_session:, step_name:, view_context:) + super(:locked) + @decorated_session = decorated_session + @step_name = step_name + @view_context = view_context + end + + def title + t("idv.failure.#{step_name}.heading") + end + + def header + t("idv.failure.#{step_name}.heading") + end + + def description + t("idv.failure.#{step_name}.fail") + end + + def message + t('headings.lock_failure') + end + + def next_steps + [sp_step, help_step, profile_step].compact + end + + private + + def sp_step + return unless (sp_name = decorated_session.sp_name) + link = link_to(sp_name, decorated_session.sp_return_url) + t('idv.messages.jurisdiction.sp_support', link: link) + end + + def help_step + link = link_to( + t('idv.messages.read_about_security_and_privacy.link'), + MarketingSite.help_privacy_and_security_url + ) + t('idv.messages.read_about_security_and_privacy.text', link: link) + end + + def profile_step + link = link_to(t('idv.messages.jurisdiction.profile_link'), account_path) + t('idv.messages.jurisdiction.profile', link: link) + end + end +end diff --git a/app/presenters/idv/ssn_failure_presenter.rb b/app/presenters/idv/ssn_failure_presenter.rb new file mode 100644 index 00000000000..7250f3c9866 --- /dev/null +++ b/app/presenters/idv/ssn_failure_presenter.rb @@ -0,0 +1,54 @@ +module Idv + class SsnFailurePresenter < FailurePresenter + attr_reader :view_context + + delegate :account_path, + :destroy_user_session_path, + :idv_session_path, + :link_to, + :t, + to: :view_context + + def initialize(view_context:) + super(:failure) + @view_context = view_context + end + + def title + t('idv.titles.dupe') + end + + def header + t('idv.titles.dupe') + end + + def description + t('idv.messages.dupe_ssn1') + end + + def message + t('headings.lock_failure') + end + + def next_steps + [try_again_step, sign_out_step, profile_step] + end + + private + + def try_again_step + link = link_to(t('idv.messages.jurisdiction.try_again_link'), idv_session_path) + t('idv.messages.jurisdiction.try_again', link: link) + end + + def sign_out_step + link = link_to(t('idv.messages.dupe_ssn2_link'), destroy_user_session_path) + t('idv.messages.dupe_ssn2_html', link: link) + end + + def profile_step + link = link_to(t('idv.messages.jurisdiction.profile_link'), account_path) + t('idv.messages.jurisdiction.profile', link: link) + end + end +end diff --git a/app/presenters/idv/warning_presenter.rb b/app/presenters/idv/warning_presenter.rb new file mode 100644 index 00000000000..7fa516466f8 --- /dev/null +++ b/app/presenters/idv/warning_presenter.rb @@ -0,0 +1,54 @@ +module Idv + class WarningPresenter < FailurePresenter + attr_reader :reason, :remaining_attempts, :step_name, :view_context + + delegate :idv_phone_path, + :idv_session_path, + :link_to, + :t, + to: :view_context + + def initialize(reason:, remaining_attempts:, step_name:, view_context:) + super(:warning) + @reason = reason + @remaining_attempts = remaining_attempts + @step_name = step_name + @view_context = view_context + end + + def title + t("idv.failure.#{step_name}.heading") + end + + def header + t("idv.failure.#{step_name}.heading") + end + + def description + t("idv.failure.#{step_name}.#{reason}") + end + + def warning_message + reason == :warning ? warning : error + end + + def button_text + t("idv.failure.button.#{reason}") + end + + def button_path + step_name == :sessions ? idv_session_path : idv_phone_path + end + + private + + def warning + t('idv.failure.attempts', count: remaining_attempts) + end + + def error + link = link_to(t('idv.failure.errors.link'), MarketingSite.contact_url) + t('idv.failure.errors.text', link: link) + end + end +end diff --git a/app/presenters/two_factor_auth_code/max_attempts_reached_presenter.rb b/app/presenters/two_factor_auth_code/max_attempts_reached_presenter.rb index 707295ac8dd..e7e8b1cc46d 100644 --- a/app/presenters/two_factor_auth_code/max_attempts_reached_presenter.rb +++ b/app/presenters/two_factor_auth_code/max_attempts_reached_presenter.rb @@ -56,8 +56,7 @@ def read_about_two_factor_authentication MarketingSite.help_url ) - t('read_about_two_factor_authentication.text_html', - scope: T_SCOPE, link: link) + t('read_about_two_factor_authentication.text_html', scope: T_SCOPE, link: link) end end end diff --git a/app/services/marketing_site.rb b/app/services/marketing_site.rb index fecfbe8faf6..5b763741968 100644 --- a/app/services/marketing_site.rb +++ b/app/services/marketing_site.rb @@ -25,4 +25,14 @@ def self.help_url def self.help_authentication_app_url URI.join(BASE_URL, locale_segment, 'help/signing-in/what-is-an-authentication-app/').to_s end + + def self.help_privacy_and_security_url + URI.join( + BASE_URL, + locale_segment, + 'help', + 'privacy-and-security', + 'how-does-logingov-protect-my-data' + ).to_s + end end diff --git a/app/view_models/idv/base.rb b/app/view_models/idv/base.rb deleted file mode 100644 index ff779335bef..00000000000 --- a/app/view_models/idv/base.rb +++ /dev/null @@ -1,95 +0,0 @@ -module Idv - class Base - include Rails.application.routes.url_helpers - - def initialize(error: nil, remaining_attempts:, idv_form:, timed_out: nil) - @error = error - @remaining_attempts = remaining_attempts - @idv_form = idv_form - @timed_out = timed_out - end - - attr_reader :error, :remaining_attempts, :idv_form - - def title - I18n.t("idv.titles.#{step_name}") - end - - def modal_partial - if error.present? - 'shared/modal_verification' - else - 'shared/null' - end - end - - def warning_partial - if %w[warning jobfail].include?(error) - 'shared/modal_verification_warning' - else - 'shared/null' - end - end - - def message - return html_paragraph(text: I18n.t("idv.modal.#{step_name}.timeout")) if timed_out? - html_paragraph(text: I18n.t("idv.modal.#{step_name}.#{error}")) if error - end - - def button - if %w[warning jobfail].include?(error) - helper.content_tag( - :button, button_link_text, id: 'js-close-modal', class: button_css_classes - ) - else - helper.link_to button_link_text, idv_fail_path, class: button_css_classes - end - end - - def flash_message - flash_heading = html_paragraph( - text: I18n.t("idv.modal.#{step_name}.heading"), css_class: 'mb2 fs-20p' - ) - flash_body = message - flash_heading + flash_body + attempts - end - - def modal_class_name - return 'modal-warning' if %w[warning jobfail].include?(error) - "modal-#{error}" - end - - private - - def timed_out? - @timed_out - end - - def button_link_text - I18n.t("idv.modal.button.#{error}") - end - - def button_css_classes - 'btn btn-wide px2 py1 rounded-lg border bw2' - end - - def attempts - if %w[warning jobfail].include?(error) - html_paragraph(text: I18n.t('idv.modal.attempts', count: remaining_attempts)) - else - '' - end - end - - # rubocop:disable Rails/OutputSafety - def html_paragraph(text:, css_class: '') - html = helper.safe_join([text.html_safe]) - helper.content_tag(:p, html, class: css_class) - end - # rubocop:enable Rails/OutputSafety - - def helper - ActionController::Base.helpers - end - end -end diff --git a/app/view_models/idv/phone_new.rb b/app/view_models/idv/phone_new.rb deleted file mode 100644 index bff92046ffe..00000000000 --- a/app/view_models/idv/phone_new.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Idv - class PhoneNew < Idv::Base - def step_name - :phone - end - end -end diff --git a/app/view_models/idv/sessions_new.rb b/app/view_models/idv/sessions_new.rb deleted file mode 100644 index 4663fc1c981..00000000000 --- a/app/view_models/idv/sessions_new.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Idv - class SessionsNew < Idv::Base - attr_accessor :selected_state - - def step_name - :sessions - end - - def unsupported_jurisdiction_error(sp_name) - return unless idv_form.unsupported_jurisdiction? - return unless sp_name - errors = idv_form.errors - error_message = [ - I18n.t('idv.errors.unsupported_jurisdiction'), - I18n.t('idv.errors.unsupported_jurisdiction_sp', sp_name: sp_name), - ].join(' ') - errors.delete(:state) - errors.add(:state, error_message) - end - end -end diff --git a/app/views/idv/_hardfail4.html.slim b/app/views/idv/_hardfail4.html.slim deleted file mode 100644 index 0c2d17ff568..00000000000 --- a/app/views/idv/_hardfail4.html.slim +++ /dev/null @@ -1,11 +0,0 @@ -p.mb1 = t('idv.messages.hardfail', hours: Figaro.env.idv_attempt_window_in_hours) -.mt2.py2.px3.col-12.center.border-box.border.border-teal.rounded-xl - p.fs-20p = t('idv.messages.hardfail4_html', sp: decorated_session.sp_name) - p - = link_to t('idv.buttons.continue_plain'), - decorated_session.sp_return_url, - class: 'btn btn-primary btn-wide' -hr.mt2 -.mt2 = link_to t('idv.messages.help_center_html'), MarketingSite.help_url -.mt2 - = link_to t('idv.messages.return_to_profile', app: APP_NAME), profile_path diff --git a/app/views/idv/_no_sp_hardfail.html.slim b/app/views/idv/_no_sp_hardfail.html.slim deleted file mode 100644 index 6b5c1f14c5b..00000000000 --- a/app/views/idv/_no_sp_hardfail.html.slim +++ /dev/null @@ -1,9 +0,0 @@ -.mt2.py2.px3.col-12.center.border-box.border.border-teal.rounded-xl - p.fs-20p - = t('idv.messages.help_center_html') - p = link_to t('idv.buttons.continue_plain'), - MarketingSite.help_url, - class: 'btn btn-primary btn-wide' -hr.mt2 -.mt2 - = link_to t('idv.messages.return_to_profile', app: APP_NAME), profile_path diff --git a/app/views/idv/fail.html.slim b/app/views/idv/fail.html.slim deleted file mode 100644 index cacceea3263..00000000000 --- a/app/views/idv/fail.html.slim +++ /dev/null @@ -1,11 +0,0 @@ -- title t('idv.titles.hardfail') -.clearfix.col-10.sm-col-12.mx-auto - .center - = image_tag(asset_url('no-verify.svg'), - alt: '', - class: 'mb2', - width: 140) - - h1.h3.mb2.my0.px1.center = t('idv.titles.hardfail', app: APP_NAME) - - = render decorated_session.idv_hardfail4_partial diff --git a/app/views/idv/jurisdiction/new.html.slim b/app/views/idv/jurisdiction/new.html.slim index 5a1303709ef..5fad74fbac7 100644 --- a/app/views/idv/jurisdiction/new.html.slim +++ b/app/views/idv/jurisdiction/new.html.slim @@ -17,7 +17,7 @@ p.mt4.mb0 id='jurisdiction-label' = t('idv.messages.jurisdiction.where') wrapper_html: { class: 'jurisdiction-select' }, input_html: { 'aria-labelledBy': 'jurisdiction-label' } - p = link_to t('idv.messages.jurisdiction.no_id'), idv_jurisdiction_fail_path(:no_id) + p = link_to t('idv.messages.jurisdiction.no_id'), idv_jurisdiction_failure_path(:no_id) .mt4 button type='submit' class='btn btn-primary btn-wide sm-col-6 col-12' diff --git a/app/views/idv/phone/new.html.slim b/app/views/idv/phone/new.html.slim index 034afb93361..f8ace36d003 100644 --- a/app/views/idv/phone/new.html.slim +++ b/app/views/idv/phone/new.html.slim @@ -1,4 +1,4 @@ -- title @view_model.title +- title t('idv.titles.phone') h1.h2.my0 = t('idv.titles.session.phone') @@ -9,7 +9,7 @@ ul.py1.m0 - t('idv.messages.phone.rules').each do |msg| li = msg -= simple_form_for(@view_model.idv_form, url: idv_phone_path, += simple_form_for(@idv_form, url: idv_phone_path, html: { autocomplete: 'off', method: :put, role: 'form', class: 'mt2' }) do |f| = f.label :phone, label: t('idv.form.phone'), class: 'bold' = f.input :phone, required: true, input_html: { class: 'us-phone' }, label: false, @@ -21,5 +21,3 @@ ul.py1.m0 = f.button :submit, t('forms.buttons.continue'), class: 'btn-wide mt6 sm-col-6 col-12' = render 'shared/cancel', link: idv_cancel_path - -= render @view_model.modal_partial, view_model: @view_model diff --git a/app/views/idv/sessions/dupe.html.slim b/app/views/idv/sessions/dupe.html.slim deleted file mode 100644 index c2742a8764b..00000000000 --- a/app/views/idv/sessions/dupe.html.slim +++ /dev/null @@ -1,7 +0,0 @@ -- title t('idv.titles.dupe') - -h1.h3.my0 = t('idv.titles.dupe') - -p.mb1 = t('idv.messages.dupe_ssn1') -p.mb1 = t('idv.messages.dupe_ssn2_html', - link: link_to(t('idv.messages.dupe_ssn2_link'), destroy_user_session_path)) diff --git a/app/views/idv/sessions/new.html.slim b/app/views/idv/sessions/new.html.slim index 7221333b143..779a7f9488c 100644 --- a/app/views/idv/sessions/new.html.slim +++ b/app/views/idv/sessions/new.html.slim @@ -1,11 +1,11 @@ -- title @view_model.title +- title t('idv.titles.sessions') -h1.h3 = @view_model.title +h1.h3 = t('idv.titles.sessions') p = link_to t('links.access_help'), 'https://login.gov/help/privacy-and-security/how-does-logingov-protect-my-data/' -= simple_form_for(@view_model.idv_form, url: idv_session_path, += simple_form_for(@idv_form, url: idv_session_path, html: { autocomplete: 'off', method: :put, role: 'form' }) do |f| = f.error_notification fieldset.ml0.p0.border-none @@ -19,7 +19,7 @@ p = link_to t('links.access_help'), hint: t('idv.form.dob_hint'), hint_html: { id: 'dob-instructs', class: 'mb1' }, pattern: '(0[1-9]|1[012])/(0[1-9]|1[0-9]|2[0-9]|3[01])/[0-9]{4}', input_html: { class: 'dob', - value: @view_model.idv_form.dob, + value: @idv_form.dob, 'aria-describedby': 'dob-instructs' } .clearfix.mxn1 .sm-col.sm-col-6.px1 @@ -27,7 +27,7 @@ p = link_to t('links.access_help'), = f.input :ssn, as: :tel, label: t('idv.form.ssn_label_html'), required: true, pattern: '^\d{3}-?\d{2}-?\d{4}$', - input_html: { class: 'ssn', value: @view_model.idv_form.ssn } + input_html: { class: 'ssn', value: @idv_form.ssn } h2.h3 = t('idv.messages.sessions.id_information_subtitle') p = t('idv.messages.sessions.id_information_message') @@ -58,7 +58,7 @@ p = link_to t('links.access_help'), "data-error-message": t('idv.errors.unsupported_jurisdiction'), "data-error-message-sp": sp_error,\ } - - selected_state = @view_model.idv_form.state || @view_model.selected_state + - selected_state = @idv_form.state || @selected_state = f.input :state, collection: us_states_territories, label: t('idv.form.state'), required: true, input_html: data_attrs, selected: selected_state, @@ -69,10 +69,9 @@ p = link_to t('links.access_help'), = f.input :zipcode, as: :tel, label: t('idv.form.zipcode'), required: true, pattern: '(\d{5}([\-]\d{4})?)', - input_html: { class: 'zipcode', value: @view_model.idv_form.zipcode } + input_html: { class: 'zipcode', value: @idv_form.zipcode } .mt3 button type='submit' class='btn btn-primary btn-wide sm-col-6 col-12' = t('forms.buttons.continue') = render 'shared/cancel', link: idv_cancel_path -= render @view_model.modal_partial, view_model: @view_model diff --git a/app/views/idv/shared/verification_failure.html.slim b/app/views/idv/shared/verification_failure.html.slim new file mode 100644 index 00000000000..34cac002f37 --- /dev/null +++ b/app/views/idv/shared/verification_failure.html.slim @@ -0,0 +1,5 @@ += render 'shared/failure', presenter: presenter +p == presenter.warning_message + +.mt4 + = link_to presenter.button_text, presenter.button_path, class: 'btn btn-primary' diff --git a/app/views/shared/_failure.html.slim b/app/views/shared/_failure.html.slim index 5031207322d..9a60389a561 100644 --- a/app/views/shared/_failure.html.slim +++ b/app/views/shared/_failure.html.slim @@ -5,7 +5,7 @@ h1.h3.mb1.mt3.my0 = presenter.header -p = presenter.description +p == presenter.description .col-2 hr class="mt3 mb2 bw4 rounded border-#{presenter.state_color}" diff --git a/app/views/shared/_modal_verification.slim b/app/views/shared/_modal_verification.slim deleted file mode 100644 index b952a611306..00000000000 --- a/app/views/shared/_modal_verification.slim +++ /dev/null @@ -1,12 +0,0 @@ -#verification-modal.display-none - = render layout: '/shared/modal_layout' do - .p3.sm-p4.cntnr-xxskinny.border-box.bg-white.rounded-xxl(class="#{view_model.modal_class_name}") - h2.my2.fs-20p.sans-serif.regular.center = t("idv.modal.#{view_model.step_name}.heading") - hr.mb3.bw4.rounded - .mb4 - p = view_model.message - = render view_model.warning_partial, count: view_model.remaining_attempts - .center - = view_model.button - -== javascript_pack_tag 'verify-modal' diff --git a/app/views/shared/_modal_verification_warning.html.slim b/app/views/shared/_modal_verification_warning.html.slim deleted file mode 100644 index b1221a1d8ae..00000000000 --- a/app/views/shared/_modal_verification_warning.html.slim +++ /dev/null @@ -1 +0,0 @@ -p == t('idv.modal.attempts', count: count) diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 6b4300eea71..7edf225b75e 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -97,7 +97,7 @@ ignore_unused: - 'errors.not_authorized' - 'event_types.*' - 'idv.errors.pattern_mismatch.*' - - 'idv.modal.*' + - 'idv.failure.*' - 'links.remove' - 'valid_email.validations.email.invalid' - 'zxcvbn.*' diff --git a/config/locales/idv/en.yml b/config/locales/idv/en.yml index 52e4a432f3e..37995f8821d 100644 --- a/config/locales/idv/en.yml +++ b/config/locales/idv/en.yml @@ -22,7 +22,6 @@ en: errors: bad_dob: Your date of birth must be a valid date. duplicate_ssn: An account already exists with the information you provided. - hardfail: We were unable to verify your identity at this time. incorrect_password: The password you entered is not correct. mail_limit_reached: You have have requested too much mail in the last month. pattern_mismatch: @@ -32,6 +31,35 @@ en: zipcode: 'Your zipcode must be entered in as #####-####' unsupported_jurisdiction: Sorry, we can't verify people from this state. unsupported_jurisdiction_sp: Please visit %{sp_name} to access your account. + failure: + attempts: + one: You have 1 attempt remaining. + other: You have %{count} attempts remaining. + button: + fail: Okay + jobfail: Try again tomorrow + timeout: Try again + warning: Try again + errors: + link: please contact us + text: If you keep getting these errors, %{link}, or try again tomorrow. + phone: + fail: For your security, identity verification for your account is locked + for 24 hours. + heading: We could not find records matching your phone information. + jobfail: Something went wrong and we cannot process your request at this time. + Please try again tomorrow. + timeout: Our request to verify your information timed out. + warning: Please check the information you entered. + sessions: + fail: For your security, identity verification for your account is locked + for 24 hours. + heading: We could not find records matching your personal information. + jobfail: Something went wrong and we cannot process your request at this time. + Please try again tomorrow. + timeout: Our request to verify your information timed out. + warning: Please check the information you entered. Common mistakes are an + incorrect Social Security Number, ZIP Code, or date of birth. form: activate_by_mail: get a code via mail instead › address1: Address @@ -77,7 +105,6 @@ en: dupe_ssn2_link: sign out now and sign back in hardfail: We can't log you in right now, but you can try verifying your identity again in %{hours} hours. - hardfail4_html: Go to %{sp} for help accessing your services. help_center_html: Visit our Help Center to learn more about verifying your account. jurisdiction: @@ -107,6 +134,9 @@ en: - not a virtual phone (such as Google Voice or Skype) - not a pre-paid phone number - a U.S. number + read_about_security_and_privacy: + link: read about how login.gov keeps your information safe + text: You can %{link} on our help page. return_to_profile: "‹ Return to your login.gov profile" return_to_sp_html: You can now log into %{sp}. review: @@ -131,32 +161,6 @@ en: success: It should arrive in 5 to 10 business days. agencies_login: You can now continue to and log into these agencies. agency_login_html: You can now continue to and into
%{sp}. - modal: - attempts: - one: You have 1 attempt remaining. - other: You have %{count} attempts remaining. - button: - fail: Okay - jobfail: Try again tomorrow - warning: Try again - phone: - fail: Your account is locked for 24 hours before you can - try to verify again. Check our Help section for more information about identity - verification. - heading: We could not find records matching your phone information. - jobfail: Something went wrong and we cannot process your request at this time. - Please try again tomorrow. - timeout: Our request to verify your information timed out. - warning: Please check the information you entered. - sessions: - fail: Your account is locked for 24 hours before you can - try to verify again. - heading: We could not find records matching your personal information. - jobfail: Something went wrong and we cannot process your request at this time. - Please try again tomorrow. - timeout: Our request to verify your information timed out. - warning: Please check the information you entered. Common mistakes are an - incorrect Social Security Number, ZIP Code, or date of birth. review: dob: Date of birth full_name: Full name diff --git a/config/locales/idv/es.yml b/config/locales/idv/es.yml index 22aaa709e4a..857a9d9a386 100644 --- a/config/locales/idv/es.yml +++ b/config/locales/idv/es.yml @@ -22,7 +22,6 @@ es: errors: bad_dob: Su fecha de nacimiento debe ser una fecha válida. duplicate_ssn: Ya existe una cuenta con la información que proporcionó. - hardfail: No pudimos verificar su identidad en este momento. incorrect_password: La contraseña que ingresó no es correcta. mail_limit_reached: Usted ha solicitado demasiado correo en el último mes. pattern_mismatch: @@ -33,6 +32,35 @@ es: unsupported_jurisdiction: Lo sentimos, no podemos verificar personas de este estado. unsupported_jurisdiction_sp: Visita %{sp_name} para acceder a tu cuenta. + failure: + attempts: + one: Tiene usted 1 intento restante. + other: Tiene usted %{count} intentos restantes. + button: + fail: Bueno + jobfail: Inténtelo de nuevo mañana + timeout: Inténtelo de nuevo + warning: Inténtelo de nuevo + errors: + link: contáctanos + text: Si sigues recibiendo estos errores, %{link} o vuelve a intentarlo mañana. + phone: + fail: Para su seguridad, la verificación de identidad de su cuenta está bloqueada + durante 24 horas. + heading: No hemos podido encontrar registros que coincidan con la información + de su teléfono. + jobfail: NOT TRANSLATED YET + timeout: NOT TRANSLATED YET + warning: Compruebe la información que ingresó. + sessions: + fail: Para su seguridad, la verificación de identidad de su cuenta está bloqueada + durante 24 horas. + heading: No hemos podido encontrar registros que coincidan con su información + personal. + jobfail: NOT TRANSLATED YET + timeout: NOT TRANSLATED YET + warning: Compruebe la información que ingresó. Los errores comunes son números + incorrectos de Seguro Social, código postal o fecha de nacimiento. form: activate_by_mail: obtener un código por correo electrónico en su lugar › address1: Dirección @@ -75,7 +103,6 @@ es: dupe_ssn2_html: Por favor %{link} con el email que utilizó originalmente. dupe_ssn2_link: Cerrar ahora y volver a iniciar sesión hardfail: NOT TRANSLATED YET - hardfail4_html: NOT TRANSLATED YET help_center_html: Visite nuestro Centro de Ayuda para obtener más información sobre la verificación de su cuenta. jurisdiction: @@ -107,6 +134,9 @@ es: - no es un teléfono virtual (como Google Voice o Skype) - no es un número de teléfono prepago - un número de EE. UU. + read_about_security_and_privacy: + link: leer sobre cómo login.gov mantiene su información segura + text: Puede %{link} en nuestra página de ayuda. return_to_profile: NOT TRANSLATED YET return_to_sp_html: NOT TRANSLATED YET review: @@ -133,32 +163,6 @@ es: success: Debe llegar en 5 a 10 días laborales. agencies_login: NOT TRANSLATED YET agency_login_html: NOT TRANSLATED YET - modal: - attempts: - one: Tiene usted 1 intento restante. - other: Tiene usted %{count} intentos restantes. - button: - fail: Bueno - jobfail: Inténtelo de nuevo mañana - warning: Inténtelo de nuevo - phone: - fail: Su cuenta está bloqueada por 24 horas antes de intentar - verificarla de nuevo. Consulte nuestra sección de Ayuda para obtener más - información sobre la verificación de identidad. - heading: No hemos podido encontrar registros que coincidan con la información - de su teléfono. - jobfail: NOT TRANSLATED YET - timeout: NOT TRANSLATED YET - warning: Compruebe la información que ingresó. - sessions: - fail: Su cuenta está bloqueada por 24 horas antes de que - pueda intentar verificarla de nuevo. - heading: No hemos podido encontrar registros que coincidan con su información - personal. - jobfail: NOT TRANSLATED YET - timeout: NOT TRANSLATED YET - warning: Compruebe la información que ingresó. Los errores comunes son números - incorrectos de Seguro Social, código postal o fecha de nacimiento. review: dob: Fecha de nacimiento full_name: Nombre completo diff --git a/config/locales/idv/fr.yml b/config/locales/idv/fr.yml index 7f31c4748cd..3043ace2ecd 100644 --- a/config/locales/idv/fr.yml +++ b/config/locales/idv/fr.yml @@ -24,7 +24,6 @@ fr: bad_dob: Votre date de naissance doit être une date valide. duplicate_ssn: Un compte existe déjà avec l'information que vous avez fournie. chiffres. - hardfail: Nous sommes dans l'incapacité de vérifier votre identité pour le moment. incorrect_password: Le mot de passe que vous avez inscrit est incorrect. mail_limit_reached: Vous avez demandé trop de lettres au cours du dernier mois. pattern_mismatch: @@ -38,6 +37,36 @@ fr: de cet état. unsupported_jurisdiction_sp: Veuillez visiter %{sp_name} pour accéder à votre compte. + failure: + attempts: + one: Il ne vous reste qu' strongune tentative./strong + other: Il ne vous reste que strong%{count} tentatives./strong + button: + fail: OK + jobfail: Essayez à nouveau demain + timeout: Essayez à nouveau + warning: Essayez à nouveau + errors: + link: contactez-nous + text: Si vous continuez à recevoir ces erreurs, %{link} ou réessayez demain. + phone: + fail: Pour votre sécurité, la vérification d'identité de votre compte est + verrouillée pendant 24 heures. + heading: Nous ne trouvons pas de données qui correspondent à vos informations + téléphoniques. + jobfail: NOT TRANSLATED YET + timeout: NOT TRANSLATED YET + warning: Veuillez vérifier l'information que vous avez fournie. + sessions: + fail: Pour votre sécurité, la vérification d'identité de votre compte est + verrouillée pendant 24 heures. + heading: Nous ne trouvons pas de données qui correspondent à vos informations + téléphoniques. + jobfail: NOT TRANSLATED YET + timeout: NOT TRANSLATED YET + warning: Veuillez vérifier l'information que vous avez fournie. Un numéro + de sécurité sociale, un code ZIP ou une date de naissance mal écrits sont + des erreurs communes. form: activate_by_mail: obtenir un code par courrier à la place › address1: Adresse @@ -81,7 +110,6 @@ fr: originalement. dupe_ssn2_link: déconnectez-vous puis connectez-vous à nouveau hardfail: NOT TRANSLATED YET - hardfail4_html: NOT TRANSLATED YET help_center_html: Visitez notre Centre d'aide pour en apprendre davantage sur la façon dont nous vérifions votre compte. jurisdiction: @@ -114,6 +142,9 @@ fr: - pas un téléphone virtuel (comme Google Voice ou Skype) - pas un numéro de téléphone prépayé - un numéro américain + read_about_security_and_privacy: + link: lire comment login.gov protège vos informations + text: Vous pouvez %{link} sur notre page d'aide. return_to_profile: NOT TRANSLATED YET return_to_sp_html: NOT TRANSLATED YET review: @@ -143,33 +174,6 @@ fr: success: Elle devrait arriver dans 5 à 10 jours ouvrables. agencies_login: NOT TRANSLATED YET agency_login_html: NOT TRANSLATED YET - modal: - attempts: - one: Il ne vous reste qu' strongune tentative./strong - other: Il ne vous reste que strong%{count} tentatives./strong - button: - fail: OK - jobfail: Essayez à nouveau demain - warning: Essayez à nouveau - phone: - fail: Votre compte est strongverrouillé pour 24 heures/strong au cours desquelles - vous ne pourrez pas y accéder. Consultez notre Centre d'aide pour plus d'information - sur la vérification de votre identité. - heading: Nous ne trouvons pas de données qui correspondent à vos informations - téléphoniques. - jobfail: NOT TRANSLATED YET - timeout: NOT TRANSLATED YET - warning: Veuillez vérifier l'information que vous avez fournie. - sessions: - fail: Votre compte est strongverrouillé pour 24 heures/strong au cours desquelles - vous ne pourrez pas y accéder. - heading: Nous ne trouvons pas de données qui correspondent à vos informations - téléphoniques. - jobfail: NOT TRANSLATED YET - timeout: NOT TRANSLATED YET - warning: Veuillez vérifier l'information que vous avez fournie. Un numéro - de sécurité sociale, un code ZIP ou une date de naissance mal écrits sont - des erreurs communes. review: dob: Date de naissance full_name: Nom complet diff --git a/config/routes.rb b/config/routes.rb index c01270118fa..9935a232575 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -187,17 +187,18 @@ get '/phone' => 'phone#new' put '/phone' => 'phone#create' get '/phone/result' => 'phone#show' + get '/phone/failure/:reason' => 'phone#failure', as: :phone_failure get '/review' => 'review#new' put '/review' => 'review#create' get '/session' => 'sessions#new' put '/session' => 'sessions#create' get '/session/result' => 'sessions#show' get '/session/success' => 'sessions#success' + get '/session/failure/:reason' => 'sessions#failure', as: :session_failure delete '/session' => 'sessions#destroy' - get '/session/dupe' => 'sessions#dupe' get '/jurisdiction' => 'jurisdiction#new' post '/jurisdiction' => 'jurisdiction#create' - get '/jurisdiction/:reason' => 'jurisdiction#show', as: :jurisdiction_fail + get '/jurisdiction/failure/:reason' => 'jurisdiction#failure', as: :jurisdiction_failure end end diff --git a/lib/proofer_mocks/resolution_mock.rb b/lib/proofer_mocks/resolution_mock.rb index 4fc373e39f0..60ad3bf31b0 100644 --- a/lib/proofer_mocks/resolution_mock.rb +++ b/lib/proofer_mocks/resolution_mock.rb @@ -11,6 +11,9 @@ class ResolutionMock < Proofer::Base if first_name.match?(/Bad/i) result.add_error(:first_name, 'Unverified first name.') + elsif first_name.match?(/Time/i) + sleep((Figaro.env.async_job_refresh_max_wait_seconds.to_i + 5).seconds) + elsif applicant[:ssn].match?(/6666/) result.add_error(:ssn, 'Unverified SSN.') diff --git a/saml_20180619025351.txt b/saml_20180619025351.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/saml_20180620023548.txt b/saml_20180620023548.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/spec/controllers/concerns/idv_step_concern_spec.rb b/spec/controllers/concerns/idv_step_concern_spec.rb index 3d997dd2443..61d589fa6d9 100644 --- a/spec/controllers/concerns/idv_step_concern_spec.rb +++ b/spec/controllers/concerns/idv_step_concern_spec.rb @@ -19,6 +19,10 @@ class StepController < ApplicationController def show render plain: 'Hello' end + + def failure_url(__) + 'foobar' + end end before(:each) do @@ -33,12 +37,11 @@ def show user.idv_attempts = 3 user.idv_attempted_at = Time.zone.now allow(subject).to receive(:confirm_idv_session_started).and_return(true) + get :show end it 'redirects to hardfail page' do - get :show - - expect(response).to redirect_to idv_fail_url + expect(response).to redirect_to 'foobar' end end @@ -47,12 +50,11 @@ def show allow(subject).to receive(:confirm_idv_session_started).and_return(true) user.idv_attempts = 3 user.idv_attempted_at = Time.zone.now + get :show end it 'redirects to hardfail page' do - get :show - - expect(response).to redirect_to idv_fail_url + expect(response).to redirect_to 'foobar' end end diff --git a/spec/controllers/idv/jurisdiction_controller_spec.rb b/spec/controllers/idv/jurisdiction_controller_spec.rb index 84f1406eecd..4d0a515dd67 100644 --- a/spec/controllers/idv/jurisdiction_controller_spec.rb +++ b/spec/controllers/idv/jurisdiction_controller_spec.rb @@ -56,7 +56,7 @@ it 'redirects to the unsupported jurisdiction fail page' do post :create, params: { jurisdiction: { state: unsupported_jurisdiction } } - expect(response).to redirect_to(idv_jurisdiction_fail_url(:unsupported_jurisdiction)) + expect(response).to redirect_to(idv_jurisdiction_failure_url(:unsupported_jurisdiction)) end end @@ -69,7 +69,7 @@ end end - describe '#show' do + describe '#failure' do let(:reason) { 'unsupported_jurisdiction' } before do @@ -77,7 +77,7 @@ end it 'renders the `_failure` template' do - get :show, params: { reason: reason } + get :failure, params: { reason: reason } expect(response).to render_template('shared/_failure') end diff --git a/spec/controllers/idv/phone_controller_spec.rb b/spec/controllers/idv/phone_controller_spec.rb index 3b446905f8b..0484ad4fd50 100644 --- a/spec/controllers/idv/phone_controller_spec.rb +++ b/spec/controllers/idv/phone_controller_spec.rb @@ -57,7 +57,7 @@ get :new - expect(response).to redirect_to idv_fail_path + expect(response).to redirect_to idv_phone_failure_url(:fail) end end @@ -185,8 +185,7 @@ it 'displays an error' do get :show - expect(response).to render_template :new - expect(flash[:warning]).to include(t('idv.modal.phone.timeout')) + expect(response).to redirect_to idv_phone_failure_path(:timeout) end it 'tracks the failure as a timeout' do @@ -242,8 +241,7 @@ vendor: { messages: [], context: {}, exception: nil }, } - expect(flash[:warning]).to match t('idv.modal.phone.heading') - expect(flash[:warning]).to match t('idv.modal.attempts', count: max_attempts - 1) + expect(response).to redirect_to idv_phone_failure_path(:warning) expect(@analytics).to have_received(:track_event).with( Analytics::IDV_PHONE_CONFIRMATION_VENDOR, result ) diff --git a/spec/controllers/idv/sessions_controller_spec.rb b/spec/controllers/idv/sessions_controller_spec.rb index def52dc7132..638d8c72993 100644 --- a/spec/controllers/idv/sessions_controller_spec.rb +++ b/spec/controllers/idv/sessions_controller_spec.rb @@ -73,7 +73,7 @@ expect(@analytics).to have_received(:track_event). with(Analytics::IDV_MAX_ATTEMPTS_EXCEEDED, result) - expect(response).to redirect_to idv_fail_url + expect(response).to redirect_to idv_session_failure_url(:fail) end end end @@ -106,8 +106,7 @@ post :create, params: { profile: user_attrs.merge(ssn: '666-66-1234') } - expect(response).to redirect_to(idv_session_dupe_path) - expect(flash[:error]).to match t('idv.errors.duplicate_ssn') + expect(response).to redirect_to(idv_session_failure_url(:dupe_ssn)) end end @@ -115,7 +114,7 @@ it 'renders the form' do post :create, params: { profile: user_attrs.merge(ssn: '') } - expect(response).to_not redirect_to(idv_session_dupe_path) + expect(response).to_not redirect_to(idv_session_failure_url(:dupe_ssn)) expect(response).to render_template(:new) end end @@ -171,8 +170,7 @@ it 'displays an error' do get :show - expect(response).to render_template :new - expect(flash[:warning]).to include(t('idv.modal.sessions.timeout')) + expect(response).to redirect_to(idv_session_failure_url(:timeout)) end it 'tracks the failure as a timeout' do @@ -216,12 +214,10 @@ ) end - it 're-renders form' do + it 'redirects to the failure page' do get :show - expect(flash[:warning]).to match t('idv.modal.sessions.heading') - expect(flash[:warning]).to match(t('idv.modal.attempts', count: max_attempts - 1)) - expect(response).to render_template(:new) + expect(response).to redirect_to(idv_session_failure_url(:warning)) end it 'creates analytics event' do @@ -252,7 +248,7 @@ ) end - it 'logs failure and re-renders form' do + it 'logs failure and redirects to the failure page' do get :show result = { @@ -266,7 +262,7 @@ expect(@analytics).to have_received(:track_event). with(Analytics::IDV_BASIC_INFO_SUBMITTED_VENDOR, result) - expect(response).to render_template(:new) + expect(response).to redirect_to(idv_session_failure_url(:warning)) end end @@ -315,7 +311,7 @@ expect(@analytics).to have_received(:track_event). with(Analytics::IDV_MAX_ATTEMPTS_EXCEEDED, result) - expect(response).to redirect_to idv_fail_url + expect(response).to redirect_to idv_session_failure_url(:fail) end end @@ -347,5 +343,25 @@ expect(response).to redirect_to(account_path) end end + + describe '#failure' do + context 'reason == :dupe_ssn' do + it 'renders the dupe_ssn failure screen' do + get :failure, params: { reason: :dupe_ssn } + + expect(response).to render_template('shared/_failure') + end + end + + context 'reason != :dupe_ssn' do + let(:reason) { :fail } + + it 'calls `render_step_failure` with step_name of :sessions and the reason' do + expect(controller).to receive(:render_idv_step_failure).with(:sessions, reason) + + get :failure, params: { reason: reason } + end + end + end end end diff --git a/spec/controllers/idv_controller_spec.rb b/spec/controllers/idv_controller_spec.rb index f75bdb6f602..42b31bdcada 100644 --- a/spec/controllers/idv_controller_spec.rb +++ b/spec/controllers/idv_controller_spec.rb @@ -142,7 +142,7 @@ get :fail - expect(response).to render_template(:fail) + expect(response).to render_template('shared/_failure') end end end diff --git a/spec/decorators/service_provider_session_decorator_spec.rb b/spec/decorators/service_provider_session_decorator_spec.rb index 47f943b48d8..6336bd8da51 100644 --- a/spec/decorators/service_provider_session_decorator_spec.rb +++ b/spec/decorators/service_provider_session_decorator_spec.rb @@ -49,12 +49,6 @@ end end - describe '#idv_hardfail4_partial' do - it 'returns the correct partial' do - expect(subject.idv_hardfail4_partial).to eq 'idv/hardfail4' - end - end - describe '#sp_name' do it 'returns the SP friendly name if present' do expect(subject.sp_name).to eq sp.friendly_name diff --git a/spec/decorators/session_decorator_spec.rb b/spec/decorators/session_decorator_spec.rb index 34d145ca63f..b867a2e6f1d 100644 --- a/spec/decorators/session_decorator_spec.rb +++ b/spec/decorators/session_decorator_spec.rb @@ -43,12 +43,6 @@ end end - describe '#idv_hardfail4_partial' do - it 'returns the correct partial' do - expect(subject.idv_hardfail4_partial).to eq 'idv/no_sp_hardfail' - end - end - describe '#sp_logo' do it 'returns nil' do expect(subject.sp_logo).to be_nil diff --git a/spec/features/idv/state_id_data_spec.rb b/spec/features/idv/state_id_data_spec.rb index ee8eba2d6f5..b7b973727d6 100644 --- a/spec/features/idv/state_id_data_spec.rb +++ b/spec/features/idv/state_id_data_spec.rb @@ -3,6 +3,8 @@ feature 'idv state id data entry', :idv_job do include IdvStepHelper + let(:locale) { LinkLocaleResolver.locale } + before do start_idv_from_sp complete_idv_steps_before_profile_step @@ -13,8 +15,8 @@ fill_in :profile_state_id_number, with: '000000000' click_idv_continue - expect(page).to have_content t('idv.modal.sessions.warning') - expect(current_path).to eq(idv_session_result_path) + expect(page).to have_content t('idv.failure.sessions.warning') + expect(current_path).to eq(idv_session_failure_path(:warning, locale: locale)) end it 'renders an error for blank state id number and does not submit a job', :email do diff --git a/spec/features/idv/steps/jurisdiction_step_spec.rb b/spec/features/idv/steps/jurisdiction_step_spec.rb index fae498190c5..75b51f2f9cd 100644 --- a/spec/features/idv/steps/jurisdiction_step_spec.rb +++ b/spec/features/idv/steps/jurisdiction_step_spec.rb @@ -30,7 +30,7 @@ click_idv_continue expect(page). - to have_current_path(idv_jurisdiction_fail_path(reason: :unsupported_jurisdiction)) + to have_current_path(idv_jurisdiction_failure_path(reason: :unsupported_jurisdiction)) expect(page).to have_content(t('idv.titles.unsupported_jurisdiction', state: 'Alabama')) end end @@ -39,7 +39,7 @@ it 'renders the `no_id` fail page' do click_on t('idv.messages.jurisdiction.no_id') - expect(page).to have_current_path(idv_jurisdiction_fail_path(reason: :no_id)) + expect(page).to have_current_path(idv_jurisdiction_failure_path(reason: :no_id)) expect(page).to have_content(t('idv.titles.no_id')) end end diff --git a/spec/features/idv/steps/phone_step_spec.rb b/spec/features/idv/steps/phone_step_spec.rb index 29c4cfbd80c..52c139bfcb9 100644 --- a/spec/features/idv/steps/phone_step_spec.rb +++ b/spec/features/idv/steps/phone_step_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'idv profile step', :idv_job do +feature 'idv phone step', :idv_job do include IdvStepHelper include IdvHelper diff --git a/spec/features/idv/steps/profile_step_spec.rb b/spec/features/idv/steps/profile_step_spec.rb index 847c4d977a2..4d836f16903 100644 --- a/spec/features/idv/steps/profile_step_spec.rb +++ b/spec/features/idv/steps/profile_step_spec.rb @@ -69,7 +69,7 @@ complete_idv_steps_before_profile_step fill_out_idv_form_fail(state: state) click_continue - click_button t('idv.modal.button.warning') + click_on t('idv.failure.button.warning') end it 'populates the state from the form' do diff --git a/spec/presenters/idv/attempt_failure_presenter_spec.rb b/spec/presenters/idv/attempt_failure_presenter_spec.rb new file mode 100644 index 00000000000..716d167ab6d --- /dev/null +++ b/spec/presenters/idv/attempt_failure_presenter_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +describe Idv::AttemptFailurePresenter do + let(:remaining_attempts) { 2 } + let(:step_name) { :sessions } + let(:presenter) do + described_class.new( + remaining_attempts: remaining_attempts, + step_name: step_name + ) + end + + describe 'it uses the :warning failure state' do + subject { presenter.state } + + it { is_expected.to eq(:warning) } + end + + context 'methods are overriden' do + %i[title header description].each do |method| + describe "##{method}" do + subject { presenter.send(method) } + + it { is_expected.to_not be_nil } + end + end + end +end diff --git a/spec/presenters/idv/idv_failure_presenter_spec.rb b/spec/presenters/idv/idv_failure_presenter_spec.rb new file mode 100644 index 00000000000..fad49064627 --- /dev/null +++ b/spec/presenters/idv/idv_failure_presenter_spec.rb @@ -0,0 +1,99 @@ +require 'rails_helper' + +describe Idv::IdvFailurePresenter do + let(:decorated_session) { mock_decorated_session } + let(:view_context) { mock_view_context } + let(:presenter) { described_class.new(view_context: view_context) } + + describe 'it uses the :locked failure state' do + subject { presenter.state } + + it { is_expected.to eq(:locked) } + end + + context 'methods are overriden' do + %i[message title header description].each do |method| + describe "##{method}" do + subject { presenter.send(method) } + + it { is_expected.to_not be_nil } + end + end + end + + describe '#title' do + subject { presenter.send(:title) } + + it 'includes the app name' do + expect(subject).to include('login.gov') + end + end + + describe '#header' do + subject { presenter.send(:header) } + + it 'includes the app name' do + expect(subject).to include('login.gov') + end + end + + describe '#description' do + subject { presenter.send(:description) } + + it 'includes the lockout window' do + expect(subject).to include(Figaro.env.idv_attempt_window_in_hours) + end + end + + describe '#next_steps' do + subject { presenter.next_steps } + + it 'includes `help_step`, `sp_step`, and `profile_step`' do + expect(subject).to eq( + [ + presenter.send(:help_step), + presenter.send(:sp_step), + presenter.send(:profile_step), + ] + ) + end + end + + describe '#help_step' do + subject { presenter.send(:help_step) } + + it 'includes help url' do + expect(subject).to include(MarketingSite.help_url) + end + end + + describe '#sp_step' do + subject { presenter.send(:sp_step) } + + it 'includes sp url' do + expect(subject).to include(decorated_session.sp_return_url) + end + end + + describe '#profile_step' do + subject { presenter.send(:profile_step) } + + it 'includes profile url' do + expect(subject).to include(view_context.account_path) + end + end + + def mock_view_context + view_context = ActionView::Base.new + allow(view_context).to receive(:account_path).and_return('Account Path') + allow(view_context).to receive(:decorated_session).and_return(mock_decorated_session) + view_context + end + + def mock_decorated_session + decorated_session = instance_double(SessionDecorator) + allow(decorated_session).to receive(:sp_name).and_return('Test SP') + allow(decorated_session).to receive(:sp_return_url).and_return('SP Link') + decorated_session + end +end diff --git a/spec/presenters/idv/ssn_failure_presenter_spec.rb b/spec/presenters/idv/ssn_failure_presenter_spec.rb new file mode 100644 index 00000000000..476a10cf170 --- /dev/null +++ b/spec/presenters/idv/ssn_failure_presenter_spec.rb @@ -0,0 +1,68 @@ +require 'rails_helper' + +describe Idv::SsnFailurePresenter do + let(:view_context) { mock_view_context } + let(:presenter) { described_class.new(view_context: view_context) } + + describe 'it uses the :failure failure state' do + subject { presenter.state } + + it { is_expected.to eq(:failure) } + end + + context 'methods are overriden' do + %i[title header description message].each do |method| + describe "##{method}" do + subject { presenter.send(method) } + + it { is_expected.to_not be_nil } + end + end + end + + describe '#next_steps' do + subject { presenter.next_steps } + + it 'includes `try_again_step`, `sign_out_step`, and `profile_step`' do + expect(subject).to eq( + [ + presenter.send(:try_again_step), + presenter.send(:sign_out_step), + presenter.send(:profile_step), + ] + ) + end + end + + describe '#try_again_step' do + subject { presenter.send(:try_again_step) } + + it 'includes session path' do + expect(subject).to include(view_context.idv_session_path) + end + end + + describe '#sign_out_step' do + subject { presenter.send(:sign_out_step) } + + it 'includes sign_out url' do + expect(subject).to include(view_context.destroy_user_session_path) + end + end + + describe '#profile_step' do + subject { presenter.send(:profile_step) } + + it 'includes profile url' do + expect(subject).to include(view_context.account_path) + end + end + + def mock_view_context + view_context = ActionView::Base.new + allow(view_context).to receive(:account_path).and_return('account path') + allow(view_context).to receive(:destroy_user_session_path).and_return('sign out path') + allow(view_context).to receive(:idv_session_path).and_return('idv session path') + view_context + end +end diff --git a/spec/presenters/idv/warning_presenter_spec.rb b/spec/presenters/idv/warning_presenter_spec.rb new file mode 100644 index 00000000000..3b5959dd02d --- /dev/null +++ b/spec/presenters/idv/warning_presenter_spec.rb @@ -0,0 +1,91 @@ +require 'rails_helper' + +describe Idv::WarningPresenter do + let(:reason) { :warning } + let(:remaining_attempts) { 2 } + let(:step_name) { :sessions } + let(:view_context) { mock_view_context } + let(:presenter) do + described_class.new( + reason: reason, + remaining_attempts: remaining_attempts, + step_name: step_name, + view_context: view_context + ) + end + + describe 'it uses the :warning failure state' do + subject { presenter.state } + + it { is_expected.to eq(:warning) } + end + + context 'methods are overriden' do + %i[title header description].each do |method| + describe "##{method}" do + subject { presenter.send(method) } + + it { is_expected.to_not be_nil } + end + end + end + + describe '#warning_message' do + context 'when `reason == :warning`' do + let(:reason) { :warning } + + subject { presenter.warning_message } + + it { is_expected.to eq(presenter.send(:warning)) } + end + + context 'when `reason != :warning`' do + let(:reason) { :fail } + + subject { presenter.warning_message } + + it { is_expected.to eq(presenter.send(:error)) } + end + end + + describe '#button_path' do + context 'when `step_name == :sessions`' do + let(:step_name) { :sessions } + + subject { presenter.button_path } + + it { is_expected.to eq(view_context.idv_session_path) } + end + + context 'when `step_name != :sessions`' do + let(:step_name) { :phone } + + subject { presenter.button_path } + + it { is_expected.to eq(view_context.idv_phone_path) } + end + end + + describe '#warning' do + subject { presenter.send(:warning) } + + it 'includes the number of remaining attempts' do + expect(subject).to include(remaining_attempts.to_s) + end + end + + describe '#error' do + subject { presenter.send(:error) } + + it 'includes the contact url' do + expect(subject).to include(MarketingSite.contact_url) + end + end + + def mock_view_context + view_context = ActionView::Base.new + allow(view_context).to receive(:idv_phone_path).and_return('idv phone path') + allow(view_context).to receive(:idv_session_path).and_return('idv session path') + view_context + end +end diff --git a/spec/support/idv_examples/fail_to_verify.rb b/spec/support/idv_examples/fail_to_verify.rb index d12e7f6f31e..2754787430e 100644 --- a/spec/support/idv_examples/fail_to_verify.rb +++ b/spec/support/idv_examples/fail_to_verify.rb @@ -1,4 +1,5 @@ shared_examples 'fail to verify idv info' do |step| + let(:locale) { LinkLocaleResolver.locale } let(:step_locale_key) do return :sessions if step == :profile step @@ -12,61 +13,32 @@ click_continue end - context 'without js' do - it 'renders a flash message and lets the user try again' do - expect_page_to_have_warning_message - expect(page).to have_current_path(idv_session_result_path) if step == :profile - expect(page).to have_current_path(idv_phone_result_path) if step == :phone + it 'renders a warning failure screen and lets the user try again' do + expect(page).to have_current_path(session_failure_path) if step == :profile + expect(page).to have_current_path(phone_failure_path) if step == :phone + expect(page).to have_content t("idv.failure.#{step_locale_key}.heading") + expect(page).to have_content t("idv.failure.#{step_locale_key}.warning") - if step == :profile - fill_out_idv_form_ok - click_idv_continue - end - fill_out_phone_form_ok if step == :phone - click_idv_continue - - expect(page).to have_content(t('idv.titles.session.phone')) if step == :profile - expect(page).to have_current_path(idv_phone_path) if step == :profile - expect(page).to have_content(t('idv.titles.otp_delivery_method')) if step == :phone - expect(page).to have_current_path(idv_otp_delivery_method_path) if step == :phone - end - end + click_on t('idv.failure.button.warning') - context 'with js', :js do - it 'renders a modal and lets the user try again' do - expect_page_to_have_warning_modal - expect(page).to have_current_path(idv_session_result_path) if step == :profile - expect(page).to have_current_path(idv_phone_result_path) if step == :phone - - dismiss_warning_modal - if step == :profile - fill_out_idv_form_ok - click_idv_continue - end - fill_out_phone_form_ok if step == :phone + if step == :profile + fill_out_idv_form_ok click_idv_continue - - expect(page).to have_content(t('idv.titles.session.phone')) if step == :profile - expect(page).to have_current_path(idv_phone_path) if step == :profile - expect(page).to have_content(t('idv.titles.otp_delivery_method')) if step == :phone - expect(page).to have_current_path(idv_otp_delivery_method_path) if step == :phone end - end + fill_out_phone_form_ok if step == :phone + click_idv_continue - def expect_page_to_have_warning_message - expect(page).to have_content t("idv.modal.#{step_locale_key}.heading") - expect(page).to have_content t("idv.modal.#{step_locale_key}.warning") + expect(page).to have_current_path(idv_phone_path) if step == :profile + expect(page).to have_current_path(idv_otp_delivery_method_path) if step == :phone + expect(page).to have_content(t('idv.titles.session.phone')) if step == :profile + expect(page).to have_content(t('idv.titles.otp_delivery_method')) if step == :phone end - def expect_page_to_have_warning_modal - expect(page).to have_css('.modal-warning', text: t("idv.modal.#{step_locale_key}.heading")) - expect(page).to have_css( - '.modal-warning', - text: strip_tags(t("idv.modal.#{step_locale_key}.warning")) - ) + def session_failure_path + idv_session_failure_path(:warning, locale: locale) end - def dismiss_warning_modal - click_button t('idv.modal.button.warning') + def phone_failure_path + idv_phone_failure_path(:warning, locale: locale) end end diff --git a/spec/support/idv_examples/failed_idv_job.rb b/spec/support/idv_examples/failed_idv_job.rb index 8319acd2101..0e1699cec07 100644 --- a/spec/support/idv_examples/failed_idv_job.rb +++ b/spec/support/idv_examples/failed_idv_job.rb @@ -1,4 +1,5 @@ shared_examples 'failed idv job' do |step| + let(:locale) { LinkLocaleResolver.locale } let(:idv_job_class) { Idv::ProoferJob } let(:step_locale_key) do return :sessions if step == :profile @@ -20,25 +21,11 @@ click_idv_continue end - context 'without js' do - it 'shows a warning' do - expect(page).to have_content t("idv.modal.#{step_locale_key}.heading") - expect(page).to have_content t("idv.modal.#{step_locale_key}.jobfail") - expect(page).to have_current_path(idv_session_result_path) if step == :profile - expect(page).to have_current_path(idv_phone_result_path) if step == :phone - end - end - - context 'with js', :js do - it 'shows a modal' do - expect(page).to have_css('.modal-warning', text: t("idv.modal.#{step_locale_key}.heading")) - expect(page).to have_css( - '.modal-warning', - text: strip_tags(t("idv.modal.#{step_locale_key}.jobfail")) - ) - expect(page).to have_current_path(idv_session_result_path) if step == :profile - expect(page).to have_current_path(idv_phone_result_path) if step == :phone - end + it 'renders a jobfail failure screen' do + expect(page).to have_current_path(session_failure_path(:jobfail)) if step == :profile + expect(page).to have_current_path(phone_failure_path(:jobfail)) if step == :phone + expect(page).to have_content t("idv.failure.#{step_locale_key}.heading") + expect(page).to have_content t("idv.failure.#{step_locale_key}.jobfail") end end @@ -60,29 +47,18 @@ Timecop.return end - context 'without js' do - it 'shows a warning' do - expect(page).to have_content t("idv.modal.#{step_locale_key}.heading") - expect(page).to have_content t("idv.modal.#{step_locale_key}.timeout") - expect(page).to have_current_path(idv_session_result_path) if step == :profile - expect(page).to have_current_path(idv_phone_result_path) if step == :phone - end - end - - context 'with js' do - it 'shows a modal' do - expect(page).to have_css('.modal-warning', text: t("idv.modal.#{step_locale_key}.heading")) - expect(page).to have_css( - '.modal-warning', - text: strip_tags(t("idv.modal.#{step_locale_key}.timeout")) - ) - expect(page).to have_current_path(idv_session_result_path) if step == :profile - expect(page).to have_current_path(idv_phone_result_path) if step == :phone - end + it 'renders a timeout failure page' do + expect(page).to have_current_path(session_failure_path(:timeout)) if step == :profile + expect(page).to have_current_path(phone_failure_path(:timeout)) if step == :phone + expect(page).to have_content t("idv.failure.#{step_locale_key}.heading") + expect(page).to have_content t("idv.failure.#{step_locale_key}.timeout") end end - # rubocop:disable Lint/HandleExceptions, Style/RedundantBegin + # rubocop:disable Lint/HandleExceptions + # rubocop:disable Style/RedundantBegin + # Disabling Style/RedundantBegin because when i remove make the changes + # to remove it, fasterer can no longer parse the code... def stub_idv_job_to_raise_error_in_background(idv_job_class) allow(Idv::Agent).to receive(:new).and_raise('this is a test error') allow(idv_job_class).to receive(:perform_now).and_wrap_original do |perform_now, *args| @@ -93,9 +69,18 @@ def stub_idv_job_to_raise_error_in_background(idv_job_class) end end end - # rubocop:enable Lint/HandleExceptions, Style/RedundantBegin + # rubocop:enable Style/RedundantBegin + # rubocop:enable Lint/HandleExceptions def stub_idv_job_to_timeout_in_background(idv_job_class) allow(idv_job_class).to receive(:perform_now) end + + def session_failure_path(reason) + idv_session_failure_path(reason, locale: locale) + end + + def phone_failure_path(reason) + idv_phone_failure_path(reason, locale: locale) + end end diff --git a/spec/support/idv_examples/max_attempts.rb b/spec/support/idv_examples/max_attempts.rb index ffda4afb25f..25fb4bdd203 100644 --- a/spec/support/idv_examples/max_attempts.rb +++ b/spec/support/idv_examples/max_attempts.rb @@ -1,4 +1,5 @@ shared_examples 'verification step max attempts' do |step, sp| + let(:locale) { LinkLocaleResolver.locale } let(:user) { user_with_2fa } let(:step_locale_key) do return :sessions if step == :profile @@ -22,13 +23,21 @@ scenario 'more than 3 attempts in 24 hours prevents further attempts' do # Blocked if visiting verify directly visit idv_url - advance_to_phone_step if step == :phone - expect_user_to_be_unable_to_perform_idv(sp) + if step == :phone + advance_to_phone_step + expect_user_to_fail_at_phone_step + else + expect_user_to_fail_at_profile_step + end # Blocked if visiting from an SP visit_idp_from_sp_with_loa3(:oidc) - advance_to_phone_step if step == :phone - expect_user_to_be_unable_to_perform_idv(sp) + if step == :phone + advance_to_phone_step + expect_user_to_fail_at_phone_step + else + expect_user_to_fail_at_profile_step + end if step == :sessions user.reload @@ -47,7 +56,7 @@ click_link t('links.sign_in') sign_in_live_with_2fa(user) - expect(page).to_not have_content(t("idv.modal.#{step_locale_key}.heading")) + expect(page).to_not have_content(t("idv.failure.#{step_locale_key}.heading")) expect(current_url).to eq(idv_jurisdiction_url) fill_out_idv_jurisdiction_ok @@ -60,22 +69,9 @@ end end - scenario 'user sees failure flash message' do - expect(page).to have_css('.alert-error', text: t("idv.modal.#{step_locale_key}.heading")) - expect(page).to have_css( - '.alert-error', - text: strip_tags(t("idv.modal.#{step_locale_key}.fail")) - ) - end - - context 'with js', :js do - scenario 'user sees the failure modal' do - expect(page).to have_css('.modal-fail', text: t("idv.modal.#{step_locale_key}.heading")) - expect(page).to have_css( - '.modal-fail', - text: strip_tags(t("idv.modal.#{step_locale_key}.fail")) - ) - end + scenario 'user sees the failure screen' do + expect(page).to have_content(t("idv.failure.#{step_locale_key}.heading")) + expect(page).to have_content(strip_tags(t("idv.failure.#{step_locale_key}.fail"))) end end @@ -85,6 +81,7 @@ fill_out_idv_form_fail if step == :profile fill_out_phone_form_fail if step == :phone click_continue + click_on t('idv.failure.button.warning') end fill_out_idv_form_ok if step == :profile @@ -105,29 +102,22 @@ def perfom_maximum_allowed_idv_step_attempts max_attempts_less_one.times do yield click_idv_continue - click_button t('idv.modal.button.warning') if javascript_enabled? + click_on t('idv.failure.button.warning') end yield click_idv_continue end - def expect_user_to_be_unable_to_perform_idv(sp) + def expect_user_to_fail_at_profile_step expect(page).to have_content(t('idv.titles.hardfail', app: 'login.gov')) - if sp.present? - expect(page).to have_content( - t('idv.messages.hardfail', hours: Figaro.env.idv_attempt_window_in_hours) - ) - expect(page).to have_content( - strip_tags(t('idv.messages.hardfail4_html', sp: 'Test SP')) - ) - else - expect(page).to have_content( - strip_tags(t('idv.messages.help_center_html')) - ) - end expect(current_url).to eq(idv_fail_url) end + def expect_user_to_fail_at_phone_step + expect(page).to have_content(t("idv.failure.#{step_locale_key}.heading")) + expect(current_url).to eq(idv_phone_failure_url(:fail, locale: locale)) + end + def advance_to_phone_step fill_out_idv_jurisdiction_ok click_idv_continue diff --git a/spec/view_models/idv/base_spec.rb b/spec/view_models/idv/base_spec.rb deleted file mode 100644 index 9a9132ada42..00000000000 --- a/spec/view_models/idv/base_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'rails_helper' - -RSpec.describe Idv::Base do - describe '#message' do - let(:timed_out) { false } - let(:view_model) do - Idv::Base.new( - error: error, - remaining_attempts: 1, - idv_form: nil, - timed_out: timed_out - ) - end - - subject(:message) { view_model.message } - - before { expect(view_model).to receive(:step_name).and_return(:phone) } - - context 'with a warning' do - let(:error) { 'warning' } - - it 'uses the warning copy' do - expect(message).to include(t('idv.modal.phone.warning')) - end - - context 'with a timeout' do - let(:timed_out) { true } - - it 'uses the timeout copy' do - expect(message).to include(t('idv.modal.phone.timeout')) - end - end - end - end - - describe '#modal_class_name' do - let(:view_model) do - Idv::Base.new( - error: error, - remaining_attempts: 1, - idv_form: nil, - timed_out: false - ) - end - - subject(:modal_class_name) { view_model.modal_class_name } - - context 'when error is warning' do - let(:error) { 'warning' } - - it 'returns modal_warning' do - expect(modal_class_name).to eq 'modal-warning' - end - end - - context 'when error is jobfail' do - let(:error) { 'jobfail' } - - it 'returns modal_warning' do - expect(modal_class_name).to eq 'modal-warning' - end - end - - context 'when error is fail' do - let(:error) { 'fail' } - - it 'returns modal_fail' do - expect(modal_class_name).to eq 'modal-fail' - end - end - end -end diff --git a/spec/views/idv/_hardfail4.html.slim_spec.rb b/spec/views/idv/_hardfail4.html.slim_spec.rb deleted file mode 100644 index fb573ef77ab..00000000000 --- a/spec/views/idv/_hardfail4.html.slim_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'rails_helper' - -RSpec.describe 'idv/_hardfail4.html.slim' do - let(:decorated_session) do - instance_double('SessionDecorator', sp_name: 'Example SP', sp_return_url: 'test.host') - end - - before do - allow(view).to receive(:decorated_session).and_return(decorated_session) - end - - it 'links to the profile' do - render - - expect(rendered).to have_link( - t('idv.messages.return_to_profile', app: APP_NAME), - href: profile_path - ) - end -end diff --git a/spec/views/idv/_no_sp_hardfail.html.slim_spec.rb b/spec/views/idv/_no_sp_hardfail.html.slim_spec.rb deleted file mode 100644 index dea6d862f7d..00000000000 --- a/spec/views/idv/_no_sp_hardfail.html.slim_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'rails_helper' - -RSpec.describe 'idv/_no_sp_hardfail.html.slim' do - it 'links to the profile' do - render - - expect(rendered).to have_link( - t('idv.messages.return_to_profile', app: APP_NAME), - href: profile_path - ) - end -end diff --git a/spec/views/idv/fail.html.slim_spec.rb b/spec/views/idv/fail.html.slim_spec.rb deleted file mode 100644 index fcc29ef4421..00000000000 --- a/spec/views/idv/fail.html.slim_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'rails_helper' - -describe 'idv/fail.html.slim' do - let(:view_context) { ActionController::Base.new.view_context } - - context 'when SP is present' do - before do - sp = build_stubbed(:service_provider, friendly_name: 'Awesome Application!') - @decorated_session = ServiceProviderSessionDecorator.new( - sp: sp, view_context: view_context, sp_session: {}, service_provider_request: nil - ) - allow(view).to receive(:decorated_session).and_return(@decorated_session) - end - - it 'displays the hardfail4 partial' do - render - - expect(view).to render_template(partial: 'idv/_hardfail4') - expect(rendered).to have_content( - strip_tags(t('idv.messages.hardfail4_html', sp: @decorated_session.sp_name)) - ) - end - end - - context 'when SP is not present' do - before do - allow(view).to receive(:decorated_session).and_return(SessionDecorator.new) - end - - it 'displays the null partial' do - render - - expect(view).to render_template(partial: 'idv/_no_sp_hardfail') - end - end -end