+<%= render IconListComponent.new(icon: :check_circle, color: :success, class: 'border-bottom border-primary-light') do |c| %>
+ <% c.with_item(class: 'padding-y-2 border-top border-primary-light') do %>
+
- <%= button_to(user_authorization_confirmation_path, class: 'usa-button usa-button--big usa-button--wide', method: :post) { t('user_authorization_confirmation.continue') } %>
-
+
+ <%= render ButtonComponent.new(
+ action: ->(**tag_options, &block) do
+ button_to(user_authorization_confirmation_path, method: :post, **tag_options, &block)
+ end,
+ big: true,
+ wide: true,
+ ).with_content(t('user_authorization_confirmation.continue')) %>
+
<%= t('user_authorization_confirmation.or') %>
-
- <%= button_to(reset_user_authorization_path, class: 'usa-button usa-button--big usa-button--wide', method: :delete) { t('user_authorization_confirmation.sign_in') } %>
-
+ <%= render ButtonComponent.new(
+ action: ->(**tag_options, &block) do
+ button_to(reset_user_authorization_path, method: :delete, **tag_options, &block)
+ end,
+ big: true,
+ wide: true,
+ ).with_content(t('user_authorization_confirmation.sign_in')) %>
diff --git a/bin/aamva-test-cert b/bin/aamva-test-cert
index 0d5ff682dae..fe66d0079db 100755
--- a/bin/aamva-test-cert
+++ b/bin/aamva-test-cert
@@ -3,38 +3,51 @@
ENV['LOGIN_TASK_LOG_LEVEL'] ||= 'warn'
require_relative '../config/environment.rb'
require 'aamva_test'
-
-auth_url = nil
-verification_url = nil
-
-parser = OptionParser.new do |opts|
- opts.banner = <<~EOM
- Usage: #{$PROGRAM_NAME} --auth-url=AUTH_URL --verification-url=VERIFICATION_URL
-
- Tests AAMVA certificate against cert environment
-
- Options:
- EOM
-
- opts.on('--auth-url=AUTH_URL', 'sets the auth url') do |url|
- auth_url = url
- end
-
- opts.on('--verification-url=VERIFICATION_URL', 'sets the verification url') do |url|
- verification_url = url
- end
-
- opts.on('--help', 'prints this help message') do
- puts opts
- exit 0
+require 'optparse'
+require 'pp'
+
+class AamvaTestCert
+ def run(out: STDOUT, argv: ARGV)
+ auth_url = nil
+ verification_url = nil
+ show_help = false
+
+ parser = OptionParser.new do |opts|
+ opts.banner = <<~EOM
+ Usage: #{$PROGRAM_NAME} --auth-url=AUTH_URL --verification-url=VERIFICATION_URL
+
+ Tests AAMVA certificate against cert environment
+
+ Options:
+ EOM
+
+ opts.on('--auth-url=AUTH_URL', 'sets the auth url') do |url|
+ auth_url = url
+ end
+
+ opts.on('--verification-url=VERIFICATION_URL', 'sets the verification url') do |url|
+ verification_url = url
+ end
+
+ opts.on('--help', 'prints this help message') do
+ show_help = true
+ end
+ end
+
+ parser.parse!(argv)
+
+ if show_help
+ out.puts parser
+ exit 0
+ elsif !auth_url || !verification_url
+ out.puts parser
+ exit 1
+ else
+ PP.pp(AamvaTest.new.test_cert(auth_url:, verification_url:), out)
+ end
end
end
-parser.parse!(ARGV)
-
-if !auth_url || !verification_url
- puts parser
- exit 1
+if $PROGRAM_NAME == __FILE__
+ AamvaTestCert.new.run
end
-
-puts AamvaTest.new.test_cert(auth_url:, verification_url:)
diff --git a/bin/aamva-test-connectivity b/bin/aamva-test-connectivity
index 9bf5c4cd461..bdb20e77ec1 100755
--- a/bin/aamva-test-connectivity
+++ b/bin/aamva-test-connectivity
@@ -4,4 +4,4 @@ ENV['LOGIN_TASK_LOG_LEVEL'] ||= 'warn'
require_relative '../config/environment.rb'
require 'aamva_test'
-puts AamvaTest.new.test_connectivity
+p AamvaTest.new.test_connectivity
diff --git a/config/initializers/job_configurations.rb b/config/initializers/job_configurations.rb
index 3c33cbf082f..ec51f0fdac9 100644
--- a/config/initializers/job_configurations.rb
+++ b/config/initializers/job_configurations.rb
@@ -188,6 +188,11 @@
cron: cron_24h,
args: -> { [14.days.ago] },
},
+ # Expire old GPO profiles
+ expire_gpo_profiles: {
+ class: 'GpoExpirationJob',
+ cron: cron_24h,
+ },
# Monthly report checking in on key metrics
monthly_key_metrics_report: {
class: 'Reports::MonthlyKeyMetricsReport',
diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb
index 99f7a8db1ad..5016c76171e 100644
--- a/config/initializers/rack_attack.rb
+++ b/config/initializers/rack_attack.rb
@@ -257,6 +257,7 @@ def headers
) do |_name, _start, _finish, _request_id, payload|
req = payload[:request]
user = req.env['warden'].user || AnonymousUser.new
- analytics = Analytics.new(user: user, request: req, session: {}, sp: nil)
+ sp = req.env.fetch('rack.session', {}).dig('sp', 'issuer')
+ analytics = Analytics.new(user: user, request: req, session: {}, sp: sp)
analytics.rate_limit_triggered(type: req.env['rack.attack.matched'])
end
diff --git a/config/locales/in_person_proofing/en.yml b/config/locales/in_person_proofing/en.yml
index 2f91302f5e5..a0044835ed7 100644
--- a/config/locales/in_person_proofing/en.yml
+++ b/config/locales/in_person_proofing/en.yml
@@ -131,13 +131,13 @@ en:
state_id_jurisdiction_hint: This is the state that issued your ID
state_id_jurisdiction_prompt: '- Select -'
state_id_number: ID number
- state_id_number_hint_html: "May include letters, numbers, and the following
- symbols:
spaces, forward
- slashes,/ asterisks,*
-
dashes-"
+ state_id_number_hint: 'May include letters, numbers, and the following symbols:'
+ state_id_number_hint_asterisks: asterisks
+ state_id_number_hint_dashes: dashes
+ state_id_number_hint_forward_slashes: forward slashes
+ state_id_number_hint_spaces: spaces
+ state_id_number_texas_hint: This is the 8-digit number on your ID. Enter only
+ numbers in this field.
zipcode: ZIP Code
headings:
address: Enter your current residential address
diff --git a/config/locales/in_person_proofing/es.yml b/config/locales/in_person_proofing/es.yml
index 855cb080701..fbd23201e29 100644
--- a/config/locales/in_person_proofing/es.yml
+++ b/config/locales/in_person_proofing/es.yml
@@ -143,13 +143,13 @@ es:
state_id_jurisdiction_hint: Este es el estado que emitió su identificación
state_id_jurisdiction_prompt: '- Seleccione -'
state_id_number: Número de identidad
- state_id_number_hint_html: "Puede incluir letras, números y los siguientes
- sÃmbolos:
espacios, barras
- diagonales, / asteriscos, * guiones-"
+ state_id_number_hint: 'Puede incluir letras, números y los siguientes sÃmbolos:'
+ state_id_number_hint_asterisks: 'asteriscos'
+ state_id_number_hint_dashes: guiones
+ state_id_number_hint_forward_slashes: 'barras diagonal'
+ state_id_number_hint_spaces: 'espacios'
+ state_id_number_texas_hint: Este es el número de 8 dÃgitos de su ID. Introduzca
+ sólo números en este campo.
zipcode: Código postal
headings:
address: Ingresa tu domicilio actual
diff --git a/config/locales/in_person_proofing/fr.yml b/config/locales/in_person_proofing/fr.yml
index 91657bdacb3..d73e40a2ef3 100644
--- a/config/locales/in_person_proofing/fr.yml
+++ b/config/locales/in_person_proofing/fr.yml
@@ -143,13 +143,13 @@ fr:
state_id_jurisdiction_hint: Il s’agit de l’État qui a émis votre pièce d’identité
state_id_jurisdiction_prompt: '- Sélectionnez -'
state_id_number: Numéro d’identification
- state_id_number_hint_html: "Il peut s’agir de lettres, de chiffres et des
- symboles suivants:
des espaces, des barres
- obliques, / des astérisques, * des
- tirets-"
+ state_id_number_hint: 'Il peut s’agir de lettres, de chiffres et des symboles suivants:'
+ state_id_number_hint_asterisks: 'des astérisques'
+ state_id_number_hint_dashes: 'des tirets'
+ state_id_number_hint_forward_slashes: 'des barres obliques'
+ state_id_number_hint_spaces: 'des espaces'
+ state_id_number_texas_hint: Il s’agit du numéro à huit chiffres figurant sur
+ votre carte d’identité. Entrez uniquement des chiffres dans ce champ.
zipcode: Code postal
headings:
address: Indiquez votre adresse résidentielle actuelle
diff --git a/config/locales/two_factor_authentication/en.yml b/config/locales/two_factor_authentication/en.yml
index 13a73ae2513..bac52964f9d 100644
--- a/config/locales/two_factor_authentication/en.yml
+++ b/config/locales/two_factor_authentication/en.yml
@@ -163,8 +163,6 @@ en:
(toll) phone numbers.
piv_cac: Government employee ID
piv_cac_info: PIV/CAC cards for government and military employees. Desktop only.
- sms: Text message / SMS
- voice: Phone call
webauthn: Security key
webauthn_info: A physical device, often shaped like a USB drive, that you plug
in to your device.
diff --git a/config/locales/two_factor_authentication/es.yml b/config/locales/two_factor_authentication/es.yml
index 2f079bd6027..c2a30013de9 100644
--- a/config/locales/two_factor_authentication/es.yml
+++ b/config/locales/two_factor_authentication/es.yml
@@ -173,8 +173,6 @@ es:
piv_cac: Identificación de empleado gubernamental
piv_cac_info: Credenciales PIV/CAC para empleados gubernamentales y del
ejército. Únicamente versión de escritorio.
- sms: Mensaje de texto / SMS
- voice: Llamada telefónica
webauthn: Clave de seguridad
webauthn_info: Un dispositivo fÃsico que suele tener la forma de una unidad USB
y se conecta a su dispositivo.
diff --git a/config/locales/two_factor_authentication/fr.yml b/config/locales/two_factor_authentication/fr.yml
index ce17a3ce3a3..52dee824d9f 100644
--- a/config/locales/two_factor_authentication/fr.yml
+++ b/config/locales/two_factor_authentication/fr.yml
@@ -182,8 +182,6 @@ fr:
piv_cac: Carte d’identification des employés du gouvernement
piv_cac_info: Cartes PIV/CAC pour les fonctionnaires et les militaires. Bureau
uniquement.
- sms: SMS
- voice: Appel téléphonique
webauthn: Clef de sécurité
webauthn_info: Un appareil physique, souvent en forme de clé USB, que vous
branchez sur votre appareil.
diff --git a/docs/frontend.md b/docs/frontend.md
index fe85d57672b..af4f5c431a4 100644
--- a/docs/frontend.md
+++ b/docs/frontend.md
@@ -137,7 +137,7 @@ See [`@18f/identity-i18n` package documentation](../app/javascript/packages/i18n
See [`@18f/identity-analytics` package documentation][analytics_package] for code examples detailing
how to track an event in JavaScript.
-Any event logged from the frontend must be added to the `EVENT_MAP` allowlist in [`FrontendLogController`][frontend_log_controller.rb].
+Any event logged from the frontend must be added to the `ALLOWED_EVENTS` allowlist in [`FrontendLogController`][frontend_log_controller.rb].
This mapping associates the event name logged from the frontend with the corresponding method from
[AnalyticsEvents][analytics_events.rb] to be called. All properties will be passed automatically to
the event from the frontend as long as they are defined in the method argument signature.
@@ -147,16 +147,13 @@ in the frontend, such as an A/B test bucket descriptor. In these scenarios, you
1. Add the value to the page markup, such as through an [HTML `data-` attribute][data_attributes],
and reference that attribute in JavaScript.
-2. Define the mapped value in `EVENT_MAP` to a service class, such as how [frontend error logging][frontend_error_logging]
-is implemented.
-3. Implement a mixin to intercept and override the default behavior of an analytics event, such as
+2. Implement a mixin to intercept and override the default behavior of an analytics event, such as
how [`Idv::AnalyticsEventEnhancer`][analytics_events_enhancer.rb] is implemented.
[analytics_package]: ../app/javascript/packages/analytics/README.md
[frontend_log_controller.rb]: https://github.com/18F/identity-idp/blob/main/app/controllers/frontend_log_controller.rb
[analytics_events.rb]: https://github.com/18F/identity-idp/blob/main/app/services/analytics_events.rb
[data_attributes]: https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
-[frontend_error_logging]: https://github.com/18F/identity-idp/blob/9c17164c0b8d9b4aefad74dde1a521c111b53aac/app/controllers/frontend_log_controller.rb#L14
[analytics_events_enhancer.rb]: https://github.com/18F/identity-idp/blob/main/app/services/idv/analytics_events_enhancer.rb
## Components
diff --git a/lib/tasks/backfill_gpo_expiration.rake b/lib/tasks/backfill_gpo_expiration.rake
deleted file mode 100644
index 59d1db6f9d0..00000000000
--- a/lib/tasks/backfill_gpo_expiration.rake
+++ /dev/null
@@ -1,69 +0,0 @@
-namespace :profiles do
- desc 'Backfill the gpo_verification_expired_at value'
-
- ##
- # Usage:
- #
- # Print pending updates
- # bundle exec rake profiles:backfill_gpo_expiration > profiles.csv
- #
- # Commit updates
- # bundle exec rake profiles:backfill_gpo_expiration UPDATE_PROFILES=true > profiles.csv
- #
- task backfill_gpo_expiration: :environment do |_task, _args|
- min_profile_age = (ENV['MIN_PROFILE_AGE_IN_DAYS'].to_i || 100).days
- update_profiles = ENV['UPDATE_PROFILES'] == 'true'
- statement_timeout = ENV['STATEMENT_TIMEOUT_IN_SECONDS'].to_i.seconds || 10.minutes
-
- count = 0
- earliest = nil
- latest = nil
-
- on_profile_expired = ->(profile:, gpo_verification_pending_at:) do
- count += 1
-
- earliest = [earliest, gpo_verification_pending_at].compact.min
- latest = [latest, gpo_verification_pending_at].compact.max
-
- puts "#{profile.id},#{gpo_verification_pending_at.iso8601}"
-
- if count % 100 == 0
- verb = update_profiles ? 'Expired' : 'Found'
- warn "#{verb} #{count} profiles (earliest: #{earliest}, latest: #{latest})"
- end
- end
-
- job = GpoExpirationJob.new(on_profile_expired: on_profile_expired)
-
- job.perform(
- now: Time.zone.now,
- min_profile_age: min_profile_age,
- dry_run: !update_profiles,
- statement_timeout: statement_timeout,
- )
- end
-
- ##
- # Usage:
- #
- # Rollback the above:
- #
- # bundle exec rake profiles:rollback_backfill_gpo_expiration < profiles.csv
- #
- task rollback_backfill_gpo_expiration: :environment do |_task, _args|
- profile_data = STDIN.read.split("\n").map do |profile_row|
- profile_row.split(',')
- end
-
- warn "Updating #{profile_data.count} records"
-
- profile_data.each do |profile_datum|
- profile_id, gpo_verification_pending_at = profile_datum
- Profile.where(id: profile_id).update!(
- gpo_verification_pending_at: Time.zone.parse(gpo_verification_pending_at),
- gpo_verification_expired_at: nil,
- )
- warn profile_id
- end
- end
-end
diff --git a/package.json b/package.json
index 81f6639a0bb..e0d12283ae6 100644
--- a/package.json
+++ b/package.json
@@ -79,7 +79,7 @@
"mocha": "^10.0.0",
"mq-polyfill": "^1.1.8",
"msw": "^1.3.2",
- "prettier": "^3.0.3",
+ "prettier": "^3.1.0",
"quibble": "^0.6.17",
"react-test-renderer": "^17.0.2",
"sinon": "^14.0.0",
diff --git a/spec/bin/aamva-test-cert_spec.rb b/spec/bin/aamva-test-cert_spec.rb
new file mode 100644
index 00000000000..12658ac3abc
--- /dev/null
+++ b/spec/bin/aamva-test-cert_spec.rb
@@ -0,0 +1,54 @@
+require 'rails_helper'
+load Rails.root.join('bin/aamva-test-cert')
+
+RSpec.describe AamvaTestCert do
+ let(:fake_aamva_test) do
+ Class.new do
+ def test_cert(auth_url:, verification_url:)
+ [auth_url, verification_url]
+ end
+ end
+ end
+
+ before { stub_const('AamvaTest', fake_aamva_test) }
+
+ subject(:instance) { AamvaTestCert.new }
+
+ describe '#run' do
+ subject(:run) { instance.run(out: out, argv: argv) }
+ let(:out) { StringIO.new('') }
+ let(:argv) { [] }
+
+ context 'missing arguments' do
+ let(:argv) { [] }
+
+ it 'exits uncleanly' do
+ expect(instance).to receive(:exit).with(1)
+
+ run
+ end
+ end
+
+ context '--help' do
+ let(:argv) { %w[--help] }
+
+ it 'exits cleanly and prints help' do
+ expect(instance).to receive(:exit).with(0)
+
+ run
+
+ expect(out.string).to include('Usage:')
+ end
+ end
+
+ context 'required arguments' do
+ let(:argv) { %w[--auth-url a --verification-url b] }
+
+ it 'pretty-prints the result' do
+ run
+
+ expect(JSON.parse(out.string)).to eq(%w[a b])
+ end
+ end
+ end
+end
diff --git a/spec/components/icon_list_component_spec.rb b/spec/components/icon_list_component_spec.rb
index b414b631c23..599ede1b38c 100644
--- a/spec/components/icon_list_component_spec.rb
+++ b/spec/components/icon_list_component_spec.rb
@@ -16,9 +16,11 @@
end
context 'with additional tag options' do
- it 'applies tag options to wrapper element' do
- rendered = render_inline IconListComponent.new(class: 'custom-class', data: { foo: 'bar' })
+ subject(:rendered) do
+ render_inline IconListComponent.new(class: 'custom-class', data: { foo: 'bar' })
+ end
+ it 'applies tag options to wrapper element' do
expect(rendered).to have_css('.usa-icon-list.custom-class[data-foo="bar"]')
end
end
@@ -65,5 +67,17 @@
expect(rendered).to have_css('.usa-icon use[href$=".svg#cancel"]', count: 1)
end
end
+
+ context 'with additional tag options on item' do
+ subject(:rendered) do
+ render_inline IconListComponent.new(icon: :cancel) do |c|
+ c.with_item(class: 'custom-class', data: { foo: 'bar' }) { 'First' }
+ end
+ end
+
+ it 'applies tag options to wrapper element' do
+ expect(rendered).to have_css('.usa-icon-list__item.custom-class[data-foo="bar"]')
+ end
+ end
end
end
diff --git a/spec/controllers/account_reset/cancel_controller_spec.rb b/spec/controllers/account_reset/cancel_controller_spec.rb
index 488f187ad25..41677ed6cd4 100644
--- a/spec/controllers/account_reset/cancel_controller_spec.rb
+++ b/spec/controllers/account_reset/cancel_controller_spec.rb
@@ -39,7 +39,7 @@
success: false,
errors: { token: [t('errors.account_reset.cancel_token_invalid', app_name: APP_NAME)] },
error_details: {
- token: [t('errors.account_reset.cancel_token_invalid', app_name: APP_NAME)],
+ token: { cancel_token_invalid: true },
},
user_id: 'anonymous-uuid',
}
@@ -55,7 +55,7 @@
analytics_hash = {
success: false,
errors: { token: [t('errors.account_reset.cancel_token_missing', app_name: APP_NAME)] },
- error_details: { token: [:blank] },
+ error_details: { token: { blank: true } },
user_id: 'anonymous-uuid',
}
@@ -100,7 +100,7 @@
success: false,
errors: { token: [t('errors.account_reset.cancel_token_invalid', app_name: APP_NAME)] },
error_details: {
- token: [t('errors.account_reset.cancel_token_invalid', app_name: APP_NAME)],
+ token: { cancel_token_invalid: true },
},
}
expect(@analytics).to receive(:track_event).
diff --git a/spec/controllers/account_reset/delete_account_controller_spec.rb b/spec/controllers/account_reset/delete_account_controller_spec.rb
index 1f02030e28b..4f147b4ddf9 100644
--- a/spec/controllers/account_reset/delete_account_controller_spec.rb
+++ b/spec/controllers/account_reset/delete_account_controller_spec.rb
@@ -41,7 +41,7 @@
user_id: 'anonymous-uuid',
success: false,
errors: invalid_token_error,
- error_details: invalid_token_error,
+ error_details: { token: { granted_token_invalid: true } },
mfa_method_counts: {},
pii_like_keypaths: [[:mfa_method_counts, :phone]],
account_age_in_days: 0,
@@ -60,7 +60,7 @@
user_id: 'anonymous-uuid',
success: false,
errors: { token: [t('errors.account_reset.granted_token_missing', app_name: APP_NAME)] },
- error_details: { token: [:blank] },
+ error_details: { token: { blank: true } },
mfa_method_counts: {},
pii_like_keypaths: [[:mfa_method_counts, :phone]],
account_age_in_days: 0,
@@ -86,9 +86,7 @@
user_id: user.uuid,
success: false,
errors: { token: [t('errors.account_reset.granted_token_expired', app_name: APP_NAME)] },
- error_details: {
- token: [t('errors.account_reset.granted_token_expired', app_name: APP_NAME)],
- },
+ error_details: { token: { granted_token_expired: true } },
mfa_method_counts: {},
pii_like_keypaths: [[:mfa_method_counts, :phone]],
account_age_in_days: 2,
@@ -114,7 +112,7 @@
user_id: 'anonymous-uuid',
success: false,
errors: invalid_token_error,
- error_details: invalid_token_error,
+ error_details: { token: { granted_token_invalid: true } },
}
expect(@analytics).to receive(:track_event).
with('Account Reset: granted token validation', properties)
@@ -134,9 +132,7 @@
user_id: user.uuid,
success: false,
errors: { token: [t('errors.account_reset.granted_token_expired', app_name: APP_NAME)] },
- error_details: {
- token: [t('errors.account_reset.granted_token_expired', app_name: APP_NAME)],
- },
+ error_details: { token: { granted_token_expired: true } },
}
expect(@analytics).to receive(:track_event).
with('Account Reset: granted token validation', properties)
diff --git a/spec/controllers/frontend_log_controller_spec.rb b/spec/controllers/frontend_log_controller_spec.rb
index 0025499ddd7..ae08ab4e70e 100644
--- a/spec/controllers/frontend_log_controller_spec.rb
+++ b/spec/controllers/frontend_log_controller_spec.rb
@@ -1,6 +1,19 @@
require 'rails_helper'
RSpec.describe FrontendLogController do
+ describe '.LEGACY_EVENT_MAP' do
+ it 'has keys sorted alphabetically' do
+ expect(described_class::LEGACY_EVENT_MAP.keys).
+ to eq(described_class::LEGACY_EVENT_MAP.keys.sort_by(&:downcase))
+ end
+ end
+
+ describe '.ALLOWED_EVENTS' do
+ it 'is sorted alphabetically' do
+ expect(described_class::ALLOWED_EVENTS).to eq(described_class::ALLOWED_EVENTS.sort)
+ end
+ end
+
describe '#create' do
subject(:action) { post :create, params: params, as: :json }
@@ -219,12 +232,5 @@
end
end
end
-
- context 'with all events' do
- it 'sorts keys alphabetically' do
- expect(described_class::EVENT_MAP.keys).
- to eq(described_class::EVENT_MAP.keys.sort_by(&:downcase))
- end
- end
end
end
diff --git a/spec/controllers/idv/by_mail/enter_code_controller_spec.rb b/spec/controllers/idv/by_mail/enter_code_controller_spec.rb
index f5bd87d0052..9bc0a47e173 100644
--- a/spec/controllers/idv/by_mail/enter_code_controller_spec.rb
+++ b/spec/controllers/idv/by_mail/enter_code_controller_spec.rb
@@ -166,8 +166,7 @@
describe '#create' do
let(:otp_code_error_message) { { otp: [t('errors.messages.confirmation_code_incorrect')] } }
- let(:otp_code_incorrect) { { otp: [:confirmation_code_incorrect] } }
- let(:success_properties) { { success: true, failure_reason: nil } }
+ let(:success_properties) { { success: true } }
subject(:action) do
post(
@@ -387,11 +386,11 @@
which_letter: nil,
letter_count: 1,
attempts: 1,
- error_details: otp_code_incorrect,
+ error_details: { otp: { confirmation_code_incorrect: true } },
pii_like_keypaths: [[:errors, :otp], [:error_details, :otp]],
)
expect(@irs_attempts_api_tracker).to receive(:idv_gpo_verification_submitted).
- with(success: false, failure_reason: otp_code_incorrect)
+ with(success: false)
action
@@ -425,7 +424,7 @@
which_letter: nil,
letter_count: 1,
attempts: 1,
- error_details: otp_code_incorrect,
+ error_details: { otp: { confirmation_code_incorrect: true } },
pii_like_keypaths: [[:errors, :otp], [:error_details, :otp]],
}
expect(@analytics).to receive(:track_event).with(
@@ -474,7 +473,7 @@
which_letter: nil,
letter_count: 1,
attempts: 1,
- error_details: otp_code_incorrect,
+ error_details: { otp: { confirmation_code_incorrect: true } },
pii_like_keypaths: [[:errors, :otp], [:error_details, :otp]],
).exactly(max_attempts - 1).times
expect(@analytics).to receive(:track_event).with(
diff --git a/spec/controllers/idv/image_uploads_controller_spec.rb b/spec/controllers/idv/image_uploads_controller_spec.rb
index 7da85f798e8..7f1efc5684a 100644
--- a/spec/controllers/idv/image_uploads_controller_spec.rb
+++ b/spec/controllers/idv/image_uploads_controller_spec.rb
@@ -62,7 +62,7 @@
front: ['Please fill in this field.'],
},
error_details: {
- front: [:blank],
+ front: { blank: true },
},
user_id: user.uuid,
attempts: 1,
@@ -123,7 +123,7 @@
front: [I18n.t('doc_auth.errors.not_a_file')],
},
error_details: {
- front: [I18n.t('doc_auth.errors.not_a_file')],
+ front: { not_a_file: true },
},
user_id: user.uuid,
attempts: 1,
@@ -148,7 +148,6 @@
document_issued: nil,
document_number: nil,
document_state: nil,
- failure_reason: { front: ['The selection was not a valid file.'] },
first_name: nil,
last_name: nil,
success: false },
@@ -261,7 +260,7 @@
limit: [I18n.t('errors.doc_auth.rate_limited_heading')],
},
error_details: {
- limit: [I18n.t('errors.doc_auth.rate_limited_heading')],
+ limit: { rate_limited: true },
},
user_id: user.uuid,
attempts: IdentityConfig.store.doc_auth_max_attempts,
@@ -292,7 +291,6 @@
document_issued: nil,
document_number: nil,
document_state: nil,
- failure_reason: { limit: ['We couldn’t verify your ID'] },
first_name: nil,
last_name: nil,
success: false },
@@ -429,7 +427,6 @@
expect(@irs_attempts_api_tracker).to receive(:track_event).with(
:idv_document_upload_submitted,
success: true,
- failure_reason: nil,
document_back_image_filename: nil,
document_front_image_filename: nil,
document_image_encryption_key: nil,
@@ -458,7 +455,6 @@
:idv_document_upload_submitted,
hash_including(
success: true,
- failure_reason: nil,
document_back_image_filename: match(document_filename_regex),
document_front_image_filename: match(document_filename_regex),
document_image_encryption_key: match(base64_regex),
@@ -525,8 +521,6 @@
expect(@irs_attempts_api_tracker).to receive(:track_event).with(
:idv_document_upload_submitted,
success: false,
- failure_reason: { name:
- ['We couldn’t read the full name on your ID. Try taking new pictures.'] },
document_state: 'ND',
document_number: nil,
document_issued: nil,
@@ -603,7 +597,7 @@
name: [I18n.t('doc_auth.errors.alerts.full_name_check')],
},
error_details: {
- name: [I18n.t('doc_auth.errors.alerts.full_name_check')],
+ name: { name: true },
},
attention_with_barcode: false,
user_id: user.uuid,
@@ -625,8 +619,6 @@
expect(@irs_attempts_api_tracker).to receive(:track_event).with(
:idv_document_upload_submitted,
success: false,
- failure_reason: { name:
- ['We couldn’t read the full name on your ID. Try taking new pictures.'] },
document_state: 'ND',
document_number: nil,
document_issued: nil,
@@ -703,7 +695,7 @@
state: [I18n.t('doc_auth.errors.general.no_liveness')],
},
error_details: {
- state: [:wrong_length],
+ state: { wrong_length: true },
},
attention_with_barcode: false,
user_id: user.uuid,
@@ -725,8 +717,6 @@
expect(@irs_attempts_api_tracker).to receive(:track_event).with(
:idv_document_upload_submitted,
success: false,
- failure_reason: { state:
- ['Try taking new pictures.'] },
document_state: 'Maryland',
document_number: nil,
document_issued: nil,
@@ -803,7 +793,7 @@
dob: [I18n.t('doc_auth.errors.alerts.birth_date_checks')],
},
error_details: {
- dob: [I18n.t('doc_auth.errors.alerts.birth_date_checks')],
+ dob: { dob: true },
},
attention_with_barcode: false,
user_id: user.uuid,
@@ -822,8 +812,6 @@
expect(@irs_attempts_api_tracker).to receive(:track_event).with(
:idv_document_upload_submitted,
success: false,
- failure_reason: { dob:
- ['We couldn’t read the birth date on your ID. Try taking new pictures.'] },
document_back_image_filename: nil,
document_front_image_filename: nil,
document_image_encryption_key: nil,
diff --git a/spec/controllers/idv/in_person/ssn_controller_spec.rb b/spec/controllers/idv/in_person/ssn_controller_spec.rb
index 62002508c24..0e622b3a339 100644
--- a/spec/controllers/idv/in_person/ssn_controller_spec.rb
+++ b/spec/controllers/idv/in_person/ssn_controller_spec.rb
@@ -75,7 +75,10 @@
irs_reproofing: false,
step: 'ssn',
same_address_as_id: true,
- pii_like_keypaths: [[:same_address_as_id], [:state_id, :state_id_jurisdiction]],
+ pii_like_keypaths: [
+ [:same_address_as_id],
+ [:proofing_results, :context, :stages, :state_id, :state_id_jurisdiction],
+ ],
}.merge(ab_test_args)
end
@@ -199,7 +202,7 @@
errors: {
ssn: ['Enter a nine-digit Social Security number'],
},
- error_details: { ssn: [:invalid] },
+ error_details: { ssn: { invalid: true } },
same_address_as_id: true,
pii_like_keypaths: [[:same_address_as_id], [:errors, :ssn], [:error_details, :ssn]],
}.merge(ab_test_args)
diff --git a/spec/controllers/idv/otp_verification_controller_spec.rb b/spec/controllers/idv/otp_verification_controller_spec.rb
index 12c31acbcf5..3c542b13646 100644
--- a/spec/controllers/idv/otp_verification_controller_spec.rb
+++ b/spec/controllers/idv/otp_verification_controller_spec.rb
@@ -170,7 +170,6 @@
expect(@irs_attempts_api_tracker).to receive(:idv_phone_otp_submitted).with(
success: true,
**phone_property,
- failure_reason: {},
)
put :update, params: otp_code_param
@@ -183,9 +182,6 @@
expect(@irs_attempts_api_tracker).to receive(:idv_phone_otp_submitted).with(
success: false,
**phone_property,
- failure_reason: {
- code_matches: false,
- },
)
put :update, params: invalid_otp_code_param
@@ -208,9 +204,6 @@
expect(@irs_attempts_api_tracker).to receive(:idv_phone_otp_submitted).with(
success: false,
**phone_property,
- failure_reason: {
- code_expired: true,
- },
)
put :update, params: otp_code_param
diff --git a/spec/controllers/idv/phone_controller_spec.rb b/spec/controllers/idv/phone_controller_spec.rb
index bee6b83d0ec..2c0d6a88298 100644
--- a/spec/controllers/idv/phone_controller_spec.rb
+++ b/spec/controllers/idv/phone_controller_spec.rb
@@ -239,12 +239,6 @@
allow(subject).to receive(:ab_test_analytics_buckets).and_return(ab_test_args)
end
context 'when form is invalid' do
- let(:improbable_phone_error) do
- {
- phone: [:improbable_phone],
- otp_delivery_preference: [:inclusion],
- }
- end
let(:improbable_phone_message) { t('errors.messages.improbable_phone') }
let(:improbable_otp_message) { 'is not included in the list' }
let(:improbable_phone_number) { '703' }
@@ -285,7 +279,6 @@
expect(@irs_attempts_api_tracker).to receive(:idv_phone_submitted).with(
success: false,
phone_number: improbable_phone_number,
- failure_reason: improbable_phone_error,
)
put :create, params: improbable_phone_form
@@ -296,7 +289,10 @@
phone: [improbable_phone_message],
otp_delivery_preference: [improbable_otp_message],
},
- error_details: improbable_phone_error,
+ error_details: {
+ phone: { improbable_phone: true },
+ otp_delivery_preference: { inclusion: true },
+ },
pii_like_keypaths: [[:errors, :phone], [:error_details, :phone]],
country_code: nil,
area_code: nil,
@@ -329,7 +325,6 @@
expect(@irs_attempts_api_tracker).to receive(:idv_phone_submitted).with(
success: true,
phone_number: good_phone,
- failure_reason: nil,
)
phone_params = {
diff --git a/spec/controllers/idv/ssn_controller_spec.rb b/spec/controllers/idv/ssn_controller_spec.rb
index 5a7921a1086..60a251e7f80 100644
--- a/spec/controllers/idv/ssn_controller_spec.rb
+++ b/spec/controllers/idv/ssn_controller_spec.rb
@@ -208,7 +208,7 @@
errors: {
ssn: [t('idv.errors.pattern_mismatch.ssn')],
},
- error_details: { ssn: [:invalid] },
+ error_details: { ssn: { invalid: true } },
pii_like_keypaths: [[:same_address_as_id], [:errors, :ssn], [:error_details, :ssn]],
}.merge(ab_test_args)
end
diff --git a/spec/controllers/idv/verify_info_controller_spec.rb b/spec/controllers/idv/verify_info_controller_spec.rb
index a0225e75013..4bcaa3dae30 100644
--- a/spec/controllers/idv/verify_info_controller_spec.rb
+++ b/spec/controllers/idv/verify_info_controller_spec.rb
@@ -190,8 +190,6 @@
document_capture_session
end
- let(:expected_failure_reason) { DocAuthHelper::SAMPLE_TMX_SUMMARY_REASON_CODE }
-
before do
controller.
idv_session.verify_info_step_document_capture_session_uuid = document_capture_session.uuid
@@ -209,7 +207,6 @@
it 'it logs IRS idv_tmx_fraud_check event' do
expect(@irs_attempts_api_tracker).to receive(:idv_tmx_fraud_check).with(
success: true,
- failure_reason: nil,
)
get :show
end
@@ -226,7 +223,6 @@
it 'it logs IRS idv_tmx_fraud_check event' do
expect(@irs_attempts_api_tracker).to receive(:idv_tmx_fraud_check).with(
success: false,
- failure_reason: expected_failure_reason,
)
get :show
end
@@ -243,7 +239,6 @@
it 'it logs IRS idv_tmx_fraud_check event' do
expect(@irs_attempts_api_tracker).to receive(:idv_tmx_fraud_check).with(
success: false,
- failure_reason: expected_failure_reason,
)
get :show
end
@@ -260,7 +255,6 @@
it 'it logs IRS idv_tmx_fraud_check event' do
expect(@irs_attempts_api_tracker).to receive(:idv_tmx_fraud_check).with(
success: false,
- failure_reason: expected_failure_reason,
)
get :show
end
diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb
index bbeb92bea08..d55eb8d4ff4 100644
--- a/spec/controllers/saml_idp_controller_spec.rb
+++ b/spec/controllers/saml_idp_controller_spec.rb
@@ -765,7 +765,7 @@ def name_id_version(format_urn)
analytics_hash = {
success: false,
errors: { authn_context: [t('errors.messages.unauthorized_authn_context')] },
- error_details: { authn_context: [:unauthorized_authn_context] },
+ error_details: { authn_context: { unauthorized_authn_context: true } },
nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT,
authn_context: ['http://idmanagement.gov/ns/assurance/loa/5'],
authn_context_comparison: 'exact',
@@ -984,7 +984,7 @@ def name_id_version(format_urn)
analytics_hash = {
success: false,
errors: { service_provider: [t('errors.messages.unauthorized_service_provider')] },
- error_details: { service_provider: [:unauthorized_service_provider] },
+ error_details: { service_provider: { unauthorized_service_provider: true } },
nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT,
authn_context: request_authn_contexts,
authn_context_comparison: 'exact',
@@ -1026,8 +1026,8 @@ def name_id_version(format_urn)
authn_context: [t('errors.messages.unauthorized_authn_context')],
},
error_details: {
- authn_context: [:unauthorized_authn_context],
- service_provider: [:unauthorized_service_provider],
+ authn_context: { unauthorized_authn_context: true },
+ service_provider: { unauthorized_service_provider: true },
},
nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT,
authn_context: ['http://idmanagement.gov/ns/assurance/loa/5'],
@@ -1417,7 +1417,7 @@ def name_id_version(format_urn)
analytics_hash = {
success: false,
errors: { nameid_format: [t('errors.messages.unauthorized_nameid_format')] },
- error_details: { nameid_format: [:unauthorized_nameid_format] },
+ error_details: { nameid_format: { unauthorized_nameid_format: true } },
nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_EMAIL,
authn_context: request_authn_contexts,
authn_context_comparison: 'exact',
diff --git a/spec/controllers/sign_up/email_confirmations_controller_spec.rb b/spec/controllers/sign_up/email_confirmations_controller_spec.rb
index 017e7fd7eef..f3dddcaea73 100644
--- a/spec/controllers/sign_up/email_confirmations_controller_spec.rb
+++ b/spec/controllers/sign_up/email_confirmations_controller_spec.rb
@@ -2,12 +2,10 @@
RSpec.describe SignUp::EmailConfirmationsController do
describe '#create' do
- let(:token_not_found_error) { { confirmation_token: [:not_found] } }
- let(:token_expired_error) { { confirmation_token: [:expired] } }
let(:analytics_token_error_hash) do
{
success: false,
- error_details: token_not_found_error,
+ error_details: { confirmation_token: { not_found: true } },
errors: { confirmation_token: ['not found'] },
user_id: nil,
}
@@ -16,7 +14,6 @@
{
email: nil,
success: false,
- failure_reason: token_not_found_error,
}
end
@@ -97,7 +94,6 @@
expect(@irs_attempts_api_tracker).to receive(:user_registration_email_confirmation).with(
email: email_address.email,
success: false,
- failure_reason: { email: [:already_confirmed] },
)
get :create, params: { confirmation_token: 'foo' }
@@ -117,7 +113,7 @@
analytics_hash = {
success: false,
errors: { confirmation_token: [t('errors.messages.expired')] },
- error_details: token_expired_error,
+ error_details: { confirmation_token: { expired: true } },
user_id: email_address.user.uuid,
}
@@ -127,7 +123,6 @@
expect(@irs_attempts_api_tracker).to receive(:user_registration_email_confirmation).with(
email: email_address.email,
success: false,
- failure_reason: token_expired_error,
)
get :create, params: { confirmation_token: 'foo' }
@@ -149,7 +144,7 @@
analytics_hash = {
success: false,
errors: { confirmation_token: [t('errors.messages.expired')] },
- error_details: token_expired_error,
+ error_details: { confirmation_token: { expired: true } },
user_id: user.uuid,
}
@@ -159,7 +154,6 @@
expect(@irs_attempts_api_tracker).to receive(:user_registration_email_confirmation).with(
email: email_address.email,
success: false,
- failure_reason: token_expired_error,
)
get :create, params: { confirmation_token: 'foo' }
@@ -229,7 +223,6 @@
expect(@irs_attempts_api_tracker).to receive(:user_registration_email_confirmation).with(
email: email_address.email,
success: true,
- failure_reason: nil,
)
get :create, params: { confirmation_token: 'foo' }
diff --git a/spec/controllers/sign_up/passwords_controller_spec.rb b/spec/controllers/sign_up/passwords_controller_spec.rb
index bb7a1a1e975..8f48a43c5bc 100644
--- a/spec/controllers/sign_up/passwords_controller_spec.rb
+++ b/spec/controllers/sign_up/passwords_controller_spec.rb
@@ -16,7 +16,7 @@
end
let(:password) { 'NewVal!dPassw0rd' }
let(:password_confirmation) { password }
- let(:success_properties) { { success: true, failure_reason: nil } }
+ let(:success_properties) { { success: true } }
context 'with valid password' do
let!(:user) { create(:user, :unconfirmed, confirmation_token: token) }
@@ -61,15 +61,6 @@
context 'with an invalid password' do
let!(:user) { create(:user, :unconfirmed, confirmation_token: token) }
- let(:analytics_hash) do
- {
- success: false,
- errors: errors,
- error_details: error_details,
- user_id: user.uuid,
- request_id_present: false,
- }
- end
before do
stub_analytics
@@ -79,70 +70,70 @@
context 'with a password that is too short' do
let(:password) { 'NewVal' }
let(:password_confirmation) { 'NewVal' }
- let(:errors) do
- {
- password:
- [t(
- 'errors.attributes.password.too_short',
- count: Devise.password_length.first,
- )],
- password_confirmation:
- [I18n.t('errors.messages.too_short', count: Devise.password_length.first)],
- }
- end
- let(:error_details) do
- {
- password: [:too_short],
- password_confirmation: [:too_short],
- }
- end
it 'tracks an invalid password event' do
- expect(@analytics).to receive(:track_event).
- with(
- 'User Registration: Email Confirmation',
- { errors: {}, error_details: nil, success: true, user_id: user.uuid },
- )
- expect(@analytics).to receive(:track_event).
- with('Password Creation', analytics_hash)
-
expect(@irs_attempts_api_tracker).to receive(:user_registration_password_submitted).
with(
success: false,
- failure_reason: error_details,
)
expect(@irs_attempts_api_tracker).not_to receive(:user_registration_email_confirmation)
subject
+
+ expect(@analytics).to have_logged_event(
+ 'User Registration: Email Confirmation',
+ errors: {},
+ error_details: nil,
+ success: true,
+ user_id: user.uuid,
+ )
+ expect(@analytics).to have_logged_event(
+ 'Password Creation',
+ success: false,
+ errors: {
+ password: [
+ t('errors.attributes.password.too_short', count: Devise.password_length.first),
+ ],
+ password_confirmation: [
+ t('errors.messages.too_short', count: Devise.password_length.first),
+ ],
+ },
+ error_details: {
+ password: { too_short: true },
+ password_confirmation: { too_short: true },
+ },
+ user_id: user.uuid,
+ request_id_present: false,
+ )
end
end
context 'when password confirmation does not match' do
let(:password) { 'NewVal!dPassw0rd' }
let(:password_confirmation) { 'bad match password' }
- let(:errors) do
- {
- password_confirmation:
- [t('errors.messages.password_mismatch')],
- }
- end
- let(:error_details) do
- {
- password_confirmation: [t('errors.messages.password_mismatch')],
- }
- end
it 'tracks invalid password_confirmation error' do
- expect(@analytics).to receive(:track_event).
- with(
- 'User Registration: Email Confirmation',
- { errors: {}, error_details: nil, success: true, user_id: user.uuid },
- )
-
- expect(@analytics).to receive(:track_event).
- with('Password Creation', analytics_hash)
-
subject
+
+ expect(@analytics).to have_logged_event(
+ 'User Registration: Email Confirmation',
+ errors: {},
+ error_details: nil,
+ success: true,
+ user_id: user.uuid,
+ )
+ expect(@analytics).to have_logged_event(
+ 'Password Creation',
+ success: false,
+ errors: {
+ password_confirmation: [t('errors.messages.password_mismatch')],
+ },
+ error_details: {
+ password_confirmation: { mismatch: true },
+ },
+ user_id: user.uuid,
+ request_id_present: false,
+ )
end
end
end
diff --git a/spec/controllers/sign_up/registrations_controller_spec.rb b/spec/controllers/sign_up/registrations_controller_spec.rb
index 2a6fe362664..33296dd4589 100644
--- a/spec/controllers/sign_up/registrations_controller_spec.rb
+++ b/spec/controllers/sign_up/registrations_controller_spec.rb
@@ -58,7 +58,7 @@
end
describe '#create' do
- let(:success_properties) { { success: true, failure_reason: nil } }
+ let(:success_properties) { { success: true } }
context 'when registering with a new email' do
it 'tracks successful user registration' do
stub_analytics
@@ -156,7 +156,7 @@
success: false,
rate_limited: false,
errors: { email: [t('valid_email.validations.email.invalid')] },
- error_details: { email: [:invalid] },
+ error_details: { email: { invalid: true } },
email_already_exists: false,
user_id: 'anonymous-uuid',
domain_name: 'invalid',
@@ -169,7 +169,6 @@
:user_registration_email_submitted,
email: 'invalid@',
success: false,
- failure_reason: { email: [:invalid] },
)
post :create, params: { user: { email: 'invalid@', request_id: '', terms_accepted: '1' } }
diff --git a/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb
index f62578349b0..71bea1af56f 100644
--- a/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb
+++ b/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb
@@ -133,7 +133,7 @@
properties = {
success: false,
- error_details: { code: [:wrong_length, 'incorrect'] },
+ error_details: { code: { wrong_length: true, incorrect: true } },
confirmation_for_add_phone: false,
context: 'authentication',
multi_factor_auth_method: 'sms',
@@ -204,7 +204,7 @@
properties = {
success: false,
- error_details: { code: [:wrong_length, 'incorrect'] },
+ error_details: { code: { wrong_length: true, incorrect: true } },
confirmation_for_add_phone: false,
context: 'authentication',
multi_factor_auth_method: 'sms',
@@ -546,7 +546,7 @@
properties = {
success: false,
errors: nil,
- error_details: { code: [:wrong_length, 'incorrect'] },
+ error_details: { code: { wrong_length: true, incorrect: true } },
confirmation_for_add_phone: true,
context: 'confirmation',
multi_factor_auth_method: 'sms',
diff --git a/spec/controllers/two_factor_authentication/personal_key_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/personal_key_verification_controller_spec.rb
index aac99a3f104..36312e154b7 100644
--- a/spec/controllers/two_factor_authentication/personal_key_verification_controller_spec.rb
+++ b/spec/controllers/two_factor_authentication/personal_key_verification_controller_spec.rb
@@ -158,7 +158,7 @@
properties = {
success: false,
errors: { personal_key: [t('errors.messages.personal_key_incorrect')] },
- error_details: { personal_key: [:personal_key_incorrect] },
+ error_details: { personal_key: { personal_key_incorrect: true } },
multi_factor_auth_method: 'personal-key',
multi_factor_auth_method_created_at: personal_key_generated_at.strftime('%s%L'),
}
diff --git a/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb
index 93d2529de60..442f3ca293a 100644
--- a/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb
+++ b/spec/controllers/two_factor_authentication/piv_cac_verification_controller_spec.rb
@@ -126,7 +126,6 @@
expect(@irs_attempts_api_tracker).to receive(:mfa_login_piv_cac).with(
success: true,
subject_dn: x509_subject,
- failure_reason: nil,
)
expect(@analytics).to receive(:track_event).
@@ -230,7 +229,6 @@
expect(@irs_attempts_api_tracker).to receive(:mfa_login_piv_cac).with(
success: false,
subject_dn: bad_dn,
- failure_reason: piv_cac_mismatch,
)
expect(@analytics).to receive(:track_event).
diff --git a/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb
index 5fd496581a1..2431abb0291 100644
--- a/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb
+++ b/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb
@@ -223,7 +223,7 @@
result = { context: 'authentication',
multi_factor_auth_method: 'webauthn',
success: false,
- error_details: { authenticator_data: ['invalid_authenticator_data'] },
+ error_details: { authenticator_data: { invalid_authenticator_data: true } },
webauthn_configuration_id: webauthn_configuration.id,
multi_factor_auth_method_created_at: webauthn_configuration.created_at.
strftime('%s%L') }
@@ -280,17 +280,18 @@
expect(@analytics).to receive(:track_mfa_submit_event).with(
success: false,
error_details: {
- authenticator_data: [:blank],
- client_data_json: [:blank],
- signature: [:blank],
- webauthn_configuration: [:blank],
- webauthn_error: [webauthn_error],
+ authenticator_data: { blank: true },
+ client_data_json: { blank: true },
+ signature: { blank: true },
+ webauthn_configuration: { blank: true },
+ webauthn_error: { present: true },
},
context: UserSessionContext::AUTHENTICATION_CONTEXT,
multi_factor_auth_method: 'webauthn_platform',
multi_factor_auth_method_created_at:
second_webauthn_platform_configuration.created_at.strftime('%s%L'),
webauthn_configuration_id: nil,
+ frontend_error: 'NotAllowedError',
)
patch :confirm, params: params
diff --git a/spec/controllers/users/edit_phone_controller_spec.rb b/spec/controllers/users/edit_phone_controller_spec.rb
index fb460dfbd84..c9df63102fd 100644
--- a/spec/controllers/users/edit_phone_controller_spec.rb
+++ b/spec/controllers/users/edit_phone_controller_spec.rb
@@ -38,7 +38,7 @@
attributes = {
success: false,
errors: hash_including(:delivery_preference),
- error_details: { delivery_preference: [:inclusion] },
+ error_details: { delivery_preference: { inclusion: true } },
delivery_preference: 'noise',
make_default_number: true,
phone_configuration_id: phone_configuration.id,
diff --git a/spec/controllers/users/passwords_controller_spec.rb b/spec/controllers/users/passwords_controller_spec.rb
index 40eb505c572..ef5e2ae8fbb 100644
--- a/spec/controllers/users/passwords_controller_spec.rb
+++ b/spec/controllers/users/passwords_controller_spec.rb
@@ -22,7 +22,7 @@
allow(@analytics).to receive(:track_event)
expect(@irs_attempts_api_tracker).to receive(:logged_in_password_change).
- with(failure_reason: nil, success: true)
+ with(success: true)
params = {
password: 'salty new password',
@@ -48,6 +48,7 @@
stub_sign_in(user)
Pii::Cacher.new(user, controller.user_session).save_decrypted_pii(
Pii::Attributes.new(ssn: '111-222-3333'),
+ user.active_profile.id,
)
params = {
@@ -132,14 +133,8 @@
end
it 'renders edit' do
- password_short_error = {
- password: [:too_short],
- password_confirmation: [:too_short],
- }
-
expect(@irs_attempts_api_tracker).to receive(:logged_in_password_change).with(
success: false,
- failure_reason: password_short_error,
)
patch :update, params: { update_user_password_form: params }
@@ -159,7 +154,10 @@
count: Devise.password_length.first,
)],
},
- error_details: password_short_error,
+ error_details: {
+ password: { too_short: true },
+ password_confirmation: { too_short: true },
+ },
pending_profile_present: false,
active_profile_present: false,
user_id: subject.current_user.uuid,
@@ -189,9 +187,6 @@
it 'renders edit' do
expect(@irs_attempts_api_tracker).to receive(:logged_in_password_change).with(
success: false,
- failure_reason: {
- password_confirmation: [t('errors.messages.password_mismatch')],
- },
)
patch :update, params: { update_user_password_form: params }
@@ -203,7 +198,7 @@
password_confirmation: [t('errors.messages.password_mismatch')],
},
error_details: {
- password_confirmation: [t('errors.messages.password_mismatch')],
+ password_confirmation: { mismatch: true },
},
pending_profile_present: false,
active_profile_present: false,
diff --git a/spec/controllers/users/phone_setup_controller_spec.rb b/spec/controllers/users/phone_setup_controller_spec.rb
index 43334bbbfe5..b898b40c7b5 100644
--- a/spec/controllers/users/phone_setup_controller_spec.rb
+++ b/spec/controllers/users/phone_setup_controller_spec.rb
@@ -70,10 +70,10 @@
],
},
error_details: {
- phone: [
- :improbable_phone,
- t('two_factor_authentication.otp_delivery_preference.voice_unsupported', location: ''),
- ],
+ phone: {
+ improbable_phone: true,
+ voice_unsupported: true,
+ },
},
otp_delivery_preference: 'sms',
area_code: nil,
diff --git a/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb b/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb
index 7151f319f8e..4c294a70f4c 100644
--- a/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb
+++ b/spec/controllers/users/piv_cac_authentication_setup_controller_spec.rb
@@ -132,7 +132,6 @@
:mfa_enroll_piv_cac,
success: true,
subject_dn: 'some dn',
- failure_reason: nil,
)
get :new, params: { token: good_token }
@@ -156,7 +155,6 @@
:mfa_enroll_piv_cac,
success: true,
subject_dn: 'some dn',
- failure_reason: nil,
)
get :new, params: { token: good_token }
@@ -172,7 +170,6 @@
:mfa_enroll_piv_cac,
success: true,
subject_dn: 'some dn',
- failure_reason: nil,
)
get :new, params: { token: good_token }
@@ -185,7 +182,6 @@
:mfa_enroll_piv_cac,
success: true,
subject_dn: 'some dn',
- failure_reason: nil,
)
get :new, params: { token: good_token }
@@ -213,7 +209,6 @@
:mfa_enroll_piv_cac,
success: false,
subject_dn: nil,
- failure_reason: { type: 'certificate.bad' },
)
get :new, params: { token: bad_token }
diff --git a/spec/controllers/users/reset_passwords_controller_spec.rb b/spec/controllers/users/reset_passwords_controller_spec.rb
index 09c557774cf..c77a019caf3 100644
--- a/spec/controllers/users/reset_passwords_controller_spec.rb
+++ b/spec/controllers/users/reset_passwords_controller_spec.rb
@@ -4,8 +4,7 @@
let(:password_error_message) do
t('errors.attributes.password.too_short.other', count: Devise.password_length.first)
end
- let(:success_properties) { { success: true, failure_reason: nil } }
- let(:token_expired_error) { 'token_expired' }
+ let(:success_properties) { { success: true } }
describe '#edit' do
let(:user) { instance_double('User', uuid: '123') }
let(:email_address) { instance_double('EmailAddress') }
@@ -24,7 +23,6 @@
end
context 'no user matches token' do
- let(:user_blank_error) { { user: [:blank] } }
let(:token) { 'foo' }
before do
session[:reset_password_token] = token
@@ -33,7 +31,7 @@
{
success: false,
errors: { user: ['invalid_token'] },
- error_details: user_blank_error,
+ error_details: { user: { blank: true } },
user_id: nil,
}
end
@@ -41,7 +39,6 @@
it 'redirects to page where user enters email for password reset token' do
expect(@irs_attempts_api_tracker).to receive(:forgot_password_email_confirmed).with(
success: false,
- failure_reason: user_blank_error,
)
get :edit
@@ -54,7 +51,6 @@
end
context 'token expired' do
- let(:user_token_error) { { user: [token_expired_error] } }
let(:token) { 'foo' }
before do
session[:reset_password_token] = token
@@ -62,8 +58,8 @@
let(:analytics_hash) do
{
success: false,
- errors: user_token_error,
- error_details: user_token_error,
+ errors: { user: ['token_expired'] },
+ error_details: { user: { token_expired: true } },
user_id: '123',
}
end
@@ -76,12 +72,11 @@
end
context 'no user matches token' do
- let(:user_blank_error) { { user: [:blank] } }
let(:analytics_hash) do
{
success: false,
errors: { user: ['invalid_token'] },
- error_details: user_blank_error,
+ error_details: { user: { blank: true } },
user_id: nil,
}
end
@@ -93,7 +88,6 @@
it 'redirects to page where user enters email for password reset token' do
expect(@irs_attempts_api_tracker).to receive(:forgot_password_email_confirmed).with(
success: false,
- failure_reason: user_blank_error,
)
get :edit
@@ -106,12 +100,11 @@
end
context 'token expired' do
- let(:user_token_error) { { user: [token_expired_error] } }
let(:analytics_hash) do
{
success: false,
- errors: user_token_error,
- error_details: user_token_error,
+ errors: { user: ['token_expired'] },
+ error_details: { user: { token_expired: true } },
user_id: '123',
}
end
@@ -125,7 +118,6 @@
it 'redirects to page where user enters email for password reset token' do
expect(@irs_attempts_api_tracker).to receive(:forgot_password_email_confirmed).with(
success: false,
- failure_reason: user_token_error,
)
get :edit
@@ -192,18 +184,7 @@
end
describe '#update' do
- let(:password_short_error) { { password: [:too_short] } }
-
- let(:password_token_error) { { reset_password_token: [token_expired_error] } }
context 'user submits new password after token expires' do
- let(:reset_password_error_details) do
- {
- **password_short_error,
- password_confirmation: [:too_short],
- **password_token_error,
- }
- end
-
it 'redirects to page where user enters email for password reset token' do
stub_analytics
stub_attempts_tracker
@@ -211,7 +192,6 @@
expect(@irs_attempts_api_tracker).to receive(:forgot_password_new_password_submitted).with(
success: false,
- failure_reason: reset_password_error_details,
)
raw_reset_token, db_confirmation_token =
@@ -240,9 +220,13 @@
'errors.messages.too_short.other',
count: Devise.password_length.first,
)],
- **password_token_error,
+ reset_password_token: ['token_expired'],
+ },
+ error_details: {
+ password: { too_short: true },
+ password_confirmation: { too_short: true },
+ reset_password_token: { token_expired: true },
},
- error_details: reset_password_error_details,
user_id: user.uuid,
profile_deactivated: false,
pending_profile_invalidated: false,
@@ -287,8 +271,8 @@
)],
},
error_details: {
- password: [:too_short],
- password_confirmation: [:too_short],
+ password: { too_short: true },
+ password_confirmation: { too_short: true },
},
user_id: user.uuid,
profile_deactivated: false,
@@ -300,10 +284,6 @@
with('Password Reset: Password Submitted', analytics_hash)
expect(@irs_attempts_api_tracker).to receive(:forgot_password_new_password_submitted).with(
success: false,
- failure_reason: {
- password: [:too_short],
- password_confirmation: [:too_short],
- },
)
put :update, params: { reset_password_form: form_params }
@@ -340,7 +320,7 @@
password_confirmation: [t('errors.messages.password_mismatch')],
},
error_details: {
- password_confirmation: [t('errors.messages.password_mismatch')],
+ password_confirmation: { mismatch: true },
},
user_id: user.uuid,
profile_deactivated: false,
@@ -352,9 +332,6 @@
with('Password Reset: Password Submitted', analytics_hash)
expect(@irs_attempts_api_tracker).to receive(:forgot_password_new_password_submitted).with(
success: false,
- failure_reason: {
- password_confirmation: [t('errors.messages.password_mismatch')],
- },
)
put :update, params: { reset_password_form: form_params }
@@ -709,7 +686,7 @@
analytics_hash = {
success: false,
errors: { email: [t('valid_email.validations.email.invalid')] },
- error_details: { email: [:invalid] },
+ error_details: { email: { invalid: true } },
user_id: 'nonexistent-uuid',
confirmed: false,
active_profile: false,
diff --git a/spec/controllers/users/totp_setup_controller_spec.rb b/spec/controllers/users/totp_setup_controller_spec.rb
index be785f60bd8..e0ef5196936 100644
--- a/spec/controllers/users/totp_setup_controller_spec.rb
+++ b/spec/controllers/users/totp_setup_controller_spec.rb
@@ -224,7 +224,7 @@
result = {
success: false,
- error_details: { name: [:blank] },
+ error_details: { name: { blank: true } },
errors: { name: [t('errors.messages.blank')] },
totp_secret_present: true,
multi_factor_auth_method: 'totp',
diff --git a/spec/controllers/users/two_factor_authentication_controller_spec.rb b/spec/controllers/users/two_factor_authentication_controller_spec.rb
index 8fc08267900..622e104260f 100644
--- a/spec/controllers/users/two_factor_authentication_controller_spec.rb
+++ b/spec/controllers/users/two_factor_authentication_controller_spec.rb
@@ -274,9 +274,7 @@ def index
let(:default_parameters) do
{ **valid_phone_number, otp_delivery_method: 'sms' }
end
- let(:success_parameters) do
- { success: true, **default_parameters, failure_reason: nil }
- end
+ let(:success_parameters) { { success: true, **default_parameters } }
before do
@user = create(:user, :with_phone)
@@ -402,9 +400,7 @@ def index
stub_attempts_tracker
expect(@irs_attempts_api_tracker).to receive(:mfa_login_phone_otp_sent).
- with(reauthentication: false, **default_parameters, success: false, failure_reason: {
- telephony: 'Telephony::OptOutError - Telephony::OptOutError',
- })
+ with(reauthentication: false, **default_parameters, success: false)
get :send_code, params: otp_delivery_form_sms
end
diff --git a/spec/controllers/users/verify_personal_key_controller_spec.rb b/spec/controllers/users/verify_personal_key_controller_spec.rb
index 4a71520eb0a..e852fcc0c08 100644
--- a/spec/controllers/users/verify_personal_key_controller_spec.rb
+++ b/spec/controllers/users/verify_personal_key_controller_spec.rb
@@ -87,8 +87,14 @@
let(:error_text) { 'Incorrect personal key' }
let(:personal_key_bad_params) { { personal_key: 'baaad' } }
let(:personal_key_error) { { personal_key: [error_text] } }
- let(:failure_properties) { { success: false, failure_reason: personal_key_error } }
- let(:pii_like_keypaths_errors) { [[:errors, :personal_key], [:error_details, :personal_key]] }
+ let(:failure_properties) { { success: false } }
+ let(:pii_like_keypaths_errors) do
+ [
+ [:errors, :personal_key],
+ [:error_details, :personal_key],
+ [:error_details, :personal_key, :personal_key],
+ ]
+ end
let(:response_ok) { FormResponse.new(success: true, errors: {}) }
let(:response_bad) { FormResponse.new(success: false, errors: personal_key_error, extra: {}) }
@@ -121,7 +127,6 @@
stub_attempts_tracker
expect(@irs_attempts_api_tracker).to receive(:personal_key_reactivation_submitted).with(
- failure_reason: nil,
success: true,
).once
@@ -163,7 +168,7 @@
expect(@analytics).to receive(:track_event).with(
'Personal key reactivation: Personal key form submitted',
errors: { personal_key: ['Please fill in this field.', error_text] },
- error_details: { personal_key: [:blank, :personal_key_incorrect] },
+ error_details: { personal_key: { blank: true, personal_key: true } },
success: false,
pii_like_keypaths: pii_like_keypaths_errors,
).once
diff --git a/spec/controllers/users/webauthn_setup_controller_spec.rb b/spec/controllers/users/webauthn_setup_controller_spec.rb
index 511b99d99b9..96758345f05 100644
--- a/spec/controllers/users/webauthn_setup_controller_spec.rb
+++ b/spec/controllers/users/webauthn_setup_controller_spec.rb
@@ -230,6 +230,18 @@
expect(additional_mfa_check).to be_truthy
end
end
+
+ context 'when the back button is clicked after platform is added' do
+ let(:user) { create(:user, :with_webauthn_platform) }
+ before do
+ controller.user_session[:in_account_creation_flow] = true
+ end
+ it 'should redirect to authentication methods setup' do
+ get :new, params: { platform: true }
+
+ expect(response).to redirect_to(authentication_methods_setup_path)
+ end
+ end
end
describe 'multiple MFA handling' do
@@ -392,10 +404,7 @@
'errors.webauthn_platform_setup.attestation_error',
link: MarketingSite.contact_url,
)] },
- error_details: { name: [I18n.t(
- 'errors.webauthn_platform_setup.attestation_error',
- link: MarketingSite.contact_url,
- )] },
+ error_details: { name: { attestation_error: true } },
in_account_creation_flow: false,
mfa_method_counts: {},
multi_factor_auth_method: 'webauthn_platform',
diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb
index 90d49d3d036..744fa2bbc33 100644
--- a/spec/features/idv/analytics_spec.rb
+++ b/spec/features/idv/analytics_spec.rb
@@ -63,10 +63,10 @@
flow_path: 'standard', step: 'document_capture', redo_document_capture: nil, acuant_sdk_upgrade_ab_test_bucket: :default, getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil, analytics_id: 'Doc Auth', skip_hybrid_handoff: nil, irs_reproofing: false
},
'Frontend: IdV: front image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
},
'Frontend: IdV: back image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
},
'IdV: doc auth image upload form submitted' => {
success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil
@@ -171,10 +171,10 @@
flow_path: 'hybrid', step: 'document_capture', acuant_sdk_upgrade_ab_test_bucket: :default, getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil, analytics_id: 'Doc Auth', irs_reproofing: false
},
'Frontend: IdV: front image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'hybrid', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil, phone_with_camera: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'hybrid', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil, phone_with_camera: nil
},
'Frontend: IdV: back image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'hybrid', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil, phone_with_camera: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'hybrid', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil, phone_with_camera: nil
},
'IdV: doc auth image upload form submitted' => {
success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'hybrid', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil
@@ -276,10 +276,10 @@
flow_path: 'standard', step: 'document_capture', redo_document_capture: nil, acuant_sdk_upgrade_ab_test_bucket: :default, getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil, skip_hybrid_handoff: nil, analytics_id: 'Doc Auth', irs_reproofing: false
},
'Frontend: IdV: front image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
},
'Frontend: IdV: back image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
},
'IdV: doc auth image upload form submitted' => {
success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil
@@ -363,10 +363,10 @@
flow_path: 'standard', step: 'document_capture', redo_document_capture: nil, acuant_sdk_upgrade_ab_test_bucket: :default, getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil, analytics_id: 'Doc Auth', skip_hybrid_handoff: nil, irs_reproofing: false
},
'Frontend: IdV: front image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
},
'Frontend: IdV: back image added' => {
- width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: 'AUTO', fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
+ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, phone_question_ab_test_bucket: 'bypass_phone_question', phone_with_camera: nil, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil
},
'IdV: doc auth image upload form submitted' => {
success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), getting_started_ab_test_bucket: :welcome_default, phone_question_ab_test_bucket: :bypass_phone_question, phone_with_camera: nil
diff --git a/spec/features/idv/doc_auth/hybrid_handoff_spec.rb b/spec/features/idv/doc_auth/hybrid_handoff_spec.rb
index c2fa0f44f69..21471799825 100644
--- a/spec/features/idv/doc_auth/hybrid_handoff_spec.rb
+++ b/spec/features/idv/doc_auth/hybrid_handoff_spec.rb
@@ -52,7 +52,6 @@
).with(
success: true,
phone_number: '+1 415-555-0199',
- failure_reason: nil,
)
expect(Telephony).to receive(:send_doc_auth_link).
@@ -92,7 +91,6 @@
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'
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 512407f2d8b..182f6544011 100644
--- a/spec/features/idv/doc_auth/verify_info_step_spec.rb
+++ b/spec/features/idv/doc_auth/verify_info_step_spec.rb
@@ -86,7 +86,6 @@
it 'logs analytics and attempts tracker events on submit' do
expect(fake_attempts_tracker).to receive(:idv_verification_submitted).with(
success: true,
- failure_reason: nil,
**fake_pii_details,
ssn: DocAuthHelper::GOOD_SSN,
)
@@ -102,7 +101,6 @@
it 'does not proceed to the next page if resolution fails' do
expect(fake_attempts_tracker).to receive(:idv_verification_submitted).with(
success: false,
- failure_reason: { ssn: ['Unverified SSN.'] },
**fake_pii_details,
ssn: DocAuthHelper::SSN_THAT_FAILS_RESOLUTION,
)
@@ -120,7 +118,6 @@
it 'does not proceed to the next page if resolution raises an exception' do
expect(fake_attempts_tracker).to receive(:idv_verification_submitted).with(
success: false,
- failure_reason: nil,
**fake_pii_details,
ssn: DocAuthHelper::SSN_THAT_RAISES_EXCEPTION,
)
@@ -371,7 +368,6 @@
it 'tracks attempts tracker event with failure reason' do
expect(fake_attempts_tracker).to receive(:idv_verification_submitted).with(
success: false,
- failure_reason: { idv_verification: [:timeout] },
**fake_pii_details,
ssn: DocAuthHelper::GOOD_SSN,
)
diff --git a/spec/features/openid_connect/authorization_confirmation_spec.rb b/spec/features/openid_connect/authorization_confirmation_spec.rb
index 308ed93dade..86e3ec3123f 100644
--- a/spec/features/openid_connect/authorization_confirmation_spec.rb
+++ b/spec/features/openid_connect/authorization_confirmation_spec.rb
@@ -95,10 +95,8 @@ def create_user_and_remember_device
perform_in_browser(:two) do
confirm_email_in_a_different_browser(email)
expect(current_path).to eq sign_up_completed_path
- within('.requested-attributes') do
- expect(page).to have_content t('help_text.requested_attributes.email')
- expect(page).to have_content email
- end
+ expect(page).to have_content t('help_text.requested_attributes.email')
+ expect(page).to have_content email
click_agree_and_continue
diff --git a/spec/features/saml/authorization_confirmation_spec.rb b/spec/features/saml/authorization_confirmation_spec.rb
index 269be1ebd93..a9e075f2ad6 100644
--- a/spec/features/saml/authorization_confirmation_spec.rb
+++ b/spec/features/saml/authorization_confirmation_spec.rb
@@ -107,10 +107,8 @@ def create_user_and_remember_device
perform_in_browser(:two) do
confirm_email_in_a_different_browser(email)
expect(current_path).to eq sign_up_completed_path
- within('.requested-attributes') do
- expect(page).to have_content t('help_text.requested_attributes.email')
- expect(page).to have_content email
- end
+ expect(page).to have_content t('help_text.requested_attributes.email')
+ expect(page).to have_content email
click_agree_and_continue
diff --git a/spec/features/saml/ial1_sso_spec.rb b/spec/features/saml/ial1_sso_spec.rb
index af747adb3c8..e2ca596dfe9 100644
--- a/spec/features/saml/ial1_sso_spec.rb
+++ b/spec/features/saml/ial1_sso_spec.rb
@@ -16,15 +16,12 @@
perform_in_browser(:two) do
confirm_email_in_a_different_browser(email)
expect(current_path).to eq sign_up_completed_path
- within('.requested-attributes') do
- expect(page).to have_content t('help_text.requested_attributes.email')
- expect(page).to have_content email
- expect(page).to_not have_content t('help_text.requested_attributes.address')
- expect(page).to_not have_content t('help_text.requested_attributes.birthdate')
- expect(page).to_not have_content t('help_text.requested_attributes.phone')
- expect(page).
- to_not have_content t('help_text.requested_attributes.social_security_number')
- end
+ expect(page).to have_content t('help_text.requested_attributes.email')
+ expect(page).to have_content email
+ expect(page).to_not have_content t('help_text.requested_attributes.address')
+ expect(page).to_not have_content t('help_text.requested_attributes.birthdate')
+ expect(page).to_not have_content t('help_text.requested_attributes.phone')
+ expect(page).to_not have_content t('help_text.requested_attributes.social_security_number')
click_agree_and_continue
diff --git a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness.json b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness.json
index 3d925a0543d..d47c7b52a28 100644
--- a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness.json
+++ b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness.json
@@ -37,6 +37,11 @@
"Name": "DocIssuerName",
"Values": [{"Value": "Connecticut"}]
},
+ {
+ "Group": "AUTHENTICATION_RESULT",
+ "Name": "DocIssuerType",
+ "Values": [{"Value": "StateProvince"}]
+ },
{
"Group": "AUTHENTICATION_RESULT",
"Name": "DocClassCode",
diff --git a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness_low_dpi.json b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness_low_dpi.json
index 216baa127ab..040084be529 100644
--- a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness_low_dpi.json
+++ b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_no_liveness_low_dpi.json
@@ -37,6 +37,11 @@
"Name": "DocIssuerName",
"Values": [{"Value": "Connecticut"}]
},
+ {
+ "Group": "AUTHENTICATION_RESULT",
+ "Name": "DocIssuerType",
+ "Values": [{"Value": "StateProvince"}]
+ },
{
"Group": "AUTHENTICATION_RESULT",
"Name": "DocClassCode",
diff --git a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_all_failures.json b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_all_failures.json
index 125d1a27384..3d3282e16f2 100644
--- a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_all_failures.json
+++ b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_all_failures.json
@@ -37,6 +37,11 @@
"Name": "DocIssuerName",
"Values": [{"Value": "Connecticut"}]
},
+ {
+ "Group": "AUTHENTICATION_RESULT",
+ "Name": "DocIssuerType",
+ "Values": [{"Value": "StateProvince"}]
+ },
{
"Group": "AUTHENTICATION_RESULT",
"Name": "DocClassCode",
diff --git a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_liveness.json b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_liveness.json
index 79c376efeb8..9ae6ac15f2c 100644
--- a/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_liveness.json
+++ b/spec/fixtures/proofing/lexis_nexis/true_id/true_id_response_failure_with_liveness.json
@@ -37,6 +37,11 @@
"Name": "DocIssuerName",
"Values": [{"Value": "Connecticut"}]
},
+ {
+ "Group": "AUTHENTICATION_RESULT",
+ "Name": "DocIssuerType",
+ "Values": [{"Value": "StateProvince"}]
+ },
{
"Group": "AUTHENTICATION_RESULT",
"Name": "DocClassCode",
diff --git a/spec/forms/idv/api_image_upload_form_spec.rb b/spec/forms/idv/api_image_upload_form_spec.rb
index 91b6f680cbf..b92875d83b5 100644
--- a/spec/forms/idv/api_image_upload_form_spec.rb
+++ b/spec/forms/idv/api_image_upload_form_spec.rb
@@ -89,7 +89,6 @@
document_issued: '2019-12-31',
document_number: '1111111111111',
document_state: 'MT',
- failure_reason: nil,
first_name: 'FAKEY',
last_name: 'MCFAKERSON',
success: true,
diff --git a/spec/forms/idv/phone_form_spec.rb b/spec/forms/idv/phone_form_spec.rb
index 356d44dc48d..46d89945415 100644
--- a/spec/forms/idv/phone_form_spec.rb
+++ b/spec/forms/idv/phone_form_spec.rb
@@ -93,16 +93,7 @@
unregistered_phone = '+400258567234'
result = subject.submit(phone: unregistered_phone)
expect(result.success?).to eq false
- expect(result.to_h).to include(
- {
- error_details: {
- phone: [t(
- 'two_factor_authentication.otp_delivery_preference.sms_unsupported',
- location: 'Romania',
- )],
- },
- },
- )
+ expect(result.to_h).to include(error_details: { phone: { sms_unsupported: true } })
end
end
diff --git a/spec/forms/openid_connect_authorize_form_spec.rb b/spec/forms/openid_connect_authorize_form_spec.rb
index dce7824be51..74395927062 100644
--- a/spec/forms/openid_connect_authorize_form_spec.rb
+++ b/spec/forms/openid_connect_authorize_form_spec.rb
@@ -64,7 +64,7 @@
expect(result.to_h).to eq(
success: false,
errors: { response_type: ['is not included in the list'] },
- error_details: { response_type: [:inclusion] },
+ error_details: { response_type: { inclusion: true } },
client_id: client_id,
prompt: 'select_account',
allow_prompt_login: true,
diff --git a/spec/forms/otp_verification_form_spec.rb b/spec/forms/otp_verification_form_spec.rb
index c4ec4fdd12c..32af977d9ff 100644
--- a/spec/forms/otp_verification_form_spec.rb
+++ b/spec/forms/otp_verification_form_spec.rb
@@ -45,7 +45,7 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- code: [:blank, :wrong_length],
+ code: { blank: true, wrong_length: true },
},
multi_factor_auth_method: 'otp_code',
multi_factor_auth_method_created_at: phone_configuration.created_at.strftime('%s%L'),
@@ -67,7 +67,7 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- code: ['user_otp_missing'],
+ code: { user_otp_missing: true },
},
multi_factor_auth_method: 'otp_code',
multi_factor_auth_method_created_at: phone_configuration.created_at.strftime('%s%L'),
@@ -89,7 +89,7 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- code: [:wrong_length, 'incorrect'],
+ code: { wrong_length: true, incorrect: true },
},
multi_factor_auth_method: 'otp_code',
multi_factor_auth_method_created_at: phone_configuration.created_at.strftime('%s%L'),
@@ -111,7 +111,7 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- code: ['pattern_mismatch', 'incorrect'],
+ code: { pattern_mismatch: true, incorrect: true },
},
multi_factor_auth_method: 'otp_code',
multi_factor_auth_method_created_at: phone_configuration.created_at.strftime('%s%L'),
@@ -136,7 +136,7 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- code: ['user_otp_expired'],
+ code: { user_otp_expired: true },
},
multi_factor_auth_method: 'otp_code',
multi_factor_auth_method_created_at: phone_configuration.created_at.strftime('%s%L'),
diff --git a/spec/forms/totp_setup_form_spec.rb b/spec/forms/totp_setup_form_spec.rb
index 79a814512d9..6e2dcd7ac8f 100644
--- a/spec/forms/totp_setup_form_spec.rb
+++ b/spec/forms/totp_setup_form_spec.rb
@@ -80,7 +80,7 @@
expect(form.submit.to_h).to include(
success: false,
- error_details: { name: [:blank] },
+ error_details: { name: { blank: true } },
errors: { name: [t('errors.messages.blank')] },
)
expect(user.auth_app_configurations.any?).to eq false
@@ -95,7 +95,7 @@
expect(form2.submit.to_h).to include(
success: false,
- error_details: { name: [t('errors.piv_cac_setup.unique_name')] },
+ error_details: { name: { unique_name: true } },
errors: { name: [t('errors.piv_cac_setup.unique_name')] },
)
end
diff --git a/spec/forms/update_user_password_form_spec.rb b/spec/forms/update_user_password_form_spec.rb
index f3222eb6738..6778e84fd35 100644
--- a/spec/forms/update_user_password_form_spec.rb
+++ b/spec/forms/update_user_password_form_spec.rb
@@ -34,7 +34,7 @@
}
expect(UpdateUser).not_to receive(:new)
- expect(ActiveProfileEncryptor).not_to receive(:new)
+ expect(UserProfilesEncryptor).not_to receive(:new)
expect(subject.submit(params).to_h).to include(
success: false,
errors: errors,
@@ -70,17 +70,21 @@
context 'when the user has an active profile' do
let(:profile) { create(:profile, :active, :verified, pii: { ssn: '1234' }) }
let(:user) { profile.user }
- let(:user_session) { { decrypted_pii: { ssn: '1234' }.to_json } }
+ let(:user_session) { {} }
+
+ before do
+ Pii::Cacher.new(user, user_session).save_decrypted_pii({ ssn: '1234' }, profile.id)
+ end
it 'encrypts the active profile' do
- encryptor = instance_double(ActiveProfileEncryptor)
- allow(ActiveProfileEncryptor).to receive(:new).
- with(user, user_session, password).and_return(encryptor)
- allow(encryptor).to receive(:call)
+ encryptor = instance_double(UserProfilesEncryptor)
+ allow(UserProfilesEncryptor).to receive(:new).
+ with(user: user, user_session: user_session, password: password).and_return(encryptor)
+ allow(encryptor).to receive(:encrypt)
subject.submit(params)
- expect(encryptor).to have_received(:call)
+ expect(encryptor).to have_received(:encrypt)
end
it 'logs that the user has an active profile' do
@@ -96,11 +100,21 @@
context 'the user has a pending profile' do
let(:profile) { create(:profile, :verify_by_mail_pending, :verified, pii: { ssn: '1234' }) }
let(:user) { profile.user }
+ let(:user_session) { {} }
- it 'does not call ActiveProfileEncryptor' do
- expect(ActiveProfileEncryptor).to_not receive(:new)
+ before do
+ Pii::Cacher.new(user, user_session).save_decrypted_pii({ ssn: '1234' }, profile.id)
+ end
+
+ it 'encrypts the pending profile' do
+ encryptor = instance_double(UserProfilesEncryptor)
+ allow(UserProfilesEncryptor).to receive(:new).
+ with(user: user, user_session: user_session, password: password).and_return(encryptor)
+ allow(encryptor).to receive(:encrypt)
subject.submit(params)
+
+ expect(encryptor).to have_received(:encrypt)
end
it 'logs that the user has a pending profile' do
@@ -114,8 +128,8 @@
end
context 'when the user does not have a profile' do
- it 'does not call ActiveProfileEncryptor' do
- expect(ActiveProfileEncryptor).to_not receive(:new)
+ it 'does not call UserProfilesEncryptor' do
+ expect(UserProfilesEncryptor).to_not receive(:new)
subject.submit(params)
end
diff --git a/spec/forms/webauthn_setup_form_spec.rb b/spec/forms/webauthn_setup_form_spec.rb
index 235307a57b9..e5207d3e6c7 100644
--- a/spec/forms/webauthn_setup_form_spec.rb
+++ b/spec/forms/webauthn_setup_form_spec.rb
@@ -215,10 +215,7 @@
'errors.webauthn_setup.attestation_error',
link: MarketingSite.contact_url,
)] },
- error_details: { name: [I18n.t(
- 'errors.webauthn_setup.attestation_error',
- link: MarketingSite.contact_url,
- )] },
+ error_details: { name: { attestation_error: true } },
**extra_attributes,
)
end
diff --git a/spec/forms/webauthn_verification_form_spec.rb b/spec/forms/webauthn_verification_form_spec.rb
index 2843d0cd3c4..efd4cd2ca1e 100644
--- a/spec/forms/webauthn_verification_form_spec.rb
+++ b/spec/forms/webauthn_verification_form_spec.rb
@@ -1,6 +1,7 @@
require 'rails_helper'
RSpec.describe WebauthnVerificationForm do
+ include Rails.application.routes.url_helpers
include WebAuthnHelper
let(:user) { create(:user) }
@@ -22,6 +23,8 @@
subject(:form) do
WebauthnVerificationForm.new(
user: user,
+ platform_authenticator:,
+ url_options: {},
challenge: challenge,
protocol: protocol,
authenticator_data: authenticator_data,
@@ -59,22 +62,21 @@
)
end
end
- end
- context 'when the input is invalid' do
- context 'when user is missing' do
- let(:user) { nil }
+ context 'with client-side webauthn error as blank string' do
+ let(:webauthn_error) { '' }
- it 'returns unsuccessful result' do
+ it 'returns successful result excluding frontend_error' do
expect(result.to_h).to eq(
- success: false,
- error_details: { user: [:blank], webauthn_configuration: [:blank] },
+ success: true,
multi_factor_auth_method: 'webauthn',
- webauthn_configuration_id: nil,
+ webauthn_configuration_id: webauthn_configuration.id,
)
end
end
+ end
+ context 'when the input is invalid' do
context 'when challenge is missing' do
let(:challenge) { nil }
@@ -82,8 +84,8 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- challenge: [:blank],
- authenticator_data: ['invalid_authenticator_data'],
+ challenge: { blank: true },
+ authenticator_data: { invalid_authenticator_data: true },
},
multi_factor_auth_method: 'webauthn',
webauthn_configuration_id: webauthn_configuration.id,
@@ -98,7 +100,7 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- authenticator_data: [:blank, 'invalid_authenticator_data'],
+ authenticator_data: { blank: true, invalid_authenticator_data: true },
},
multi_factor_auth_method: 'webauthn',
webauthn_configuration_id: webauthn_configuration.id,
@@ -113,8 +115,8 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- client_data_json: [:blank],
- authenticator_data: ['invalid_authenticator_data'],
+ client_data_json: { blank: true },
+ authenticator_data: { invalid_authenticator_data: true },
},
multi_factor_auth_method: 'webauthn',
webauthn_configuration_id: webauthn_configuration.id,
@@ -129,8 +131,8 @@
expect(result.to_h).to eq(
success: false,
error_details: {
- signature: [:blank],
- authenticator_data: ['invalid_authenticator_data'],
+ signature: { blank: true },
+ authenticator_data: { invalid_authenticator_data: true },
},
multi_factor_auth_method: 'webauthn',
webauthn_configuration_id: webauthn_configuration.id,
@@ -144,22 +146,22 @@
it 'returns unsuccessful result' do
expect(result.to_h).to eq(
success: false,
- error_details: { webauthn_configuration: [:blank] },
+ error_details: { webauthn_configuration: { blank: true } },
multi_factor_auth_method: 'webauthn',
- webauthn_configuration_id: nil,
)
end
end
context 'when a client-side webauthn error is present' do
- let(:webauthn_error) { 'Unexpected error!' }
+ let(:webauthn_error) { 'NotAllowedError' }
it 'returns unsuccessful result including client-side webauthn error text' do
expect(result.to_h).to eq(
success: false,
- error_details: { webauthn_error: [webauthn_error] },
+ error_details: { webauthn_error: { present: true } },
multi_factor_auth_method: 'webauthn',
webauthn_configuration_id: webauthn_configuration.id,
+ frontend_error: webauthn_error,
)
end
end
@@ -172,7 +174,7 @@
it 'returns unsuccessful result' do
expect(result.to_h).to eq(
success: false,
- error_details: { authenticator_data: ['invalid_authenticator_data'] },
+ error_details: { authenticator_data: { invalid_authenticator_data: true } },
multi_factor_auth_method: 'webauthn',
webauthn_configuration_id: webauthn_configuration.id,
)
@@ -188,7 +190,7 @@
it 'returns unsucessful result' do
expect(result.to_h).to eq(
success: false,
- error_details: { authenticator_data: ['invalid_authenticator_data'] },
+ error_details: { authenticator_data: { invalid_authenticator_data: true } },
multi_factor_auth_method: 'webauthn',
webauthn_configuration_id: webauthn_configuration.id,
)
diff --git a/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx b/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx
index d3a46c94e1b..28fd65c4487 100644
--- a/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx
+++ b/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx
@@ -1188,7 +1188,7 @@ describe('document-capture/components/acuant-capture', () => {
mimeType: 'image/jpeg',
size: sinon.match.number,
attempt: sinon.match.number,
- acuantCaptureMode: 'AUTO',
+ acuantCaptureMode: null,
}),
);
});
diff --git a/spec/javascript/packs/puerto-rico-guidance-spec.js b/spec/javascript/packs/puerto-rico-guidance-spec.js
deleted file mode 100644
index 3760eac59bd..00000000000
--- a/spec/javascript/packs/puerto-rico-guidance-spec.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { showOrHidePuertoRicoExtras } from '../../../app/javascript/packs/puerto-rico-guidance';
-
-describe('puerto-rico-guidance', () => {
- describe('showOrHidePuertoRicoExtras', () => {
- beforeEach(() => {
- document.body.innerHTML = `
-
-
-
-
-
-
- `;
- });
-
- it('includes class display-none if state is not PR', () => {
- const forStateCode = 'NY';
- showOrHidePuertoRicoExtras(forStateCode);
- const prExtrasElemClassList = document.querySelector('.puerto-rico-extras')?.classList;
-
- expect(prExtrasElemClassList).to.contain(['puerto-rico-extras', 'display-none']);
- });
-
- it('does not include class display-none if state is PR', () => {
- const forStateCode = 'PR';
- showOrHidePuertoRicoExtras(forStateCode);
- const prExtrasElemClassList = document.querySelector('.puerto-rico-extras')?.classList;
-
- expect(prExtrasElemClassList).to.contain(['puerto-rico-extras']);
- });
- });
-});
diff --git a/spec/javascript/packs/state-guidance-spec.js b/spec/javascript/packs/state-guidance-spec.js
new file mode 100644
index 00000000000..6314f2a7f3d
--- /dev/null
+++ b/spec/javascript/packs/state-guidance-spec.js
@@ -0,0 +1,101 @@
+import { expect } from 'chai';
+import {
+ showOrHideJurisdictionExtras,
+ showOrHidePuertoRicoExtras,
+} from '../../../app/javascript/packs/state-guidance';
+
+describe('state-guidance', () => {
+ describe('showOrHidePuertoRicoExtras', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+ `;
+ });
+
+ it('includes class display-none if state is not PR', () => {
+ const forStateCode = 'NY';
+ showOrHidePuertoRicoExtras(forStateCode);
+ const prExtrasElemClassList = document.querySelector('.puerto-rico-extras')?.classList;
+
+ expect(prExtrasElemClassList).to.contain(['puerto-rico-extras', 'display-none']);
+ });
+
+ it('does not include class display-none if state is PR', () => {
+ const forStateCode = 'PR';
+ showOrHidePuertoRicoExtras(forStateCode);
+ const prExtrasElemClassList = document.querySelector('.puerto-rico-extras')?.classList;
+
+ expect(prExtrasElemClassList).to.contain(['puerto-rico-extras']);
+ });
+ });
+
+ describe('showOrHideJurisdictionExtras', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+ `;
+ });
+
+ it('includes Texas specific hint text when Texas is selected', () => {
+ const jurisdictionCode = 'TX';
+ showOrHideJurisdictionExtras(jurisdictionCode);
+
+ const allHintTexts = document.querySelectorAll('.jurisdiction-extras [data-state]');
+ const texasText = document.querySelectorAll('.jurisdiction-extras [data-state=TX]');
+ const nonTexasText = document.querySelectorAll(
+ '.jurisdiction-extras [data-state].display-none',
+ );
+
+ expect(texasText.length).to.eq(1);
+ expect(texasText[0].classList.contains('display-none')).to.eq(false);
+
+ expect(nonTexasText.length + texasText.length).to.eq(allHintTexts.length);
+ });
+
+ it('includes default hint text when no state is selected', () => {
+ const jurisdictionCode = '';
+ showOrHideJurisdictionExtras(jurisdictionCode);
+
+ const allHintTexts = document.querySelectorAll('.jurisdiction-extras [data-state]');
+ const defaultText = document.querySelectorAll('.jurisdiction-extras [data-state=default]');
+ const nonDefaultText = document.querySelectorAll(
+ '.jurisdiction-extras [data-state].display-none',
+ );
+
+ expect(defaultText.length).to.eq(1);
+ expect(defaultText[0].classList.contains('display-none')).to.eq(false);
+
+ expect(nonDefaultText.length + defaultText.length).to.eq(allHintTexts.length);
+ });
+
+ it('includes default hint text when a state without a state specific hint is selected', () => {
+ const jurisdictionCode = 'NY';
+ showOrHideJurisdictionExtras(jurisdictionCode);
+
+ const allHintTexts = document.querySelectorAll('.jurisdiction-extras [data-state]');
+ const defaultText = document.querySelectorAll('.jurisdiction-extras [data-state=default]');
+ const nonDefaultText = document.querySelectorAll(
+ '.jurisdiction-extras [data-state].display-none',
+ );
+
+ expect(defaultText.length).to.eq(1);
+ expect(defaultText[0].classList.contains('display-none')).to.eq(false);
+
+ expect(nonDefaultText.length + defaultText.length).to.eq(allHintTexts.length);
+ });
+ });
+});
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index bfc0d2b908b..a37d56cf47e 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -923,6 +923,14 @@
user.suspend!
end
+ it 'send account disabled push event' do
+ expect(PushNotification::HttpPush).to receive(:deliver).once.
+ with(PushNotification::AccountDisabledEvent.new(
+ user: user,
+ ))
+ user.suspend!
+ end
+
it 'logs out the suspended user from the active session' do
# Add information to session store to allow `exists?` check to work as desired
OutOfBandSessionAccessor.new(mock_session_id).put_pii(
@@ -985,6 +993,14 @@
user.reinstate!
end
+ it 'send account enabled push event' do
+ expect(PushNotification::HttpPush).to receive(:deliver).once.
+ with(PushNotification::AccountEnabledEvent.new(
+ user: user,
+ ))
+ user.reinstate!
+ end
+
it 'raises an error if the user is not currently suspended' do
user.suspended_at = nil
expect(user.analytics).to receive(:user_reinstated).with(
diff --git a/spec/presenters/two_factor_authentication/selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/selection_presenter_spec.rb
deleted file mode 100644
index 009b7180107..00000000000
--- a/spec/presenters/two_factor_authentication/selection_presenter_spec.rb
+++ /dev/null
@@ -1,140 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe TwoFactorAuthentication::SelectionPresenter do
- let(:placeholder_presenter_class) do
- Class.new(TwoFactorAuthentication::SelectionPresenter) do
- def method
- :missing
- end
- end
- end
-
- let(:user) { build(:user) }
-
- subject(:presenter) { described_class.new(user: user) }
-
- describe '#render_in' do
- it 'renders captured block content' do
- view_context = ActionController::Base.new.view_context
-
- expect(view_context).to receive(:capture) do |*args, &block|
- expect(block.call).to eq('content')
- end
-
- presenter.render_in(view_context) { 'content' }
- end
- end
-
- describe '#disabled?' do
- let(:single_configuration_only) {}
- let(:mfa_configuration_count) {}
-
- before do
- allow(presenter).to receive(:single_configuration_only?).and_return(single_configuration_only)
- allow(presenter).to receive(:mfa_configuration_count).and_return(mfa_configuration_count)
- end
-
- context 'without single configuration restriction' do
- let(:single_configuration_only) { false }
-
- it 'is an mfa that allows multiple configurations' do
- expect(presenter.disabled?).to eq(false)
- end
- end
-
- context 'with single configuration only' do
- let(:single_configuration_only) { true }
-
- context 'with default mfa count implementation' do
- before do
- allow(presenter).to receive(:mfa_configuration_count).and_call_original
- end
-
- it 'is mfa with unimplemented mfa count and single config' do
- expect(presenter.disabled?).to eq(false)
- end
- end
-
- context 'with no configured mfas' do
- let(:mfa_configuration_count) { 0 }
-
- it 'is configured with no mfa' do
- expect(presenter.disabled?).to eq(false)
- end
- end
-
- context 'with at least one configured mfa' do
- let(:mfa_configuration_count) { 1 }
-
- it 'is mfa with at least one configured' do
- expect(presenter.disabled?).to eq(true)
- end
- end
- end
- context 'with configuration' do
- let(:single_configuration_only) { true }
- let(:mfa_configuration_count) { 1 }
- let(:configuration) { create(:phone_configuration, user: user) }
- before do
- allow(presenter).to receive(:configuration).and_return(configuration)
- end
- it { expect(presenter.disabled?).to eq(false) }
- end
- end
-
- describe '#single_configuration_only?' do
- it { expect(presenter.single_configuration_only?).to eq(false) }
- end
-
- describe '#mfa_added_label' do
- subject(:mfa_added_label) { presenter.mfa_added_label }
- before do
- allow(presenter).to receive(:mfa_configuration_count).and_return('1')
- end
- it 'is a count of configured MFAs' do
- expect(presenter.mfa_added_label).to include('added')
- end
-
- context 'with single configuration only' do
- before do
- allow(presenter).to receive(:single_configuration_only?).and_return(true)
- end
-
- it 'is an empty string' do
- expect(presenter.mfa_added_label).to eq('')
- end
- end
- end
-
- describe '#label' do
- context 'with no configuration' do
- it 'raises with missing translation' do
- expect { placeholder_presenter_class.new(user: user).label }.to raise_error(RuntimeError)
- end
- end
-
- context 'with configuration' do
- it 'raises with missing translation' do
- expect do
- placeholder_presenter_class.new(configuration: 1, user: user).label
- end.to raise_error(RuntimeError)
- end
- end
- end
-
- describe '#info' do
- context 'with no configuration' do
- it 'raises with missing translation' do
- expect { placeholder_presenter_class.new(user: user).info }.to raise_error(RuntimeError)
- end
- end
-
- context 'with configuration' do
- it 'raises with missing translation' do
- expect do
- placeholder_presenter_class.new(configuration: 1, user: user).info
- end.to raise_error(RuntimeError)
- end
- end
- end
-end
diff --git a/spec/presenters/two_factor_authentication/set_up_auth_app_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/set_up_auth_app_selection_presenter_spec.rb
index ada58bceb8d..6118cacb57c 100644
--- a/spec/presenters/two_factor_authentication/set_up_auth_app_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/set_up_auth_app_selection_presenter_spec.rb
@@ -13,7 +13,7 @@
describe '#type' do
it 'returns auth_app' do
- expect(presenter_without_mfa.type).to eq 'auth_app'
+ expect(presenter_without_mfa.type).to eq :auth_app
end
end
diff --git a/spec/presenters/two_factor_authentication/phone_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/set_up_phone_selection_presenter_spec.rb
similarity index 82%
rename from spec/presenters/two_factor_authentication/phone_selection_presenter_spec.rb
rename to spec/presenters/two_factor_authentication/set_up_phone_selection_presenter_spec.rb
index b22167d42f3..8c9e9137218 100644
--- a/spec/presenters/two_factor_authentication/phone_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/set_up_phone_selection_presenter_spec.rb
@@ -1,15 +1,13 @@
require 'rails_helper'
-RSpec.describe TwoFactorAuthentication::PhoneSelectionPresenter do
+RSpec.describe TwoFactorAuthentication::SetUpPhoneSelectionPresenter do
let(:user_without_mfa) { create(:user) }
let(:user_with_mfa) { create(:user, :with_phone) }
- let(:presenter_with_mfa) { described_class.new(configuration: phone, user: user_with_mfa) }
- let(:presenter_without_mfa) { described_class.new(configuration: phone, user: user_without_mfa) }
+ let(:presenter_with_mfa) { described_class.new(user: user_with_mfa) }
+ let(:presenter_without_mfa) { described_class.new(user: user_without_mfa) }
describe '#info' do
context 'when a user does not have a phone configuration (first time)' do
- let(:phone) { nil }
-
it 'includes a note about choosing voice or sms' do
expect(presenter_without_mfa.info).
to include(t('two_factor_authentication.two_factor_choice_options.phone_info'))
@@ -28,8 +26,6 @@
end
describe '#disabled?' do
- let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }
-
it { expect(presenter_without_mfa.disabled?).to eq(false) }
context 'all phone vendor outage' do
@@ -42,7 +38,6 @@
end
describe '#mfa_configuration' do
- let(:phone) { nil }
it 'returns an empty string when user has not configured this authenticator' do
expect(presenter_without_mfa.mfa_configuration_description).to eq('')
end
diff --git a/spec/presenters/two_factor_authentication/set_up_piv_cac_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/set_up_piv_cac_selection_presenter_spec.rb
index cb5744107ba..79cc227b621 100644
--- a/spec/presenters/two_factor_authentication/set_up_piv_cac_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/set_up_piv_cac_selection_presenter_spec.rb
@@ -12,7 +12,7 @@
describe '#type' do
it 'returns piv_cac' do
- expect(presenter_without_mfa.type).to eq 'piv_cac'
+ expect(presenter_without_mfa.type).to eq :piv_cac
end
end
diff --git a/spec/presenters/two_factor_authentication/set_up_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/set_up_selection_presenter_spec.rb
index eec0b2649ba..4b74dbb20fa 100644
--- a/spec/presenters/two_factor_authentication/set_up_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/set_up_selection_presenter_spec.rb
@@ -2,11 +2,7 @@
RSpec.describe TwoFactorAuthentication::SetUpSelectionPresenter do
let(:placeholder_presenter_class) do
- Class.new(TwoFactorAuthentication::SetUpSelectionPresenter) do
- def method
- :missing
- end
- end
+ Class.new(TwoFactorAuthentication::SetUpSelectionPresenter)
end
let(:user) { build(:user) }
@@ -93,15 +89,21 @@ def method
end
end
+ describe '#type' do
+ it 'raises with missing implementation' do
+ expect { placeholder_presenter_class.new(user:).type }.to raise_error(NotImplementedError)
+ end
+ end
+
describe '#label' do
- it 'raises with missing translation' do
- expect { placeholder_presenter_class.new(user: user).label }.to raise_error(RuntimeError)
+ it 'raises with missing implementation' do
+ expect { placeholder_presenter_class.new(user:).label }.to raise_error(NotImplementedError)
end
end
describe '#info' do
- it 'raises with missing translation' do
- expect { placeholder_presenter_class.new(user: user).info }.to raise_error(RuntimeError)
+ it 'raises with missing implementation' do
+ expect { placeholder_presenter_class.new(user:).info }.to raise_error(NotImplementedError)
end
end
end
diff --git a/spec/presenters/two_factor_authentication/set_up_webauthn_platform_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/set_up_webauthn_platform_selection_presenter_spec.rb
index 65fd19dcf3f..879e8509f11 100644
--- a/spec/presenters/two_factor_authentication/set_up_webauthn_platform_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/set_up_webauthn_platform_selection_presenter_spec.rb
@@ -19,7 +19,7 @@
describe '#type' do
it 'returns webauthn_platform' do
- expect(presenter_without_mfa.type).to eq 'webauthn_platform'
+ expect(presenter_without_mfa.type).to eq :webauthn_platform
end
end
diff --git a/spec/presenters/two_factor_authentication/set_up_webauthn_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/set_up_webauthn_selection_presenter_spec.rb
index 620868ca79d..1e74d55f580 100644
--- a/spec/presenters/two_factor_authentication/set_up_webauthn_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/set_up_webauthn_selection_presenter_spec.rb
@@ -13,7 +13,7 @@
describe '#type' do
it 'returns webauthn' do
- expect(presenter_without_mfa.type).to eq 'webauthn'
+ expect(presenter_without_mfa.type).to eq :webauthn
end
end
diff --git a/spec/presenters/two_factor_authentication/sign_in_auth_app_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/sign_in_auth_app_selection_presenter_spec.rb
index 5fe3027a668..857de98bd20 100644
--- a/spec/presenters/two_factor_authentication/sign_in_auth_app_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/sign_in_auth_app_selection_presenter_spec.rb
@@ -10,7 +10,7 @@
describe '#type' do
it 'returns auth_app' do
- expect(presenter.type).to eq 'auth_app'
+ expect(presenter.type).to eq :auth_app
end
end
diff --git a/spec/presenters/two_factor_authentication/sign_in_personal_key_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/sign_in_personal_key_selection_presenter_spec.rb
index b2993d839e5..98cbdf07633 100644
--- a/spec/presenters/two_factor_authentication/sign_in_personal_key_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/sign_in_personal_key_selection_presenter_spec.rb
@@ -10,7 +10,7 @@
subject(:type) { presenter.type }
it 'returns personal key type' do
- expect(type).to eq 'personal_key'
+ expect(type).to eq :personal_key
end
end
diff --git a/spec/presenters/two_factor_authentication/sign_in_phone_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/sign_in_phone_selection_presenter_spec.rb
new file mode 100644
index 00000000000..c70580f29fb
--- /dev/null
+++ b/spec/presenters/two_factor_authentication/sign_in_phone_selection_presenter_spec.rb
@@ -0,0 +1,125 @@
+require 'rails_helper'
+
+RSpec.describe TwoFactorAuthentication::SignInPhoneSelectionPresenter do
+ let(:user) { create(:user) }
+ let(:configuration) { create(:phone_configuration, user: user) }
+ let(:delivery_method) { nil }
+
+ let(:presenter) do
+ described_class.new(user:, configuration:, delivery_method:)
+ end
+
+ describe '#type' do
+ context 'without a defined delivery method' do
+ let(:delivery_method) { nil }
+
+ it 'returns generic phone type' do
+ expect(presenter.type).to eq :phone
+ end
+ end
+
+ context 'with delivery method' do
+ let(:delivery_method) { :sms }
+
+ context 'with user having a single configuration' do
+ it 'returns delivery method' do
+ expect(presenter.type).to eq :sms
+ end
+ end
+
+ context 'with user having multiple configurations' do
+ let(:user) { create(:user, :with_phone) }
+
+ it 'returns delivery method appended with configuration id' do
+ expect(presenter.type).to eq "sms_#{configuration.id}".to_sym
+ end
+ end
+ end
+ end
+
+ describe '#info' do
+ context 'without a defined delivery method' do
+ let(:delivery_method) { nil }
+
+ it 'returns the correct translation for setup' do
+ expect(presenter.info).to eq(
+ t('two_factor_authentication.two_factor_choice_options.phone_info'),
+ )
+ end
+ end
+
+ context 'with sms delivery method' do
+ let(:delivery_method) { :sms }
+
+ it 'returns the correct translation for sms' do
+ expect(presenter.info).to eq(
+ t(
+ 'two_factor_authentication.login_options.sms_info_html',
+ phone: configuration.masked_phone,
+ ),
+ )
+ end
+ end
+
+ context 'with voice delivery method' do
+ let(:delivery_method) { :voice }
+
+ it 'returns the correct translation for voice' do
+ expect(presenter.info).to eq(
+ t(
+ 'two_factor_authentication.login_options.voice_info_html',
+ phone: configuration.masked_phone,
+ ),
+ )
+ end
+ end
+ end
+
+ describe '#disabled?' do
+ let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }
+
+ context 'without a defined delivery method' do
+ let(:delivery_method) { nil }
+
+ it { expect(presenter.disabled?).to eq(false) }
+
+ context 'all phone vendor outage' do
+ before do
+ allow_any_instance_of(OutageStatus).to receive(:all_phone_vendor_outage?).and_return(true)
+ end
+
+ it { expect(presenter.disabled?).to eq(true) }
+ end
+ end
+
+ context 'with sms delivery method' do
+ let(:delivery_method) { :sms }
+
+ it { expect(presenter.disabled?).to eq(false) }
+
+ context 'sms vendor outage' do
+ before do
+ allow_any_instance_of(OutageStatus).to receive(:vendor_outage?).with(:sms).
+ and_return(true)
+ end
+
+ it { expect(presenter.disabled?).to eq(true) }
+ end
+ end
+
+ context 'with voice delivery method' do
+ let(:delivery_method) { :voice }
+
+ it { expect(presenter.disabled?).to eq(false) }
+
+ context 'voice vendor outage' do
+ before do
+ allow_any_instance_of(OutageStatus).to receive(:vendor_outage?).with(:voice).
+ and_return(true)
+ end
+
+ it { expect(presenter.disabled?).to eq(true) }
+ end
+ end
+ end
+end
diff --git a/spec/presenters/two_factor_authentication/sign_in_piv_cac_selection_presenter.spec.rb b/spec/presenters/two_factor_authentication/sign_in_piv_cac_selection_presenter.spec.rb
index 214bf954038..e2d6d5fa8bb 100644
--- a/spec/presenters/two_factor_authentication/sign_in_piv_cac_selection_presenter.spec.rb
+++ b/spec/presenters/two_factor_authentication/sign_in_piv_cac_selection_presenter.spec.rb
@@ -10,7 +10,7 @@
describe '#type' do
it 'returns piv_cac' do
- expect(presenter.type).to eq 'piv_cac'
+ expect(presenter.type).to eq :piv_cac
end
end
diff --git a/spec/presenters/two_factor_authentication/sign_in_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/sign_in_selection_presenter_spec.rb
index e31720e78fa..d0ce9e0810c 100644
--- a/spec/presenters/two_factor_authentication/sign_in_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/sign_in_selection_presenter_spec.rb
@@ -2,11 +2,7 @@
RSpec.describe TwoFactorAuthentication::SignInSelectionPresenter do
let(:placeholder_presenter_class) do
- Class.new(TwoFactorAuthentication::SignInSelectionPresenter) do
- def method
- :missing
- end
- end
+ Class.new(TwoFactorAuthentication::SignInSelectionPresenter)
end
let(:user) { build(:user) }
@@ -27,24 +23,20 @@ def method
end
describe '#label' do
- it 'raises with missing translation' do
- expect do
- presenter.label
- end.to raise_error(RuntimeError)
+ it 'raises with missing implementation' do
+ expect { presenter.label }.to raise_error(NotImplementedError)
end
end
describe '#type' do
- it 'returns missing as type' do
- expect(presenter.type).to eq('missing')
+ it 'raises with missing implementation' do
+ expect { presenter.type }.to raise_error(NotImplementedError)
end
end
describe '#info' do
- it 'raises with missing translation' do
- expect do
- presenter.info
- end.to raise_error(RuntimeError)
+ it 'raises with missing implementation' do
+ expect { presenter.info }.to raise_error(NotImplementedError)
end
end
end
diff --git a/spec/presenters/two_factor_authentication/sign_in_webauthn_platform_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/sign_in_webauthn_platform_selection_presenter_spec.rb
index 14b7400f57e..2744d974f6b 100644
--- a/spec/presenters/two_factor_authentication/sign_in_webauthn_platform_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/sign_in_webauthn_platform_selection_presenter_spec.rb
@@ -10,7 +10,7 @@
describe '#type' do
it 'returns webauthn_platform' do
- expect(presenter.type).to eq 'webauthn_platform'
+ expect(presenter.type).to eq :webauthn_platform
end
end
diff --git a/spec/presenters/two_factor_authentication/sign_in_webauthn_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/sign_in_webauthn_selection_presenter_spec.rb
index 4676124561f..7bc097bb33d 100644
--- a/spec/presenters/two_factor_authentication/sign_in_webauthn_selection_presenter_spec.rb
+++ b/spec/presenters/two_factor_authentication/sign_in_webauthn_selection_presenter_spec.rb
@@ -10,7 +10,7 @@
describe '#type' do
it 'returns webauthn' do
- expect(presenter.type).to eq 'webauthn'
+ expect(presenter.type).to eq :webauthn
end
end
diff --git a/spec/presenters/two_factor_authentication/sms_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/sms_selection_presenter_spec.rb
deleted file mode 100644
index 54064ce07d3..00000000000
--- a/spec/presenters/two_factor_authentication/sms_selection_presenter_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe TwoFactorAuthentication::SmsSelectionPresenter do
- let(:subject) { described_class.new(configuration: phone, user: user) }
- let(:user) { build(:user) }
-
- describe '#type' do
- context 'when a user has only one phone configuration' do
- let(:user) { create(:user, :with_phone) }
- let(:phone) { MfaContext.new(user).phone_configurations.first }
-
- it 'returns sms' do
- expect(subject.type).to eq 'sms'
- end
- end
-
- context 'when a user has more than one phone configuration' do
- let(:user) { create(:user, :with_phone) }
- let(:phone) do
- record = create(:phone_configuration, user: user)
- user.reload
- record
- end
-
- it 'returns sms:id' do
- expect(subject.type).to eq "sms_#{phone.id}"
- end
- end
- end
-
- describe '#info' do
- context 'when a user has a phone configuration' do
- let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }
- it 'includes the masked the number' do
- expect(subject.info).to include('(***) ***-5309')
- end
- end
- end
-
- describe '#disabled?' do
- let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }
- it { expect(subject.disabled?).to eq(false) }
-
- context 'sms vendor outage' do
- before do
- allow_any_instance_of(OutageStatus).to receive(:vendor_outage?).with(:sms).and_return(true)
- end
-
- it { expect(subject.disabled?).to eq(true) }
- end
- end
-end
diff --git a/spec/presenters/two_factor_authentication/voice_selection_presenter_spec.rb b/spec/presenters/two_factor_authentication/voice_selection_presenter_spec.rb
deleted file mode 100644
index edb1d87d6d3..00000000000
--- a/spec/presenters/two_factor_authentication/voice_selection_presenter_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe TwoFactorAuthentication::VoiceSelectionPresenter do
- let(:subject) { described_class.new(configuration: phone, user: user) }
- let(:user) { build(:user) }
- describe '#type' do
- context 'when a user has only one phone configuration' do
- let(:user) { create(:user, :with_phone) }
- let(:phone) { MfaContext.new(user).phone_configurations.first }
-
- it 'returns voice' do
- expect(subject.type).to eq 'voice'
- end
- end
-
- context 'when a user has more than one phone configuration' do
- let(:user) { create(:user, :with_phone) }
- let(:phone) do
- record = create(:phone_configuration, user: user)
- user.reload
- record
- end
-
- it 'returns voice:id' do
- expect(subject.type).to eq "voice_#{phone.id}"
- end
- end
- end
-
- describe '#info' do
- context 'when a user has a phone configuration' do
- let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }
- it 'includes the masked the number' do
- expect(subject.info).to include('(***) ***-5309')
- end
- end
- end
-
- describe '#disabled?' do
- let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }
- it { expect(subject.disabled?).to eq(false) }
-
- context 'voice vendor outage' do
- before do
- allow_any_instance_of(OutageStatus).to receive(:vendor_outage?).with(:voice).
- and_return(true)
- end
-
- it { expect(subject.disabled?).to eq(true) }
- end
- end
-end
diff --git a/spec/presenters/two_factor_login_options_presenter_spec.rb b/spec/presenters/two_factor_login_options_presenter_spec.rb
index d1ff9ad4dfc..1386d500dd9 100644
--- a/spec/presenters/two_factor_login_options_presenter_spec.rb
+++ b/spec/presenters/two_factor_login_options_presenter_spec.rb
@@ -82,8 +82,8 @@
it 'returns classes for mfas associated with account' do
expect(options_classes).to eq(
[
- TwoFactorAuthentication::SmsSelectionPresenter,
- TwoFactorAuthentication::VoiceSelectionPresenter,
+ TwoFactorAuthentication::SignInPhoneSelectionPresenter,
+ TwoFactorAuthentication::SignInPhoneSelectionPresenter,
TwoFactorAuthentication::SignInWebauthnSelectionPresenter,
TwoFactorAuthentication::SignInBackupCodeSelectionPresenter,
TwoFactorAuthentication::SignInPivCacSelectionPresenter,
@@ -114,8 +114,8 @@
it 'returns all mfas associated with account' do
expect(options_classes).to eq(
[
- TwoFactorAuthentication::SmsSelectionPresenter,
- TwoFactorAuthentication::VoiceSelectionPresenter,
+ TwoFactorAuthentication::SignInPhoneSelectionPresenter,
+ TwoFactorAuthentication::SignInPhoneSelectionPresenter,
TwoFactorAuthentication::SignInWebauthnSelectionPresenter,
TwoFactorAuthentication::SignInBackupCodeSelectionPresenter,
TwoFactorAuthentication::SignInPivCacSelectionPresenter,
@@ -145,8 +145,8 @@
it 'returns all mfas associated with account' do
expect(options_classes).to eq(
[
- TwoFactorAuthentication::SmsSelectionPresenter,
- TwoFactorAuthentication::VoiceSelectionPresenter,
+ TwoFactorAuthentication::SignInPhoneSelectionPresenter,
+ TwoFactorAuthentication::SignInPhoneSelectionPresenter,
TwoFactorAuthentication::SignInWebauthnSelectionPresenter,
TwoFactorAuthentication::SignInBackupCodeSelectionPresenter,
TwoFactorAuthentication::SignInPivCacSelectionPresenter,
diff --git a/spec/presenters/two_factor_options_presenter_spec.rb b/spec/presenters/two_factor_options_presenter_spec.rb
index d644a20b6e4..97233969597 100644
--- a/spec/presenters/two_factor_options_presenter_spec.rb
+++ b/spec/presenters/two_factor_options_presenter_spec.rb
@@ -27,7 +27,7 @@
expect(presenter.options.map(&:class)).to eq [
TwoFactorAuthentication::SetUpWebauthnPlatformSelectionPresenter,
TwoFactorAuthentication::SetUpAuthAppSelectionPresenter,
- TwoFactorAuthentication::PhoneSelectionPresenter,
+ TwoFactorAuthentication::SetUpPhoneSelectionPresenter,
TwoFactorAuthentication::SetUpBackupCodeSelectionPresenter,
TwoFactorAuthentication::SetUpWebauthnSelectionPresenter,
TwoFactorAuthentication::SetUpPivCacSelectionPresenter,
@@ -76,7 +76,7 @@
expect(presenter.options.map(&:class)).to eq [
TwoFactorAuthentication::SetUpWebauthnPlatformSelectionPresenter,
TwoFactorAuthentication::SetUpAuthAppSelectionPresenter,
- TwoFactorAuthentication::PhoneSelectionPresenter,
+ TwoFactorAuthentication::SetUpPhoneSelectionPresenter,
TwoFactorAuthentication::SetUpBackupCodeSelectionPresenter,
TwoFactorAuthentication::SetUpWebauthnSelectionPresenter,
TwoFactorAuthentication::SetUpPivCacSelectionPresenter,
diff --git a/spec/requests/rack_attack_spec.rb b/spec/requests/rack_attack_spec.rb
index 982c90ec627..075633b2af2 100644
--- a/spec/requests/rack_attack_spec.rb
+++ b/spec/requests/rack_attack_spec.rb
@@ -163,6 +163,37 @@
expect(analytics).
to have_received(:track_event).with('Rate Limit Triggered', type: 'req/ip')
end
+
+ it 'logs the service provider' do
+ analytics = FakeAnalytics.new
+ allow(Analytics).to receive(:new).and_return(analytics)
+
+ client_id = 'urn:gov:gsa:openidconnect:sp:server'
+ state = SecureRandom.hex
+ nonce = SecureRandom.hex
+ params = {
+ client_id: client_id,
+ response_type: 'code',
+ acr_values: Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF,
+ scope: 'openid email profile:name social_security_number',
+ redirect_uri: 'http://localhost:7654/auth/result',
+ state: state,
+ nonce: nonce,
+ prompt: 'select_account',
+ }
+
+ get(
+ openid_connect_authorize_path,
+ params: params,
+ headers: { REMOTE_ADDR: '1.2.3.4' },
+ )
+ requests_per_ip_limit.times do
+ get '/', headers: { REMOTE_ADDR: '1.2.3.4' }
+ end
+
+ expect(Analytics).to have_received(:new).with(include(sp: client_id)).at_least(:once)
+ expect(analytics).to have_logged_event('Rate Limit Triggered', type: 'req/ip')
+ end
end
end
diff --git a/spec/services/account_reset/delete_account_spec.rb b/spec/services/account_reset/delete_account_spec.rb
index fe561d2dbc5..582236929f7 100644
--- a/spec/services/account_reset/delete_account_spec.rb
+++ b/spec/services/account_reset/delete_account_spec.rb
@@ -3,10 +3,6 @@
RSpec.describe AccountReset::DeleteAccount do
include AccountResetHelper
- let(:expired_token_message) do
- t('errors.account_reset.granted_token_expired', app_name: APP_NAME)
- end
- let(:expired_token_error) { { token: [expired_token_message] } }
let(:user) { create(:user) }
let(:request) { FakeRequest.new }
let(:analytics) { FakeAnalytics.new }
@@ -57,7 +53,6 @@
it 'logs attempts api event with success true if the token is good' do
expect(fake_attempts_tracker).to receive(:account_reset_account_deleted).with(
success: true,
- failure_reason: nil,
)
create_account_reset_request_for(user, service_provider.issuer)
@@ -69,7 +64,6 @@
it 'logs attempts api event with failure reason if the token is expired' do
expect(fake_attempts_tracker).to receive(:account_reset_account_deleted).with(
success: false,
- failure_reason: expired_token_error,
)
create_account_reset_request_for(user, service_provider.issuer)
diff --git a/spec/services/account_reset/validate_granted_token_spec.rb b/spec/services/account_reset/validate_granted_token_spec.rb
index cde471c1c7b..de23fbaf3d3 100644
--- a/spec/services/account_reset/validate_granted_token_spec.rb
+++ b/spec/services/account_reset/validate_granted_token_spec.rb
@@ -3,10 +3,6 @@
RSpec.describe AccountReset::ValidateGrantedToken do
include AccountResetHelper
- let(:expired_token_message) do
- t('errors.account_reset.granted_token_expired', app_name: APP_NAME)
- end
- let(:expired_token_error) { { token: [expired_token_message] } }
let(:user) { create(:user) }
let(:request) { FakeRequest.new }
let(:analytics) { FakeAnalytics.new }
@@ -33,7 +29,6 @@
it 'logs attempts api event with failure reason if the token is expired' do
expect(fake_attempts_tracker).to receive(:account_reset_account_deleted).with(
success: false,
- failure_reason: expired_token_error,
)
create_account_reset_request_for(user, service_provider.issuer)
diff --git a/spec/services/active_profile_encryptor_spec.rb b/spec/services/active_profile_encryptor_spec.rb
deleted file mode 100644
index 568ff20e0de..00000000000
--- a/spec/services/active_profile_encryptor_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe ActiveProfileEncryptor do
- describe '#call' do
- it 'encrypts the profile' do
- decrypted_pii = { ssn: '1234' }.to_json
- user_session = { decrypted_pii: decrypted_pii }
- profile = create(:profile, :active, :verified, pii: { ssn: '1234' })
- user = profile.user
- password = user.password
- current_pii = Pii::Attributes.new_from_json(decrypted_pii)
-
- allow(user).to receive(:active_profile).and_return(profile)
- allow(profile).to receive(:encrypt_pii)
- allow(profile).to receive(:save!)
- allow(Pii::Attributes).to receive(:new_from_json).with(decrypted_pii).
- and_return(current_pii)
-
- ActiveProfileEncryptor.new(user, user_session, password).call
-
- expect(profile).to have_received(:encrypt_pii).with(current_pii, password)
- expect(profile).to have_received(:save!)
- end
- end
-end
diff --git a/spec/services/doc_auth/acuant/issuer_types_spec.rb b/spec/services/doc_auth/acuant/issuer_types_spec.rb
new file mode 100644
index 00000000000..163c90946e1
--- /dev/null
+++ b/spec/services/doc_auth/acuant/issuer_types_spec.rb
@@ -0,0 +1,15 @@
+require 'rails_helper'
+
+RSpec.describe DocAuth::Acuant::IssuerTypes do
+ describe '.from_int' do
+ it 'is a result code for the int' do
+ issuer_type = DocAuth::Acuant::IssuerTypes.from_int(1)
+ expect(issuer_type).to be_a(DocAuth::Acuant::IssuerTypes::IssuerType)
+ end
+
+ it 'is nil when there is no matching code' do
+ issuer_type = DocAuth::Acuant::IssuerTypes.from_int(999)
+ expect(issuer_type).to be_nil
+ end
+ end
+end
diff --git a/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb b/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb
index 5795ba59d60..178b6027ffe 100644
--- a/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb
+++ b/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb
@@ -39,23 +39,25 @@
alert_failure_count: 2,
tamper_result: 'Passed',
classification_info: {
- 'Back' => {
- 'ClassName' => 'Identification Card',
- 'Issue' => '2014',
- 'IssueType' => 'Back',
- 'Name' => 'North Dakota (ND) Back',
- 'IssuerCode' => 'ND',
- 'IssuerName' => 'North Dakota',
- 'CountryCode' => 'USA',
+ Back: {
+ ClassName: 'Identification Card',
+ Issue: '2014',
+ IssueType: 'Back',
+ Name: 'North Dakota (ND) Back',
+ IssuerCode: 'ND',
+ IssuerName: 'North Dakota',
+ CountryCode: 'USA',
+ IssuerType: 'StateProvince',
},
- 'Front' => {
- 'ClassName' => 'Identification Card',
- 'Issue' => '2014',
- 'IssueType' => 'Non-Driver Identification Card',
- 'Name' => 'North Dakota (ND) Non-Driver Identification Card',
- 'IssuerCode' => 'ND',
- 'IssuerName' => 'North Dakota',
- 'CountryCode' => 'USA',
+ Front: {
+ ClassName: 'Identification Card',
+ Issue: '2014',
+ IssueType: 'Non-Driver Identification Card',
+ Name: 'North Dakota (ND) Non-Driver Identification Card',
+ IssuerCode: 'ND',
+ IssuerName: 'North Dakota',
+ CountryCode: 'USA',
+ IssuerType: 'StateProvince',
},
},
address_line2_present: true,
@@ -393,23 +395,25 @@
alert_failure_count: 2,
tamper_result: 'Passed',
classification_info: {
- 'Back' => {
- 'ClassName' => 'Tribal Identification',
- 'Issue' => '2014',
- 'IssueType' => 'Back',
- 'Name' => 'Cowlitz Indian Tribe Back',
- 'IssuerCode' => 'ND',
- 'IssuerName' => 'Cowlitz Indian Tribe',
- 'CountryCode' => 'USA',
+ Back: {
+ ClassName: 'Tribal Identification',
+ Issue: '2014',
+ IssueType: 'Back',
+ Name: 'Cowlitz Indian Tribe Back',
+ IssuerCode: 'ND',
+ IssuerName: 'Cowlitz Indian Tribe',
+ CountryCode: 'USA',
+ IssuerType: 'StateProvince',
},
- 'Front' => {
- 'ClassName' => 'Tribal Identification',
- 'Issue' => '2014',
- 'IssueType' => 'Tribal Identification Card',
- 'Name' => 'Cowlitz Indian Tribe Tribal Identification',
- 'IssuerCode' => 'ND',
- 'IssuerName' => 'Cowlitz Indian Tribe',
- 'CountryCode' => 'USA',
+ Front: {
+ ClassName: 'Tribal Identification',
+ Issue: '2014',
+ IssueType: 'Tribal Identification Card',
+ Name: 'Cowlitz Indian Tribe Tribal Identification',
+ IssuerCode: 'ND',
+ IssuerName: 'Cowlitz Indian Tribe',
+ CountryCode: 'USA',
+ IssuerType: 'StateProvince',
},
},
address_line2_present: true,
@@ -472,23 +476,25 @@
alert_failure_count: 2,
tamper_result: 'Passed',
classification_info: {
- 'Back' => {
- 'ClassName' => 'Identification Card',
- 'Issue' => '2014',
- 'IssueType' => 'Back',
- 'Name' => 'North Dakota (ND) Back',
- 'IssuerCode' => 'ND',
- 'IssuerName' => 'North Dakota',
- 'CountryCode' => 'CAN',
+ Back: {
+ ClassName: 'Identification Card',
+ Issue: '2014',
+ IssueType: 'Back',
+ Name: 'North Dakota (ND) Back',
+ IssuerCode: 'ND',
+ IssuerName: 'North Dakota',
+ CountryCode: 'CAN',
+ IssuerType: 'StateProvince',
},
- 'Front' => {
- 'ClassName' => 'Identification Card',
- 'Issue' => '2014',
- 'IssueType' => 'Non-Driver Identification Card',
- 'Name' => 'North Dakota (ND) Non-Driver Identification Card',
- 'IssuerCode' => 'ND',
- 'IssuerName' => 'North Dakota',
- 'CountryCode' => 'CAN',
+ Front: {
+ ClassName: 'Identification Card',
+ Issue: '2014',
+ IssueType: 'Non-Driver Identification Card',
+ Name: 'North Dakota (ND) Non-Driver Identification Card',
+ IssuerCode: 'ND',
+ IssuerName: 'North Dakota',
+ CountryCode: 'CAN',
+ IssuerType: 'StateProvince',
},
},
address_line2_present: true,
diff --git a/spec/services/doc_auth/classification_concern_spec.rb b/spec/services/doc_auth/classification_concern_spec.rb
new file mode 100644
index 00000000000..116192e1919
--- /dev/null
+++ b/spec/services/doc_auth/classification_concern_spec.rb
@@ -0,0 +1,53 @@
+require 'rails_helper'
+
+RSpec.describe DocAuth::ClassificationConcern do
+ let(:class_name) { 'Identification Card' }
+ let(:country_code) { 'USA' }
+ let(:issuer_type) { 'StateProvince' }
+ let(:info) do
+ {
+ Front: {
+ ClassName: class_name,
+ CountryCode: country_code,
+ IssuerType: issuer_type,
+ },
+ Back: {
+ ClassName: class_name,
+ CountryCode: country_code,
+ IssuerType: issuer_type,
+ },
+ }
+ end
+
+ subject do
+ Class.new do
+ include DocAuth::ClassificationConcern
+ attr_reader :classification_info
+ def initialize(classification_info)
+ @classification_info = classification_info
+ end
+ end.new(info)
+ end
+
+ describe '#id_type_supported?' do
+ context 'with state issued identification card' do
+ it 'returns true' do
+ expect(subject.id_type_supported?).to eq(true)
+ end
+ end
+
+ context 'with US passport card' do
+ let(:issuer_type) { 'Country' }
+ it 'returns false' do
+ expect(subject.id_type_supported?).to eq(false)
+ end
+ end
+
+ context 'with state issued drivers license' do
+ let(:class_name) { 'Drivers License' }
+ it 'returns true' do
+ expect(subject.id_type_supported?).to eq(true)
+ end
+ end
+ end
+end
diff --git a/spec/services/doc_auth/error_generator_spec.rb b/spec/services/doc_auth/error_generator_spec.rb
index 5cb19447916..2d78483712f 100644
--- a/spec/services/doc_auth/error_generator_spec.rb
+++ b/spec/services/doc_auth/error_generator_spec.rb
@@ -15,7 +15,8 @@
IssueType: 'ePassport',
Name: 'United States (USA) ePassport',
IssuerCode: 'USA',
- IssuerName: 'United States' }
+ IssuerName: 'United States',
+ IssuerType: 'Country' }
end
let(:unknown_classification_details) do
{ ClassName: 'Unknown',
@@ -25,6 +26,15 @@
IssuerCode: nil,
IssuerName: nil }
end
+ let(:vhic_classification_details) do
+ { ClassName: 'Identification Card',
+ Issue: '2020',
+ IssueType: 'Veteran Health Identification Card',
+ Name: 'United States (USA) Veteran Health Identification Card',
+ IssuerCode: 'USA',
+ IssuerName: 'United States',
+ IssuerType: 'Country' }
+ end
def build_error_info(
doc_result: nil,
@@ -262,6 +272,28 @@ def build_error_info(
expect(output[:front]).to contain_exactly(DocAuth::Errors::CARD_TYPE)
expect(output[:hints]).to eq(true)
end
+
+ it 'DocAuthResult is success with VHIC' do
+ error_info = build_error_info(
+ doc_result: 'Passed',
+ passed: [{ name: 'Not a known alert', result: 'Passed' }],
+ failed: [],
+ classification_info: { Back: vhic_classification_details,
+ Front: vhic_classification_details },
+ )
+
+ expect(warn_notifier).to receive(:call).
+ with(hash_including(:response_info, :message, :unknown_alerts)).once
+
+ output = described_class.new(config).generate_doc_auth_errors(error_info)
+
+ expect(output.keys).to contain_exactly(:general, :front, :back, :hints)
+ expect(output[:general]).to contain_exactly(DocAuth::Errors::DOC_TYPE_CHECK)
+ expect(output[:front]).to contain_exactly(DocAuth::Errors::CARD_TYPE)
+ expect(output[:back]).to contain_exactly(DocAuth::Errors::CARD_TYPE)
+ expect(output[:hints]).to eq(true)
+ end
+
it 'DocAuthResult is failed with unknown doc type' do
error_info = build_error_info(
doc_result: 'Failed',
@@ -467,4 +499,41 @@ def build_error_info(
expect(output[:hints]).to eq(false)
end
end
+
+ context 'with both doc type error and image metric error' do
+ let(:metrics) do
+ {
+ front: {
+ 'HorizontalResolution' => 300,
+ 'VerticalResolution' => 300,
+ 'SharpnessMetric' => 50,
+ 'GlareMetric' => 50,
+ },
+ back: {
+ 'HorizontalResolution' => 300,
+ 'VerticalResolution' => 300,
+ 'SharpnessMetric' => 50,
+ 'GlareMetric' => 50,
+ },
+ }
+ end
+ it 'generate doc type error' do
+ metrics[:front]['HorizontalResolution'] = 50
+ error_info = build_error_info(
+ doc_result: 'Failed',
+ failed: [{ name: '2D Barcode Read', result: 'Attention' }],
+ classification_info: { Back: vhic_classification_details,
+ Front: vhic_classification_details },
+ image_metrics: metrics,
+ )
+
+ output = described_class.new(config).generate_doc_auth_errors(error_info)
+ expect(output.keys).to contain_exactly(:general, :front, :back, :hints)
+
+ expect(output[:general]).to contain_exactly(DocAuth::Errors::DOC_TYPE_CHECK)
+ expect(output[:back]).to contain_exactly(DocAuth::Errors::CARD_TYPE)
+ expect(output[:front]).to contain_exactly(DocAuth::Errors::CARD_TYPE)
+ expect(output[:hints]).to eq(true)
+ end
+ end
end
diff --git a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb
index caa2df20f6f..c95940c1a0e 100644
--- a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb
+++ b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb
@@ -133,8 +133,8 @@
'DocAuthTamperResult' => 'Passed',
'DocAuthTamperSensitivity' => 'Normal',
classification_info: {
- Front: a_hash_including(:ClassName, :CountryCode),
- Back: a_hash_including(:ClassName, :CountryCode),
+ Front: a_hash_including(:ClassName, :CountryCode, :IssuerType),
+ Back: a_hash_including(:ClassName, :CountryCode, :IssuerType),
},
)
passed_alerts = response_hash.dig(:processed_alerts, :passed)
@@ -160,6 +160,24 @@
it 'mark doc type as supported' do
expect(response.doc_type_supported?).to eq(true)
end
+
+ context 'when identification card issued by a country' do
+ let(:success_response) do
+ body = JSON.parse(LexisNexisFixtures.true_id_response_success_3).tap do |json|
+ doc_class_node = json['Products'].first['ParameterDetails'].
+ select { |f| f['Name'] == 'DocClassName' && f['Group'] == 'AUTHENTICATION_RESULT' }
+ doc_class_node.first['Values'].first['Value'] = 'Identification Card'
+ doc_issuer_type = json['Products'].first['ParameterDetails'].
+ select { |f| f['Name'] == 'DocIssuerType' && f['Group'] == 'AUTHENTICATION_RESULT' }
+ doc_issuer_type.first['Values'].first['Value'] = 'Country'
+ end.to_json
+ instance_double(Faraday::Response, status: 200, body: body)
+ end
+ it 'mark doc type as not supported' do
+ expect(response.doc_type_supported?).to eq(false)
+ expect(response.success?).to eq(false)
+ end
+ end
end
context 'when there is no address line 2' do
@@ -338,6 +356,7 @@ def get_decision_product(resp)
'DocClassName' => 'Drivers License',
'DocumentName' => 'Connecticut (CT) Driver License',
'DocIssuerCode' => 'CT',
+ 'DocIssuerType' => 'StateProvince',
'DocIssuerName' => 'Connecticut',
'DocIssue' => '2009',
'DocIssueType' => 'Driver License',
@@ -345,8 +364,8 @@ def get_decision_product(resp)
'OrientationChanged' => 'false',
'PresentationChanged' => 'false',
classification_info: {
- Front: a_hash_including(:ClassName, :CountryCode),
- Back: a_hash_including(:ClassName, :CountryCode),
+ Front: a_hash_including(:ClassName, :CountryCode, :IssuerType),
+ Back: a_hash_including(:ClassName, :CountryCode, :IssuerType),
},
)
end
@@ -554,9 +573,26 @@ def get_decision_product(resp)
context 'when country code is not supported' do
let(:success_response) do
body = JSON.parse(LexisNexisFixtures.true_id_response_success_3).tap do |json|
- doc_class_node = json['Products'].first['ParameterDetails'].
+ doc_country_node = json['Products'].first['ParameterDetails'].
select { |f| f['Name'] == 'Fields_CountryCode' && f['Group'] == 'IDAUTH_FIELD_DATA' }
- doc_class_node.first['Values'].first['Value'] = 'CAN'
+ doc_country_node.first['Values'].first['Value'] = 'CAN'
+ end.to_json
+ instance_double(Faraday::Response, status: 200, body: body)
+ end
+ it 'identify as unsupported doc type' do
+ is_expected.to eq(false)
+ end
+ end
+
+ context 'when id is federal identification card' do
+ let(:success_response) do
+ body = JSON.parse(LexisNexisFixtures.true_id_response_success_3).tap do |json|
+ doc_class_node = json['Products'].first['ParameterDetails'].
+ select { |f| f['Name'] == 'DocClassName' && f['Group'] == 'AUTHENTICATION_RESULT' }
+ doc_class_node.first['Values'].first['Value'] = 'Identification Card'
+ doc_issuer_type = json['Products'].first['ParameterDetails'].
+ select { |f| f['Name'] == 'DocIssuerType' && f['Group'] == 'AUTHENTICATION_RESULT' }
+ doc_issuer_type.first['Values'].first['Value'] = 'Country'
end.to_json
instance_double(Faraday::Response, status: 200, body: body)
end
@@ -564,5 +600,30 @@ def get_decision_product(resp)
is_expected.to eq(false)
end
end
+
+ context 'when id is federal ID and image dpi is low' do
+ let(:error_response) do
+ body = JSON.parse(LexisNexisFixtures.true_id_response_success_3).tap do |json|
+ doc_class_node = json['Products'].first['ParameterDetails'].
+ select { |f| f['Name'] == 'DocClassName' && f['Group'] == 'AUTHENTICATION_RESULT' }
+ doc_class_node.first['Values'].first['Value'] = 'Identification Card'
+ doc_issuer_type = json['Products'].first['ParameterDetails'].
+ select { |f| f['Name'] == 'DocIssuerType' && f['Group'] == 'AUTHENTICATION_RESULT' }
+ doc_issuer_type.first['Values'].first['Value'] = 'Country'
+
+ image_metric_resolution = json['Products'].first['ParameterDetails'].
+ select do |f|
+ f['Group'] == 'IMAGE_METRICS_RESULT' &&
+ f['Name'] == 'HorizontalResolution'
+ end
+ image_metric_resolution.first['Values'].first['Value'] = 50
+ end.to_json
+ instance_double(Faraday::Response, status: 200, body: body)
+ end
+ it 'mark doc type as not supported' do
+ response = described_class.new(error_response, config)
+ expect(response.doc_type_supported?).to eq(false)
+ end
+ end
end
end
diff --git a/spec/services/doc_auth/mock/result_response_spec.rb b/spec/services/doc_auth/mock/result_response_spec.rb
index ce74c806ef5..09a81706549 100644
--- a/spec/services/doc_auth/mock/result_response_spec.rb
+++ b/spec/services/doc_auth/mock/result_response_spec.rb
@@ -514,8 +514,53 @@
end
it 'returns doc type as not supported' do
expect(response.doc_type_supported?).to eq(false)
+ expect(response.errors).to eq(
+ general: [DocAuth::Errors::DOC_TYPE_CHECK],
+ front: [DocAuth::Errors::CARD_TYPE],
+ back: [DocAuth::Errors::CARD_TYPE],
+ hints: true,
+ )
+ end
+ end
+
+ context 'with a passed yaml file containing unsupported doc type and bad image metrics' do
+ let(:input) do
+ <<~YAML
+ doc_auth_result: Passed
+ classification_info:
+ Front:
+ ClassName: Identification Card
+ CountryCode: USA
+ IssuerType: Country
+ Back:
+ ClassName: Identification Card
+ CountryCode: USA
+ IssuerType: StateProvince
+ image_metrics:
+ front:
+ HorizontalResolution: 50
+ VerticalResolution: 300
+ SharpnessMetric: 50
+ GlareMetric: 50
+ back:
+ HorizontalResolution: 300
+ VerticalResolution: 300,
+ SharpnessMetric: 50,
+ GlareMetric: 50
+ YAML
+ end
+ it 'returns doc type as not supported and generate errors for doc type' do
+ expect(response.doc_type_supported?).to eq(false)
+ expect(response.errors).to eq(
+ general: [DocAuth::Errors::DOC_TYPE_CHECK],
+ front: [DocAuth::Errors::CARD_TYPE],
+ hints: true,
+ )
+ expect(response.exception).to be_nil
+ expect(response.success?).to eq(false)
end
end
+
context 'with a yaml file that does not include classification info' do
let(:input) do
<<~YAML
diff --git a/spec/services/form_response_spec.rb b/spec/services/form_response_spec.rb
index 9898d2e5eb7..76f3659702d 100644
--- a/spec/services/form_response_spec.rb
+++ b/spec/services/form_response_spec.rb
@@ -78,7 +78,9 @@
response2 = FormResponse.new(success: false, errors: errors2)
combined_response = response1.merge(response2)
- expect(combined_response.to_h[:error_details]).to eq(email_language: [:blank, :invalid])
+ expect(combined_response.to_h[:error_details]).to eq(
+ email_language: { blank: true, invalid: true },
+ )
end
it 'merges hash and ActiveModel::Errors' do
@@ -93,7 +95,7 @@
expect(combined_response.errors).to eq(
email_language: ['Language cannot be blank', 'Language is not valid'],
)
- expect(combined_response.to_h[:error_details]).to eq(email_language: [:blank])
+ expect(combined_response.to_h[:error_details]).to eq(email_language: { blank: true })
end
it 'returns true if one is false and one is true' do
@@ -146,13 +148,32 @@
email_language: ['Language cannot be blank'],
},
error_details: {
- email_language: [:blank],
+ email_language: { blank: true },
},
}
expect(response.to_h).to eq response_hash
end
+ context 'without error type' do
+ it 'falls back to message as key for details' do
+ errors = ActiveModel::Errors.new(build_stubbed(:user))
+ errors.add(:email_language, :blank)
+ response = FormResponse.new(success: false, errors: errors)
+ response_hash = {
+ success: false,
+ errors: {
+ email_language: [t('errors.messages.blank')],
+ },
+ error_details: {
+ email_language: { blank: true },
+ },
+ }
+
+ expect(response.to_h).to eq response_hash
+ end
+ end
+
it 'omits details if errors are empty' do
errors = ActiveModel::Errors.new(build_stubbed(:user))
response = FormResponse.new(success: true, errors: errors)
@@ -177,6 +198,25 @@
expect(combined_response.to_h).to eq response_hash
end
+ context 'with error detail symbol defined as type option on error' do
+ it 'returns a hash with success, errors, and error_details keys' do
+ errors = ActiveModel::Errors.new(build_stubbed(:user))
+ errors.add(:email_language, 'Language cannot be blank', type: :blank)
+ response = FormResponse.new(success: false, errors: errors)
+ response_hash = {
+ success: false,
+ errors: {
+ email_language: ['Language cannot be blank'],
+ },
+ error_details: {
+ email_language: { blank: true },
+ },
+ }
+
+ expect(response.to_h).to eq response_hash
+ end
+ end
+
context 'with serialize_error_details_only' do
it 'excludes errors from the hash' do
errors = ActiveModel::Errors.new(build_stubbed(:user))
@@ -190,7 +230,7 @@
expect(response.to_h).to eq(
success: false,
error_details: {
- email_language: [:blank],
+ email_language: { blank: true },
},
)
end
diff --git a/spec/services/push_notification/account_disabled_event_spec.rb b/spec/services/push_notification/account_disabled_event_spec.rb
new file mode 100644
index 00000000000..99ceec32c3d
--- /dev/null
+++ b/spec/services/push_notification/account_disabled_event_spec.rb
@@ -0,0 +1,34 @@
+require 'rails_helper'
+
+RSpec.describe PushNotification::AccountDisabledEvent do
+ include Rails.application.routes.url_helpers
+
+ subject(:event) do
+ PushNotification::AccountDisabledEvent.new(user: user)
+ end
+
+ let(:user) { build(:user) }
+
+ describe '#event_type' do
+ it 'is the RISC event type' do
+ expect(event.event_type).to eq(PushNotification::AccountDisabledEvent::EVENT_TYPE)
+ end
+ end
+
+ describe '#payload' do
+ let(:iss_sub) { SecureRandom.uuid }
+
+ subject(:payload) { event.payload(iss_sub: iss_sub) }
+
+ it 'is a subject with the provided iss_sub and reason' do
+ expect(payload).to eq(
+ subject: {
+ subject_type: 'iss-sub',
+ sub: iss_sub,
+ iss: root_url,
+ },
+ reason: 'account-suspension',
+ )
+ end
+ end
+end
diff --git a/spec/services/push_notification/account_enabled_event_spec.rb b/spec/services/push_notification/account_enabled_event_spec.rb
new file mode 100644
index 00000000000..17be59943c1
--- /dev/null
+++ b/spec/services/push_notification/account_enabled_event_spec.rb
@@ -0,0 +1,33 @@
+require 'rails_helper'
+
+RSpec.describe PushNotification::AccountEnabledEvent do
+ include Rails.application.routes.url_helpers
+
+ subject(:event) do
+ PushNotification::AccountEnabledEvent.new(user: user)
+ end
+
+ let(:user) { build(:user) }
+
+ describe '#event_type' do
+ it 'is the RISC event type' do
+ expect(event.event_type).to eq(PushNotification::AccountEnabledEvent::EVENT_TYPE)
+ end
+ end
+
+ describe '#payload' do
+ let(:iss_sub) { SecureRandom.uuid }
+
+ subject(:payload) { event.payload(iss_sub: iss_sub) }
+
+ it 'is a subject with the provided iss_sub ' do
+ expect(payload).to eq(
+ subject: {
+ subject_type: 'iss-sub',
+ sub: iss_sub,
+ iss: root_url,
+ },
+ )
+ end
+ end
+end
diff --git a/spec/services/user_profiles_encryptor_spec.rb b/spec/services/user_profiles_encryptor_spec.rb
new file mode 100644
index 00000000000..4602d8fb5d6
--- /dev/null
+++ b/spec/services/user_profiles_encryptor_spec.rb
@@ -0,0 +1,121 @@
+require 'rails_helper'
+
+RSpec.describe UserProfilesEncryptor do
+ describe '#call' do
+ let(:user_session) { {}.with_indifferent_access }
+ let(:pii) { Pii::Attributes.new(ssn: '1234') }
+ let(:profile) { create(:profile, :active, :verified, pii: pii.to_h) }
+ let(:user) { profile.user }
+ let(:password) { 'a new and incredibly exciting password' }
+
+ before do
+ Pii::Cacher.new(user, user_session).save_decrypted_pii(pii, profile.id)
+ end
+
+ context 'when the user has an active profile' do
+ it 'encrypts the PII for the active profile with the password' do
+ encryptor = UserProfilesEncryptor.new(
+ user: user,
+ user_session: user_session,
+ password: password,
+ )
+ encryptor.encrypt
+
+ profile.reload
+
+ personal_key = PersonalKeyGenerator.new(user).normalize(encryptor.personal_key)
+
+ decrypted_profile_pii = profile.decrypt_pii(password)
+ decrypted_profile_recovery_pii = profile.recover_pii(personal_key)
+
+ expect(pii).to eq(decrypted_profile_pii)
+ expect(pii).to eq(decrypted_profile_recovery_pii)
+ expect(user.valid_personal_key?(personal_key)).to eq(true)
+ end
+ end
+
+ context 'when the user has a pending profile' do
+ let(:profile) { create(:profile, :verify_by_mail_pending, :verified, pii: pii.to_h) }
+
+ it 'encrypts the PII for the pending profile with the password' do
+ encryptor = UserProfilesEncryptor.new(
+ user: user,
+ user_session: user_session,
+ password: password,
+ )
+ encryptor.encrypt
+
+ profile.reload
+
+ personal_key = PersonalKeyGenerator.new(user).normalize(encryptor.personal_key)
+
+ decrypted_profile_pii = profile.decrypt_pii(password)
+ decrypted_profile_recovery_pii = profile.recover_pii(personal_key)
+
+ expect(pii).to eq(decrypted_profile_pii)
+ expect(pii).to eq(decrypted_profile_recovery_pii)
+ expect(user.valid_personal_key?(personal_key)).to eq(true)
+ end
+ end
+
+ context 'when the user has an active and a pending profile' do
+ let(:active_pii) { pii }
+ let(:active_profile) { profile }
+ let(:pending_pii) { Pii::Attributes.new(ssn: '5555') }
+ let(:pending_profile) do
+ create(
+ :profile,
+ :verify_by_mail_pending,
+ :verified,
+ pii: pending_pii.to_h,
+ user: user,
+ )
+ end
+
+ before do
+ Pii::Cacher.new(user, user_session).save_decrypted_pii(pending_pii, pending_profile.id)
+ end
+
+ it 'encrypts the PII for both profiles with the password' do
+ encryptor = UserProfilesEncryptor.new(
+ user: user,
+ user_session: user_session,
+ password: password,
+ )
+ encryptor.encrypt
+
+ active_profile.reload
+ pending_profile.reload
+
+ decrypted_active_profile_pii = active_profile.decrypt_pii(password)
+ decrypted_pending_profile_pii = pending_profile.decrypt_pii(password)
+
+ expect(decrypted_active_profile_pii).to eq(active_pii)
+ expect(decrypted_pending_profile_pii).to eq(pending_pii)
+ end
+
+ it 'sets the pending profile personal key as the personal key' do
+ encryptor = UserProfilesEncryptor.new(
+ user: user,
+ user_session: user_session,
+ password: password,
+ )
+ encryptor.encrypt
+
+ active_profile.reload
+ pending_profile.reload
+
+ personal_key = PersonalKeyGenerator.new(user).normalize(encryptor.personal_key)
+
+ expect do
+ active_profile.recover_pii(personal_key)
+ end.to raise_error(Encryption::EncryptionError)
+
+ decrypted_pending_profile_recovery_pii = pending_profile.recover_pii(personal_key)
+ expect(decrypted_pending_profile_recovery_pii).to eq(pending_pii)
+
+ expect(user.valid_personal_key?(personal_key)).to eq(true)
+ end
+ end
+ end
+end
diff --git a/spec/support/doc_pii_helper.rb b/spec/support/doc_pii_helper.rb
index a1d20041ab3..2f9be8fb391 100644
--- a/spec/support/doc_pii_helper.rb
+++ b/spec/support/doc_pii_helper.rb
@@ -2,14 +2,27 @@ module DocPiiHelper
def pii_like_keypaths
[
[:pii],
- [:name, :dob, :dob_min_age, :address1, :state, :zipcode, :jurisdiction],
- [:errors, :name], [:error_details, :name],
- [:errors, :dob], [:error_details, :dob],
- [:errors, :dob_min_age], [:error_details, :dob_min_age],
- [:errors, :address1], [:error_details, :address1],
- [:errors, :state], [:error_details, :state],
- [:errors, :zipcode], [:error_details, :zipcode],
- [:errors, :jurisdiction], [:error_details, :jurisdiction]
+ [:errors, :name],
+ [:error_details, :name],
+ [:error_details, :name, :name],
+ [:errors, :dob],
+ [:error_details, :dob],
+ [:error_details, :dob, :dob],
+ [:errors, :dob_min_age],
+ [:error_details, :dob_min_age],
+ [:error_details, :dob_min_age, :dob_min_age],
+ [:errors, :address1],
+ [:error_details, :address1],
+ [:error_details, :address1, :address1],
+ [:errors, :state],
+ [:error_details, :state],
+ [:error_details, :state, :state],
+ [:errors, :zipcode],
+ [:error_details, :zipcode],
+ [:error_details, :zipcode, :zipcode],
+ [:errors, :jurisdiction],
+ [:error_details, :jurisdiction],
+ [:error_details, :jurisdiction, :jurisdiction],
]
end
end
diff --git a/spec/support/fake_analytics.rb b/spec/support/fake_analytics.rb
index 07dddee9acc..bf1ce740c10 100644
--- a/spec/support/fake_analytics.rb
+++ b/spec/support/fake_analytics.rb
@@ -56,7 +56,7 @@ def track_event(event, original_attributes = {})
ERROR
end
- check_recursive.call(val, [key])
+ check_recursive.call(val, current_keypath)
end
when Array
value.each { |val| check_recursive.call(val, keypath) }
diff --git a/spec/support/fake_attempts_tracker.rb b/spec/support/fake_attempts_tracker.rb
index fa0add2a3cc..768a9c045ff 100644
--- a/spec/support/fake_attempts_tracker.rb
+++ b/spec/support/fake_attempts_tracker.rb
@@ -13,17 +13,5 @@ def track_event(event, attributes = {})
events[event] << attributes
nil
end
-
- def parse_failure_reason(result)
- return result.to_h[:error_details] || result.errors.presence
- end
-
- def track_mfa_submit_event(_attributes)
- # no-op
- end
-
- def browser_attributes
- {}
- end
end
end
diff --git a/spec/support/idv_examples/sp_requested_attributes.rb b/spec/support/idv_examples/sp_requested_attributes.rb
index 53e942c1d2f..d2ee8560579 100644
--- a/spec/support/idv_examples/sp_requested_attributes.rb
+++ b/spec/support/idv_examples/sp_requested_attributes.rb
@@ -22,22 +22,20 @@
expect(current_path).to eq(sign_up_completed_path)
- within('.requested-attributes') do
- expect(page).to have_content t('help_text.requested_attributes.email')
- expect(page).to have_content user.email
- expect(page).to_not have_content t('help_text.requested_attributes.address')
- expect(page).to_not have_content t('help_text.requested_attributes.birthdate')
- expect(page).to have_content t('help_text.requested_attributes.full_name')
- expect(page).to have_content 'FAKEY MCFAKERSON'
- expect(page).to have_content t('help_text.requested_attributes.phone')
- expect(page).to have_content '+1 202-555-1212'
- expect(page).to have_content t('help_text.requested_attributes.social_security_number')
- expect(page).to have_css(
- '.masked-text__text',
- text: DocAuthHelper::GOOD_SSN,
- visible: :hidden,
- )
- end
+ expect(page).to have_content t('help_text.requested_attributes.email')
+ expect(page).to have_content user.email
+ expect(page).to_not have_content t('help_text.requested_attributes.address')
+ expect(page).to_not have_content t('help_text.requested_attributes.birthdate')
+ expect(page).to have_content t('help_text.requested_attributes.full_name')
+ expect(page).to have_content 'FAKEY MCFAKERSON'
+ expect(page).to have_content t('help_text.requested_attributes.phone')
+ expect(page).to have_content '+1 202-555-1212'
+ expect(page).to have_content t('help_text.requested_attributes.social_security_number')
+ expect(page).to have_css(
+ '.masked-text__text',
+ text: DocAuthHelper::GOOD_SSN,
+ visible: :hidden,
+ )
end
end
@@ -88,18 +86,16 @@
expect(current_path).to eq(sign_up_completed_path)
- within('.requested-attributes') do
- expect(page).to have_content t('help_text.requested_attributes.email')
- expect(page).to have_content user.email
- expect(page).to_not have_content t('help_text.requested_attributes.address')
- expect(page).to_not have_content t('help_text.requested_attributes.birthdate')
- expect(page).to have_content t('help_text.requested_attributes.full_name')
- expect(page).to have_content 'FAKEY MCFAKERSON'
- expect(page).to have_content t('help_text.requested_attributes.phone')
- expect(page).to have_content '+1 202-555-1212'
- expect(page).to have_content t('help_text.requested_attributes.social_security_number')
- expect(page).to have_content DocAuthHelper::GOOD_SSN
- end
+ expect(page).to have_content t('help_text.requested_attributes.email')
+ expect(page).to have_content user.email
+ expect(page).to_not have_content t('help_text.requested_attributes.address')
+ expect(page).to_not have_content t('help_text.requested_attributes.birthdate')
+ expect(page).to have_content t('help_text.requested_attributes.full_name')
+ expect(page).to have_content 'FAKEY MCFAKERSON'
+ expect(page).to have_content t('help_text.requested_attributes.phone')
+ expect(page).to have_content '+1 202-555-1212'
+ expect(page).to have_content t('help_text.requested_attributes.social_security_number')
+ expect(page).to have_content DocAuthHelper::GOOD_SSN
end
end
end
diff --git a/spec/views/idv/in_person/state_id.html.erb_spec.rb b/spec/views/idv/in_person/state_id.html.erb_spec.rb
new file mode 100644
index 00000000000..f9be82b9844
--- /dev/null
+++ b/spec/views/idv/in_person/state_id.html.erb_spec.rb
@@ -0,0 +1,37 @@
+require 'rails_helper'
+
+RSpec.describe 'idv/in_person/state_id.html.erb' do
+ let(:pii) { {} }
+ let(:form) { Idv::StateIdForm.new(pii) }
+ let(:parsed_dob) { Date.new(1970, 1, 1) }
+
+ before do
+ allow(view).to receive(:url_for).and_return('https://example.com/')
+ end
+
+ subject(:render_template) do
+ render template: 'idv/in_person/state_id',
+ locals: { updating_state_id: true, form: form, pii: pii, parsed_dob: parsed_dob }
+ end
+
+ it 'renders state ID hint text with correct screenreader tags', aggregate_failures: true do
+ render_template
+
+ doc = Nokogiri::HTML(rendered)
+
+ jurisdiction_extras = doc.at_css('.jurisdiction-extras')
+
+ all_hints = jurisdiction_extras.css('[data-state]')
+ shown = jurisdiction_extras.css('[data-state]:not(.display-none)')
+ hidden = jurisdiction_extras.css('[data-state].display-none')
+
+ expect(shown.size).to eq(1), 'only shows one hint'
+ expect(shown.size + hidden.size).to eq(all_hints.size)
+
+ default_hint = jurisdiction_extras.at_css('[data-state=default]')
+ default_hint_screenreader_tags = default_hint.css('.usa-sr-only')
+ *first, last = default_hint_screenreader_tags.map(&:text)
+ expect(first).to all end_with(',')
+ expect(last).to_not end_with(',')
+ end
+end
diff --git a/yarn.lock b/yarn.lock
index 7c9e782c6e7..a77727f7c3e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2936,11 +2936,6 @@ dirty-chai@^2.0.1:
resolved "https://registry.yarnpkg.com/dirty-chai/-/dirty-chai-2.0.1.tgz#6b2162ef17f7943589da840abc96e75bda01aff3"
integrity sha512-ys79pWKvDMowIDEPC6Fig8d5THiC0DJ2gmTeGzVAoEH18J8OzLud0Jh7I9IWg3NSk8x2UocznUuFmfHCXYZx9w==
-dlv@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
- integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
-
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@@ -4550,6 +4545,11 @@ known-css-properties@^0.27.0:
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.27.0.tgz#82a9358dda5fe7f7bd12b5e7142c0a205393c0c5"
integrity sha512-uMCj6+hZYDoffuvAJjFAPz56E9uoowFHmTkqRtRq5WyC5Q6Cu/fTZKNQpX/RbzChBYLLl3lo8CjFZBAZXq9qFg==
+known-css-properties@^0.29.0:
+ version "0.29.0"
+ resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.29.0.tgz#e8ba024fb03886f23cb882e806929f32d814158f"
+ integrity sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==
+
language-subtag-registry@~0.3.2:
version "0.3.20"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.20.tgz#a00a37121894f224f763268e431c55556b0c0755"
@@ -5439,12 +5439,12 @@ postcss-safe-parser@^6.0.0:
resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1"
integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==
-postcss-scss@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.6.tgz#5d62a574b950a6ae12f2aa89b60d63d9e4432bfd"
- integrity sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==
+postcss-scss@^4.0.9:
+ version "4.0.9"
+ resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.9.tgz#a03c773cd4c9623cb04ce142a52afcec74806685"
+ integrity sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==
-postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.13:
+postcss-selector-parser@^6.0.13:
version "6.0.13"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b"
integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==
@@ -5478,10 +5478,10 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
-prettier@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
- integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
+prettier@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e"
+ integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==
pretty-format@^26.6.2:
version "26.6.2"
@@ -6382,19 +6382,19 @@ style-search@^0.1.0:
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=
-stylelint-config-recommended-scss@^10.0.0:
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-10.0.0.tgz#06c5c6ad893d2641d7207994de3a5aa2fdcb4078"
- integrity sha512-+YvPgUHi0W5mCJCKdupBCIsWPYNbWuJcRmFtSYujwNg+41ljFknhO9bpY6C+oahv659zW7W1AT7i6DQvJYYr1A==
+stylelint-config-recommended-scss@^13.1.0:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-13.1.0.tgz#04e529ae0e9c1abb1e04de79258461c07811876f"
+ integrity sha512-8L5nDfd+YH6AOoBGKmhH8pLWF1dpfY816JtGMePcBqqSsLU+Ysawx44fQSlMOJ2xTfI9yTGpup5JU77c17w1Ww==
dependencies:
- postcss-scss "^4.0.6"
- stylelint-config-recommended "^11.0.0"
- stylelint-scss "^4.6.0"
+ postcss-scss "^4.0.9"
+ stylelint-config-recommended "^13.0.0"
+ stylelint-scss "^5.3.0"
-stylelint-config-recommended@^11.0.0:
- version "11.0.0"
- resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-11.0.0.tgz#b1cb7d71bd92f9b8593f93c2ca6df16ed7d61522"
- integrity sha512-SoGIHNI748OCZn6BxFYT83ytWoYETCINVHV3LKScVAWQQauWdvmdDqJC5YXWjpBbxg2E761Tg5aUGKLFOVhEkA==
+stylelint-config-recommended@^13.0.0:
+ version "13.0.0"
+ resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-13.0.0.tgz#c48a358cc46b629ea01f22db60b351f703e00597"
+ integrity sha512-EH+yRj6h3GAe/fRiyaoO2F9l9Tgg50AOFhaszyfov9v6ayXJ1IkSHwTxd7lB48FmOeSGDPLjatjO11fJpmarkQ==
stylelint-prettier@^4.0.2:
version "4.0.2"
@@ -6403,15 +6403,15 @@ stylelint-prettier@^4.0.2:
dependencies:
prettier-linter-helpers "^1.0.0"
-stylelint-scss@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-4.6.0.tgz#f7602d6d562bb256802e38e3fd5e49c46d2e31b6"
- integrity sha512-M+E0BQim6G4XEkaceEhfVjP/41C9Klg5/tTPTCQVlgw/jm2tvB+OXJGaU0TDP5rnTCB62aX6w+rT+gqJW/uwjA==
+stylelint-scss@^5.3.0:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-5.3.1.tgz#7f0f5f06d0a2a3c515aa71d3a8de3548045e03e1"
+ integrity sha512-5I9ZDIm77BZrjOccma5WyW2nJEKjXDd4Ca8Kk+oBapSO4pewSlno3n+OyimcyVJJujQZkBN2D+xuMkIamSc6hA==
dependencies:
- dlv "^1.1.3"
+ known-css-properties "^0.29.0"
postcss-media-query-parser "^0.2.3"
postcss-resolve-nested-selector "^0.1.1"
- postcss-selector-parser "^6.0.11"
+ postcss-selector-parser "^6.0.13"
postcss-value-parser "^4.2.0"
stylelint@^15.10.1:
@@ -7155,10 +7155,10 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-yaml@^2.3.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
- integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
+yaml@^2.3.4:
+ version "2.3.4"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2"
+ integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==
yargs-parser@20.2.4:
version "20.2.4"