diff --git a/app/controllers/concerns/idv/step_utilities_concern.rb b/app/controllers/concerns/idv/step_utilities_concern.rb
new file mode 100644
index 00000000000..cd8b183cd56
--- /dev/null
+++ b/app/controllers/concerns/idv/step_utilities_concern.rb
@@ -0,0 +1,41 @@
+module Idv
+ module StepUtilitiesConcern
+ extend ActiveSupport::Concern
+
+ def flow_session
+ user_session['idv/doc_auth']
+ end
+
+ # copied from doc_auth_controller
+ def flow_path
+ flow_session[:flow_path]
+ end
+
+ def confirm_pii_from_doc
+ @pii = flow_session['pii_from_doc'] # hash with indifferent access
+ return if @pii.present?
+ flow_session.delete('Idv::Steps::DocumentCaptureStep')
+ redirect_to idv_doc_auth_url
+ end
+
+ # Copied from capture_doc_flow.rb
+ # and from doc_auth_flow.rb
+ def acuant_sdk_ab_test_analytics_args
+ capture_session_uuid = flow_session[:document_capture_session_uuid]
+ if capture_session_uuid
+ {
+ acuant_sdk_upgrade_ab_test_bucket:
+ AbTests::ACUANT_SDK.bucket(capture_session_uuid),
+ }
+ else
+ {}
+ end
+ end
+
+ def irs_reproofing?
+ effective_user&.decorate&.reproof_for_irs?(
+ service_provider: current_sp,
+ ).present?
+ end
+ end
+end
diff --git a/app/controllers/idv/ssn_controller.rb b/app/controllers/idv/ssn_controller.rb
new file mode 100644
index 00000000000..fc4f938a90e
--- /dev/null
+++ b/app/controllers/idv/ssn_controller.rb
@@ -0,0 +1,88 @@
+module Idv
+ class SsnController < ApplicationController
+ include IdvSession
+ include StepIndicatorConcern
+ include StepUtilitiesConcern
+ include Steps::ThreatMetrixStepHelper
+
+ before_action :render_404_if_ssn_controller_disabled
+ before_action :confirm_two_factor_authenticated
+ before_action :confirm_pii_from_doc
+
+ attr_accessor :error_message
+
+ def show
+ increment_step_counts
+
+ analytics.idv_doc_auth_redo_ssn_submitted(**analytics_arguments) if updating_ssn
+
+ analytics.idv_doc_auth_ssn_visited(**analytics_arguments)
+
+ render :show, locals: extra_view_variables
+ end
+
+ def update
+ @error_message = nil
+ form_response = form_submit
+
+ unless form_response.success?
+ @error_message = form_response.first_error_message
+ redirect_to idv_ssn_url
+ end
+
+ flow_session['pii_from_doc'][:ssn] = params[:doc_auth][:ssn]
+
+ analytics.idv_doc_auth_ssn_submitted(**analytics_arguments)
+
+ irs_attempts_api_tracker.idv_ssn_submitted(
+ ssn: params[:doc_auth][:ssn],
+ )
+
+ idv_session.ssn_updated!
+
+ redirect_to idv_verify_info_url
+ end
+
+ def extra_view_variables
+ {
+ updating_ssn: updating_ssn,
+ success_alert_enabled: !updating_ssn,
+ **threatmetrix_view_variables,
+ }
+ end
+
+ private
+
+ def render_404_if_ssn_controller_disabled
+ render_not_found unless IdentityConfig.store.doc_auth_ssn_controller_enabled
+ end
+
+ def analytics_arguments
+ {
+ flow_path: flow_path,
+ step: 'ssn',
+ step_count: current_flow_step_counts['Idv::Steps::SsnStep'],
+ analytics_id: 'Doc Auth',
+ irs_reproofing: irs_reproofing?,
+ }.merge(**acuant_sdk_ab_test_analytics_args)
+ end
+
+ def current_flow_step_counts
+ user_session['idv/doc_auth_flow_step_counts'] ||= {}
+ user_session['idv/doc_auth_flow_step_counts'].default = 0
+ user_session['idv/doc_auth_flow_step_counts']
+ end
+
+ def increment_step_counts
+ current_flow_step_counts['Idv::Steps::SsnStep'] += 1
+ end
+
+ def form_submit
+ Idv::SsnFormatForm.new(current_user).submit(params.require(:doc_auth).permit(:ssn))
+ end
+
+ def updating_ssn
+ flow_session.dig('pii_from_doc', :ssn).present?
+ end
+ end
+end
diff --git a/app/controllers/idv/verify_info_controller.rb b/app/controllers/idv/verify_info_controller.rb
index 10e5e6063f4..c60bc760926 100644
--- a/app/controllers/idv/verify_info_controller.rb
+++ b/app/controllers/idv/verify_info_controller.rb
@@ -1,6 +1,7 @@
module Idv
class VerifyInfoController < ApplicationController
include IdvSession
+ include StepUtilitiesConcern
before_action :confirm_two_factor_authenticated
before_action :confirm_ssn_step_complete
@@ -73,21 +74,6 @@ def update
private
- # copied from doc_auth_controller
- def flow_session
- user_session['idv/doc_auth']
- end
-
- def flow_path
- flow_session[:flow_path]
- end
-
- def irs_reproofing?
- effective_user&.decorate&.reproof_for_irs?(
- service_provider: current_sp,
- ).present?
- end
-
def analytics_arguments
{
flow_path: flow_path,
@@ -98,20 +84,6 @@ def analytics_arguments
}.merge(**acuant_sdk_ab_test_analytics_args)
end
- # Copied from capture_doc_flow.rb
- # and from doc_auth_flow.rb
- def acuant_sdk_ab_test_analytics_args
- capture_session_uuid = flow_session[:document_capture_session_uuid]
- if capture_session_uuid
- {
- acuant_sdk_upgrade_ab_test_bucket:
- AbTests::ACUANT_SDK.bucket(capture_session_uuid),
- }
- else
- {}
- end
- end
-
# copied from verify_step
def pii
@pii = flow_session[:pii_from_doc] if flow_session
@@ -125,7 +97,11 @@ def delete_pii
# copied from address_controller
def confirm_ssn_step_complete
return if pii.present? && pii[:ssn].present?
- redirect_to idv_doc_auth_url
+ if IdentityConfig.store.doc_auth_ssn_controller_enabled
+ redirect_to idv_ssn_url
+ else
+ redirect_to idv_doc_auth_url
+ end
end
def confirm_profile_not_already_confirmed
diff --git a/app/services/idv/session.rb b/app/services/idv/session.rb
index 3f7234bf895..08b7d97a3d2 100644
--- a/app/services/idv/session.rb
+++ b/app/services/idv/session.rb
@@ -136,6 +136,24 @@ def user_phone_confirmation_session=(new_user_phone_confirmation_session)
session[:user_phone_confirmation_session] = new_user_phone_confirmation_session.to_h
end
+ def ssn_updated!
+ # Guard against unvalidated attributes from in-person flow in review controller
+ session[:applicant] = nil
+
+ invalidate_verify_info_step!
+ invalidate_phone_step!
+ end
+
+ def invalidate_verify_info_step!
+ session[:resolution_successful] = nil
+ session[:profile_confirmation] = nil
+ end
+
+ def invalidate_phone_step!
+ session[:vendor_phone_confirmation] = nil
+ session[:user_phone_confirmation] = nil
+ end
+
private
attr_accessor :user_session
diff --git a/app/services/idv/steps/document_capture_step.rb b/app/services/idv/steps/document_capture_step.rb
index e2df7019cdd..9f3408b2f5a 100644
--- a/app/services/idv/steps/document_capture_step.rb
+++ b/app/services/idv/steps/document_capture_step.rb
@@ -15,6 +15,8 @@ def self.analytics_submitted_event
def call
handle_stored_result if !FeatureManagement.document_capture_async_uploads_enabled?
+
+ exit_flow_state_machine if IdentityConfig.store.doc_auth_ssn_controller_enabled
end
def extra_view_variables
@@ -38,6 +40,11 @@ def extra_view_variables
private
+ def exit_flow_state_machine
+ flow_session[:flow_path] = @flow.flow_path
+ redirect_to idv_ssn_url
+ end
+
def native_camera_ab_testing_variables
{
acuant_sdk_upgrade_ab_test_bucket:
diff --git a/app/views/idv/ssn/show.html.erb b/app/views/idv/ssn/show.html.erb
new file mode 100644
index 00000000000..f744c8ccedb
--- /dev/null
+++ b/app/views/idv/ssn/show.html.erb
@@ -0,0 +1,91 @@
+<%#
+Renders a page asking the user to enter their SSN or update their SSN if they had previously entered it.
+
+locals:
+* success_alert_enabled: whether or not to display a "We've successfully verified your ID" success alert
+* updating_ssn: true if the user is updating their SSN instead of providing it for the first time. This
+ will render a different page heading and different navigation buttons in the page footer
+%>
+<% content_for(:pre_flash_content) do %>
+ <%= render StepIndicatorComponent.new(
+ steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS,
+ current_step: :verify_info,
+ locale_scope: 'idv',
+ class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4',
+ ) %>
+<% end %>
+
+<% title t('titles.doc_auth.ssn') %>
+
+<% if success_alert_enabled %>
+ <%= render AlertComponent.new(
+ type: :success,
+ class: 'margin-bottom-4',
+ ) do %>
+ <%= t('doc_auth.headings.capture_complete') %>
+ <% end %>
+<% end %>
+
+<% if updating_ssn %>
+ <%= render PageHeadingComponent.new.with_content(t('doc_auth.headings.ssn_update')) %>
+<% else %>
+ <%= render PageHeadingComponent.new.with_content(t('doc_auth.headings.ssn')) %>
+<% end %>
+
+
+ <%= t('doc_auth.info.ssn') %>
+ <%= new_window_link_to(t('doc_auth.instructions.learn_more'), MarketingSite.security_and_privacy_practices_url) %>
+
+
+<% if FeatureManagement.proofing_device_profiling_collecting_enabled? %>
+ <% if threatmetrix_session_id.present? %>
+ <% threatmetrix_javascript_urls.each do |threatmetrix_javascript_url| %>
+ <%= javascript_include_tag threatmetrix_javascript_url, nonce: true %>
+ <% end %>
+
+ <% end %>
+<% end %>
+
+<% if IdentityConfig.store.proofer_mock_fallback %>
+
+
+
+ <%= t('doc_auth.instructions.test_ssn') %>
+
+
+
+<% end %>
+
+<%= simple_form_for(
+ :doc_auth,
+ url: idv_ssn_url,
+ method: :put,
+ html: { autocomplete: 'off' },
+ ) do |f| %>
+
+ <%= render 'shared/ssn_field', f: f %>
+
+
+ <%= @error_message %>
+
+ <%= f.submit class: 'display-block margin-y-5' do %>
+ <% if updating_ssn %>
+ <%= t('forms.buttons.submit.update') %>
+ <% else %>
+ <%= t('forms.buttons.continue') %>
+ <% end %>
+ <% end %>
+<% end %>
+
+<% if updating_ssn %>
+ <%= render 'idv/shared/back', action: 'cancel_update_ssn' %>
+<% else %>
+ <%= render 'idv/doc_auth/cancel', step: 'ssn' %>
+<% end %>
diff --git a/app/views/idv/verify_info/show.html.erb b/app/views/idv/verify_info/show.html.erb
index 26c528d38ed..42a8f012139 100644
--- a/app/views/idv/verify_info/show.html.erb
+++ b/app/views/idv/verify_info/show.html.erb
@@ -102,6 +102,16 @@ locals:
toggle_label: t('forms.ssn.show'),
) %>
+<% if IdentityConfig.store.doc_auth_ssn_controller_enabled %>
+
+ <%= button_to(
+ idv_ssn_url,
+ method: :get,
+ class: 'usa-button usa-button--unstyled',
+ 'aria-label': t('idv.buttons.change_ssn_label'),
+ ) { t('idv.buttons.change_label') } %>
+
+<% else %>
<%= button_to(
idv_doc_auth_step_url(step: :redo_ssn),
@@ -110,6 +120,7 @@ locals:
'aria-label': t('idv.buttons.change_ssn_label'),
) { t('idv.buttons.change_label') } %>
+<% end %>
<%= render SpinnerButtonComponent.new(
diff --git a/config/application.yml.default b/config/application.yml.default
index 39df9509e4d..90352964ee5 100644
--- a/config/application.yml.default
+++ b/config/application.yml.default
@@ -70,6 +70,7 @@ country_phone_number_overrides: '{}'
doc_auth_error_dpi_threshold: 290
doc_auth_error_sharpness_threshold: 40
doc_auth_error_glare_threshold: 40
+doc_auth_ssn_controller_enabled: false
database_pool_extra_connections_for_worker: 4
database_pool_idp: 5
database_statement_timeout: 2_500
diff --git a/config/routes.rb b/config/routes.rb
index 497774d2ffb..8f31eb5ac83 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -308,6 +308,8 @@
post '/forgot_password' => 'forgot_password#update'
get '/otp_delivery_method' => 'otp_delivery_method#new'
put '/otp_delivery_method' => 'otp_delivery_method#create'
+ get '/ssn' => 'ssn#show'
+ put '/ssn' => 'ssn#update'
get '/verify_info' => 'verify_info#show'
put '/verify_info' => 'verify_info#update'
get '/phone' => 'phone#new'
diff --git a/lib/identity_config.rb b/lib/identity_config.rb
index b206c48da18..ebd4f974ec1 100644
--- a/lib/identity_config.rb
+++ b/lib/identity_config.rb
@@ -166,6 +166,7 @@ def self.build_store(config_map)
config.add(:doc_auth_max_submission_attempts_before_native_camera, type: :integer)
config.add(:doc_auth_max_capture_attempts_before_tips, type: :integer)
config.add(:doc_auth_s3_request_timeout, type: :integer)
+ config.add(:doc_auth_ssn_controller_enabled, type: :boolean)
config.add(:doc_auth_vendor, type: :string)
config.add(:doc_auth_vendor_randomize, type: :boolean)
config.add(:doc_auth_vendor_randomize_percent, type: :integer)
diff --git a/spec/controllers/idv/ssn_controller_spec.rb b/spec/controllers/idv/ssn_controller_spec.rb
new file mode 100644
index 00000000000..b12d9dc9c73
--- /dev/null
+++ b/spec/controllers/idv/ssn_controller_spec.rb
@@ -0,0 +1,175 @@
+require 'rails_helper'
+
+describe Idv::SsnController do
+ include IdvHelper
+
+ let(:flow_session) do
+ { 'document_capture_session_uuid' => 'fd14e181-6fb1-4cdc-92e0-ef66dad0df4e',
+ 'pii_from_doc' => Idp::Constants::MOCK_IDV_APPLICANT.dup,
+ :threatmetrix_session_id => 'c90ae7a5-6629-4e77-b97c-f1987c2df7d0',
+ :flow_path => 'standard' }
+ end
+
+ let(:user) { build(:user, :with_phone, with: { phone: '+1 (415) 555-0130' }) }
+
+ before do
+ allow(subject).to receive(:flow_session).and_return(flow_session)
+ stub_sign_in(user)
+ end
+
+ describe 'before_actions' do
+ it 'checks that feature flag is enabled' do
+ expect(subject).to have_actions(
+ :before,
+ :render_404_if_ssn_controller_disabled,
+ )
+ end
+
+ it 'includes authentication before_action' do
+ expect(subject).to have_actions(
+ :before,
+ :confirm_two_factor_authenticated,
+ )
+ end
+
+ it 'checks that the previous step is complete' do
+ expect(subject).to have_actions(
+ :before,
+ :confirm_pii_from_doc,
+ )
+ end
+ end
+
+ context 'when doc_auth_ssn_controller_enabled' do
+ before do
+ allow(IdentityConfig.store).to receive(:doc_auth_ssn_controller_enabled).
+ and_return(true)
+ stub_analytics
+ stub_attempts_tracker
+ allow(@analytics).to receive(:track_event)
+ end
+
+ describe '#show' do
+ let(:analytics_name) { 'IdV: doc auth ssn visited' }
+ let(:analytics_args) do
+ {
+ analytics_id: 'Doc Auth',
+ flow_path: 'standard',
+ irs_reproofing: false,
+ step: 'ssn',
+ step_count: 1,
+ }
+ end
+
+ context 'when doc_auth_ssn_controller_enabled' do
+ before do
+ allow(IdentityConfig.store).to receive(:doc_auth_ssn_controller_enabled).
+ and_return(true)
+ end
+
+ it 'renders the show template' do
+ get :show
+
+ expect(response).to render_template :show
+ end
+
+ it 'sends analytics_visited event' do
+ get :show
+
+ expect(@analytics).to have_received(:track_event).with(analytics_name, analytics_args)
+ end
+
+ it 'sends correct step count to analytics' do
+ get :show
+ get :show
+ analytics_args[:step_count] = 2
+
+ expect(@analytics).to have_received(:track_event).with(analytics_name, analytics_args)
+ end
+ end
+ end
+
+ describe '#update' do
+ context 'with valid ssn' do
+ let(:ssn) { Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN[:ssn] }
+ let(:params) { { doc_auth: { ssn: ssn } } }
+ let(:analytics_name) { 'IdV: doc auth ssn submitted' }
+ let(:analytics_args) do
+ {
+ analytics_id: 'Doc Auth',
+ flow_path: 'standard',
+ irs_reproofing: false,
+ step: 'ssn',
+ step_count: 1,
+ }
+ end
+
+ it 'merges ssn into pii session value' do
+ put :update, params: params
+
+ expect(flow_session['pii_from_doc'][:ssn]).to eq(ssn)
+ end
+
+ it 'sends analytics_submitted event with correct step count' do
+ get :show
+ put :update, params: params
+
+ expect(@analytics).to have_received(:track_event).with(analytics_name, analytics_args)
+ end
+
+ it 'logs attempts api event' do
+ expect(@irs_attempts_api_tracker).to receive(:idv_ssn_submitted).with(
+ ssn: ssn,
+ )
+ put :update, params: params
+ end
+
+ context 'with existing session applicant' do
+ it 'clears applicant' do
+ subject.idv_session.applicant = Idp::Constants::MOCK_IDV_APPLICANT
+
+ put :update, params: params
+
+ expect(subject.idv_session.applicant).to be_blank
+ end
+ end
+
+ it 'adds a threatmetrix session id to flow session' do
+ subject.extra_view_variables
+ expect(flow_session[:threatmetrix_session_id]).to_not eq(nil)
+ end
+
+ it 'does not change threatmetrix_session_id when updating ssn' do
+ flow_session['pii_from_doc'][:ssn] = ssn
+ put :update, params: params
+ session_id = flow_session[:threatmetrix_session_id]
+ subject.extra_view_variables
+ expect(flow_session[:threatmetrix_session_id]).to eq(session_id)
+ end
+ end
+
+ context 'when pii_from_doc is not present' do
+ it 'marks previous step as incomplete' do
+ flow_session.delete('pii_from_doc')
+ flow_session['Idv::Steps::DocumentCaptureStep'] = true
+ put :update
+ expect(flow_session['Idv::Steps::DocumentCaptureStep']).to eq nil
+ expect(response.status).to eq 302
+ end
+ end
+ end
+ end
+
+ context 'when doc_auth_ssn_controller_enabled is false' do
+ before do
+ allow(IdentityConfig.store).to receive(:doc_auth_ssn_controller_enabled).
+ and_return(false)
+ end
+
+ it 'returns 404' do
+ get :show
+
+ expect(response.status).to eq(404)
+ end
+ end
+end
diff --git a/spec/controllers/idv/verify_info_controller_spec.rb b/spec/controllers/idv/verify_info_controller_spec.rb
index bea98420782..ac56fda9afd 100644
--- a/spec/controllers/idv/verify_info_controller_spec.rb
+++ b/spec/controllers/idv/verify_info_controller_spec.rb
@@ -100,10 +100,36 @@
).increment_to_throttled!
end
- it 'redirects to ssn failure url' do
- get :show
+ context 'when using new ssn controller' do
+ before do
+ allow(IdentityConfig.store).to receive(:doc_auth_ssn_controller_enabled).
+ and_return(true)
+ end
- expect(response).to redirect_to idv_session_errors_ssn_failure_url
+ it 'redirects to ssn controller when ssn info is missing' do
+ flow_session[:pii_from_doc][:ssn] = nil
+
+ get :show
+
+ expect(response).to redirect_to(idv_ssn_url)
+ end
+ end
+
+ context 'when the user is ssn throttled' do
+ before do
+ Throttle.new(
+ target: Pii::Fingerprinter.fingerprint(
+ Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN[:ssn],
+ ),
+ throttle_type: :proof_ssn,
+ ).increment_to_throttled!
+ end
+
+ it 'redirects to ssn failure url' do
+ get :show
+
+ expect(response).to redirect_to idv_session_errors_ssn_failure_url
+ end
end
end
diff --git a/spec/features/idv/doc_auth/document_capture_step_spec.rb b/spec/features/idv/doc_auth/document_capture_step_spec.rb
index bce2bbdefa5..a630d6094c0 100644
--- a/spec/features/idv/doc_auth/document_capture_step_spec.rb
+++ b/spec/features/idv/doc_auth/document_capture_step_spec.rb
@@ -207,6 +207,20 @@
end
end
+ context 'when new ssn controller is enabled' do
+ before do
+ allow(IdentityConfig.store).to receive(:doc_auth_ssn_controller_enabled).
+ and_return(true)
+ end
+ it 'redirects to ssn controller' do
+ expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id'))
+
+ attach_and_submit_images
+
+ expect(page).to have_current_path(idv_ssn_url)
+ end
+ end
+
def next_step
idv_doc_auth_ssn_step
end
diff --git a/spec/features/idv/doc_auth/ssn_spec.rb b/spec/features/idv/doc_auth/ssn_spec.rb
new file mode 100644
index 00000000000..d1d7c6b373d
--- /dev/null
+++ b/spec/features/idv/doc_auth/ssn_spec.rb
@@ -0,0 +1,45 @@
+require 'rails_helper'
+
+feature 'doc auth ssn step', :js do
+ include IdvStepHelper
+ include DocAuthHelper
+ include DocCaptureHelper
+
+ before do
+ allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:enabled)
+ allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_org_id).and_return('test_org')
+ allow(IdentityConfig.store).to receive(:doc_auth_ssn_controller_enabled).and_return(true)
+
+ sign_in_and_2fa_user
+ complete_doc_auth_steps_before_ssn_step
+ end
+
+ it 'proceeds to the next page with valid info' do
+ expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_info'))
+
+ fill_out_ssn_form_ok
+
+ match = page.body.match(/session_id=(?[^"&]+)/)
+ session_id = match && match[:session_id]
+ expect(session_id).to be_present
+
+ select 'Review', from: 'mock_profiling_result'
+
+ expect(page.find_field(t('idv.form.ssn_label_html'))['aria-invalid']).to eq('false')
+ click_idv_continue
+
+ expect(page).to have_current_path(idv_verify_info_url)
+
+ profiling_result = Proofing::Mock::DeviceProfilingBackend.new.profiling_result(session_id)
+ expect(profiling_result).to eq('review')
+ end
+
+ it 'does not proceed to the next page with invalid info' do
+ fill_out_ssn_form_fail
+ click_idv_continue
+
+ expect(page.find_field(t('idv.form.ssn_label_html'))['aria-invalid']).to eq('true')
+
+ expect(page).to have_current_path(idv_ssn_url)
+ end
+end
diff --git a/spec/features/idv/doc_auth/verify_info_step_spec.rb b/spec/features/idv/doc_auth/verify_info_step_spec.rb
index 64cd6c07a85..fd281d50f1c 100644
--- a/spec/features/idv/doc_auth/verify_info_step_spec.rb
+++ b/spec/features/idv/doc_auth/verify_info_step_spec.rb
@@ -374,4 +374,32 @@
expect(page).to have_current_path(idv_phone_path)
end
end
+
+ context 'with ssn_controller enabled' do
+ before do
+ allow(IdentityConfig.store).to receive(:doc_auth_ssn_controller_enabled).
+ and_return(true)
+ allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics)
+ sign_in_and_2fa_user
+ complete_doc_auth_steps_before_verify_step
+ end
+
+ it 'uses ssn controller to enter a new ssn and displays updated info' do
+ click_button t('idv.buttons.change_ssn_label')
+ expect(page).to have_current_path(idv_ssn_path)
+
+ fill_in t('idv.form.ssn_label_html'), with: '900456789'
+ click_button t('forms.buttons.submit.update')
+
+ expect(fake_analytics).to have_logged_event(
+ 'IdV: doc auth redo_ssn submitted',
+ )
+
+ expect(page).to have_current_path(idv_verify_info_path)
+
+ expect(page).to have_text('9**-**-***9')
+ check t('forms.ssn.show')
+ expect(page).to have_text('900-45-6789')
+ end
+ end
end