diff --git a/app/controllers/concerns/idv/step_indicator_concern.rb b/app/controllers/concerns/idv/step_indicator_concern.rb new file mode 100644 index 00000000000..366f5f0be34 --- /dev/null +++ b/app/controllers/concerns/idv/step_indicator_concern.rb @@ -0,0 +1,50 @@ +module Idv + module StepIndicatorConcern + extend ActiveSupport::Concern + + include IdvSession + + included do + helper_method :step_indicator_steps + end + + def step_indicator_steps + if in_person_proofing? + if gpo_address_verification? + Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS_GPO + else + Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS + end + elsif gpo_address_verification? + Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO + else + Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS + end + end + + private + + def in_person_proofing? + proofing_components_as_hash['document_check'] == Idp::Constants::Vendors::USPS + end + + def gpo_address_verification? + # Proofing component values are (currently) never reset between proofing attempts, hence why + # this refers to the session address verification mechanism and not the proofing component. + !!current_user.pending_profile || idv_session.address_verification_mechanism == 'gpo' + end + + def proofing_components_as_hash + # A proofing component record exists as a zero-or-one-to-one relation with a user, and values + # are set during identity verification. These values are recorded to the profile at creation, + # including for a pending profile. + @proofing_components_as_hash ||= begin + if current_user.pending_profile + current_user.pending_profile.proofing_components + else + ProofingComponent.find_by(user: current_user).as_json + end + end.to_h + end + end +end diff --git a/app/controllers/idv/come_back_later_controller.rb b/app/controllers/idv/come_back_later_controller.rb index f1daaceac71..f51840f782b 100644 --- a/app/controllers/idv/come_back_later_controller.rb +++ b/app/controllers/idv/come_back_later_controller.rb @@ -1,5 +1,7 @@ module Idv class ComeBackLaterController < ApplicationController + include StepIndicatorConcern + before_action :confirm_two_factor_authenticated before_action :confirm_user_needs_gpo_confirmation diff --git a/app/controllers/idv/gpo_controller.rb b/app/controllers/idv/gpo_controller.rb index 01d07a7d06a..0e1e80bf5c5 100644 --- a/app/controllers/idv/gpo_controller.rb +++ b/app/controllers/idv/gpo_controller.rb @@ -1,6 +1,7 @@ module Idv class GpoController < ApplicationController include IdvSession + include StepIndicatorConcern before_action :confirm_two_factor_authenticated before_action :confirm_idv_needed @@ -10,6 +11,7 @@ class GpoController < ApplicationController def index @presenter = GpoPresenter.new(current_user, url_options) + @step_indicator_current_step = step_indicator_current_step analytics.idv_gpo_address_visited( letter_already_sent: @presenter.letter_already_sent?, ) @@ -35,6 +37,14 @@ def gpo_mail_service private + def step_indicator_current_step + if resend_requested? + :get_a_letter + else + :verify_phone_or_address + end + end + def update_tracking analytics.idv_gpo_address_letter_requested(resend: resend_requested?) irs_attempts_api_tracker.idv_letter_requested(success: true, resend: resend_requested?) diff --git a/app/controllers/idv/gpo_verify_controller.rb b/app/controllers/idv/gpo_verify_controller.rb index 2b0ec93fcd7..37d5bb8559a 100644 --- a/app/controllers/idv/gpo_verify_controller.rb +++ b/app/controllers/idv/gpo_verify_controller.rb @@ -1,6 +1,7 @@ module Idv class GpoVerifyController < ApplicationController include IdvSession + include StepIndicatorConcern before_action :confirm_two_factor_authenticated before_action :confirm_verification_needed diff --git a/app/controllers/idv/in_person/ready_to_verify_controller.rb b/app/controllers/idv/in_person/ready_to_verify_controller.rb index b6a60279008..f50c866c93f 100644 --- a/app/controllers/idv/in_person/ready_to_verify_controller.rb +++ b/app/controllers/idv/in_person/ready_to_verify_controller.rb @@ -2,6 +2,7 @@ module Idv module InPerson class ReadyToVerifyController < ApplicationController include RenderConditionConcern + include StepIndicatorConcern check_or_render_not_found -> { IdentityConfig.store.in_person_proofing_enabled } diff --git a/app/controllers/idv/otp_delivery_method_controller.rb b/app/controllers/idv/otp_delivery_method_controller.rb index 005b35153a2..7389ce4123d 100644 --- a/app/controllers/idv/otp_delivery_method_controller.rb +++ b/app/controllers/idv/otp_delivery_method_controller.rb @@ -1,6 +1,7 @@ module Idv class OtpDeliveryMethodController < ApplicationController include IdvSession + include StepIndicatorConcern include PhoneOtpRateLimitable include PhoneOtpSendable diff --git a/app/controllers/idv/otp_verification_controller.rb b/app/controllers/idv/otp_verification_controller.rb index 2ad46468497..f962403c68d 100644 --- a/app/controllers/idv/otp_verification_controller.rb +++ b/app/controllers/idv/otp_verification_controller.rb @@ -1,6 +1,7 @@ module Idv class OtpVerificationController < ApplicationController include IdvSession + include StepIndicatorConcern include PhoneOtpRateLimitable # confirm_two_factor_authenticated before action is in PhoneOtpRateLimitable diff --git a/app/controllers/idv/personal_key_controller.rb b/app/controllers/idv/personal_key_controller.rb index dec646a1a31..7bad9cc9a7c 100644 --- a/app/controllers/idv/personal_key_controller.rb +++ b/app/controllers/idv/personal_key_controller.rb @@ -1,6 +1,7 @@ module Idv class PersonalKeyController < ApplicationController include IdvSession + include StepIndicatorConcern include SecureHeadersConcern before_action :apply_secure_headers_override @@ -9,7 +10,6 @@ class PersonalKeyController < ApplicationController before_action :confirm_profile_has_been_created def show - @step_indicator_steps = step_indicator_steps analytics.idv_personal_key_visited add_proofing_component @@ -26,14 +26,6 @@ def update private - def step_indicator_steps - if idv_session.address_verification_mechanism == 'gpo' - Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO - else - Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS - end - end - def next_step if pending_profile? && idv_session.address_verification_mechanism == 'gpo' idv_come_back_later_url diff --git a/app/controllers/idv/phone_controller.rb b/app/controllers/idv/phone_controller.rb index 9a844613d79..dbb4645366f 100644 --- a/app/controllers/idv/phone_controller.rb +++ b/app/controllers/idv/phone_controller.rb @@ -1,6 +1,7 @@ module Idv class PhoneController < ApplicationController include IdvStepConcern + include StepIndicatorConcern attr_reader :idv_form diff --git a/app/controllers/idv/review_controller.rb b/app/controllers/idv/review_controller.rb index ebf993a529c..c2dbd69e136 100644 --- a/app/controllers/idv/review_controller.rb +++ b/app/controllers/idv/review_controller.rb @@ -3,6 +3,7 @@ class ReviewController < ApplicationController before_action :personal_key_confirmed include IdvStepConcern + include StepIndicatorConcern include PhoneConfirmation before_action :confirm_idv_steps_complete @@ -34,7 +35,6 @@ def confirm_current_password def new @applicant = idv_session.applicant - @step_indicator_steps = step_indicator_steps analytics.idv_review_info_visited gpo_mail_service = Idv::GpoMail.new(current_user) @@ -64,14 +64,6 @@ def redirect_to_idv_app_if_enabled redirect_to idv_app_path end - def step_indicator_steps - if idv_session.address_verification_mechanism == 'gpo' - Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO - else - Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS - end - end - def flash_message_content if idv_session.address_verification_mechanism != 'gpo' phone_of_record_msg = ActionController::Base.helpers.content_tag( diff --git a/app/services/idv/flows/in_person_flow.rb b/app/services/idv/flows/in_person_flow.rb index 50ee75e7a3c..e5e33831da0 100644 --- a/app/services/idv/flows/in_person_flow.rb +++ b/app/services/idv/flows/in_person_flow.rb @@ -24,10 +24,6 @@ class InPersonFlow < Flow::BaseFlow redo_ssn: Idv::Actions::RedoSsnAction, }.freeze - # WILLFIX: (LG-6308) move this to the barcode page when - # we finish setting up IPP step indicators - # i18n-tasks-use t('step_indicator.flows.idv.go_to_the_post_office') - STEP_INDICATOR_STEPS = [ { name: :find_a_post_office }, { name: :verify_info }, @@ -36,6 +32,14 @@ class InPersonFlow < Flow::BaseFlow { name: :go_to_the_post_office }, ].freeze + STEP_INDICATOR_STEPS_GPO = [ + { name: :find_a_post_office }, + { name: :verify_info }, + { name: :secure_account }, + { name: :get_a_letter }, + { name: :go_to_the_post_office }, + ].freeze + def initialize(controller, session, name) @idv_session = self.class.session_idv(session) super(controller, STEPS, ACTIONS, session[name]) diff --git a/app/views/idv/come_back_later/show.html.erb b/app/views/idv/come_back_later/show.html.erb index a4b42efbb81..d30ac255012 100644 --- a/app/views/idv/come_back_later/show.html.erb +++ b/app/views/idv/come_back_later/show.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO, + steps: step_indicator_steps, current_step: :get_a_letter, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/gpo/index.html.erb b/app/views/idv/gpo/index.html.erb index 38a077dcdfb..40adc2b4189 100644 --- a/app/views/idv/gpo/index.html.erb +++ b/app/views/idv/gpo/index.html.erb @@ -2,8 +2,8 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS, - current_step: :verify_phone_or_address, + steps: step_indicator_steps, + current_step: @step_indicator_current_step, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', } %> diff --git a/app/views/idv/gpo_verify/index.html.erb b/app/views/idv/gpo_verify/index.html.erb index b21afa9d9f9..3a0db712445 100644 --- a/app/views/idv/gpo_verify/index.html.erb +++ b/app/views/idv/gpo_verify/index.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO, + steps: step_indicator_steps, current_step: :get_a_letter, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/in_person/ready_to_verify/show.html.erb b/app/views/idv/in_person/ready_to_verify/show.html.erb index 71ff6114e88..594d16d84b2 100644 --- a/app/views/idv/in_person/ready_to_verify/show.html.erb +++ b/app/views/idv/in_person/ready_to_verify/show.html.erb @@ -2,7 +2,7 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS, + steps: step_indicator_steps, current_step: :go_to_the_post_office, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/otp_delivery_method/new.html.erb b/app/views/idv/otp_delivery_method/new.html.erb index 681fde0512d..3b7b3fc5356 100644 --- a/app/views/idv/otp_delivery_method/new.html.erb +++ b/app/views/idv/otp_delivery_method/new.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS, + steps: step_indicator_steps, current_step: :verify_phone_or_address, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/otp_verification/show.html.erb b/app/views/idv/otp_verification/show.html.erb index 498f4e670f7..2fb2fdc57bc 100644 --- a/app/views/idv/otp_verification/show.html.erb +++ b/app/views/idv/otp_verification/show.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS, + steps: step_indicator_steps, current_step: :verify_phone_or_address, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/personal_key/show.html.erb b/app/views/idv/personal_key/show.html.erb index 3cf94aa1791..afb3c740477 100644 --- a/app/views/idv/personal_key/show.html.erb +++ b/app/views/idv/personal_key/show.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: @step_indicator_steps, + steps: step_indicator_steps, current_step: :secure_account, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/phone/new.html.erb b/app/views/idv/phone/new.html.erb index dfc825161b1..b5f074b1a7b 100644 --- a/app/views/idv/phone/new.html.erb +++ b/app/views/idv/phone/new.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS, + steps: step_indicator_steps, current_step: :verify_phone_or_address, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/review/new.html.erb b/app/views/idv/review/new.html.erb index 26266a254ef..4acc313a176 100644 --- a/app/views/idv/review/new.html.erb +++ b/app/views/idv/review/new.html.erb @@ -2,7 +2,7 @@ <% content_for(:pre_flash_content) do %> <%= render 'shared/step_indicator', { - steps: @step_indicator_steps, + steps: step_indicator_steps, current_step: :secure_account, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/shared/_step_indicator.html.erb b/app/views/shared/_step_indicator.html.erb index 57257457882..bfb925bffaf 100644 --- a/app/views/shared/_step_indicator.html.erb +++ b/app/views/shared/_step_indicator.html.erb @@ -27,7 +27,7 @@ locals: status: step[:status] || if current_step == step[:name] :current - elsif current_step_index > index + elsif current_step_index.to_i > index :complete end, ) { step[:title] } %> diff --git a/spec/controllers/concerns/idv/step_indicator_concern_spec.rb b/spec/controllers/concerns/idv/step_indicator_concern_spec.rb new file mode 100644 index 00000000000..cdfb9f763b9 --- /dev/null +++ b/spec/controllers/concerns/idv/step_indicator_concern_spec.rb @@ -0,0 +1,82 @@ +require 'rails_helper' + +RSpec.describe Idv::StepIndicatorConcern, type: :controller do + controller ApplicationController do + include Idv::StepIndicatorConcern + end + + let(:profile) { nil } + let(:user) { create(:user, profiles: [profile].compact) } + + before { stub_sign_in(user) } + + describe '#step_indicator_steps' do + subject(:steps) { controller.step_indicator_steps } + + it 'returns doc auth steps' do + expect(steps).to eq Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS + end + + context 'with pending profile' do + let(:profile) { create(:profile, deactivation_reason: :gpo_verification_pending) } + + it 'returns doc auth gpo steps' do + expect(steps).to eq Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO + end + end + + context 'with gpo address verification method' do + before do + idv_session = instance_double(Idv::Session) + allow(idv_session).to receive(:method_missing). + with(:address_verification_mechanism). + and_return('gpo') + allow(controller).to receive(:idv_session).and_return(idv_session) + end + + it 'returns doc auth gpo steps' do + expect(steps).to eq Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO + end + end + + context 'with in person proofing component' do + context 'with proofing component via pending profile' do + let(:profile) do + create( + :profile, + deactivation_reason: :gpo_verification_pending, + proofing_components: { 'document_check' => Idp::Constants::Vendors::USPS }, + ) + end + + it 'returns in person gpo steps' do + expect(steps).to eq Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS_GPO + end + end + + context 'with proofing component via current idv session' do + before do + ProofingComponent.create(user: user, document_check: Idp::Constants::Vendors::USPS) + end + + it 'returns in person steps' do + expect(steps).to eq Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS + end + + context 'with gpo address verification method' do + before do + idv_session = instance_double(Idv::Session) + allow(idv_session).to receive(:method_missing). + with(:address_verification_mechanism). + and_return('gpo') + allow(controller).to receive(:idv_session).and_return(idv_session) + end + + it 'returns in person gpo steps' do + expect(steps).to eq Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS_GPO + end + end + end + end + end +end diff --git a/spec/controllers/idv/gpo_controller_spec.rb b/spec/controllers/idv/gpo_controller_spec.rb index c3771ccf1f7..534f09977b2 100644 --- a/spec/controllers/idv/gpo_controller_spec.rb +++ b/spec/controllers/idv/gpo_controller_spec.rb @@ -52,6 +52,12 @@ expect(response).to be_ok end + it 'assigns the current step indicator step as "verify phone or address"' do + get :index + + expect(assigns(:step_indicator_current_step)).to eq(:verify_phone_or_address) + end + context 'with letter already sent' do before do allow_any_instance_of(Idv::GpoPresenter).to receive(:letter_already_sent?).and_return(true) @@ -66,6 +72,18 @@ ) end end + + context 'resending a letter' do + before do + allow(controller).to receive(:resend_requested?).and_return(true) + end + + it 'assigns the current step indicator step as "get a letter"' do + get :index + + expect(assigns(:step_indicator_current_step)).to eq(:get_a_letter) + end + end end describe '#create' do diff --git a/spec/controllers/idv/personal_key_controller_spec.rb b/spec/controllers/idv/personal_key_controller_spec.rb index 161f2e11631..36aee6d1eae 100644 --- a/spec/controllers/idv/personal_key_controller_spec.rb +++ b/spec/controllers/idv/personal_key_controller_spec.rb @@ -113,21 +113,6 @@ def index get :show expect(flash[:success]).to eq t('idv.messages.confirm') end - - context 'user selected gpo verification' do - before do - subject.idv_session.address_verification_mechanism = 'gpo' - end - - it 'assigns step indicator steps with gpo letter step' do - get :show - - steps = assigns(:step_indicator_steps) - - expect(flash.now[:success]).to eq t('idv.messages.mail_sent') - expect(steps).to eq(Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO) - end - end end describe '#update' do diff --git a/spec/controllers/idv/review_controller_spec.rb b/spec/controllers/idv/review_controller_spec.rb index ec076861515..da12784db4a 100644 --- a/spec/controllers/idv/review_controller_spec.rb +++ b/spec/controllers/idv/review_controller_spec.rb @@ -209,14 +209,6 @@ def show ) end - it 'shows steps' do - get :new - - steps = subject.view_assigns['step_indicator_steps'] - - expect(steps).to eq(Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS) - end - context 'idv app password confirm step is enabled' do before do allow(IdentityConfig.store).to receive(:idv_api_enabled_steps). @@ -231,20 +223,6 @@ def show end end - context 'user chooses address verification' do - before do - idv_session.address_verification_mechanism = 'gpo' - end - - it 'shows gpo steps' do - get :new - - steps = subject.view_assigns['step_indicator_steps'] - - expect(steps).to eq(Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO) - end - end - context 'user has not requested too much mail' do before do idv_session.address_verification_mechanism = 'gpo' diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index 003be1fe652..9147e177d0c 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -27,18 +27,22 @@ complete_prepare_step(user) # state ID page + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) expect(page).to have_content(t('in_person_proofing.headings.state_id')) complete_state_id_step(user) # address page + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) expect(page).to have_content(t('in_person_proofing.headings.address')) complete_address_step(user) # ssn page + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) expect(page).to have_content(t('doc_auth.headings.ssn')) complete_ssn_step(user) # verify page + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) expect(page).to have_content(t('headings.verify')) expect(page).to have_text(InPersonHelper::GOOD_FIRST_NAME) expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) @@ -71,14 +75,29 @@ complete_verify_step(user) # phone page + expect_in_person_step_indicator_current_step( + t('step_indicator.flows.idv.verify_phone_or_address'), + ) expect(page).to have_content(t('idv.titles.session.phone')) - complete_phone_step(user) + fill_out_phone_form_ok(MfaContext.new(user).phone_configurations.first.phone) + click_idv_continue + expect_in_person_step_indicator_current_step( + t('step_indicator.flows.idv.verify_phone_or_address'), + ) + choose_idv_otp_delivery_method_sms + expect_in_person_step_indicator_current_step( + t('step_indicator.flows.idv.verify_phone_or_address'), + ) + fill_in_code_with_last_phone_otp + click_submit_default # password confirm page + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.secure_account')) expect(page).to have_content(t('idv.titles.session.review', app_name: APP_NAME)) complete_review_step(user) # personal key page + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.secure_account')) expect(page).to have_content(t('titles.idv.personal_key')) deadline = nil freeze_time do @@ -89,6 +108,9 @@ end # ready to verify page + expect_in_person_step_indicator_current_step( + t('step_indicator.flows.idv.go_to_the_post_office'), + ) expect(page).to be_axe_clean.according_to :section508, :"best-practice", :wcag21aa enrollment_code = JSON.parse( UspsInPersonProofing::Mock::Fixtures.request_enroll_response, @@ -213,10 +235,16 @@ begin_in_person_proofing complete_all_in_person_proofing_steps click_on t('idv.troubleshooting.options.verify_by_mail') + expect_in_person_step_indicator_current_step( + t('step_indicator.flows.idv.verify_phone_or_address'), + ) click_on t('idv.buttons.mail.send') + expect_in_person_gpo_step_indicator_current_step(t('step_indicator.flows.idv.secure_account')) complete_review_step + expect_in_person_gpo_step_indicator_current_step(t('step_indicator.flows.idv.secure_account')) acknowledge_and_confirm_personal_key + expect_in_person_gpo_step_indicator_current_step(t('step_indicator.flows.idv.get_a_letter')) expect(page).to have_content(t('idv.titles.come_back_later')) expect(page).to have_current_path(idv_come_back_later_path) @@ -224,9 +252,13 @@ expect(page).to have_current_path(account_path) expect(page).not_to have_content(t('headings.account.verified_account')) click_on t('account.index.verification.reactivate_button') + expect_in_person_gpo_step_indicator_current_step(t('step_indicator.flows.idv.get_a_letter')) click_button t('forms.verify_profile.submit') expect(page).to have_current_path(idv_in_person_ready_to_verify_path) + expect_in_person_gpo_step_indicator_current_step( + t('step_indicator.flows.idv.go_to_the_post_office'), + ) expect(page).not_to have_content(t('account.index.verification.success')) end diff --git a/spec/features/idv/steps/gpo_otp_verification_step_spec.rb b/spec/features/idv/steps/gpo_otp_verification_step_spec.rb index 5d1905d32c6..50ee9ecc7f9 100644 --- a/spec/features/idv/steps/gpo_otp_verification_step_spec.rb +++ b/spec/features/idv/steps/gpo_otp_verification_step_spec.rb @@ -3,13 +3,95 @@ feature 'idv gpo otp verification step', :js do include IdvStepHelper - it_behaves_like 'gpo otp verification step' - it_behaves_like 'gpo otp verification step', :oidc - it_behaves_like 'gpo otp verification step', :saml - - context 'with GPO proofing disabled it still lets users with a letter verify' do - it_behaves_like 'gpo otp verification step' - it_behaves_like 'gpo otp verification step', :oidc - it_behaves_like 'gpo otp verification step', :saml + let(:otp) { 'ABC123' } + let(:profile) do + create( + :profile, + deactivation_reason: :gpo_verification_pending, + pii: { ssn: '123-45-6789', dob: '1970-01-01' }, + ) + end + let(:gpo_confirmation_code) do + create( + :gpo_confirmation_code, + profile: profile, + otp_fingerprint: Pii::Fingerprinter.fingerprint(otp), + ) + end + let(:user) { profile.user } + + it 'prompts for confirmation code at sign in' do + sign_in_live_with_2fa(user) + + expect(current_path).to eq idv_gpo_verify_path + expect(page).to have_content t('idv.messages.gpo.resend') + + gpo_confirmation_code + fill_in t('forms.verify_profile.name'), with: otp + click_button t('forms.verify_profile.submit') + + expect(user.events.account_verified.size).to eq 1 + expect(page).to_not have_content(t('account.index.verification.reactivate_button')) + end + + it 'renders an error for an expired GPO OTP' do + sign_in_live_with_2fa(user) + + gpo_confirmation_code.update(code_sent_at: 11.days.ago) + fill_in t('forms.verify_profile.name'), with: otp + click_button t('forms.verify_profile.submit') + + expect(current_path).to eq idv_gpo_verify_path + expect(page).to have_content t('errors.messages.gpo_otp_expired') + + user.reload + + expect(user.events.account_verified.size).to eq 0 + expect(user.active_profile).to be_nil + end + + it 'allows a user to resend a letter' do + allow(Base32::Crockford).to receive(:encode).and_return(otp) + + sign_in_live_with_2fa(user) + + expect(GpoConfirmation.count).to eq(0) + expect(GpoConfirmationCode.count).to eq(0) + + click_on t('idv.messages.gpo.resend') + + expect_step_indicator_current_step(t('step_indicator.flows.idv.get_a_letter')) + + click_on t('idv.buttons.mail.send') + + expect(GpoConfirmation.count).to eq(1) + expect(GpoConfirmationCode.count).to eq(1) + expect(current_path).to eq idv_come_back_later_path + + confirmation_code = GpoConfirmationCode.first + otp_fingerprint = Pii::Fingerprinter.fingerprint(otp) + + expect(confirmation_code.otp_fingerprint).to eq(otp_fingerprint) + expect(confirmation_code.profile).to eq(profile) + end + + context 'with gpo feature disabled' do + before do + allow(IdentityConfig.store).to receive(:enable_gpo_verification?).and_return(true) + end + + it 'allows a user to verify their account for an existing pending profile' do + sign_in_live_with_2fa(user) + + expect(current_path).to eq idv_gpo_verify_path + expect(page).to have_content t('idv.messages.gpo.resend') + + gpo_confirmation_code + fill_in t('forms.verify_profile.name'), with: otp + click_button t('forms.verify_profile.submit') + + expect(user.events.account_verified.size).to eq 1 + expect(page).to_not have_content(t('account.index.verification.reactivate_button')) + end end end diff --git a/spec/support/features/in_person_helper.rb b/spec/support/features/in_person_helper.rb index 85844fa09f6..db3cbe16420 100644 --- a/spec/support/features/in_person_helper.rb +++ b/spec/support/features/in_person_helper.rb @@ -92,4 +92,14 @@ def expect_in_person_step_indicator_current_step(text) expect_step_indicator_current_step(text) end + + def expect_in_person_gpo_step_indicator_current_step(text) + # Ensure that GPO letter step is shown in the step indicator. + expect(page).to have_css( + '.step-indicator__step', + text: t('step_indicator.flows.idv.get_a_letter'), + ) + + expect_in_person_step_indicator_current_step(text) + end end diff --git a/spec/support/idv_examples/gpo_otp_verification_step.rb b/spec/support/idv_examples/gpo_otp_verification_step.rb deleted file mode 100644 index f2a6a8f1485..00000000000 --- a/spec/support/idv_examples/gpo_otp_verification_step.rb +++ /dev/null @@ -1,96 +0,0 @@ -shared_examples 'gpo otp verification step' do |sp| - let(:otp) { 'ABC123' } - let(:profile) do - create( - :profile, - deactivation_reason: :gpo_verification_pending, - pii: { ssn: '123-45-6789', dob: '1970-01-01' }, - ) - end - let(:gpo_confirmation_code) do - create( - :gpo_confirmation_code, - profile: profile, - otp_fingerprint: Pii::Fingerprinter.fingerprint(otp), - ) - end - let(:user) { profile.user } - - it 'prompts for confirmation code at sign in' do - sign_in_from_sp(sp) - - expect(current_path).to eq idv_gpo_verify_path - expect(page).to have_content t('idv.messages.gpo.resend') - - gpo_confirmation_code - fill_in t('forms.verify_profile.name'), with: otp - click_button t('forms.verify_profile.submit') - - expect(user.events.account_verified.size).to eq 1 - expect(page).to_not have_content(t('account.index.verification.reactivate_button')) - - if %i[saml oidc].include?(sp) - expect(current_path).to eq(sign_up_completed_path) - - click_agree_and_continue - - if sp == :saml - expect(current_path).to eq(test_saml_decode_assertion_path) - elsif sp == :oidc - redirect_uri = URI(current_url) - - expect(redirect_uri.to_s).to start_with('http://localhost:7654/auth/result') - end - else - expect(current_path).to eq account_path - end - end - - it 'renders an error for an expired GPO OTP' do - sign_in_from_sp(sp) - - gpo_confirmation_code.update(code_sent_at: 11.days.ago) - fill_in t('forms.verify_profile.name'), with: otp - click_button t('forms.verify_profile.submit') - - expect(current_path).to eq idv_gpo_verify_path - expect(page).to have_content t('errors.messages.gpo_otp_expired') - - user.reload - - expect(user.events.account_verified.size).to eq 0 - expect(user.active_profile).to be_nil - end - - it 'allows a user to resend a letter' do - allow(Base32::Crockford).to receive(:encode).and_return(otp) - - sign_in_from_sp(sp) - - expect(GpoConfirmation.count).to eq(0) - expect(GpoConfirmationCode.count).to eq(0) - - click_on t('idv.messages.gpo.resend') - click_on t('idv.buttons.mail.send') - - expect(GpoConfirmation.count).to eq(1) - expect(GpoConfirmationCode.count).to eq(1) - expect(current_path).to eq idv_come_back_later_path - - confirmation_code = GpoConfirmationCode.first - otp_fingerprint = Pii::Fingerprinter.fingerprint(otp) - - expect(confirmation_code.otp_fingerprint).to eq(otp_fingerprint) - expect(confirmation_code.profile).to eq(profile) - end - - def sign_in_from_sp(sp) - visit_idp_from_sp_with_ial2(sp) - - if %i[saml oidc].include?(sp) - sign_in_via_branded_page(user) - else - sign_in_live_with_2fa(user) - end - end -end diff --git a/spec/views/idv/come_back_later/show.html.erb_spec.rb b/spec/views/idv/come_back_later/show.html.erb_spec.rb index ddbf55c2fcd..83004c5d39f 100644 --- a/spec/views/idv/come_back_later/show.html.erb_spec.rb +++ b/spec/views/idv/come_back_later/show.html.erb_spec.rb @@ -2,11 +2,13 @@ describe 'idv/come_back_later/show.html.erb' do let(:sp_name) { '🔒🌐💻' } + let(:step_indicator_steps) { Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS_GPO } before do @decorated_session = instance_double(ServiceProviderSessionDecorator) allow(@decorated_session).to receive(:sp_name).and_return(sp_name) allow(view).to receive(:decorated_session).and_return(@decorated_session) + allow(view).to receive(:step_indicator_steps).and_return(step_indicator_steps) end context 'with an SP' do diff --git a/spec/views/idv/gpo/index.html.erb_spec.rb b/spec/views/idv/gpo/index.html.erb_spec.rb index a627f5c332d..3db3acecfa7 100644 --- a/spec/views/idv/gpo/index.html.erb_spec.rb +++ b/spec/views/idv/gpo/index.html.erb_spec.rb @@ -4,6 +4,7 @@ let(:letter_already_sent) { false } let(:user_needs_address_otp_verification) { false } let(:go_back_path) { nil } + let(:step_indicator_steps) { Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS } let(:presenter) do user = build_stubbed(:user, :signed_up) Idv::GpoPresenter.new(user, {}) @@ -11,6 +12,7 @@ before do allow(view).to receive(:go_back_path).and_return(go_back_path) + allow(view).to receive(:step_indicator_steps).and_return(step_indicator_steps) allow(presenter).to receive(:letter_already_sent?).and_return(letter_already_sent) allow(presenter).to receive(:user_needs_address_otp_verification?). diff --git a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb index 6796f9afd2b..1bccbe79489 100644 --- a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb +++ b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb @@ -23,9 +23,11 @@ ) end let(:presenter) { Idv::InPerson::ReadyToVerifyPresenter.new(enrollment: enrollment) } + let(:step_indicator_steps) { Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS } before do assign(:presenter, presenter) + allow(view).to receive(:step_indicator_steps).and_return(step_indicator_steps) end context 'with enrollment where current address matches id' do diff --git a/spec/views/idv/otp_delivery_method/new.html.erb_spec.rb b/spec/views/idv/otp_delivery_method/new.html.erb_spec.rb index de831c6ec3d..97b0accbd72 100644 --- a/spec/views/idv/otp_delivery_method/new.html.erb_spec.rb +++ b/spec/views/idv/otp_delivery_method/new.html.erb_spec.rb @@ -2,11 +2,13 @@ describe 'idv/otp_delivery_method/new.html.erb' do let(:gpo_letter_available) { false } + let(:step_indicator_steps) { Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS } before do allow(view).to receive(:user_signing_up?).and_return(false) allow(view).to receive(:user_fully_authenticated?).and_return(true) allow(view).to receive(:gpo_letter_available).and_return(gpo_letter_available) + allow(view).to receive(:step_indicator_steps).and_return(step_indicator_steps) end subject(:rendered) { render template: 'idv/otp_delivery_method/new' } diff --git a/spec/views/idv/phone/new.html.erb_spec.rb b/spec/views/idv/phone/new.html.erb_spec.rb index c9043852844..eef92ef544c 100644 --- a/spec/views/idv/phone/new.html.erb_spec.rb +++ b/spec/views/idv/phone/new.html.erb_spec.rb @@ -2,11 +2,13 @@ describe 'idv/phone/new.html.erb' do let(:gpo_letter_available) { false } + let(:step_indicator_steps) { Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS } before do allow(view).to receive(:user_signing_up?).and_return(false) allow(view).to receive(:user_fully_authenticated?).and_return(true) allow(view).to receive(:gpo_letter_available).and_return(gpo_letter_available) + allow(view).to receive(:step_indicator_steps).and_return(step_indicator_steps) @idv_form = Idv::PhoneForm.new(user: build_stubbed(:user), previous_params: nil) end diff --git a/spec/views/idv/review/new.html.erb_spec.rb b/spec/views/idv/review/new.html.erb_spec.rb index 632669872a4..6aa51f33264 100644 --- a/spec/views/idv/review/new.html.erb_spec.rb +++ b/spec/views/idv/review/new.html.erb_spec.rb @@ -9,6 +9,8 @@ before do user = build_stubbed(:user, :signed_up) allow(view).to receive(:current_user).and_return(user) + allow(view).to receive(:step_indicator_steps). + and_return(Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS) @applicant = { first_name: 'Some', last_name: 'One', @@ -20,7 +22,6 @@ zipcode: '12345', phone: '+1 (213) 555-0000', } - @step_indicator_steps = Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS render end diff --git a/spec/views/shared/_step_indicator.html.erb_spec.rb b/spec/views/shared/_step_indicator.html.erb_spec.rb index 4aaa96e5414..8b92939c4b3 100644 --- a/spec/views/shared/_step_indicator.html.erb_spec.rb +++ b/spec/views/shared/_step_indicator.html.erb_spec.rb @@ -138,4 +138,12 @@ end end end + + context 'with invalid step' do + let(:current_step) { :missing } + + it 'renders without a current step' do + expect(rendered).not_to have_css('.step-indicator__step--current') + end + end end