-
-
-
-<%= t('doc_auth.info.upload_from_computer') %>
-<%= simple_form_for(
- :doc_auth,
- url: url_for(type: :desktop),
- method: 'PUT',
- html: { class: 'display-inline' },
- ) do |f| %>
- <%= f.submit t('doc_auth.info.upload_computer_link'), unstyled: true, big: false %>
-<% end %>
-
-<%= render 'idv/doc_auth/cancel', step: 'upload' %>
diff --git a/config/application.yml.default b/config/application.yml.default
index e9b1e7412f4..351be8be1cb 100644
--- a/config/application.yml.default
+++ b/config/application.yml.default
@@ -65,6 +65,7 @@ broken_personal_key_window_start: '2021-07-29T00:00:00Z'
broken_personal_key_window_finish: '2021-09-22T00:00:00Z'
component_previews_enabled: false
country_phone_number_overrides: '{}'
+doc_auth_combined_hybrid_handoff_enabled: false
doc_auth_error_dpi_threshold: 290
doc_auth_error_sharpness_threshold: 40
doc_auth_error_glare_threshold: 40
diff --git a/config/locales/doc_auth/en.yml b/config/locales/doc_auth/en.yml
index 3bb2eaa7457..293b7869c76 100644
--- a/config/locales/doc_auth/en.yml
+++ b/config/locales/doc_auth/en.yml
@@ -113,6 +113,9 @@ en:
information below is incorrect, please %{link} of your state-issued ID.
capture_scan_warning_link: upload new photos
capture_troubleshooting_tips: Having trouble adding your state-issued ID?
+ combined_upload: How would you like to add your ID?
+ combined_upload_from_computer: Continue on this computer
+ combined_upload_from_phone: Use your phone to take photos
document_capture: Add your state-issued ID
document_capture_back: Back of your ID
document_capture_front: Front of your ID
@@ -146,6 +149,11 @@ en:
capture_status_none: Align
capture_status_small_document: Move Closer
capture_status_tap_to_capture: Tap to Capture
+ combined_upload: We’ll collect information about you by reading your state-issued ID.
+ combined_upload_from_computer: Don’t have a phone? Upload photos of your ID from this computer.
+ combined_upload_from_phone: You won’t have to sign in again, and you’ll switch
+ back to this computer after you take photos. Your mobile phone must have
+ a camera and a web browser.
document_capture_intro_acknowledgment: We’ll collect information about you by
reading your state-issued ID. We use this information to verify your
identity.
diff --git a/config/locales/doc_auth/es.yml b/config/locales/doc_auth/es.yml
index a8091e798e3..8759204de69 100644
--- a/config/locales/doc_auth/es.yml
+++ b/config/locales/doc_auth/es.yml
@@ -139,6 +139,9 @@ es:
de su ID emitido por el estado.
capture_scan_warning_link: suba nuevas fotos
capture_troubleshooting_tips: '¿Tiene problemas para agregar su identificación emitida por el estado?'
+ combined_upload: '¿Cómo desea añadir su documento de identidad?'
+ combined_upload_from_computer: Continuar en esta computadora
+ combined_upload_from_phone: Utilice su teléfono para tomar las fotos
document_capture: Añada su documento de identidad expedido por el estado
document_capture_back: Parte trasera de su documento de identidad
document_capture_front: Parte delantera de su documento de identidad
@@ -175,6 +178,13 @@ es:
capture_status_none: Alinea
capture_status_small_document: Muévete mas cerca
capture_status_tap_to_capture: Toque para capturar
+ combined_upload: Recopilaremos información sobre usted leyendo su documento de
+ identidad expedido por el estado.
+ combined_upload_from_computer: ¿No tiene teléfono? Suba fotos de su documento de
+ identidad desde esta computadora.
+ combined_upload_from_phone: No tendrá que volver a iniciar sesión y volverá a
+ cambiar a esta computadora después de tomar las fotos. Su teléfono móvil
+ debe tener una cámara y un navegador web.
document_capture_intro_acknowledgment: Recopilaremos información sobre usted
leyendo su documento de identidad expedido por el Estado. Usamos esta
información para verificar su identidad.
diff --git a/config/locales/doc_auth/fr.yml b/config/locales/doc_auth/fr.yml
index 6be14becdc2..ca6d047fc38 100644
--- a/config/locales/doc_auth/fr.yml
+++ b/config/locales/doc_auth/fr.yml
@@ -145,6 +145,9 @@ fr:
veuillez %{link} de votre carte d’identité délivrée par l’État.
capture_scan_warning_link: télécharger de nouvelles photos
capture_troubleshooting_tips: Vous rencontrez des difficultés pour ajouter votre pièce d’identité?
+ combined_upload: Comment voulez-vous ajouter votre identifiant ?
+ combined_upload_from_computer: Continuer sur cet ordinateur
+ combined_upload_from_phone: Utilisez votre téléphone pour prendre des photos
document_capture: Ajoutez votre carte d’identité délivrée par l’État
document_capture_back: Verso de votre carte d’identité
document_capture_front: Recto de votre carte d’identité
@@ -181,6 +184,13 @@ fr:
capture_status_none: Alignez
capture_status_small_document: Approchez-vous
capture_status_tap_to_capture: Appuyez pour capturer
+ combined_upload: Nous recueillons des informations sur vous en lisant votre
+ carte d’identité délivrée par l’État.
+ combined_upload_from_computer: Vous n’avez pas de téléphone ? Téléchargez les
+ photos de votre carte d’identité depuis cet ordinateur.
+ combined_upload_from_phone: Vous n’aurez pas à vous reconnecter. Vous reviendrez
+ sur cet ordinateur après avoir pris des photos. Votre téléphone portable
+ doit être équipé d’un appareil photo et d’un navigateur web.
document_capture_intro_acknowledgment: Nous recueillons des informations sur
vous en lisant votre pièce d’identité délivrée par l’État. Nous
utilisons ces informations pour vérifier votre identité.
@@ -218,7 +228,7 @@ fr:
take_picture: Utilisez l’appareil photo sur votre téléphone portable et
téléchargez des images de votre identifiant. Nous utilisons uniquement
les images pour vérifier votre identité.
- upload: Nous recueillons des informations vous concernant en lisant votre carte
+ upload: Nous recueillons des informations sur vous en lisant votre carte
d’identité délivrée par l’État.
upload_computer_link: Téléchargez depuis votre ordinateur
upload_from_computer: Vous n’avez pas de téléphone?
diff --git a/config/locales/forms/en.yml b/config/locales/forms/en.yml
index e9d01484d10..e419da73a71 100644
--- a/config/locales/forms/en.yml
+++ b/config/locales/forms/en.yml
@@ -42,11 +42,13 @@ en:
edit: Edit
manage: Manage
resend_confirmation: Resend confirmation instructions
+ send_link: Send link
send_one_time_code: Send code
submit:
confirm_change: Confirm change
default: Submit
update: Update
+ upload_photos: Upload photos
confirmation:
show_hdr: Create a strong password
email:
diff --git a/config/locales/forms/es.yml b/config/locales/forms/es.yml
index 2d8553542f4..309a2642399 100644
--- a/config/locales/forms/es.yml
+++ b/config/locales/forms/es.yml
@@ -47,11 +47,13 @@ es:
edit: Editar
manage: Administrar
resend_confirmation: Reenviar instrucciones de confirmación
+ send_link: Enviar enlace
send_one_time_code: Enviar código
submit:
confirm_change: Confirmar cambio
default: Enviar
update: Actualización
+ upload_photos: Subir fotos
confirmation:
show_hdr: Crear una contraseña segura
email:
diff --git a/config/locales/forms/fr.yml b/config/locales/forms/fr.yml
index c4a0b1a0319..396d0c49004 100644
--- a/config/locales/forms/fr.yml
+++ b/config/locales/forms/fr.yml
@@ -48,11 +48,13 @@ fr:
edit: Modifier
manage: Administrer
resend_confirmation: Envoyer les instructions de confirmation de nouveau
+ send_link: Envoyer le lien
send_one_time_code: Envoyer le code
submit:
confirm_change: Confirmer le changement
default: Soumettre
update: Mettre à jour
+ upload_photos: Télécharger des photos
confirmation:
show_hdr: Créez un mot de passe fort
email:
diff --git a/config/locales/image_description/en.yml b/config/locales/image_description/en.yml
index 256abf41038..0ad51b973e4 100644
--- a/config/locales/image_description/en.yml
+++ b/config/locales/image_description/en.yml
@@ -6,6 +6,7 @@ en:
error: Red error x
error_lock: Red error lock
info_question: Blue question mark
+ laptop: Laptop computer
personal_key: Personal key
totp_qrcode: QR code for authenticator app
us_flag: US flag
diff --git a/config/locales/image_description/es.yml b/config/locales/image_description/es.yml
index 2fcd4e59573..16f5ec5b245 100644
--- a/config/locales/image_description/es.yml
+++ b/config/locales/image_description/es.yml
@@ -1,11 +1,12 @@
---
es:
image_description:
- camera_mobile_phone: Cámara parpadeando en un teléfono móvil
+ camera_mobile_phone: Cámara del teléfono móvil que parpadea
delete: Bote de basura rojo
error: x roja de error
error_lock: candado rojo de error
info_question: signo de interrogación azul
+ laptop: Computadora portátil
personal_key: Clave personal
totp_qrcode: Código QR para la aplicación de autenticación
us_flag: Bandera de estados unidos
diff --git a/config/locales/image_description/fr.yml b/config/locales/image_description/fr.yml
index 769d2969d71..2acde6571d7 100644
--- a/config/locales/image_description/fr.yml
+++ b/config/locales/image_description/fr.yml
@@ -1,11 +1,12 @@
---
fr:
image_description:
- camera_mobile_phone: Appareil photo clignotant sur un téléphone mobile
+ camera_mobile_phone: Caméra flash d’un téléphone portable
delete: Poubelle rouge
error: erreur rouge x
error_lock: verrouillage rouge des erreurs
info_question: point d’interrogation bleu
+ laptop: Ordinateur portable
personal_key: Clé personnelle
totp_qrcode: Code QR pour l’application d’authentification
us_flag: Drapeau américain
diff --git a/lib/identity_config.rb b/lib/identity_config.rb
index 73b03b99e33..f4790c68cf1 100644
--- a/lib/identity_config.rb
+++ b/lib/identity_config.rb
@@ -154,6 +154,7 @@ def self.build_store(config_map)
config.add(:doc_auth_attempt_window_in_minutes, type: :integer)
config.add(:doc_auth_client_glare_threshold, type: :integer)
config.add(:doc_auth_client_sharpness_threshold, type: :integer)
+ config.add(:doc_auth_combined_hybrid_handoff_enabled, type: :boolean)
config.add(:doc_auth_enable_presigned_s3_urls, type: :boolean)
config.add(:doc_auth_error_dpi_threshold, type: :integer)
config.add(:doc_auth_error_glare_threshold, type: :integer)
diff --git a/spec/features/idv/doc_auth/upload_step_spec.rb b/spec/features/idv/doc_auth/upload_step_spec.rb
index 6f12ad2fd02..47f00985e9a 100644
--- a/spec/features/idv/doc_auth/upload_step_spec.rb
+++ b/spec/features/idv/doc_auth/upload_step_spec.rb
@@ -3,88 +3,281 @@
feature 'doc auth upload step' do
include IdvStepHelper
include DocAuthHelper
+ include ActionView::Helpers::DateHelper
- let(:fake_analytics) { FakeAnalytics.new }
- let(:fake_attempts_tracker) { IrsAttemptsApiTrackingHelper::FakeAttemptsTracker.new }
+ context 'with combined hybrid handoff disabled', js: true do
+ let(:fake_analytics) { FakeAnalytics.new }
+ let(:fake_attempts_tracker) { IrsAttemptsApiTrackingHelper::FakeAttemptsTracker.new }
- before do
- sign_in_and_2fa_user
- allow_any_instance_of(Idv::Steps::UploadStep).to receive(:mobile_device?).and_return(true)
- complete_doc_auth_steps_before_upload_step
- allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics)
- allow_any_instance_of(ApplicationController).to receive(:irs_attempts_api_tracker).
- and_return(fake_attempts_tracker)
- end
-
- context 'on a mobile device' do
before do
- allow(BrowserCache).to receive(:parse).and_return(mobile_device)
+ allow(IdentityConfig.store).
+ to receive(:doc_auth_combined_hybrid_handoff_enabled).
+ and_return(false)
+ sign_in_and_2fa_user
+ allow_any_instance_of(Idv::Steps::UploadStep).to receive(:mobile_device?).and_return(true)
+ complete_doc_auth_steps_before_upload_step
+ allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics)
+ allow_any_instance_of(ApplicationController).to receive(:irs_attempts_api_tracker).
+ and_return(fake_attempts_tracker)
end
- it 'proceeds to send link via email page when user chooses to upload from computer' do
- expect(fake_attempts_tracker).to receive(
- :idv_document_upload_method_selected,
- ).with({ upload_method: 'desktop' })
+ context 'on a desktop device' do
+ before do
+ allow_any_instance_of(Idv::Steps::UploadStep).to receive(:mobile_device?).and_return(false)
+ end
- expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id'))
+ it 'proceeds to document capture when user chooses to upload from computer' do
+ expect(fake_attempts_tracker).to receive(
+ :idv_document_upload_method_selected,
+ ).with({ upload_method: 'desktop' })
- click_on t('doc_auth.info.upload_computer_link')
+ expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id'))
- expect(page).to have_current_path(idv_doc_auth_email_sent_step)
- expect(fake_analytics).to have_logged_event(
- 'IdV: doc auth upload submitted',
- hash_including(step: 'upload', destination: :email_sent),
- )
- end
+ click_on t('doc_auth.info.upload_computer_link')
- it 'proceeds to document capture when user chooses to use phone' do
- expect(fake_attempts_tracker).to receive(
- :idv_document_upload_method_selected,
- ).with({ upload_method: 'mobile' })
+ expect(page).to have_current_path(idv_doc_auth_document_capture_step)
+ expect(fake_analytics).to have_logged_event(
+ 'IdV: doc auth upload submitted',
+ hash_including(step: 'upload', destination: :document_capture),
+ )
+ end
- click_on t('doc_auth.buttons.use_phone')
+ it 'proceeds to send link to phone page when user chooses to use phone' do
+ expect(fake_attempts_tracker).to receive(
+ :idv_document_upload_method_selected,
+ ).with({ upload_method: 'mobile' })
- expect(page).to have_current_path(idv_doc_auth_document_capture_step)
- expect(fake_analytics).to have_logged_event(
- 'IdV: doc auth upload submitted',
- hash_including(step: 'upload', destination: :document_capture),
- )
+ click_on t('doc_auth.buttons.use_phone')
+
+ expect(page).to have_current_path(idv_doc_auth_send_link_step)
+ expect(fake_analytics).to have_logged_event(
+ 'IdV: doc auth upload submitted',
+ hash_including(step: 'upload', destination: :send_link),
+ )
+ end
end
end
- context 'on a desktop device' do
+ context 'with combined hybrid handoff enabled' do
+ let(:fake_analytics) { FakeAnalytics.new }
+ let(:fake_attempts_tracker) { IrsAttemptsApiTrackingHelper::FakeAttemptsTracker.new }
+ let(:document_capture_session) { DocumentCaptureSession.create! }
+ let(:idv_send_link_max_attempts) { 3 }
+ let(:idv_send_link_attempt_window_in_minutes) do
+ IdentityConfig.store.idv_send_link_attempt_window_in_minutes
+ end
+
before do
- allow_any_instance_of(Idv::Steps::UploadStep).to receive(:mobile_device?).and_return(false)
+ allow(IdentityConfig.store).
+ to receive(:doc_auth_combined_hybrid_handoff_enabled).
+ and_return(true)
+ sign_in_and_2fa_user
+ allow_any_instance_of(Idv::Steps::UploadStep).to receive(:mobile_device?).and_return(true)
+ complete_doc_auth_steps_before_upload_step
+ allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics)
+ allow_any_instance_of(ApplicationController).to receive(:irs_attempts_api_tracker).
+ and_return(fake_attempts_tracker)
end
- it 'proceeds to document capture when user chooses to upload from computer' do
- expect(fake_attempts_tracker).to receive(
- :idv_document_upload_method_selected,
- ).with({ upload_method: 'desktop' })
+ context 'on a desktop device', js: true do
+ before do
+ allow_any_instance_of(Idv::Steps::UploadStep).to receive(:mobile_device?).and_return(false)
+ end
- expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id'))
+ it 'proceeds to document capture when user chooses to upload from computer' do
+ expect(fake_attempts_tracker).to receive(
+ :idv_document_upload_method_selected,
+ ).with({ upload_method: 'desktop' })
- click_on t('doc_auth.info.upload_computer_link')
+ expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id'))
- expect(page).to have_current_path(idv_doc_auth_document_capture_step)
- expect(fake_analytics).to have_logged_event(
- 'IdV: doc auth upload submitted',
- hash_including(step: 'upload', destination: :document_capture),
- )
- end
+ click_upload_from_computer
+
+ expect(page).to have_current_path(idv_doc_auth_document_capture_step)
+ expect(fake_analytics).to have_logged_event(
+ 'IdV: doc auth upload submitted',
+ hash_including(step: 'upload', destination: :document_capture),
+ )
+ end
+
+ it "defaults phone to user's 2fa phone number" do
+ field = page.find_field(t('two_factor_authentication.phone_label'))
+ expect(field.value).to eq('(202) 555-1212')
+ end
+
+ it 'proceeds to link sent page when user chooses to use phone' do
+ expect(fake_attempts_tracker).to receive(
+ :idv_document_upload_method_selected,
+ ).with({ upload_method: 'mobile' })
+
+ click_send_link
+
+ expect(page).to have_current_path(idv_doc_auth_link_sent_step)
+ expect(fake_analytics).to have_logged_event(
+ 'IdV: doc auth upload submitted',
+ hash_including(step: 'upload', destination: :link_sent),
+ )
+ end
+
+ it 'proceeds to the next page with valid info' do
+ expect(fake_attempts_tracker).to receive(
+ :idv_phone_upload_link_sent,
+ ).with(
+ success: true,
+ phone_number: '+1 415-555-0199',
+ failure_reason: nil,
+ )
+
+ expect(Telephony).to receive(:send_doc_auth_link).
+ with(hash_including(to: '+1 415-555-0199')).
+ and_call_original
+
+ expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_id'))
+
+ fill_in :doc_auth_phone, with: '415-555-0199'
+ click_send_link
+
+ expect(page).to have_current_path(idv_doc_auth_link_sent_step)
+ end
+
+ it 'does not proceed to the next page with invalid info' do
+ fill_in :doc_auth_phone, with: ''
+ click_send_link
+
+ expect(page).to have_current_path(idv_doc_auth_upload_step, ignore_query: true)
+ end
+
+ it 'sends a link that does not contain any underscores' do
+ # because URLs with underscores sometimes get messed up by carriers
+ expect(Telephony).to receive(:send_doc_auth_link).and_wrap_original do |impl, config|
+ expect(config[:link]).to_not include('_')
+
+ impl.call(**config)
+ end
+
+ fill_in :doc_auth_phone, with: '415-555-0199'
+ click_send_link
+
+ expect(page).to have_current_path(idv_doc_auth_link_sent_step)
+ end
+
+ it 'does not proceed if Telephony raises an error', js: true do
+ expect(fake_attempts_tracker).to receive(:idv_phone_upload_link_sent).with(
+ success: false,
+ phone_number: '+1 225-555-1000',
+ failure_reason: { telephony: ['TelephonyError'] },
+ )
+ fill_in :doc_auth_phone, with: '225-555-1000'
+ click_send_link
+
+ expect(page).to have_current_path(idv_doc_auth_upload_step, ignore_query: true)
+ expect(page).to have_content I18n.t('telephony.error.friendly_message.generic')
+ end
+
+ it 'displays error if user selects a country to which we cannot send SMS', js: true do
+ page.find('div[aria-label="Country code"]').click
+ within(page.find('.iti__flag-container', visible: :all)) do
+ find('span', text: 'Sri Lanka').click
+ end
+ focused_input = page.find('.phone-input__number:focus')
+
+ error_message_id = focused_input[:'aria-describedby']&.split(' ')&.find do |id|
+ page.has_css?(".usa-error-message##{id}")
+ end
+ expect(error_message_id).to_not be_empty
+
+ error_message = page.find_by_id(error_message_id)
+ expect(error_message).to have_content(
+ t(
+ 'two_factor_authentication.otp_delivery_preference.sms_unsupported',
+ location: 'Sri Lanka',
+ ),
+ )
+ click_send_link
+ expect(page.find(':focus')).to match_css('.phone-input__number')
+ end
+
+ it 'throttles sending the link', js: true do
+ user = user_with_2fa
+ sign_in_and_2fa_user(user)
+ complete_doc_auth_steps_before_upload_step
+ timeout = distance_of_time_in_words(
+ Throttle.attempt_window_in_minutes(:idv_send_link).minutes,
+ )
+ allow(IdentityConfig.store).to receive(:idv_send_link_max_attempts).
+ and_return(idv_send_link_max_attempts)
+
+ expect(fake_attempts_tracker).to receive(
+ :idv_phone_send_link_rate_limited,
+ ).with({ phone_number: '+1 415-555-0199' })
+
+ freeze_time do
+ (idv_send_link_max_attempts - 1).times do
+ expect(page).to_not have_content(
+ I18n.t('errors.doc_auth.send_link_throttle', timeout: timeout),
+ )
+
+ fill_in :doc_auth_phone, with: '415-555-0199'
+ click_send_link
+
+ expect(page).to have_current_path(idv_doc_auth_link_sent_step)
+
+ click_doc_auth_back_link
+ end
+
+ fill_in :doc_auth_phone, with: '415-555-0199'
+
+ click_send_link
+ expect(page).to have_current_path(idv_doc_auth_upload_step, ignore_query: true)
+ expect(page).to have_content(
+ I18n.t(
+ 'errors.doc_auth.send_link_throttle',
+ timeout: timeout,
+ ),
+ )
+ end
+ expect(fake_analytics).to have_logged_event(
+ 'Throttler Rate Limit Triggered',
+ throttle_type: :idv_send_link,
+ )
+
+ # Manual expiration is needed for now since the Throttle uses
+ # Redis ttl instead of expiretime
+ Throttle.new(throttle_type: :idv_send_link, user: user).reset!
+ travel_to(Time.zone.now + idv_send_link_attempt_window_in_minutes.minutes) do
+ fill_in :doc_auth_phone, with: '415-555-0199'
+ click_send_link
+ expect(page).to have_current_path(idv_doc_auth_link_sent_step)
+ end
+ end
+
+ it 'includes expected URL parameters' do
+ allow_any_instance_of(Flow::BaseFlow).to receive(:flow_session).and_return(
+ document_capture_session_uuid: document_capture_session.uuid,
+ )
+
+ expect(Telephony).to receive(:send_doc_auth_link).and_wrap_original do |impl, config|
+ params = Rack::Utils.parse_nested_query URI(config[:link]).query
+ expect(params).to eq('document-capture-session' => document_capture_session.uuid)
+
+ impl.call(**config)
+ end
+
+ fill_in :doc_auth_phone, with: '415-555-0199'
+ click_send_link
+ end
- it 'proceeds to send link to phone page when user chooses to use phone' do
- expect(fake_attempts_tracker).to receive(
- :idv_document_upload_method_selected,
- ).with({ upload_method: 'mobile' })
+ it 'sets requested_at on the capture session' do
+ allow_any_instance_of(Flow::BaseFlow).to receive(:flow_session).and_return(
+ document_capture_session_uuid: document_capture_session.uuid,
+ )
- click_on t('doc_auth.buttons.use_phone')
+ fill_in :doc_auth_phone, with: '415-555-0199'
+ click_send_link
- expect(page).to have_current_path(idv_doc_auth_send_link_step)
- expect(fake_analytics).to have_logged_event(
- 'IdV: doc auth upload submitted',
- hash_including(step: 'upload', destination: :send_link),
- )
+ document_capture_session.reload
+ expect(document_capture_session).to have_attributes(requested_at: a_kind_of(Time))
+ end
end
end
end
diff --git a/spec/services/idv/steps/upload_step_spec.rb b/spec/services/idv/steps/upload_step_spec.rb
new file mode 100644
index 00000000000..5d3beba11de
--- /dev/null
+++ b/spec/services/idv/steps/upload_step_spec.rb
@@ -0,0 +1,100 @@
+require 'rails_helper'
+
+describe Idv::Steps::UploadStep do
+ context 'with combined hybrid handoff enabled' do
+ let(:user) { build(:user) }
+
+ let(:service_provider) do
+ create(
+ :service_provider,
+ issuer: 'http://sp.example.com',
+ app_id: '123',
+ )
+ end
+
+ let(:request) do
+ double(
+ 'request',
+ remote_ip: Faker::Internet.ip_v4_address,
+ headers: { 'X-Amzn-Trace-Id' => amzn_trace_id },
+ )
+ end
+
+ let(:params) do
+ ActionController::Parameters.new(
+ {
+ doc_auth: { phone: '(201) 555-1212' },
+ },
+ )
+ end
+
+ let(:controller) do
+ instance_double(
+ 'controller',
+ session: { sp: { issuer: service_provider.issuer } },
+ params: params,
+ current_user: user,
+ current_sp: service_provider,
+ analytics: FakeAnalytics.new,
+ url_options: {},
+ request: request,
+ )
+ end
+
+ let(:amzn_trace_id) { SecureRandom.uuid }
+
+ let(:pii_from_doc) do
+ {
+ ssn: '123-45-6789',
+ first_name: 'bob',
+ }
+ end
+
+ let(:flow) do
+ Idv::Flows::DocAuthFlow.new(controller, {}, 'idv/doc_auth').tap do |flow|
+ flow.flow_session = { pii_from_doc: pii_from_doc }
+ end
+ end
+
+ let(:irs_attempts_api_tracker) do
+ IrsAttemptsApiTrackingHelper::FakeAttemptsTracker.new
+ end
+
+ subject(:step) do
+ Idv::Steps::SendLinkStep.new(flow)
+ end
+
+ before do
+ allow(controller).to receive(:irs_attempts_api_tracker).
+ and_return(irs_attempts_api_tracker)
+ allow(IdentityConfig.store).
+ to receive(:doc_auth_combined_hybrid_handoff_enabled).
+ and_return(true)
+ end
+
+ describe '#extra_view_variables' do
+ it 'includes form' do
+ expect(step.extra_view_variables).to include(
+ {
+ idv_phone_form: be_an_instance_of(Idv::PhoneForm),
+ },
+ )
+ end
+ end
+
+ describe 'the return value from #call' do
+ let(:response) { step.call }
+
+ it 'includes the telephony response' do
+ expect(response.extra[:telephony_response]).to eq(
+ {
+ errors: {},
+ message_id: 'fake-message-id',
+ request_id: 'fake-message-request-id',
+ success: true,
+ },
+ )
+ end
+ end
+ end
+end
diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb
index 110d19d6f39..ce3708d3b5d 100644
--- a/spec/support/features/doc_auth_helper.rb
+++ b/spec/support/features/doc_auth_helper.rb
@@ -35,6 +35,14 @@ def click_doc_auth_back_link
click_on '‹ ' + t('forms.buttons.back')
end
+ def click_send_link
+ click_on t('forms.buttons.send_link')
+ end
+
+ def click_upload_from_computer
+ click_on t('forms.buttons.upload_photos')
+ end
+
def idv_doc_auth_welcome_step
idv_doc_auth_step_path(step: :welcome)
end