diff --git a/app/controllers/idv/choose_id_type_controller.rb b/app/controllers/idv/choose_id_type_controller.rb index 13dba851d82..e3c6022ddad 100644 --- a/app/controllers/idv/choose_id_type_controller.rb +++ b/app/controllers/idv/choose_id_type_controller.rb @@ -12,9 +12,10 @@ class ChooseIdTypeController < ApplicationController def show analytics.idv_doc_auth_choose_id_type_visited(**analytics_arguments) render 'idv/shared/choose_id_type', - locals: { form_url: idv_choose_id_type_path, - is_hybrid: false, - auto_check_value: auto_check_value }, + locals: { + presenter: Idv::ChooseIdTypePresenter.new, + auto_check_value: auto_check_value, + }, layout: true end diff --git a/app/controllers/idv/hybrid_mobile/choose_id_type_controller.rb b/app/controllers/idv/hybrid_mobile/choose_id_type_controller.rb index a2502b151f5..87c9c8eb9e7 100644 --- a/app/controllers/idv/hybrid_mobile/choose_id_type_controller.rb +++ b/app/controllers/idv/hybrid_mobile/choose_id_type_controller.rb @@ -14,8 +14,7 @@ class ChooseIdTypeController < ApplicationController def show analytics.idv_doc_auth_choose_id_type_visited(**analytics_arguments) render 'idv/shared/choose_id_type', - locals: { form_url: idv_hybrid_mobile_choose_id_type_path, - is_hybrid: true, + locals: { presenter: Idv::HybridMobile::ChooseIdTypePresenter.new, auto_check_value: auto_check_value } end diff --git a/app/controllers/idv/in_person/choose_id_type_controller.rb b/app/controllers/idv/in_person/choose_id_type_controller.rb new file mode 100644 index 00000000000..b6e5d964ce0 --- /dev/null +++ b/app/controllers/idv/in_person/choose_id_type_controller.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +class Idv::InPerson::ChooseIdTypeController < ApplicationController + include Idv::AvailabilityConcern + include IdvStepConcern + + before_action :confirm_step_allowed + + def show + analytics.idv_in_person_proofing_choose_id_type_visited(**analytics_arguments) + render 'idv/shared/choose_id_type', + locals: { + presenter: Idv::InPerson::ChooseIdTypePresenter.new, + auto_check_value: '', + }, + layout: true + end + + def update + end + + def self.step_info + Idv::StepInfo.new( + key: :ipp_choose_id_type, + controller: self, + next_steps: [], + preconditions: ->(idv_session:, user:) { + idv_session.in_person_passports_allowed? && user.has_establishing_in_person_enrollment? + }, + undo_step: -> {}, + ) + end + + private + + def analytics_arguments + { + flow_path: idv_session.flow_path, + step: 'choose_id_type', + analytics_id: 'In Person Proofing', + }.merge(ab_test_analytics_buckets) + .merge(extra_analytics_properties) + end +end diff --git a/app/controllers/idv/in_person_controller.rb b/app/controllers/idv/in_person_controller.rb index b1091df590b..72fc95749e5 100644 --- a/app/controllers/idv/in_person_controller.rb +++ b/app/controllers/idv/in_person_controller.rb @@ -4,6 +4,7 @@ module Idv class InPersonController < ApplicationController include Idv::AvailabilityConcern include RenderConditionConcern + include IdvStepConcern check_or_render_not_found -> { InPersonConfig.enabled_for_issuer?(current_sp&.issuer) } @@ -13,11 +14,19 @@ class InPersonController < ApplicationController before_action :set_usps_form_presenter def index - redirect_to idv_in_person_state_id_url + if idv_session.in_person_passports_allowed? + redirect_to idv_in_person_choose_id_type_url + else + redirect_to idv_in_person_state_id_url + end end def update - redirect_to idv_in_person_state_id_url + if idv_session.in_person_passports_allowed? + redirect_to idv_in_person_choose_id_type_url + else + redirect_to idv_in_person_state_id_url + end end private diff --git a/app/policies/idv/flow_policy.rb b/app/policies/idv/flow_policy.rb index 8385438f1e5..06d684dc910 100644 --- a/app/policies/idv/flow_policy.rb +++ b/app/policies/idv/flow_policy.rb @@ -23,6 +23,7 @@ class FlowPolicy document_capture: Idv::DocumentCaptureController.step_info, socure_document_capture: Idv::Socure::DocumentCaptureController.step_info, socure_errors: Idv::Socure::ErrorsController.step_info, + ipp_choose_id_type: Idv::InPerson::ChooseIdTypeController.step_info, ipp_state_id: Idv::InPerson::StateIdController.step_info, ipp_address: Idv::InPerson::AddressController.step_info, ssn: Idv::SsnController.step_info, diff --git a/app/presenters/idv/choose_id_type_presenter.rb b/app/presenters/idv/choose_id_type_presenter.rb new file mode 100644 index 00000000000..54874ab0602 --- /dev/null +++ b/app/presenters/idv/choose_id_type_presenter.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class Idv::ChooseIdTypePresenter + include ActionView::Helpers::TranslationHelper + + def choose_id_type_info_text + t('doc_auth.info.choose_id_type') + end + + def current_step + :verify_id + end + + def hybrid_flow? + false + end + + def step_indicator_steps + Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS + end +end diff --git a/app/presenters/idv/hybrid_mobile/choose_id_type_presenter.rb b/app/presenters/idv/hybrid_mobile/choose_id_type_presenter.rb new file mode 100644 index 00000000000..86184e51ce1 --- /dev/null +++ b/app/presenters/idv/hybrid_mobile/choose_id_type_presenter.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class Idv::HybridMobile::ChooseIdTypePresenter < Idv::ChooseIdTypePresenter + def hybrid_flow? + true + end +end diff --git a/app/presenters/idv/in_person/choose_id_type_presenter.rb b/app/presenters/idv/in_person/choose_id_type_presenter.rb new file mode 100644 index 00000000000..8a4e62c2cb3 --- /dev/null +++ b/app/presenters/idv/in_person/choose_id_type_presenter.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class Idv::InPerson::ChooseIdTypePresenter < Idv::ChooseIdTypePresenter + def choose_id_type_info_text + t('in_person_proofing.info.choose_id_type') + end + + def current_step + :verify_info + end + + def step_indicator_steps + Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS_IPP + end +end diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 508c95fdc75..0583c56b5fc 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -3103,6 +3103,30 @@ def idv_in_person_proofing_address_visited( ) end + # @param ["hybrid","standard"] flow_path Document capture user flow + # @param [String] step Current IdV step + # @param [String] analytics_id + # @param [Boolean] opted_in_to_in_person_proofing Whether user opted into in person proofing + # @param [Boolean] skip_hybrid_handoff Whether skipped hybrid handoff A/B test is active + def idv_in_person_proofing_choose_id_type_visited( + flow_path:, + step:, + analytics_id:, + opted_in_to_in_person_proofing: nil, + skip_hybrid_handoff: nil, + **extra + ) + track_event( + :idv_in_person_proofing_choose_id_type_visited, + flow_path:, + step:, + analytics_id:, + opted_in_to_in_person_proofing:, + skip_hybrid_handoff:, + **extra, + ) + end + # A job to check USPS notifications about in-person enrollment status updates has completed # @param [Integer] fetched_items items fetched # @param [Integer] processed_items items fetched and processed diff --git a/app/services/idv/session.rb b/app/services/idv/session.rb index 176b0b6ece3..3b79b45fc89 100644 --- a/app/services/idv/session.rb +++ b/app/services/idv/session.rb @@ -378,6 +378,10 @@ def idv_consent_given? !!session[:idv_consent_given_at] end + def in_person_passports_allowed? + passport_allowed && IdentityConfig.store.in_person_passports_enabled + end + private attr_reader :user_session diff --git a/app/views/idv/shared/choose_id_type.html.erb b/app/views/idv/shared/choose_id_type.html.erb index 49c0682cb34..8684717c554 100644 --- a/app/views/idv/shared/choose_id_type.html.erb +++ b/app/views/idv/shared/choose_id_type.html.erb @@ -2,14 +2,14 @@ <% content_for(:pre_flash_content) do %> <%= render StepIndicatorComponent.new( - steps: Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS, - current_step: :verify_id, + steps: presenter.step_indicator_steps, + current_step: presenter.current_step, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', ) %> <% end %> -<% if is_hybrid %> +<% if presenter.hybrid_flow? %> <%= render AlertComponent.new(type: :warning, class: 'margin-bottom-4') do %> <%= t('doc_auth.info.login_access_sp', app_name: APP_NAME, sp_name: decorated_sp_session.sp_name) %> <%= t('doc_auth.info.add_id_consent_with_phone', app_name: APP_NAME) %> @@ -21,7 +21,7 @@ <% end %>
- <%= t('doc_auth.info.choose_id_type') %> + <%= presenter.choose_id_type_info_text %>
<%= new_tab_link_to( @@ -30,12 +30,12 @@ category: 'verify-your-identity', article: 'accepted-identification-documents', ), - ) + ) %> <%= simple_form_for( :doc_auth, - url: form_url, + url: url_for, method: :put, ) do |f| %> <%= render ValidatedFieldComponent.new( @@ -53,7 +53,7 @@ checked: auto_check_value, error_messages: { valueMissing: t('doc_auth.errors.choose_id_type_check') }, ) %> - <%= f.submit t('forms.buttons.continue'), class: 'margin-y-2' %> + <%= f.submit t('forms.buttons.continue'), class: 'margin-bottom-2' %> <% end %> <%= render 'idv/doc_auth/cancel', step: 'choose_id_type' %> diff --git a/config/locales/en.yml b/config/locales/en.yml index e63795c77c3..5a5d0423491 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1320,6 +1320,7 @@ in_person_proofing.headings.state_id_milestone_2: Enter the information on your in_person_proofing.headings.switch_back: Switch back to your computer to prepare to verify your identity in person in_person_proofing.headings.update_address: Update your current residential address in_person_proofing.headings.update_state_id: Update the information on your ID +in_person_proofing.info.choose_id_type: Select the type of document that you want to use. You’ll need to bring this document to the Post Office. in_person_proofing.process.barcode.caption_label: Enrollment code in_person_proofing.process.barcode.heading: Show your %{app_name} barcode in_person_proofing.process.barcode.info: The retail associate needs to scan your barcode at the top of this page. You can print this page or show it on your mobile device. diff --git a/config/locales/es.yml b/config/locales/es.yml index 23d1bac99ac..6bea5710a05 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1331,6 +1331,7 @@ in_person_proofing.headings.state_id_milestone_2: Ingrese la información de su in_person_proofing.headings.switch_back: Vuelva a su computadora para preparar la verificación de su identidad en persona in_person_proofing.headings.update_address: Actualice su domicilio actual in_person_proofing.headings.update_state_id: Actualice la información de su identificación +in_person_proofing.info.choose_id_type: Select the type of document that you want to use. You’ll need to bring this document to the Post Office. in_person_proofing.process.barcode.caption_label: Código de registro in_person_proofing.process.barcode.heading: Muestre su código de barras de %{app_name} in_person_proofing.process.barcode.info: El empleado debe escanear el código de barras que aparece en la parte superior de esta página. Puede imprimir esta página o mostrarla en su dispositivo móvil. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 8bce19caf84..52e9c38ad07 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1320,6 +1320,7 @@ in_person_proofing.headings.state_id_milestone_2: Saisissez les informations fig in_person_proofing.headings.switch_back: Revenez à votre ordinateur pour vous préparer à confirmer votre identité en personne in_person_proofing.headings.update_address: Mettre à jour votre adresse personnelle in_person_proofing.headings.update_state_id: Mettez à jour les informations figurant sur votre document d’identité +in_person_proofing.info.choose_id_type: Select the type of document that you want to use. You’ll need to bring this document to the Post Office. in_person_proofing.process.barcode.caption_label: Code d’inscription in_person_proofing.process.barcode.heading: Montrez votre code-barres %{app_name} in_person_proofing.process.barcode.info: Le préposé doit scanner votre code-barres en haut de cette page. Vous pouvez imprimer cette page ou la montrer sur votre appareil mobile. diff --git a/config/locales/zh.yml b/config/locales/zh.yml index bacd5c66d15..409f5fa66ca 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -1333,6 +1333,7 @@ in_person_proofing.headings.state_id_milestone_2: 输入你州政府颁发身份 in_person_proofing.headings.switch_back: 切换回你的电脑,来准备亲身去验证身份。 in_person_proofing.headings.update_address: 更新你当前的住宅地址 in_person_proofing.headings.update_state_id: 更新你身份证件上的信息 +in_person_proofing.info.choose_id_type: Select the type of document that you want to use. You’ll need to bring this document to the Post Office. in_person_proofing.process.barcode.caption_label: 注册代码 in_person_proofing.process.barcode.heading: 出示你的 %{app_name} 条形码 in_person_proofing.process.barcode.info: 邮局工作人员需要扫描该页顶部的条形码你可以把该页打印出来,或在你的移动设备上显示。 diff --git a/config/routes.rb b/config/routes.rb index 7ed8e829b5a..bdf1d197a84 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -442,6 +442,8 @@ as: :capture_doc_dashes get '/in_person' => 'in_person#index' put '/in_person' => 'in_person#update' + get '/in_person/choose_id_type' => 'in_person/choose_id_type#show' + put '/in_person/choose_id_type' => 'in_person/choose_id_type#update' get '/in_person/ready_to_verify' => 'in_person/ready_to_verify#show', as: :in_person_ready_to_verify post '/in_person/usps_locations' => 'in_person/usps_locations#index' diff --git a/spec/controllers/idv/in_person/choose_id_type_controller_spec.rb b/spec/controllers/idv/in_person/choose_id_type_controller_spec.rb new file mode 100644 index 00000000000..8d6c392c5b7 --- /dev/null +++ b/spec/controllers/idv/in_person/choose_id_type_controller_spec.rb @@ -0,0 +1,191 @@ +require 'rails_helper' + +RSpec.describe Idv::InPerson::ChooseIdTypeController do + include FlowPolicyHelper + + let(:user) { create(:user) } + let(:idv_session) { subject.idv_session } + + before do + stub_sign_in(user) + stub_up_to(:hybrid_handoff, idv_session: subject.idv_session) + allow(IdentityConfig.store).to receive(:in_person_proofing_opt_in_enabled).and_return(true) + stub_analytics + end + + describe 'before_actions' do + it 'includes confirm step allowed before_action' do + expect(subject).to have_actions(:before, :confirm_step_allowed) + end + end + + describe '#show' do + context 'when in person passports are allowed' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(true) + end + + context 'when the user has an existing establishing enrollment' do + let!(:enrollment) { create(:in_person_enrollment, :establishing, user: user) } + let(:analytics_arguments) do + { + flow_path: 'standard', + step: 'choose_id_type', + analytics_id: 'In Person Proofing', + skip_hybrid_handoff: false, + opted_in_to_in_person_proofing: true, + } + end + + before do + subject.idv_session.opted_in_to_in_person_proofing = + analytics_arguments[:opted_in_to_in_person_proofing] + subject.idv_session.skip_hybrid_handoff = analytics_arguments[:skip_hybrid_handoff] + get :show + end + + it 'renders the choose id type form' do + expect(response).to render_template 'idv/shared/choose_id_type' + end + + it 'logs the idv_in_person_proofing_choose_id_type event' do + expect(@analytics).to have_logged_event( + :idv_in_person_proofing_choose_id_type_visited, analytics_arguments + ) + end + end + + context 'when the user does not have an existing establishing enrollment' do + before do + get :show + end + + it 'returns a redirect' do + expect(response).to be_redirect + end + + it 'does not log the idv_in_person_proofing_choose_id_type event' do + expect(@analytics).to_not have_logged_event( + :idv_in_person_proofing_choose_id_type_visited, + ) + end + end + end + + context 'when in person passports are not allowed' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(false) + end + + context 'when the user has an existing establishing enrollment' do + let!(:enrollment) { create(:in_person_enrollment, :establishing, user: user) } + let(:analytics_arguments) do + { + flow_path: 'standard', + step: 'choose_id_type', + analytics_id: 'In Person Proofing', + skip_hybrid_handoff: false, + opted_in_to_in_person_proofing: true, + } + end + + before do + subject.idv_session.opted_in_to_in_person_proofing = + analytics_arguments[:opted_in_to_in_person_proofing] + subject.idv_session.skip_hybrid_handoff = analytics_arguments[:skip_hybrid_handoff] + get :show + end + + it 'returns a redirect response' do + expect(response).to be_redirect + end + + it 'does not log the idv_in_person_proofing_choose_id_type event' do + expect(@analytics).to_not have_logged_event( + :idv_in_person_proofing_choose_id_type_visited, + ) + end + end + + context 'when the user does not have an existing establishing enrollment' do + before do + get :show + end + + it 'returns a redirect response' do + expect(response).to be_redirect + end + + it 'does not log the idv_in_person_proofing_choose_id_type event' do + expect(@analytics).to_not have_logged_event( + :idv_in_person_proofing_choose_id_type_visited, + ) + end + end + end + end + + describe '#update' do + context 'when in person passports are allowed' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(true) + end + + context 'when the user has an existing establishing enrollment' do + let!(:enrollment) { create(:in_person_enrollment, :establishing, user: user) } + + before do + put :update + end + + it 'returns a no_content response' do + expect(response).to be_no_content + end + end + + context 'when the user does not have an existing establishing enrollment' do + before do + put :update + end + + it 'returns a redirect response' do + expect(response).to be_redirect + end + end + end + + context 'when in person passports are not allowed' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(false) + end + + context 'when the user has an existing establishing enrollment' do + let!(:enrollment) { create(:in_person_enrollment, :establishing, user: user) } + + before do + put :update + end + + it 'returns a redirect response' do + expect(response).to be_redirect + end + end + + context 'when the user does not have an existing establishing enrollment' do + before do + put :update + end + + it 'returns a redirect response' do + expect(response).to be_redirect + end + end + end + end + + describe '.step_info' do + it 'returns a valid StepInfo Object' do + expect(described_class.step_info).to be_valid + end + end +end diff --git a/spec/controllers/idv/in_person_controller_spec.rb b/spec/controllers/idv/in_person_controller_spec.rb index 473053ababb..3f44d4d8a5e 100644 --- a/spec/controllers/idv/in_person_controller_spec.rb +++ b/spec/controllers/idv/in_person_controller_spec.rb @@ -3,7 +3,14 @@ RSpec.describe Idv::InPersonController do let(:in_person_proofing_enabled) { false } let(:sp) { nil } - let(:user) { nil } + let(:user) { build(:user) } + let(:idv_session) do + Idv::Session.new( + user_session: controller.user_session, + current_user: user, + service_provider: nil, + ) + end before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled) @@ -25,94 +32,196 @@ end describe '#index' do - it 'renders 404 not found' do - get :index - expect(response.status).to eq 404 - end - - context 'with in person proofing enabled' do - let(:in_person_proofing_enabled) { true } + context 'when the service provider has IPP enabled' do + let(:sp) { create(:service_provider, in_person_proofing_enabled: true) } - it 'redirects to the root url' do - get :index - - expect(response).to redirect_to root_url - end + context 'when in person proofing enabled in the application' do + let(:user) { nil } + let(:in_person_proofing_enabled) { true } - context 'signed in' do - let(:user) { build(:user) } - - it 'redirects to idv' do + it 'redirects to the root url' do get :index - expect(response).to redirect_to idv_url + expect(response).to redirect_to root_url end - context 'with establishing in-person enrollment' do + context 'signed in' do + let(:user) { build(:user) } + before do - create(:in_person_enrollment, :establishing, user: user) + allow(controller).to receive(:idv_session).and_return(idv_session) end - it 'initializes the in-person session' do + it 'redirects to idv' do get :index - expect(controller.user_session['idv/in_person']).to include( - pii_from_user: { uuid: user.uuid }, - ) + + expect(response).to redirect_to idv_url end - it 'redirects to the first step' do - get :index + context 'when user has an establishing in-person enrollment' do + before do + create(:in_person_enrollment, :establishing, user: user) + end - expect(response).to redirect_to idv_in_person_state_id_path - end + it 'initializes the in-person session' do + get :index - it 'has non-nil presenter' do - get :index - expect(assigns(:presenter)).to be_kind_of(Idv::InPerson::UspsFormPresenter) - end + expect(controller.user_session['idv/in_person']).to include( + pii_from_user: { uuid: user.uuid }, + ) + end + + it 'redirects to the first step' do + get :index - context 'with associated service provider' do - let(:sp) { create(:service_provider, in_person_proofing_enabled: false) } + expect(response).to redirect_to idv_in_person_state_id_path + end - it 'renders 404 not found' do + it 'has non-nil presenter' do get :index - expect(response.status).to eq 404 + expect(assigns(:presenter)).to be_kind_of(Idv::InPerson::UspsFormPresenter) end - context 'with in person proofing enabled for service provider' do + context 'when in person passports are allowed' do before do - ServiceProvider.find_by(issuer: sp.issuer) - .update(in_person_proofing_enabled: true) + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(true) end - it 'redirects to the first step' do + it 'redirects to the choose ID type page' do + get :index + + expect(response).to redirect_to idv_in_person_choose_id_type_path + end + end + + context 'when passports are not allowed' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(false) + end + + it 'redirects to the state ID page' do get :index expect(response).to redirect_to idv_in_person_state_id_path end end end + end + end + end + + context 'when the service provider has IPP disabled' do + let(:sp) { create(:service_provider, in_person_proofing_enabled: false) } + + it 'renders 404 not found' do + get :index + + expect(response.status).to eq 404 + end + end + end + + describe '#update' do + context 'when the service provider has IPP enabled' do + let(:sp) { create(:service_provider, in_person_proofing_enabled: true) } + + context 'with in person proofing enabled' do + let(:user) { nil } + let(:in_person_proofing_enabled) { true } + + it 'redirects to the root url' do + put :update + + expect(response).to redirect_to root_url + end + + context 'signed in' do + let(:user) { build(:user) } + + before do + allow(controller).to receive(:idv_session).and_return(idv_session) + end + + it 'redirects to idv' do + put :update - context 'with an existing applicant' do + expect(response).to redirect_to idv_url + end + + context 'with establishing in-person enrollment' do before do - idv_session = Idv::Session.new( - user_session: controller.user_session, - current_user: user, - service_provider: nil, + create(:in_person_enrollment, :establishing, user: user) + end + + it 'initializes the in-person session' do + put :update + + expect(controller.user_session['idv/in_person']).to include( + pii_from_user: { uuid: user.uuid }, ) - idv_session.applicant = {} - allow(controller).to receive(:idv_session).and_return(idv_session) end - it 'finishes the flow' do + it 'redirects to the first step' do put :update expect(response).to redirect_to idv_in_person_state_id_path end + + it 'has non-nil presenter' do + put :update + + expect(assigns(:presenter)).to be_kind_of(Idv::InPerson::UspsFormPresenter) + end + + context 'when in person passports are allowed' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(true) + end + + it 'redirects to the choose ID type page' do + put :update + + expect(response).to redirect_to idv_in_person_choose_id_type_path + end + end + + context 'when passports are not allowed' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(false) + end + + it 'redirects to the state ID page' do + put :update + + expect(response).to redirect_to idv_in_person_state_id_path + end + end + + context 'with an existing applicant' do + before do + allow(idv_session).to receive(:applicant).and_return({}) + end + + it 'finishes the flow' do + put :update + + expect(response).to redirect_to idv_in_person_state_id_path + end + end end end end end + + context 'when the service provider has IPP disabled' do + let(:sp) { create(:service_provider, in_person_proofing_enabled: false) } + + it 'renders 404 not found' do + put :update + + expect(response.status).to eq 404 + end + end end end diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index bb556f10bf7..bcde71bb00d 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -1250,6 +1250,7 @@ before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) allow(IdentityConfig.store).to receive(:in_person_proofing_opt_in_enabled).and_return(false) + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(false) allow(Idv::InPersonConfig).to receive(:enabled_for_issuer?).and_return(true) allow_any_instance_of(Idv::InPerson::ReadyToVerifyPresenter) .to receive(:service_provider_homepage_url).and_return(return_sp_url) diff --git a/spec/features/idv/in_person/passport_scenario_spec.rb b/spec/features/idv/in_person/passport_scenario_spec.rb new file mode 100644 index 00000000000..0ee2df04a91 --- /dev/null +++ b/spec/features/idv/in_person/passport_scenario_spec.rb @@ -0,0 +1,146 @@ +## frozen_string_literal: true + +require 'rails_helper' +require 'axe-rspec' + +RSpec.describe 'In Person Proofing Passports', js: true do + include IdvStepHelper + include InPersonHelper + include AbTestsHelper + include PassportApiHelpers + + let(:service_provider) { :oidc } + let(:user) { user_with_2fa } + let(:service_provider_name) { 'Test SP' } + + before do + ServiceProvider.find_by(issuer: service_provider_issuer(service_provider)) + .update(in_person_proofing_enabled: true) + allow(IdentityConfig.store).to receive(:in_person_proofing_opt_in_enabled).and_return(true) + allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) + end + + context 'when passports are allowed' do + before do + allow(IdentityConfig.store).to receive(:doc_auth_passports_enabled).and_return(true) + allow(IdentityConfig.store).to receive(:doc_auth_passports_percent).and_return(100) + stub_health_check_settings + stub_health_check_endpoints + end + + context 'when in person passports are enabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(true) + end + + it 'allows the user to accesss in person passport content' do + reload_ab_tests + visit_idp_from_sp_with_ial2(service_provider) + sign_in_live_with_2fa(user) + + expect(page).to have_current_path(idv_welcome_path) + expect(page).to have_content t('doc_auth.headings.welcome', sp_name: service_provider_name) + expect(page).to have_content t('doc_auth.instructions.bullet1b') + + complete_welcome_step + + expect(page).to have_current_path(idv_agreement_path) + complete_agreement_step + + expect(page).to have_current_path(idv_how_to_verify_path) + expect(page).to have_content t('doc_auth.info.verify_online_description_passport') + + click_on t('forms.buttons.continue_ipp') + + expect(page).to have_current_path(idv_document_capture_path(step: 'how_to_verify')) + + click_on t('forms.buttons.continue') + complete_location_step(user) + + expect(page).to have_current_path(idv_in_person_choose_id_type_path) + + expect(page).to have_content t('doc_auth.headings.choose_id_type') + expect(page).to have_content t('in_person_proofing.info.choose_id_type') + expect(page).to have_content t('doc_auth.forms.id_type_preference.drivers_license') + expect(page).to have_content t('doc_auth.forms.id_type_preference.passport') + end + end + + context 'when in person passports are disabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(false) + end + + it 'does not allow the user to access in person passport content' do + reload_ab_tests + visit_idp_from_sp_with_ial2(service_provider) + sign_in_live_with_2fa(user) + + expect(page).to have_current_path(idv_welcome_path) + expect(page).to have_content t('doc_auth.headings.welcome', sp_name: service_provider_name) + expect(page).to have_content t('doc_auth.instructions.bullet1b') + + complete_welcome_step + + expect(page).to have_current_path(idv_agreement_path) + complete_agreement_step + + expect(page).to have_current_path(idv_how_to_verify_path) + expect(page).to have_content strip_tags( + t('doc_auth.info.verify_at_post_office_description_passport_html'), + ) + + click_on t('forms.buttons.continue_ipp') + + expect(page).to have_current_path(idv_document_capture_path(step: 'how_to_verify')) + + click_on t('forms.buttons.continue') + complete_location_step(user) + + expect(page).to have_current_path(idv_in_person_state_id_path) + end + end + end + + context 'when passports are not allowed' do + before do + allow(IdentityConfig.store).to receive(:doc_auth_passports_enabled).and_return(false) + end + + context 'when in person passports are enabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(true) + end + + it 'does not allow the user to access in person passport content' do + reload_ab_tests + visit_idp_from_sp_with_ial2(service_provider) + sign_in_live_with_2fa(user) + + expect(page).to have_current_path(idv_welcome_path) + expect(page).to have_content t('doc_auth.headings.welcome', sp_name: service_provider_name) + expect(page).to have_content t('doc_auth.instructions.bullet1a') + + complete_welcome_step + + expect(page).to have_current_path(idv_agreement_path) + complete_agreement_step + + expect(page).to have_current_path(idv_how_to_verify_path) + expect(page).to_not have_content t('doc_auth.info.verify_online_description_passport') + expect(page).to_not have_content strip_tags( + t('doc_auth.info.verify_at_post_office_description_passport_html'), + ) + + click_on t('forms.buttons.continue_ipp') + + expect(page).to have_current_path(idv_document_capture_path(step: 'how_to_verify')) + + click_on t('forms.buttons.continue') + complete_location_step(user) + + expect(page).to have_current_path(idv_in_person_state_id_path) + end + end + end +end diff --git a/spec/i18n_spec.rb b/spec/i18n_spec.rb index ed65be38544..ae57f2198a5 100644 --- a/spec/i18n_spec.rb +++ b/spec/i18n_spec.rb @@ -74,6 +74,7 @@ class BaseTask { key: 'datetime.dotiw.minutes.other' }, # "minute is minute" in French and English { key: 'datetime.dotiw.words_connector' }, # " , " is only punctuation and not translated { key: 'in_person_proofing.process.eipp_bring_id.image_alt_text', locales: %i[fr es zh] }, # Real ID is considered a proper noun in this context, ID translated to ID Card in Chinese + { key: 'in_person_proofing.info.choose_id_type', locales: %i[fr es zh] }, # Waiting on translations { key: 'links.contact', locales: %i[fr] }, # "Contact" is "Contact" in French { key: 'saml_idp.auth.error.title', locales: %i[es] }, # "Error" is "Error" in Spanish { key: 'simple_form.no', locales: %i[es] }, # "No" is "No" in Spanish diff --git a/spec/policies/idv/flow_policy_spec.rb b/spec/policies/idv/flow_policy_spec.rb index 85f77475308..8ba9927ce7b 100644 --- a/spec/policies/idv/flow_policy_spec.rb +++ b/spec/policies/idv/flow_policy_spec.rb @@ -247,6 +247,21 @@ end end + context 'preconditions for ipp_choose_id_type are present' do + before do + allow(idv_session).to receive(:in_person_passports_allowed?).and_return(true) + allow(user).to receive(:has_establishing_in_person_enrollment?).and_return(true) + end + + it 'returns ipp_choose_id_type' do + expect( + subject.controller_allowed?( + controller: Idv::InPerson::ChooseIdTypeController, + ), + ).to be + end + end + context 'preconditions for in_person verify_info are present' do it 'returns ipp_verify_info' do stub_up_to(:ipp_ssn, idv_session: idv_session) diff --git a/spec/presenters/idv/choose_id_type_presenter_spec.rb b/spec/presenters/idv/choose_id_type_presenter_spec.rb new file mode 100644 index 00000000000..a7eabf4e5b4 --- /dev/null +++ b/spec/presenters/idv/choose_id_type_presenter_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe Idv::ChooseIdTypePresenter do + describe '#choose_id_type_info_text' do + it 'returns the "doc_auth.info.choose_id_type" translation' do + expect(subject.choose_id_type_info_text).to eq(t('doc_auth.info.choose_id_type')) + end + end + + describe '#current_step' do + it 'returns verify id' do + expect(subject.current_step).to eq(:verify_id) + end + end + + describe '#hybrid_flow?' do + it 'returns false' do + expect(subject.hybrid_flow?).to be(false) + end + end + + describe '#step_indicator_steps' do + it 'returns the step indicator steps' do + expect(subject.step_indicator_steps).to eq( + Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS, + ) + end + end +end diff --git a/spec/presenters/idv/hybrid_mobile/choose_id_type_presenter_spec.rb b/spec/presenters/idv/hybrid_mobile/choose_id_type_presenter_spec.rb new file mode 100644 index 00000000000..b7c62391ea0 --- /dev/null +++ b/spec/presenters/idv/hybrid_mobile/choose_id_type_presenter_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe Idv::HybridMobile::ChooseIdTypePresenter do + describe '#choose_id_type_info_text' do + it 'returns the "doc_auth.info.choose_id_type" translation' do + expect(subject.choose_id_type_info_text).to eq(t('doc_auth.info.choose_id_type')) + end + end + + describe '#current_step' do + it 'returns verify id' do + expect(subject.current_step).to eq(:verify_id) + end + end + + describe '#hybrid_flow?' do + it 'returns true' do + expect(subject.hybrid_flow?).to be(true) + end + end + + describe '#step_indicator_steps' do + it 'returns the step indicator steps' do + expect(subject.step_indicator_steps).to eq( + Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS, + ) + end + end +end diff --git a/spec/presenters/idv/in_person/choose_id_type_presenter_spec.rb b/spec/presenters/idv/in_person/choose_id_type_presenter_spec.rb new file mode 100644 index 00000000000..f0da4e9b04a --- /dev/null +++ b/spec/presenters/idv/in_person/choose_id_type_presenter_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe Idv::InPerson::ChooseIdTypePresenter do + describe '#choose_id_type_info_text' do + it 'returns the "in_person_proofing.info.choose_id_type" translation' do + expect(subject.choose_id_type_info_text).to eq(t('in_person_proofing.info.choose_id_type')) + end + end + + describe '#current_step' do + it 'returns verify info' do + expect(subject.current_step).to eq(:verify_info) + end + end + + describe '#hybrid_flow?' do + it 'returns false' do + expect(subject.hybrid_flow?).to be(false) + end + end + + describe '#step_indicator_steps' do + it 'returns the IPP step indicator steps' do + expect(subject.step_indicator_steps).to eq( + Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS_IPP, + ) + end + end +end diff --git a/spec/services/idv/session_spec.rb b/spec/services/idv/session_spec.rb index 1e98c324e0c..4f3e69cb5d7 100644 --- a/spec/services/idv/session_spec.rb +++ b/spec/services/idv/session_spec.rb @@ -443,4 +443,58 @@ expect(subject.address_mechanism_chosen?).to eq(false) end end + + describe '#in_person_passports_allowed?' do + context 'when passports are allowed' do + before do + subject.passport_allowed = true + end + + context 'when in person passports are enabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(true) + end + + it 'returns true' do + expect(subject.in_person_passports_allowed?).to be(true) + end + end + + context 'when in person passports are disabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(false) + end + + it 'returns false' do + expect(subject.in_person_passports_allowed?).to be(false) + end + end + end + + context 'when passports are not allowed' do + before do + subject.passport_allowed = false + end + + context 'when in person passports are enabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(true) + end + + it 'returns false' do + expect(subject.in_person_passports_allowed?).to be(false) + end + end + + context 'when in person passports are disabled' do + before do + allow(IdentityConfig.store).to receive(:in_person_passports_enabled).and_return(false) + end + + it 'returns false' do + expect(subject.in_person_passports_allowed?).to be(false) + end + end + end + end end