diff --git a/.rubocop.yml b/.rubocop.yml index 44b0c7a76db..aac7ab70285 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -7,6 +7,7 @@ require: - rubocop-rails - rubocop-rspec - rubocop-performance + - rubocop-capybara - ./lib/linters/i18n_helper_html_linter.rb - ./lib/linters/analytics_event_name_linter.rb - ./lib/linters/localized_validation_message_linter.rb @@ -43,6 +44,9 @@ Bundler/DuplicatedGem: Bundler/InsecureProtocolSource: Enabled: true +Capybara/CurrentPathExpectation: + Enabled: true + Gemspec/DuplicatedAssignment: Enabled: true diff --git a/Gemfile b/Gemfile index ee19f1969e6..04e1f823c9d 100644 --- a/Gemfile +++ b/Gemfile @@ -122,6 +122,7 @@ group :development, :test do gem 'rubocop-performance', '~> 1.23.0', require: false gem 'rubocop-rails', '~> 2.27.0', require: false gem 'rubocop-rspec', '~> 3.2.0', require: false + gem 'rubocop-capybara', require: false gem 'sqlite3', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index 6ffcee2c82b..e152e8df347 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -471,7 +471,7 @@ GEM orm_adapter (0.5.0) ostruct (0.6.1) parallel (1.26.3) - parser (3.3.4.2) + parser (3.3.6.0) ast (~> 2.4.1) racc pg (1.5.9) @@ -635,6 +635,8 @@ GEM unicode-display_width (>= 2.4.0, < 4.0) rubocop-ast (1.36.2) parser (>= 3.3.1.0) + rubocop-capybara (2.21.0) + rubocop (~> 1.41) rubocop-performance (1.23.0) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) @@ -853,6 +855,7 @@ DEPENDENCIES rspec-retry rspec_junit_formatter rubocop (~> 1.69.1) + rubocop-capybara rubocop-performance (~> 1.23.0) rubocop-rails (~> 2.27.0) rubocop-rspec (~> 3.2.0) diff --git a/Makefile b/Makefile index 482082e652d..a2aba78f2db 100644 --- a/Makefile +++ b/Makefile @@ -68,9 +68,9 @@ lint: ## Runs all lint tests @echo "--- rubocop ---" mkdir -p tmp ifdef JUNIT_OUTPUT - bundle exec rubocop --parallel --format progress --format junit --out rubocop.xml --display-only-failed --color 2> tmp/rubocop.txt + bundle exec rubocop --parallel --format progress --format junit --out rubocop.xml --display-only-failed --color 2> tmp/rubocop.txt || (cat tmp/rubocop.txt; exit 1) else - bundle exec rubocop --parallel --color 2> tmp/rubocop.txt + bundle exec rubocop --parallel --color 2> tmp/rubocop.txt || (cat tmp/rubocop.txt; exit 1) endif awk 'NF {exit 1}' tmp/rubocop.txt || (printf "Error: Unexpected stderr output from Rubocop\n"; cat tmp/rubocop.txt; exit 1) @echo "--- analytics_events ---" diff --git a/app/assets/stylesheets/components/_header.scss b/app/assets/stylesheets/components/_header.scss index e74a5cabd55..fff657c9302 100644 --- a/app/assets/stylesheets/components/_header.scss +++ b/app/assets/stylesheets/components/_header.scss @@ -10,3 +10,10 @@ @include u-height(9); } } + +/* + Workaround for https://github.com/uswds/uswds/issues/6260 + */ +.usa-skipnav { + top: -5rem; +} diff --git a/app/controllers/accounts/connected_accounts/selected_email_controller.rb b/app/controllers/accounts/connected_accounts/selected_email_controller.rb index f782b052491..eacdfd4f300 100644 --- a/app/controllers/accounts/connected_accounts/selected_email_controller.rb +++ b/app/controllers/accounts/connected_accounts/selected_email_controller.rb @@ -14,6 +14,7 @@ def edit @select_email_form = build_select_email_form @can_add_email = EmailPolicy.new(current_user).can_add_email? analytics.sp_select_email_visited + @email_id = @identity.email_address_id || last_email end def update @@ -50,6 +51,10 @@ def identity return @identity if defined?(@identity) @identity = current_user.identities.find_by(id: params[:identity_id]) end + + def last_email + EmailContext.new(current_user).last_sign_in_email_address.id + end end end end diff --git a/app/controllers/concerns/idv/document_capture_concern.rb b/app/controllers/concerns/idv/document_capture_concern.rb index 1d61388a6dd..6445a77e82b 100644 --- a/app/controllers/concerns/idv/document_capture_concern.rb +++ b/app/controllers/concerns/idv/document_capture_concern.rb @@ -24,21 +24,16 @@ def successful_response # copied from Flow::Failure module def failure(message = nil, extra = nil) form_response_params = { success: false } - form_response_params[:errors] = make_error_hash(message) + form_response_params[:errors] = error_hash(message) form_response_params[:extra] = extra unless extra.nil? FormResponse.new(**form_response_params) end - def make_error_hash(message) - Rails.logger.info("make_error_hash: stored_result: #{stored_result.inspect}") - - error_hash = { message: message || I18n.t('doc_auth.errors.general.network_error') } - - if stored_result&.errors&.has_key?(:socure) - error_hash[:socure] = stored_result.errors[:socure] - end - - error_hash + def error_hash(message) + { + message: message || I18n.t('doc_auth.errors.general.network_error'), + socure: stored_result&.errors&.dig(:socure), + } end def extract_pii_from_doc(user, store_in_session: false) diff --git a/app/controllers/concerns/idv/step_indicator_concern.rb b/app/controllers/concerns/idv/step_indicator_concern.rb index 6d95ba445f8..8329f6af596 100644 --- a/app/controllers/concerns/idv/step_indicator_concern.rb +++ b/app/controllers/concerns/idv/step_indicator_concern.rb @@ -20,13 +20,21 @@ module StepIndicatorConcern { name: :secure_account }, ].freeze + STEP_INDICATOR_STEPS_IPP = [ + { name: :find_a_post_office }, + { name: :verify_info }, + { name: :verify_phone }, + { name: :re_enter_password }, + { name: :go_to_the_post_office }, + ].freeze + included do helper_method :step_indicator_steps end def step_indicator_steps if in_person_proofing? - Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS + Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS_IPP elsif gpo_address_verification? Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS_GPO else diff --git a/app/controllers/idv/by_mail/request_letter_controller.rb b/app/controllers/idv/by_mail/request_letter_controller.rb index 77197dbb477..a7ae8df4857 100644 --- a/app/controllers/idv/by_mail/request_letter_controller.rb +++ b/app/controllers/idv/by_mail/request_letter_controller.rb @@ -59,11 +59,7 @@ def confirm_letter_sends_allowed end def step_indicator_steps - if in_person_proofing? - Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS_GPO - else - StepIndicatorConcern::STEP_INDICATOR_STEPS_GPO - end + StepIndicatorConcern::STEP_INDICATOR_STEPS_GPO end end end diff --git a/app/controllers/idv/by_mail/resend_letter_controller.rb b/app/controllers/idv/by_mail/resend_letter_controller.rb index 9e583cc46af..4faed1d29fd 100644 --- a/app/controllers/idv/by_mail/resend_letter_controller.rb +++ b/app/controllers/idv/by_mail/resend_letter_controller.rb @@ -83,11 +83,7 @@ def pii_locked? end def step_indicator_steps - if in_person_proofing? - Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS_GPO - else - StepIndicatorConcern::STEP_INDICATOR_STEPS_GPO - end + StepIndicatorConcern::STEP_INDICATOR_STEPS_GPO end end end diff --git a/app/controllers/sign_up/select_email_controller.rb b/app/controllers/sign_up/select_email_controller.rb index 2d691d85d8a..9775efd1603 100644 --- a/app/controllers/sign_up/select_email_controller.rb +++ b/app/controllers/sign_up/select_email_controller.rb @@ -7,7 +7,6 @@ class SelectEmailController < ApplicationController check_or_render_not_found -> { IdentityConfig.store.feature_select_email_to_share_enabled } before_action :confirm_two_factor_authenticated before_action :verify_needs_completions_screen - before_action :verify_multiple_emails def show @sp_name = current_sp.friendly_name || sp.agency&.name @@ -56,10 +55,6 @@ def last_email end end - def verify_multiple_emails - redirect_to sign_up_completed_path if user_emails.count < 2 - end - def verify_needs_completions_screen redirect_to account_url unless needs_completion_screen_reason end diff --git a/app/controllers/socure_webhook_controller.rb b/app/controllers/socure_webhook_controller.rb index 0028767330d..5344db65f34 100644 --- a/app/controllers/socure_webhook_controller.rb +++ b/app/controllers/socure_webhook_controller.rb @@ -11,6 +11,7 @@ class SocureWebhookController < ApplicationController def create begin log_webhook_receipt + repeat_webhook process_webhook_event rescue StandardError => e NewRelic::Agent.notice_error(e) @@ -134,4 +135,20 @@ def user def docv_transaction_token @docv_transaction_token ||= event[:docvTransactionToken] || event[:docVTransactionToken] end + + def repeat_webhook + endpoints = IdentityConfig.store.socure_docv_webhook_repeat_endpoints + return if endpoints.blank? + + headers = { + Authorization: request.headers['Authorization'], + 'Content-Type': request.headers['Content-Type'], + } + + body = socure_params.to_h + + endpoints.each do |endpoint| + SocureDocvRepeatWebhookJob.perform_later(body:, headers:, endpoint:) + end + end end diff --git a/app/controllers/test/ipp_controller.rb b/app/controllers/test/ipp_controller.rb new file mode 100644 index 00000000000..d7b5552eada --- /dev/null +++ b/app/controllers/test/ipp_controller.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Test + class IppController < ApplicationController + layout 'no_card' + + before_action :render_not_found_in_production + + def index + @enrollments = InPersonEnrollment + .order(created_at: :desc) + .limit(10) + + @enrollments_with_actions = @enrollments.map do |e| + case e.status + when 'pending' then [e, :approve] + else [e] + end + end + end + + def update + enrollment_id = params['enrollment'].to_i + enrollment = InPersonEnrollment.find(enrollment_id) + + if enrollment.present? + approve_enrollment(enrollment) + end + + redirect_to test_ipp_url + end + + private + + def approve_enrollment(enrollment) + return if !enrollment.pending? + + res = JSON.parse( + UspsInPersonProofing::Mock::Fixtures.request_passed_proofing_results_response, + ) + + job = GetUspsProofingResultsJob.new + job.instance_variable_set( + :@enrollment_outcomes, + { enrollments_passed: 0, + enrollments_failed: 0, + enrollments_errored: 0, + enrollments_expired: 0, + enrollments_checked: 0 }, + ) + + job.send(:process_enrollment_response, enrollment, res) + end + + def render_not_found_in_production + return unless Rails.env.production? + render_not_found + end + end +end diff --git a/app/forms/select_email_form.rb b/app/forms/select_email_form.rb index b00bc3ce636..e4c86499f0b 100644 --- a/app/forms/select_email_form.rb +++ b/app/forms/select_email_form.rb @@ -7,6 +7,9 @@ class SelectEmailForm attr_reader :user, :identity, :selected_email_id validate :validate_owns_selected_email + validates :selected_email_id, presence: { + message: proc { I18n.t('simple_form.required.text') }, + } def initialize(user:, identity: nil) @user = user diff --git a/app/javascript/packages/analytics/digital-analytics-program.spec.ts b/app/javascript/packages/analytics/digital-analytics-program.spec.ts index f44fcae26e2..e2726a04ee8 100644 --- a/app/javascript/packages/analytics/digital-analytics-program.spec.ts +++ b/app/javascript/packages/analytics/digital-analytics-program.spec.ts @@ -4,12 +4,7 @@ import { pathToFileURL } from 'node:url'; describe('digital analytics program', () => { it('parses without syntax error', async () => { - // Future: Replace with Promise.withResolvers once supported - // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers - let resolve; - const promise = new Promise((_resolve) => { - resolve = _resolve; - }); + const { promise, resolve } = Promise.withResolvers(); // Reference: https://github.com/nodejs/node/issues/30682 const toDataURL = (source: string) => diff --git a/app/javascript/packs/document-capture.tsx b/app/javascript/packs/document-capture.tsx index e88dd898a76..afdf1e31857 100644 --- a/app/javascript/packs/document-capture.tsx +++ b/app/javascript/packs/document-capture.tsx @@ -178,7 +178,7 @@ render( isSelfieCaptureEnabled: getSelfieCaptureEnabled(), isSelfieDesktopTestMode: String(docAuthSelfieDesktopTestMode) === 'true', showHelpInitially: true, - immediatelyBeginCapture: true, + immediatelyBeginCapture: false, }} > exception + NewRelic::Agent.notice_error( + exception, + custom_params: { + event: 'Failed to repeat webhook', + endpoint:, + body:, + }, + ) + end + + private + + def send_http_post_request(endpoint) + faraday_connection(endpoint).post do |req| + req.options.context = { service_name: 'socure_webhook_repeater' } + req.body = body.to_json + end + end + + def faraday_connection(endpoint) + retry_options = { + max: 2, + interval: 0.05, + interval_randomness: 0.5, + backoff_factor: 2, + retry_statuses: [404, 500], + retry_block: lambda do |env:, options:, retry_count:, exception:, will_retry_in:| + NewRelic::Agent.notice_error(exception, custom_params: { retry: retry_count }) + end, + } + + timeout = 15 + + Faraday.new(url: url(endpoint).to_s, headers: request_headers) do |conn| + conn.request :retry, retry_options + conn.request :instrumentation, name: 'request_metric.faraday' + conn.adapter :net_http + conn.options.timeout = timeout + conn.options.read_timeout = timeout + conn.options.open_timeout = timeout + conn.options.write_timeout = timeout + end + end + + def url(endpoint) + URI.join(endpoint) + end + + def request_headers(extras = {}) + headers.merge(extras) + end + end + end +end diff --git a/app/services/idv/analytics_events_enhancer.rb b/app/services/idv/analytics_events_enhancer.rb index 41c8c2994e9..8084338b99a 100644 --- a/app/services/idv/analytics_events_enhancer.rb +++ b/app/services/idv/analytics_events_enhancer.rb @@ -1,75 +1,53 @@ # frozen_string_literal: true module Idv + # For events beginning with +idv_+, add additional information to the event + # when a User object is available: + # - +proofing_components+: User's current proofing components + # - +active_profile_idv_level+: ID verification level of user's active profile. + # - +pending_profile_idv_level+: ID verification level of user's pending profile. + # Generally, analytics events that are called in contexts where there is no expectation + # of an {Idv::Session} being present or may be excessively noisy are opted-out. + # (e.g., jobs, client-generated events, action scripts). + # + # Additionally, +profile_history+, the list of a User's profiles + # (sorted by creation date, oldest to newest), may be added to events, but this is opt-in only. + # See #METHODS_WITH_PROFILE_HISTORY for the list of included events. module AnalyticsEventsEnhancer - IGNORED_METHODS = %i[ + EXCLUDED_FRONTEND_EVENT_METHODS = %i[ idv_acuant_sdk_loaded - idv_address_submitted - idv_address_visit - idv_back_image_added - idv_back_image_clicked idv_barcode_warning_continue_clicked idv_barcode_warning_retake_photos_clicked idv_capture_troubleshooting_dismissed idv_consent_checkbox_toggled - idv_doc_auth_agreement_submitted - idv_doc_auth_agreement_visited - idv_doc_auth_capture_complete_visited - idv_doc_auth_document_capture_submitted - idv_doc_auth_document_capture_visited - idv_doc_auth_exception_visited - idv_doc_auth_failed_image_resubmitted - idv_doc_auth_how_to_verify_submitted - idv_doc_auth_how_to_verify_visited - idv_doc_auth_hybrid_handoff_submitted - idv_doc_auth_hybrid_handoff_visited - idv_doc_auth_link_sent_submitted - idv_doc_auth_link_sent_visited - idv_doc_auth_redo_ssn_submitted - idv_doc_auth_socure_webhook_received - idv_doc_auth_ssn_submitted - idv_doc_auth_ssn_visited - idv_doc_auth_submitted_image_upload_form - idv_doc_auth_submitted_image_upload_vendor - idv_doc_auth_submitted_pii_validation - idv_doc_auth_verify_proofing_results - idv_doc_auth_verify_submitted - idv_doc_auth_verify_visited - idv_doc_auth_warning_visited - idv_doc_auth_welcome_submitted - idv_doc_auth_welcome_visited - idv_front_image_added - idv_front_image_clicked - idv_gpo_confirm_start_over_before_letter_visited - idv_gpo_confirm_start_over_visited + idv_image_capture_failed + idv_in_person_location_submitted + idv_in_person_ready_to_verify_sp_link_clicked + idv_in_person_ready_to_verify_what_to_bring_link_clicked + idv_sdk_error_before_init + idv_sdk_selfie_image_capture_closed_without_photo + idv_sdk_selfie_image_capture_failed + idv_sdk_selfie_image_capture_initialized + idv_sdk_selfie_image_capture_opened + idv_sdk_selfie_image_re_taken + idv_sdk_selfie_image_taken + idv_selfie_image_added + idv_verify_in_person_troubleshooting_option_clicked + ].freeze + + EXCLUDED_JOB_EVENT_METHODS = %i[ idv_gpo_expired idv_gpo_reminder_email_sent - idv_image_capture_failed idv_in_person_email_reminder_job_email_initiated idv_in_person_email_reminder_job_exception - idv_in_person_location_submitted - idv_in_person_location_visited - idv_in_person_locations_request_failure - idv_in_person_locations_searched - idv_in_person_prepare_submitted - idv_in_person_prepare_visited - idv_in_person_proofing_address_visited idv_in_person_proofing_enrollments_ready_for_status_check_job_completed idv_in_person_proofing_enrollments_ready_for_status_check_job_ingestion_error idv_in_person_proofing_enrollments_ready_for_status_check_job_started - idv_in_person_proofing_nontransliterable_characters_submitted - idv_in_person_proofing_residential_address_submitted - idv_in_person_proofing_state_id_submitted - idv_in_person_proofing_state_id_visited - idv_in_person_ready_to_verify_sp_link_clicked - idv_in_person_ready_to_verify_what_to_bring_link_clicked idv_in_person_send_proofing_notification_attempted idv_in_person_send_proofing_notification_job_completed idv_in_person_send_proofing_notification_job_exception idv_in_person_send_proofing_notification_job_skipped idv_in_person_send_proofing_notification_job_started - idv_in_person_switch_back_submitted - idv_in_person_switch_back_visited idv_in_person_usps_proofing_enrollment_code_email_received idv_in_person_usps_proofing_results_job_completed idv_in_person_usps_proofing_results_job_deadline_passed_email_exception @@ -82,32 +60,21 @@ module AnalyticsEventsEnhancer idv_in_person_usps_proofing_results_job_started idv_in_person_usps_proofing_results_job_unexpected_response idv_in_person_usps_proofing_results_job_user_sent_to_fraud_review - idv_in_person_usps_request_enroll_exception idv_ipp_deactivated_for_never_visiting_post_office - idv_link_sent_capture_doc_polling_complete - idv_link_sent_capture_doc_polling_started - idv_mail_only_warning_visited - idv_native_camera_forced - idv_not_verified_visited - idv_phone_use_different - idv_request_letter_visited - idv_sdk_selfie_image_capture_closed_without_photo - idv_sdk_selfie_image_capture_failed - idv_sdk_selfie_image_capture_opened - idv_selfie_image_added - idv_session_error_visited - idv_socure_document_request_submitted + idv_socure_reason_code_download + idv_socure_shadow_mode_proofing_result + idv_socure_shadow_mode_proofing_result_missing idv_socure_verification_data_requested - idv_threatmetrix_response_body idv_usps_auth_token_refresh_job_completed idv_usps_auth_token_refresh_job_network_error idv_usps_auth_token_refresh_job_started - idv_verify_by_mail_enter_code_submitted - idv_verify_by_mail_enter_code_visited - idv_verify_in_person_troubleshooting_option_clicked - idv_warning_action_triggered - idv_warning_shown - ].to_set.freeze + ].freeze + + IGNORED_METHODS = [ + *EXCLUDED_FRONTEND_EVENT_METHODS, + *EXCLUDED_JOB_EVENT_METHODS, + :idv_threatmetrix_response_body, # Prevent duplication when doing joins across events + ].uniq.freeze STANDARD_ARGUMENTS = %i[ proofing_components @@ -121,7 +88,7 @@ module AnalyticsEventsEnhancer idv_final idv_please_call_visited idv_start_over - ].to_set.freeze + ].freeze def self.included(_mod) raise 'this mixin is intended to be prepended, not included' diff --git a/app/views/accounts/connected_accounts/selected_email/edit.html.erb b/app/views/accounts/connected_accounts/selected_email/edit.html.erb index c32e05f522b..2052adb85f7 100644 --- a/app/views/accounts/connected_accounts/selected_email/edit.html.erb +++ b/app/views/accounts/connected_accounts/selected_email/edit.html.erb @@ -16,6 +16,7 @@ :selected_email_id, as: :radio_buttons, label: false, + required: true, wrapper_html: { aria: { labelledby: 'select-email-heading', @@ -26,7 +27,7 @@ [ email.email, email.id, - checked: email.id == @identity.email_address_id, + checked: email.id == @email_id, ] end, ) %> diff --git a/app/views/idv/in_person/address/show.html.erb b/app/views/idv/in_person/address/show.html.erb index e5a7ab2be63..4a06cea6aa0 100644 --- a/app/views/idv/in_person/address/show.html.erb +++ b/app/views/idv/in_person/address/show.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render StepIndicatorComponent.new( - steps: Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS, + steps: Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS_IPP, current_step: :verify_info, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/idv/in_person/state_id/show.html.erb b/app/views/idv/in_person/state_id/show.html.erb index ebcf6df6ed3..a3400b9d881 100644 --- a/app/views/idv/in_person/state_id/show.html.erb +++ b/app/views/idv/in_person/state_id/show.html.erb @@ -1,6 +1,6 @@ <% content_for(:pre_flash_content) do %> <%= render StepIndicatorComponent.new( - steps: Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS, + steps: Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS_IPP, current_step: :verify_info, locale_scope: 'idv', class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', diff --git a/app/views/test/ipp/index.html.erb b/app/views/test/ipp/index.html.erb new file mode 100644 index 00000000000..b9bef3a6e14 --- /dev/null +++ b/app/views/test/ipp/index.html.erb @@ -0,0 +1,67 @@ +<% self.title = 'In-person proofing enrollments' %> + +<%= content_for(:meta_refresh) { '15' } %> + +

In-person proofing enrollments

+ +
+
+ <% if @enrollments.count == 0 %> +

+ There are no recent in-person enrollments. +

+ <% else %> +

+ Listed below + <%= @enrollments.count == 1 ? 'is' : 'are' %> + the <%= @enrollments.count %> most recent + in-person enrollment<%= @enrollments.count == 1 ? '' : 's' %>. +

+ + + + + + + + + + + <% @enrollments_with_actions.each_with_index do |(e, action), index| %> + + + + + + + <% end %> + +
UUIDStatus
+ + + + <%= e.user.uuid %> + <%= case e.status + when 'pending' then '🤔' + when 'passed' then '✅' + when 'failed' then '🙀' + else '⚪️' + end %> + <%= e.status %> + + <%= case action + when :approve + button_to( + '👍 Approve', + test_ipp_path(enrollment: e.id), + method: 'put', + class: 'usa-button usa-button-small', + title: 'Simulate the user passing the check at the post office', + ) + end %> +
+ <% end %> +
+
diff --git a/app/views/user_mailer/in_person_please_call.html.erb b/app/views/user_mailer/idv_please_call.html.erb similarity index 69% rename from app/views/user_mailer/in_person_please_call.html.erb rename to app/views/user_mailer/idv_please_call.html.erb index f8cef7a4ae8..54f4a89ba9f 100644 --- a/app/views/user_mailer/in_person_please_call.html.erb +++ b/app/views/user_mailer/idv_please_call.html.erb @@ -4,16 +4,16 @@ width: 88, height: 88, ) %> -

<%= t('user_mailer.in_person_please_call.header') %>

+

<%= t('user_mailer.idv_please_call.header') %>

<%= t( - 'user_mailer.in_person_please_call.body.intro_html', + 'user_mailer.idv_please_call.body.intro_html', date: I18n.l(14.days.from_now, format: I18n.t('time.formats.full_date')), ) %>

<%= t( - 'user_mailer.in_person_please_call.body.contact_message_html', + 'user_mailer.idv_please_call.body.contact_message_html', contact_number: IdentityConfig.store.idv_contact_phone_number, support_code: IdentityConfig.store.lexisnexis_threatmetrix_support_code, ) %> diff --git a/config/application.yml.default b/config/application.yml.default index 549a443c771..dcd7ef6c452 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -387,6 +387,7 @@ socure_docv_document_request_endpoint: '' socure_docv_enabled: false socure_docv_verification_data_test_mode: false socure_docv_verification_data_test_mode_tokens: '[]' +socure_docv_webhook_repeat_endpoints: '[]' socure_docv_webhook_secret_key: '' socure_docv_webhook_secret_key_queue: '[]' socure_idplus_api_key: '' @@ -512,7 +513,6 @@ production: aamva_send_id_type: false aamva_send_middle_name: false aamva_verification_url: 'https://verificationservices-cert.aamva.org:18449/dldv/2.1/online' - available_locales: 'en,es,fr' disable_email_sending: false disable_logout_get_request: false email_registrations_per_ip_track_only_mode: true diff --git a/config/locales/en.yml b/config/locales/en.yml index 89b9f965ec0..a999cd2a1cd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1875,6 +1875,10 @@ user_mailer.email_deleted.header: An email address was deleted from your %{app_n user_mailer.email_deleted.help_html: If you did not want to delete this email address, please visit the %{app_name_html} %{help_link_html} or %{contact_link_html}. user_mailer.email_deleted.subject: Email address deleted user_mailer.help_link_text: Help Center +user_mailer.idv_please_call.body.contact_message_html: Call %{contact_number} and provide them with the error code %{support_code}. +user_mailer.idv_please_call.body.intro_html: Call our contact center by %{date} to continue verifying your identity. +user_mailer.idv_please_call.header: Please give us a call +user_mailer.idv_please_call.subject: Call %{app_name} to continue with your identity verification user_mailer.in_person_completion_survey.body.cta.callout: Click the button below to get started. user_mailer.in_person_completion_survey.body.cta.label: Take our survey user_mailer.in_person_completion_survey.body.greeting: Hello, @@ -1900,10 +1904,6 @@ user_mailer.in_person_failed.intro: Your identity could not be verified at the % user_mailer.in_person_failed.subject: Your identity could not be verified in person user_mailer.in_person_failed.verifying_identity: 'When verifying your identity:' user_mailer.in_person_failed.verifying_step_not_expired: Your state‑issued ID or driver’s license must not be expired. We do not currently accept any other forms of identification, such as passports and military IDs. -user_mailer.in_person_please_call.body.contact_message_html: Call %{contact_number} and provide them with the error code %{support_code}. -user_mailer.in_person_please_call.body.intro_html: Call our contact center by %{date} to continue verifying your identity. -user_mailer.in_person_please_call.header: Please give us a call -user_mailer.in_person_please_call.subject: Call %{app_name} to continue with your identity verification user_mailer.in_person_ready_to_verify_reminder.greeting: Hello, user_mailer.in_person_ready_to_verify_reminder.heading.one: You have %{count} day left to verify your identity in person user_mailer.in_person_ready_to_verify_reminder.heading.other: You have %{count} days left to verify your identity in person diff --git a/config/locales/es.yml b/config/locales/es.yml index e790124af69..57b1e9bf60f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1887,6 +1887,10 @@ user_mailer.email_deleted.header: Se eliminó una dirección de correo electrón user_mailer.email_deleted.help_html: Si no deseaba eliminar esta dirección de correo electrónico, visite %{help_link_html} de %{app_name_html} o %{contact_link_html}. user_mailer.email_deleted.subject: Dirección de correo electrónico eliminada user_mailer.help_link_text: Centro de ayuda +user_mailer.idv_please_call.body.contact_message_html: Llame al %{contact_number} y proporcione el código de error %{support_code}. +user_mailer.idv_please_call.body.intro_html: Llame a nuestro centro de contacto antes del %{date} para seguir verificando su identidad. +user_mailer.idv_please_call.header: Llámenos +user_mailer.idv_please_call.subject: Llame a %{app_name} para continuar con la verificación de identidad user_mailer.in_person_completion_survey.body.cta.callout: Haga clic en el botón siguiente para empezar. user_mailer.in_person_completion_survey.body.cta.label: Responda a nuestra encuesta user_mailer.in_person_completion_survey.body.greeting: 'Hola:' @@ -1912,10 +1916,6 @@ user_mailer.in_person_failed.intro: No se pudo verificar su identidad en la ofic user_mailer.in_person_failed.subject: No se pudo verificar su identidad en persona user_mailer.in_person_failed.verifying_identity: 'Cuando verifique su identidad:' user_mailer.in_person_failed.verifying_step_not_expired: Su licencia de conducir o identificación emitida por el estado debe estar vigente. Actualmente no aceptamos otras formas de identificación, como pasaportes o identificaciones militares. -user_mailer.in_person_please_call.body.contact_message_html: Llame al %{contact_number} y proporcione el código de error %{support_code}. -user_mailer.in_person_please_call.body.intro_html: Llame a nuestro centro de contacto antes del %{date} para seguir verificando su identidad. -user_mailer.in_person_please_call.header: Llámenos -user_mailer.in_person_please_call.subject: Llame a %{app_name} para continuar con la verificación de identidad user_mailer.in_person_ready_to_verify_reminder.greeting: 'Hola:' user_mailer.in_person_ready_to_verify_reminder.heading.one: Le queda %{count} día para verificar su identidad en persona user_mailer.in_person_ready_to_verify_reminder.heading.other: Le quedan %{count} días para verificar su identidad en persona diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 6775afb05c9..5ea53a3c147 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1875,6 +1875,10 @@ user_mailer.email_deleted.header: Une adresse e-mail a été supprimée de votre user_mailer.email_deleted.help_html: Si vous ne souhaitez pas supprimer cette adresse e-mail, veuillez visiter le %{help_link_html} de %{app_name_html} ou %{contact_link_html}. user_mailer.email_deleted.subject: Adresse e-mail supprimée user_mailer.help_link_text: Centre d’aide +user_mailer.idv_please_call.body.contact_message_html: Appelez le %{contact_number} et indiquez le code d’erreur %{support_code}. +user_mailer.idv_please_call.body.intro_html: Appelez notre centre de contact avant le %{date} pour continuer à vérifier votre identité. +user_mailer.idv_please_call.header: S’il vous plaît, appelez-nous +user_mailer.idv_please_call.subject: Appeler %{app_name} afin de poursuivre la vérification de votre identité user_mailer.in_person_completion_survey.body.cta.callout: Cliquez sur le bouton ci-dessous pour commencer. user_mailer.in_person_completion_survey.body.cta.label: Répondez à notre enquête user_mailer.in_person_completion_survey.body.greeting: Bonjour, @@ -1900,10 +1904,6 @@ user_mailer.in_person_failed.intro: Votre identité n’a pas pu être vérifié user_mailer.in_person_failed.subject: Votre identité n’a pas pu être vérifiée en personne user_mailer.in_person_failed.verifying_identity: 'Lors de la vérification de votre identité :' user_mailer.in_person_failed.verifying_step_not_expired: Votre carte d’identité délivrée par l’État ou votre permis de conduire ne doit pas être périmé. Nous n’acceptons actuellement aucune autre pièce d’identité, comme les passeports et les cartes d’identité militaires. -user_mailer.in_person_please_call.body.contact_message_html: Appelez le %{contact_number} et indiquez le code d’erreur %{support_code}. -user_mailer.in_person_please_call.body.intro_html: Appelez notre centre de contact avant le %{date} pour continuer à vérifier votre identité. -user_mailer.in_person_please_call.header: S’il vous plaît, appelez-nous -user_mailer.in_person_please_call.subject: Appeler %{app_name} afin de poursuivre la vérification de votre identité user_mailer.in_person_ready_to_verify_reminder.greeting: Bonjour, user_mailer.in_person_ready_to_verify_reminder.heading.one: Il vous reste %{count} jour pour vérifier votre identité en personne user_mailer.in_person_ready_to_verify_reminder.heading.other: Il vous reste %{count} jours pour vérifier votre identité en personne diff --git a/config/locales/zh.yml b/config/locales/zh.yml index aaebc735fad..2797d52219e 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -1888,6 +1888,10 @@ user_mailer.email_deleted.header: 一个电邮地址被从你的 %{app_name} 用 user_mailer.email_deleted.help_html: 如果你没有想删除这一电邮地址,请访问 %{app_name_html} %{help_link_html} 或者 %{contact_link_html}。 user_mailer.email_deleted.subject: 电邮地址已删除 user_mailer.help_link_text: 帮助中心 +user_mailer.idv_please_call.body.contact_message_html: 打电话给 %{contact_number} 并向他们提供错误 代码 %{support_code}。 +user_mailer.idv_please_call.body.intro_html: 请在 %{date} 之前给我们的联系中心打电话,以继续验证你的身份。 +user_mailer.idv_please_call.header: 请给我们打个电话 +user_mailer.idv_please_call.subject: 致电 %{app_name} 继续进行身份验证 user_mailer.in_person_completion_survey.body.cta.callout: 点击下面的按钮来开始 user_mailer.in_person_completion_survey.body.cta.label: 填写我们的意见调查 user_mailer.in_person_completion_survey.body.greeting: 你好, @@ -1913,10 +1917,6 @@ user_mailer.in_person_failed.intro: 你的身份于 %{date}在 %{location} 邮 user_mailer.in_person_failed.subject: 你的身份未能亲身被验证。 user_mailer.in_person_failed.verifying_identity: '验证你的身份时:' user_mailer.in_person_failed.verifying_step_not_expired: 你的州政府颁发的身份证件或驾照绝对没有过期。我们目前不接受任何其他形式的身份证件,比如护照和军队身份证件。 -user_mailer.in_person_please_call.body.contact_message_html: 打电话给 %{contact_number} 并向他们提供错误 代码 %{support_code}。 -user_mailer.in_person_please_call.body.intro_html: 请在 %{date} 之前给我们的联系中心打电话,以继续验证你的身份。 -user_mailer.in_person_please_call.header: 请给我们打个电话 -user_mailer.in_person_please_call.subject: 致电 %{app_name} 继续进行身份验证 user_mailer.in_person_ready_to_verify_reminder.greeting: 你好, user_mailer.in_person_ready_to_verify_reminder.heading.one: 你距离亲身验证身份截止日期还有 %{count} 天 user_mailer.in_person_ready_to_verify_reminder.heading.other: 你距离亲身验证身份截止日期还有 %{count} 天 diff --git a/config/routes.rb b/config/routes.rb index 78c4010b282..adeab6c9807 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -149,6 +149,9 @@ if IdentityConfig.store.enable_test_routes namespace :test do + get '/ipp' => 'ipp#index' + put '/ipp' => 'ipp#update' + # Assertion granting test start + return. get '/saml/login' => 'saml_test#index' get '/saml' => 'saml_test#start' @@ -413,11 +416,6 @@ get '/capture-doc' => 'hybrid_mobile/entry#show', # sometimes underscores get messed up when linked to via SMS as: :capture_doc_dashes - - # Deprecated route - temporary redirect while state id changes are rolled out - get '/in_person_proofing/state_id' => redirect('verify/in_person/state_id', status: 307) - put '/in_person_proofing/state_id' => redirect('verify/in_person/state_id', status: 307) - get '/in_person' => 'in_person#index' get '/in_person/ready_to_verify' => 'in_person/ready_to_verify#show', as: :in_person_ready_to_verify diff --git a/dockerfiles/application.yaml b/dockerfiles/application.yaml index 67ad0b394b4..e854cfb627c 100644 --- a/dockerfiles/application.yaml +++ b/dockerfiles/application.yaml @@ -384,11 +384,31 @@ spec: logo: '18f.svg' certs: - 'identity_dashboard_cert' - return_to_sp_url: 'https://dashboard.{{ENVIRONMENT}}.identitysandbox.gov/' + return_to_sp_url: 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov/' redirect_uris: - - 'https://dashboard.{{ENVIRONMENT}}.identitysandbox.gov/auth/logindotgov/callback' - - 'https://dashboard.{{ENVIRONMENT}}.identitysandbox.gov' - push_notification_url: 'https://dashboard.{{ENVIRONMENT}}.identitysandbox.gov/api/security_events' + - 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov/auth/logindotgov/callback' + - 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov' + push_notification_url: 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov/api/security_events' + - target: + kind: ConfigMap + name: service-providers-yml-dbsetup + patch: |- + - op: replace + path: /data/service_providers.yml + value: | + production: + 'urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:dashboard': + friendly_name: 'Dashboard' + agency: 'GSA' + agency_id: 2 + logo: '18f.svg' + certs: + - 'identity_dashboard_cert' + return_to_sp_url: 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov/' + redirect_uris: + - 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov/auth/logindotgov/callback' + - 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov' + push_notification_url: 'https://{{ENVIRONMENT}}-dashboard.reviewapps.identitysandbox.gov/api/security_events' # Patch idp database setup jobs - target: kind: Job diff --git a/lib/analytics_events_documenter.rb b/lib/analytics_events_documenter.rb index 60161c85626..6200eab1216 100644 --- a/lib/analytics_events_documenter.rb +++ b/lib/analytics_events_documenter.rb @@ -15,6 +15,10 @@ class AnalyticsEventsDocumenter DOCUMENTATION_OPTIONAL_PARAMS = %w[ pii_like_keypaths + active_profile_idv_level + pending_profile_idv_level + proofing_components + profile_history ].freeze attr_reader :database_path, :class_name diff --git a/lib/identity_config.rb b/lib/identity_config.rb index cd90324d7ed..c8178d27958 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -423,6 +423,7 @@ def self.store config.add(:socure_docv_enabled, type: :boolean) config.add(:socure_docv_verification_data_test_mode, type: :boolean) config.add(:socure_docv_verification_data_test_mode_tokens, type: :json) + config.add(:socure_docv_webhook_repeat_endpoints, type: :json) config.add(:socure_docv_webhook_secret_key_queue, type: :json) config.add(:socure_docv_webhook_secret_key, type: :string) config.add(:socure_idplus_api_key, type: :string) diff --git a/lib/linters/mail_later_linter.rb b/lib/linters/mail_later_linter.rb index 12c891d5df3..cd576be1d6b 100644 --- a/lib/linters/mail_later_linter.rb +++ b/lib/linters/mail_later_linter.rb @@ -28,12 +28,12 @@ def on_send(node) mailer_name = if receiver.const_type? # MailerClass.email.send_later receiver.const_name - elsif receiver.method_name == :with + elsif receiver.send_type? && receiver.method_name == :with # MailerClass.with(...).email.send_later receiver.receiver.const_name end - add_offense(node) if mailer_name == 'UserMailer' + add_offense(node) if mailer_name.nil? || mailer_name == 'UserMailer' end end end diff --git a/package.json b/package.json index 9467e2175b3..74a0f354452 100644 --- a/package.json +++ b/package.json @@ -36,13 +36,12 @@ "cleave.js": "^1.6.0", "concurrently": "^8.2.2", "core-js": "^3.21.1", - "fast-glob": "^3.3.2", "foundation-emails": "^2.3.1", "intl-tel-input": "^24.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", "source-map-loader": "^4.0.0", - "webpack": "^5.94.0", + "webpack": "^5.97.1", "webpack-assets-manifest": "^5.2.1", "webpack-cli": "^5.1.4" }, @@ -58,7 +57,7 @@ "@types/dirty-chai": "^2.0.2", "@types/grecaptcha": "^3.0.4", "@types/mocha": "^10.0.0", - "@types/node": "^22.10.1", + "@types/node": "^22.10.2", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.11", "@types/sinon": "^10.0.13", @@ -68,7 +67,7 @@ "@typescript-eslint/parser": "^6.7.5", "chai": "^4.3.10", "chai-as-promised": "^7.1.1", - "clipboard-polyfill": "^3.0.3", + "clipboard-polyfill": "^4.1.1", "dirty-chai": "^2.0.1", "dom-accessibility-api": "^0.5.14", "eslint": "^8.43.0", @@ -91,7 +90,7 @@ "stylelint": "^16.2.1", "svgo": "^3.2.0", "swr": "^2.0.0", - "typescript": "^5.2.2", + "typescript": "^5.7.2", "yarn-deduplicate": "^6.0.2" }, "resolutions": { diff --git a/scripts/enforce-typescript-files.mjs b/scripts/enforce-typescript-files.mjs index f75d5f728bd..df91c749c32 100755 --- a/scripts/enforce-typescript-files.mjs +++ b/scripts/enforce-typescript-files.mjs @@ -1,9 +1,8 @@ #!/usr/bin/env node import assert from 'node:assert'; -import { readFile } from 'node:fs/promises'; -import { dirname, join } from 'node:path'; -import glob from 'fast-glob'; +import { readFile, glob } from 'node:fs/promises'; +import { dirname, relative, join } from 'node:path'; // Do not add to this list! All new scripts should be written in TypeScript, so this list should // only ever shrink over time. Scripts which are loaded directly by Node.js should exist within @@ -70,15 +69,26 @@ const LEGACY_FILE_EXCEPTIONS = [ 'spec/javascript/packages/document-capture/services/upload-spec.js', ]; -const packagesWithEntrypoints = await glob('app/javascript/packages/*/package.json') +const packagesWithEntrypoints = await Array.fromAsync( + glob('app/javascript/packages/*/package.json'), +) .then((files) => Promise.all(files.map(async (file) => [file, await readFile(file, 'utf-8')]))) .then((contents) => contents.map(([file, content]) => [file, JSON.parse(content)])) .then((manifests) => manifests.filter(([_file, manifest]) => manifest.exports || manifest.main)) .then((manifests) => manifests.map(([file]) => dirname(file))); -const jsFiles = await glob( - ['app/{javascript/packages,components}/**/*.{js,jsx}', 'spec/javascript/*/**/*.{js,jsx}'], - { ignore: packagesWithEntrypoints.map((path) => join(path, '**')) }, +const jsFileEntries = await Array.fromAsync( + glob(['app/{javascript/packages,components}/**/*.{js,jsx}', 'spec/javascript/*/**/*.{js,jsx}'], { + exclude: (fileName) => + packagesWithEntrypoints.some((path) => + relative(process.cwd(), fileName.parentPath).startsWith(path), + ), + withFileTypes: true, + }), +); + +const jsFiles = jsFileEntries.map(({ parentPath, name }) => + relative(process.cwd(), join(parentPath, name)), ); const invalidExceptions = LEGACY_FILE_EXCEPTIONS.filter((file) => !jsFiles.includes(file)); diff --git a/scripts/validate-workspaces.mjs b/scripts/validate-workspaces.mjs index 7774f39efa3..9c2cd8ddabf 100755 --- a/scripts/validate-workspaces.mjs +++ b/scripts/validate-workspaces.mjs @@ -1,8 +1,7 @@ #!/usr/bin/env node -import { readFile, stat } from 'node:fs/promises'; +import { readFile, stat, glob } from 'node:fs/promises'; import { dirname, basename, join, resolve, relative } from 'node:path'; -import glob from 'fast-glob'; /** @typedef {[path: string, manifest: Record]} ManifestPair */ /** @typedef {ManifestPair[]} ManifestPairs */ @@ -129,7 +128,9 @@ function checkPackageSideEffectsIncludesCustomElements(manifests) { return Promise.all( manifests.map(async ([manifestPath, manifest]) => { const manifestDirectory = dirname(manifestPath); - const customElementPaths = await glob(join(manifestDirectory, '*-element.ts')); + const customElementPaths = await Array.fromAsync( + glob(join(manifestDirectory, '*-element.ts')), + ); const expectedPaths = customElementPaths.map((path) => resolve(path)); const actualPaths = Array.from(manifest.sideEffects).map((path) => resolve(join(manifestDirectory, path)), @@ -170,7 +171,7 @@ const EXCEPTIONS = { checkHaveCorrectPackageName: ['app/javascript/packages/eslint-plugin/package.json'], }; -const manifestPaths = await glob('app/javascript/packages/*/package.json'); +const manifestPaths = await Array.fromAsync(glob('app/javascript/packages/*/package.json')); Promise.all(manifestPaths.map(async (path) => [path, await readFile(path, 'utf-8')])) .then((contents) => contents.map(([path, content]) => /** @type {ManifestPair} */ ([path, JSON.parse(content)])), diff --git a/spec/controllers/accounts/connected_accounts/selected_email_controller_spec.rb b/spec/controllers/accounts/connected_accounts/selected_email_controller_spec.rb index 63bb9d45175..9bd0a95dcdf 100644 --- a/spec/controllers/accounts/connected_accounts/selected_email_controller_spec.rb +++ b/spec/controllers/accounts/connected_accounts/selected_email_controller_spec.rb @@ -29,6 +29,19 @@ expect(assigns(:identity)).to be_kind_of(ServiceProviderIdentity) expect(assigns(:select_email_form)).to be_kind_of(SelectEmailForm) expect(assigns(:can_add_email)).to eq(true) + expect(assigns(:email_id)).to eq(user.email_addresses.first.id) + end + + context 'user has signed in with a different email address than has been assigned' do + it 'assigns the user identity email id' do + identity_email = user.email_addresses.last.id + identity.email_address_id = identity_email + identity.save + + response + + expect(assigns(:email_id)).to eq(identity_email) + end end context 'with an identity parameter not associated with the user' do @@ -113,7 +126,7 @@ expect(@analytics).to have_logged_event( :sp_select_email_submitted, success: false, - error_details: { selected_email_id: { not_found: true } }, + error_details: { selected_email_id: { blank: true, not_found: true } }, ) end end diff --git a/spec/controllers/idv/link_sent_controller_spec.rb b/spec/controllers/idv/link_sent_controller_spec.rb index e8feadcee66..967cefa019f 100644 --- a/spec/controllers/idv/link_sent_controller_spec.rb +++ b/spec/controllers/idv/link_sent_controller_spec.rb @@ -223,8 +223,10 @@ before do expect(FormResponse).to receive(:new).with( - { success: false, - errors: { message: error_message } }, + { + success: false, + errors: hash_including(message: error_message), + }, ) end diff --git a/spec/controllers/sign_up/select_email_controller_spec.rb b/spec/controllers/sign_up/select_email_controller_spec.rb index e151c14ebd7..7eefddb0368 100644 --- a/spec/controllers/sign_up/select_email_controller_spec.rb +++ b/spec/controllers/sign_up/select_email_controller_spec.rb @@ -61,16 +61,6 @@ end end - context 'with only one verified email address' do - let(:user) { create(:user) } - - it 'redirects to the sign up completed path' do - response - - expect(response).to redirect_to(sign_up_completed_path) - end - end - context 'when users has max number of emails' do before do allow(user).to receive(:email_address_count).and_return(2) diff --git a/spec/controllers/socure_webhook_controller_spec.rb b/spec/controllers/socure_webhook_controller_spec.rb index 409a18ccaf5..3f9db2cd559 100644 --- a/spec/controllers/socure_webhook_controller_spec.rb +++ b/spec/controllers/socure_webhook_controller_spec.rb @@ -63,6 +63,51 @@ before do request.headers['Authorization'] = socure_secret_key end + + shared_examples 'repeats webhooks' do + let(:headers) do + { + Authorization: socure_secret_key_queue.last, + 'Content-Type': 'application/json', + } + end + let(:endpoints) do + 3.times.map { |i| "https://#{i}.example.test/endpoint" } + end + let(:repeated_body) do + b = {}.merge(webhook_body) + b[:event].delete(:data) + b + end + + before do + allow(IdentityConfig.store) + .to receive(:socure_docv_webhook_repeat_endpoints).and_return(endpoints) + allow(SocureDocvResultsJob).to receive(:perform_now) + allow(SocureDocvRepeatWebhookJob).to receive(:perform_later) + + dcs = create(:document_capture_session, :socure) + webhook_body[:event][:docvTransactionToken] = dcs.socure_docv_transaction_token + + request.headers['Authorization'] = headers[:Authorization] + request.headers['Content-Type'] = headers[:'Content-Type'] + end + + context 'when idv workers are enabled' do + it 'queues SocureDocvRepeatWebhook jobs' do + endpoints.each do |endpoint| + expect(SocureDocvRepeatWebhookJob).to receive(:perform_later) do |*args| + expect(args.first[:body]).to eq(JSON.parse(repeated_body.to_json)) + expect(args.first[:endpoint]).to eq(endpoint) + expect(args.first[:headers]).to eq(headers) + end + end + + post :create, params: webhook_body + end + end + end + it 'returns OK and logs an event with a correct secret key and body' do post :create, params: webhook_body @@ -92,6 +137,8 @@ end end + it_behaves_like 'repeats webhooks' + context 'when document capture session exists' do it 'logs the user\'s uuid' do dcs = create(:document_capture_session, :socure) @@ -113,6 +160,8 @@ context 'when DOCUMENTS_UPLOADED event received' do let(:event_type) { 'DOCUMENTS_UPLOADED' } + it_behaves_like 'repeats webhooks' + it 'returns OK and logs an event with a correct secret key and body' do dcs = create(:document_capture_session, :socure) webhook_body[:event][:docvTransactionToken] = dcs.socure_docv_transaction_token @@ -181,6 +230,8 @@ context 'when SESSION_COMPLETE event received' do let(:event_type) { 'SESSION_COMPLETE' } + it_behaves_like 'repeats webhooks' + it 'does not increment rate limiter of user' do dcs = create(:document_capture_session, :socure) webhook_body[:event][:docvTransactionToken] = dcs.socure_docv_transaction_token @@ -220,6 +271,8 @@ context 'when SESSION_EXPIRED event received' do let(:event_type) { 'SESSION_EXPIRED' } + it_behaves_like 'repeats webhooks' + it 'does not increment rate limiter of user' do dcs = create(:document_capture_session, :socure) webhook_body[:event][:docvTransactionToken] = dcs.socure_docv_transaction_token diff --git a/spec/factories/proofing_components.rb b/spec/factories/proofing_components.rb deleted file mode 100644 index d0cabeab586..00000000000 --- a/spec/factories/proofing_components.rb +++ /dev/null @@ -1,10 +0,0 @@ -FactoryBot.define do - factory :proofing_component do - association :user, factory: %i[user fully_registered] - - trait :eligible_for_review do - verified_at { Time.zone.now } - threatmetrix_review_status { 'review' } - end - end -end diff --git a/spec/features/accessibility/idv_pages_spec.rb b/spec/features/accessibility/idv_pages_spec.rb index d5d92c3374a..3b24a0007e5 100644 --- a/spec/features/accessibility/idv_pages_spec.rb +++ b/spec/features/accessibility/idv_pages_spec.rb @@ -19,7 +19,7 @@ complete_welcome_step complete_agreement_step - expect(current_path).to eq idv_how_to_verify_path + expect(page).to have_current_path idv_how_to_verify_path expect(page).to have_unique_form_landmark_labels expect_page_to_have_no_accessibility_violations(page) end @@ -28,7 +28,7 @@ sign_in_and_2fa_user visit idv_cancel_path - expect(current_path).to eq idv_cancel_path + expect(page).to have_current_path idv_cancel_path expect_page_to_have_no_accessibility_violations(page) visit idv_path @@ -37,7 +37,7 @@ fill_in t('idv.form.password'), with: Features::SessionHelper::VALID_PASSWORD click_continue - expect(current_path).to eq idv_personal_key_path + expect(page).to have_current_path idv_personal_key_path expect_page_to_have_no_accessibility_violations(page) end @@ -48,7 +48,7 @@ fill_in t('idv.form.password'), with: Features::SessionHelper::VALID_PASSWORD click_continue - expect(current_path).to eq idv_personal_key_path + expect(page).to have_current_path idv_personal_key_path expect_page_to_have_no_accessibility_violations(page) end end diff --git a/spec/features/accessibility/user_pages_spec.rb b/spec/features/accessibility/user_pages_spec.rb index 175161ed927..87af1a3addd 100644 --- a/spec/features/accessibility/user_pages_spec.rb +++ b/spec/features/accessibility/user_pages_spec.rb @@ -6,7 +6,7 @@ email = 'test@example.com' sign_up_with(email) - expect(current_path).to eq(sign_up_verify_email_path) + expect(page).to have_current_path(sign_up_verify_email_path) # We can't validate markup here, since markup validation requires a page reload when using the # JS driver, but the sign up verify email path can only be visited once before redirecting to # the account creation form. Instead, we validate markup separately with the non-JS driver. @@ -18,7 +18,7 @@ email = 'test@example.com' sign_up_with(email) - expect(current_path).to eq(sign_up_verify_email_path) + expect(page).to have_current_path(sign_up_verify_email_path) expect(page).to have_valid_markup end end @@ -28,14 +28,14 @@ create(:user, :unconfirmed) confirm_last_user - expect(current_path).to eq(sign_up_enter_password_path) + expect(page).to have_current_path(sign_up_enter_password_path, ignore_query: true) expect_page_to_have_no_accessibility_violations(page) end scenario 'invalid confirmation token' do visit sign_up_create_email_confirmation_path(confirmation_token: '123456') - expect(current_path).to eq(sign_up_register_path) + expect(page).to have_current_path(sign_up_register_path) expect(page).to have_content(t('errors.messages.confirmation_invalid_token')) expect_page_to_have_no_accessibility_violations(page) end @@ -45,7 +45,7 @@ scenario 'two factor options page' do sign_up_and_set_password - expect(current_path).to eq(authentication_methods_setup_path) + expect(page).to have_current_path(authentication_methods_setup_path) expect_page_to_have_no_accessibility_violations(page) phone_checkbox = page.find_field('two_factor_options_form_selection_phone', visible: :all) expect(phone_checkbox).to have_name( @@ -61,7 +61,7 @@ find("label[for='two_factor_options_form_selection_phone']").click click_button t('forms.buttons.continue') - expect(current_path).to eq(phone_setup_path) + expect(page).to have_current_path(phone_setup_path) expect_page_to_have_no_accessibility_violations(page) end @@ -69,7 +69,7 @@ user = create(:user, :fully_registered) sign_in_before_2fa(user) - expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: 'sms')) + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') expect_page_to_have_no_accessibility_violations(page) end @@ -79,7 +79,7 @@ sign_in_before_2fa(user) visit login_two_factor_path(otp_delivery_preference: 'sms') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') expect_page_to_have_no_accessibility_violations(page) end end @@ -90,7 +90,7 @@ sign_in_before_2fa(user) visit login_two_factor_path(otp_delivery_preference: 'voice') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'voice') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'voice') expect_page_to_have_no_accessibility_violations(page) end end diff --git a/spec/features/account/backup_codes_spec.rb b/spec/features/account/backup_codes_spec.rb index 4009440f9d2..97a1545c162 100644 --- a/spec/features/account/backup_codes_spec.rb +++ b/spec/features/account/backup_codes_spec.rb @@ -88,7 +88,7 @@ let(:user) { create(:user, :with_backup_code) } it 'the user is not prompted to set up another MFA upon login' do - expect(current_path).to eq account_two_factor_authentication_path + expect(page).to have_current_path account_two_factor_authentication_path end end end diff --git a/spec/features/account_connected_apps_spec.rb b/spec/features/account_connected_apps_spec.rb index 70a0254b563..9ed731123a6 100644 --- a/spec/features/account_connected_apps_spec.rb +++ b/spec/features/account_connected_apps_spec.rb @@ -3,7 +3,14 @@ RSpec.describe 'Account connected applications' do include NavigationHelper - let(:user) { create(:user, :fully_registered, created_at: Time.zone.now - 100.days) } + let(:user) do + create( + :user, + :fully_registered, + :with_multiple_emails, + created_at: Time.zone.now - 100.days, + ) + end let(:identity) do create( :service_provider_identity, @@ -84,26 +91,44 @@ click_link(t('help_text.requested_attributes.change_email_link')) end - expect(page).to have_field(user.email) { |field| !field[:checked] } + expect(page).to have_field(user.email) { |field| field[:checked] } - choose user.email + choose user.email_addresses.last.email click_on t('help_text.requested_attributes.select_email_link') within('li', text: identity.display_name) do expect(page).not_to have_content(t('account.connected_apps.email_not_selected')) - expect(page).to have_content(user.email) + expect(page).to have_content(user.email_addresses.last.email) click_link(t('help_text.requested_attributes.change_email_link')) end - expect(page).to have_field(user.email) { |field| field[:checked] } + expect(page).to have_field(user.email_addresses.last.email) { |field| field[:checked] } + + choose user.email click_on(t('help_text.requested_attributes.select_email_link')) + within('li', text: identity.display_name) do + expect(page).to have_content(user.email) + end + expect(page).to have_content strip_tags( t('account.connected_apps.email_update_success_html', sp_name: identity.display_name), ) end + scenario 'changing email shared with SP when SP has an assigned email' do + identity.email_address_id = user.email_addresses.last.id + identity.save + + within('li', text: identity.display_name) do + expect(page).to have_content(t('account.connected_apps.email_not_selected')) + click_link(t('help_text.requested_attributes.change_email_link')) + end + + expect(page).to have_field(user.email_addresses.last.email) { |field| field[:checked] } + end + def build_account_connected_apps identity identity_without_link diff --git a/spec/features/account_creation/completions_cancel_spec.rb b/spec/features/account_creation/completions_cancel_spec.rb index 7f8e9b7b477..7bd3fbbd06e 100644 --- a/spec/features/account_creation/completions_cancel_spec.rb +++ b/spec/features/account_creation/completions_cancel_spec.rb @@ -9,19 +9,24 @@ select_2fa_option('backup_code') click_continue - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_on t('links.cancel') - expect(current_path).to eq(sign_up_completed_cancel_path) + expect(page).to have_current_path(sign_up_completed_cancel_path) click_on t('login_cancel.keep_going') - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_on t('links.cancel') - expect(current_path).to eq(sign_up_completed_cancel_path) + expect(page).to have_current_path(sign_up_completed_cancel_path) click_on t('login_cancel.exit', app_name: APP_NAME) + expect(page).to have_current_path( + 'http://localhost:7654/auth/result', + url: true, + ignore_query: true, + ) expect(current_url).to start_with('http://localhost:7654/auth/result?error=access_denied') end end diff --git a/spec/features/event_disavowal_spec.rb b/spec/features/event_disavowal_spec.rb index fb4bdcf4329..637498c3243 100644 --- a/spec/features/event_disavowal_spec.rb +++ b/spec/features/event_disavowal_spec.rb @@ -172,7 +172,9 @@ # We should be on the MFA screen because we logged in with the new password expect(page).to have_content(t('two_factor_authentication.header_text')) - expect(page.current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms)) + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: :sms), + ) end scenario 'disavowing an event with javascript enabled', :js do @@ -194,8 +196,10 @@ end def submit_prefilled_otp_code(user, delivery_preference) - expect(current_path) - .to eq login_two_factor_path(otp_delivery_preference: delivery_preference) + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: delivery_preference), + ignore_query: true, + ) fill_in('code', with: user.reload.direct_otp) click_button t('forms.buttons.submit.default') end @@ -232,7 +236,9 @@ def disavow_last_action_and_reset_password expect(page).to have_current_path(login_two_factor_piv_cac_path) else expect(page).to have_content(t('two_factor_authentication.header_text')) - expect(page.current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms)) + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: :sms), + ) end end end diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index c74a2975ad8..cc498b88dce 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -10,6 +10,7 @@ let(:proofing_device_profiling) { :enabled } let(:threatmetrix) { true } let(:idv_level) { 'in_person' } + let(:threatmetrix_response_body) do { account_lex_id: 'super-cool-test-lex-id', @@ -24,6 +25,7 @@ tmx_summary_reason_code: ['Identity_Negative_History'], } end + let(:threatmetrix_response) do { client: nil, @@ -37,6 +39,7 @@ transaction_id: 'ddp-mock-transaction-id-123', } end + let(:base_proofing_components) do { document_check: 'mock', @@ -47,9 +50,11 @@ threatmetrix_review_status: 'pass', } end + let(:lexis_nexis_address_proofing_components) do base_proofing_components.merge(address_check: 'lexis_nexis_address') end + let(:gpo_letter_proofing_components) do base_proofing_components.merge(address_check: 'gpo_letter') end @@ -216,19 +221,24 @@ success: true, errors: {}, user_id: user.uuid, submit_attempts: 1, remaining_submit_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {}, id_issued_status: 'present', id_expiration_status: 'present' }, 'IdV: doc auth document_capture submitted' => { - success: true, errors: {}, flow_path: 'standard', step: 'document_capture', analytics_id: 'Doc Auth', selfie_check_required: boolean, liveness_checking_required: boolean + success: true, errors: {}, flow_path: 'standard', step: 'document_capture', analytics_id: 'Doc Auth', selfie_check_required: boolean, liveness_checking_required: boolean, + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth ssn visited' => { - flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth ssn submitted' => { - success: true, errors: {}, flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth' + success: true, errors: {}, flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify visited' => { - flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify submitted' => { - flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, idv_threatmetrix_response_body: ( if threatmetrix_response_body.present? @@ -237,10 +247,10 @@ ), 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', - proofing_results: doc_auth_verify_proofing_results + proofing_results: doc_auth_verify_proofing_results, + proofing_components: base_proofing_components }, 'IdV: phone of record visited' => { - proofing_components: base_proofing_components, }, 'IdV: phone confirmation form' => { @@ -295,6 +305,7 @@ }.compact end + # TODO: Add ["IdV: doc auth link_sent visited", "IdV: doc auth capture_complete visited", "IdV: doc auth link_sent submitted"] let(:happy_hybrid_path_events) do { 'IdV: intro visited' => {}, @@ -339,16 +350,20 @@ success: true, errors: {}, flow_path: 'hybrid', step: 'document_capture', analytics_id: 'Doc Auth', selfie_check_required: boolean, liveness_checking_required: boolean }, 'IdV: doc auth ssn visited' => { - flow_path: 'hybrid', step: 'ssn', analytics_id: 'Doc Auth' + flow_path: 'hybrid', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth ssn submitted' => { - success: true, errors: {}, flow_path: 'hybrid', step: 'ssn', analytics_id: 'Doc Auth' + success: true, errors: {}, flow_path: 'hybrid', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify visited' => { - flow_path: 'hybrid', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'hybrid', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify submitted' => { - flow_path: 'hybrid', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'hybrid', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, idv_threatmetrix_response_body: ( if threatmetrix_response_body.present? @@ -357,10 +372,10 @@ ), 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'hybrid', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', - proofing_results: doc_auth_verify_proofing_results + proofing_results: doc_auth_verify_proofing_results, + proofing_components: base_proofing_components }, 'IdV: phone of record visited' => { - proofing_components: base_proofing_components, }, 'IdV: phone confirmation form' => { @@ -415,6 +430,7 @@ }.compact end + # TODO: Add ["IdV: consent checkbox toggled"] let(:gpo_path_events) do { 'IdV: intro visited' => {}, @@ -453,19 +469,24 @@ success: true, errors: {}, user_id: user.uuid, submit_attempts: 1, remaining_submit_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {}, id_issued_status: 'present', id_expiration_status: 'present' }, 'IdV: doc auth document_capture submitted' => { - success: true, errors: {}, flow_path: 'standard', step: 'document_capture', analytics_id: 'Doc Auth', selfie_check_required: boolean, liveness_checking_required: boolean + success: true, errors: {}, flow_path: 'standard', step: 'document_capture', analytics_id: 'Doc Auth', selfie_check_required: boolean, liveness_checking_required: boolean, + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth ssn visited' => { - flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth ssn submitted' => { - success: true, errors: {}, flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth' + success: true, errors: {}, flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify visited' => { - flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify submitted' => { - flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, idv_threatmetrix_response_body: ( if threatmetrix_response_body.present? @@ -474,7 +495,8 @@ ), 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', - proofing_results: doc_auth_verify_proofing_results + proofing_results: doc_auth_verify_proofing_results, + proofing_components: base_proofing_components }, 'IdV: phone of record visited' => { proofing_components: base_proofing_components, @@ -483,7 +505,9 @@ resend: false, phone_step_attempts: 0, hours_since_first_letter: 0, proofing_components: base_proofing_components }, - 'IdV: request letter visited' => {}, + 'IdV: request letter visited' => { + proofing_components: base_proofing_components, + }, :idv_enter_password_visited => { address_verification_method: 'gpo', proofing_components: gpo_letter_proofing_components, @@ -509,6 +533,7 @@ }.compact end + # TODO: Add ["IdV: consent checkbox toggled", "IdV: doc auth image upload vendor pii validation", "IdV: in person proofing location search submitted", "IdV: phone of record visited"] let(:in_person_path_events) do { 'IdV: doc auth welcome visited' => { @@ -558,28 +583,28 @@ flow_path: 'standard', opted_in_to_in_person_proofing: false }, 'IdV: in person proofing state_id visited' => { - step: 'state_id', flow_path: 'standard', analytics_id: 'In Person Proofing' + step: 'state_id', flow_path: 'standard', analytics_id: 'In Person Proofing', proofing_components: { document_check: 'usps' } }, 'IdV: in person proofing state_id submitted' => { - success: true, flow_path: 'standard', step: 'state_id', analytics_id: 'In Person Proofing', errors: {}, birth_year: '1938', document_zip_code: '12345' + success: true, flow_path: 'standard', step: 'state_id', analytics_id: 'In Person Proofing', errors: {}, birth_year: '1938', document_zip_code: '12345', proofing_components: { document_check: 'usps' } }, 'IdV: in person proofing address visited' => { - step: 'address', flow_path: 'standard', analytics_id: 'In Person Proofing' + step: 'address', flow_path: 'standard', analytics_id: 'In Person Proofing', proofing_components: { document_check: 'usps' } }, 'IdV: in person proofing residential address submitted' => { - success: true, step: 'address', flow_path: 'standard', analytics_id: 'In Person Proofing', errors: {}, current_address_zip_code: '59010' + success: true, step: 'address', flow_path: 'standard', analytics_id: 'In Person Proofing', errors: {}, current_address_zip_code: '59010', proofing_components: { document_check: 'usps' } }, 'IdV: doc auth ssn visited' => { - analytics_id: 'In Person Proofing', step: 'ssn', flow_path: 'standard' + analytics_id: 'In Person Proofing', step: 'ssn', flow_path: 'standard', proofing_components: { document_check: 'usps' } }, 'IdV: doc auth ssn submitted' => { - analytics_id: 'In Person Proofing', success: true, step: 'ssn', flow_path: 'standard', errors: {} + analytics_id: 'In Person Proofing', success: true, step: 'ssn', flow_path: 'standard', errors: {}, proofing_components: { document_check: 'usps' } }, 'IdV: doc auth verify visited' => { - analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard' + analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard', proofing_components: { document_check: 'usps' } }, 'IdV: doc auth verify submitted' => { - analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard' + analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard', proofing_components: { document_check: 'usps' } }, idv_threatmetrix_response_body: ( if threatmetrix_response_body.present? @@ -588,7 +613,8 @@ ), 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'In Person Proofing', step: 'verify', - proofing_results: in_person_path_proofing_results + proofing_results: in_person_path_proofing_results, + proofing_components: { document_check: 'usps', resolution_check: 'lexis_nexis', source_check: 'StateIdMock', threatmetrix: threatmetrix, threatmetrix_review_status: 'pass' } }, 'IdV: phone confirmation form' => { success: true, errors: {}, phone_type: :mobile, types: [:fixed_or_mobile], carrier: 'Test Mobile Carrier', country_code: 'US', area_code: '202', otp_delivery_preference: 'sms', @@ -687,22 +713,27 @@ success: true, errors: {}, user_id: user.uuid, submit_attempts: 1, remaining_submit_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), selfie_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {}, id_issued_status: 'present', id_expiration_status: 'present' }, 'IdV: doc auth document_capture submitted' => { - success: true, errors: {}, flow_path: 'standard', step: 'document_capture', analytics_id: 'Doc Auth', selfie_check_required: boolean, liveness_checking_required: true + success: true, errors: {}, flow_path: 'standard', step: 'document_capture', analytics_id: 'Doc Auth', selfie_check_required: boolean, liveness_checking_required: true, + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, :idv_selfie_image_added => { acuant_version: kind_of(String), captureAttempts: 1, fingerprint: 'aIzxkX_iMtoxFOURZr55qkshs53emQKUOr7VfTf6G1Q', flow_path: 'standard', height: 38, mimeType: 'image/png', size: 3694, source: 'upload', width: 284, liveness_checking_required: boolean, selfie_attempts: 0 }, 'IdV: doc auth ssn visited' => { - flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth ssn submitted' => { - success: true, errors: {}, flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth' + success: true, errors: {}, flow_path: 'standard', step: 'ssn', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify visited' => { - flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, 'IdV: doc auth verify submitted' => { - flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth' + flow_path: 'standard', step: 'verify', analytics_id: 'Doc Auth', + proofing_components: { document_check: 'mock', document_type: 'state_id' } }, idv_threatmetrix_response_body: ( if threatmetrix_response_body.present? @@ -711,10 +742,10 @@ ), 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', - proofing_results: doc_auth_verify_proofing_results + proofing_results: doc_auth_verify_proofing_results, + proofing_components: base_proofing_components }, 'IdV: phone of record visited' => { - proofing_components: base_proofing_components, }, 'IdV: phone confirmation form' => { @@ -826,6 +857,7 @@ let(:proofing_device_profiling) { :disabled } let(:threatmetrix) { false } let(:threatmetrix_response_body) { nil } + let(:threatmetrix_response) do { client: 'tmx_disabled', @@ -906,6 +938,7 @@ let(:proofing_device_profiling) { :disabled } let(:threatmetrix) { false } let(:threatmetrix_response_body) { nil } + let(:threatmetrix_response) do { client: 'tmx_disabled', @@ -932,6 +965,7 @@ context 'GPO path' do before do + fake_analytics.events.clear sign_in_and_2fa_user(user) visit_idp_from_sp_with_ial2(:oidc) complete_welcome_step @@ -946,8 +980,10 @@ end it 'records all of the events' do - gpo_path_events.each do |event, attributes| - expect(fake_analytics).to have_logged_event(event, attributes) + aggregate_failures 'analytics_events' do + gpo_path_events.each do |event, attributes| + expect(fake_analytics).to have_logged_event(event, attributes) + end end end @@ -955,6 +991,7 @@ let(:proofing_device_profiling) { :disabled } let(:threatmetrix) { false } let(:threatmetrix_response_body) { nil } + let(:threatmetrix_response) do { client: 'tmx_disabled', @@ -970,8 +1007,10 @@ end it 'records all of the events' do - gpo_path_events.each do |event, attributes| - expect(fake_analytics).to have_logged_event(event, attributes) + aggregate_failures 'analytics events' do + gpo_path_events.each do |event, attributes| + expect(fake_analytics).to have_logged_event(event, attributes) + end end end end @@ -1018,6 +1057,7 @@ let(:proofing_device_profiling) { :disabled } let(:threatmetrix) { false } let(:threatmetrix_response_body) { nil } + let(:threatmetrix_response) do { client: 'tmx_disabled', @@ -1077,6 +1117,7 @@ let(:proofing_device_profiling) { :disabled } let(:threatmetrix) { false } let(:threatmetrix_response_body) { nil } + let(:threatmetrix_response) do { client: 'tmx_disabled', @@ -1158,6 +1199,7 @@ let(:proofing_device_profiling) { :disabled } let(:threatmetrix) { false } let(:threatmetrix_response_body) { nil } + let(:threatmetrix_response) do { client: 'tmx_disabled', @@ -1221,6 +1263,7 @@ let(:idv_level) { 'legacy_in_person' } let(:threatmetrix) { false } let(:threatmetrix_response_body) { nil } + let(:threatmetrix_response) do { client: 'tmx_disabled', diff --git a/spec/features/idv/cancel_spec.rb b/spec/features/idv/cancel_spec.rb index 08a51076df3..11c8995e553 100644 --- a/spec/features/idv/cancel_spec.rb +++ b/spec/features/idv/cancel_spec.rb @@ -26,7 +26,7 @@ click_link t('links.cancel') expect(page).to have_content(t('idv.cancel.headings.prompt.standard')) - expect(current_path).to eq(idv_cancel_path) + expect(page).to have_current_path(idv_cancel_path, ignore_query: true) expect(fake_analytics).to have_logged_event( 'IdV: cancellation visited', hash_including(step: 'agreement'), @@ -40,7 +40,7 @@ click_on(t('idv.cancel.actions.keep_going')) - expect(current_path).to eq(original_path) + expect(page).to have_current_path(original_path) expect(fake_analytics).to have_logged_event( 'IdV: cancellation go back', hash_including(step: 'agreement'), @@ -51,7 +51,7 @@ click_link t('links.cancel') expect(page).to have_content(t('idv.cancel.headings.prompt.standard')) - expect(current_path).to eq(idv_cancel_path) + expect(page).to have_current_path(idv_cancel_path, ignore_query: true) expect(fake_analytics).to have_logged_event( 'IdV: cancellation visited', hash_including(step: 'agreement'), @@ -65,7 +65,7 @@ click_on t('idv.cancel.actions.start_over') - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) expect(fake_analytics).to have_logged_event( 'IdV: start over', hash_including(step: 'agreement'), @@ -76,7 +76,7 @@ click_link t('links.cancel') expect(page).to have_content(t('idv.cancel.headings.prompt.standard')) - expect(current_path).to eq(idv_cancel_path) + expect(page).to have_current_path(idv_cancel_path, ignore_query: true) expect(fake_analytics).to have_logged_event( 'IdV: cancellation visited', hash_including(step: 'agreement'), @@ -90,7 +90,7 @@ click_spinner_button_and_wait t('idv.cancel.actions.account_page') - expect(current_path).to eq(account_path) + expect(page).to have_current_path(account_path) expect(fake_analytics).to have_logged_event( 'IdV: cancellation confirmed', hash_including(step: 'agreement'), @@ -98,7 +98,7 @@ # After visiting /verify, expect to redirect to the first step in the IdV flow. visit idv_path - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) end context 'when user has recorded proofing components' do @@ -173,7 +173,7 @@ click_link t('links.cancel') expect(page).to have_content(t('idv.cancel.headings.prompt.standard')) - expect(current_path).to eq(idv_cancel_path) + expect(page).to have_current_path(idv_cancel_path, ignore_query: true) expect(fake_analytics).to have_logged_event( 'IdV: cancellation visited', hash_including(step: 'agreement'), @@ -187,6 +187,11 @@ click_spinner_button_and_wait t('idv.cancel.actions.exit', app_name: APP_NAME) + expect(page).to have_current_path( + 'http://localhost:7654/auth/result', + url: true, + ignore_query: true, + ) expect(current_url).to start_with('http://localhost:7654/auth/result?error=access_denied') expect(fake_analytics).to have_logged_event( 'IdV: cancellation confirmed', @@ -194,7 +199,7 @@ ) start_idv_from_sp(sp) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) end end end diff --git a/spec/features/idv/confirm_start_over_spec.rb b/spec/features/idv/confirm_start_over_spec.rb index 742086d6dd0..0f10fc6b912 100644 --- a/spec/features/idv/confirm_start_over_spec.rb +++ b/spec/features/idv/confirm_start_over_spec.rb @@ -34,13 +34,13 @@ complete_idv_steps_before_gpo_step click_on t('idv.messages.gpo.start_over_link_text') - expect(current_path).to eq idv_confirm_start_over_before_letter_path + expect(page).to have_current_path idv_confirm_start_over_before_letter_path expect(page).to have_content(t('idv.cancel.description.gpo.start_over_new_address')) expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_phone')) expect(fake_analytics).to have_logged_event(:idv_gpo_confirm_start_over_before_letter_visited) click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end end @@ -50,19 +50,19 @@ end it 'can cancel from confirmation screen' do - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path click_on t('idv.gpo.address_accordion.title') click_on t('idv.gpo.address_accordion.cta_link') - expect(current_path).to eq idv_confirm_start_over_path + expect(page).to have_current_path idv_confirm_start_over_path expect(page).to have_content(t('idv.cancel.description.gpo.start_over')) expect_step_indicator_current_step(t('step_indicator.flows.idv.verify_address')) expect(fake_analytics).to have_logged_event('IdV: gpo confirm start over visited') click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end it 'can return back to verify screen from confirm screen' do @@ -71,7 +71,7 @@ click_on t('forms.buttons.back') expect(fake_analytics).to have_logged_event('IdV: gpo confirm start over visited') - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path end end end diff --git a/spec/features/idv/doc_auth/hybrid_handoff_spec.rb b/spec/features/idv/doc_auth/hybrid_handoff_spec.rb index 7621a89b627..29b3865b839 100644 --- a/spec/features/idv/doc_auth/hybrid_handoff_spec.rb +++ b/spec/features/idv/doc_auth/hybrid_handoff_spec.rb @@ -60,7 +60,7 @@ fill_in :doc_auth_phone, with: '' click_send_link - expect(page).to have_current_path(idv_hybrid_handoff_path, ignore_query: true) + expect(page).to have_current_path(idv_hybrid_handoff_path) end it 'sends a link that does not contain any underscores' do @@ -82,7 +82,7 @@ click_send_link - expect(page).to have_current_path(idv_hybrid_handoff_path, ignore_query: true) + expect(page).to have_current_path(idv_hybrid_handoff_path) expect(page).to have_content I18n.t('telephony.error.friendly_message.generic') end @@ -136,7 +136,7 @@ fill_in :doc_auth_phone, with: '415-555-0199' click_send_link - expect(page).to have_current_path(idv_hybrid_handoff_path, ignore_query: true) + expect(page).to have_current_path(idv_hybrid_handoff_path) expect(page).to have_content( I18n.t( 'doc_auth.errors.send_link_limited', @@ -308,7 +308,7 @@ def verify_upload_photos_section_and_link(page) click_link t('links.cancel') expect(page).to have_content(t('idv.cancel.headings.prompt.standard')) - expect(current_path).to eq(idv_cancel_path) + expect(page).to have_current_path(idv_cancel_path, ignore_query: true) end def verify_no_upload_photos_section_and_link(page) diff --git a/spec/features/idv/doc_auth/socure_document_capture_spec.rb b/spec/features/idv/doc_auth/socure_document_capture_spec.rb index 490f97ecc3d..480299b7a83 100644 --- a/spec/features/idv/doc_auth/socure_document_capture_spec.rb +++ b/spec/features/idv/doc_auth/socure_document_capture_spec.rb @@ -12,6 +12,7 @@ let(:fake_socure_docv_document_request_endpoint) { 'https://fake-socure.test/document-request' } let(:fake_socure_document_capture_app_url) { 'https://verify.fake-socure.test/something' } let(:socure_docv_verification_data_test_mode) { false } + let(:socure_docv_webhook_repeat_endpoints) { [] } before(:each) do allow(IdentityConfig.store).to receive(:socure_docv_enabled).and_return(true) @@ -22,11 +23,15 @@ .and_return(socure_docv_webhook_secret_key) allow(IdentityConfig.store).to receive(:socure_docv_document_request_endpoint) .and_return(fake_socure_docv_document_request_endpoint) + allow(IdentityConfig.store).to receive(:socure_docv_webhook_repeat_endpoints) + .and_return(socure_docv_webhook_repeat_endpoints) + socure_docv_webhook_repeat_endpoints.each { |endpoint| stub_request(:post, endpoint) } allow(IdentityConfig.store).to receive(:ruby_workers_idv_enabled).and_return(false) allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics) @docv_transaction_token = stub_docv_document_request allow(IdentityConfig.store).to receive(:socure_docv_verification_data_test_mode) .and_return(socure_docv_verification_data_test_mode) + allow(IdentityConfig.store).to receive(:doc_auth_max_attempts).and_return(max_attempts) end context 'happy path', allow_browser_log: true do @@ -43,14 +48,23 @@ end context 'rate limits calls to backend docauth vendor', allow_browser_log: true do + let(:socure_docv_webhook_repeat_endpoints) do # repeat webhooks + ['https://1.example.test/thepath', 'https://2.example.test/thepath'] + end + before do - allow(IdentityConfig.store).to receive(:doc_auth_max_attempts).and_return(max_attempts) + expect(SocureDocvRepeatWebhookJob).to receive(:perform_later) + .exactly(6 * max_attempts * socure_docv_webhook_repeat_endpoints.length) + .times.and_call_original (max_attempts - 1).times do socure_docv_upload_documents(docv_transaction_token: @docv_transaction_token) end end it 'redirects to the rate limited error page' do + # recovers when fails to repeat webhook to an endpoint + allow_any_instance_of(DocAuth::Socure::WebhookRepeater) + .to receive(:send_http_post_request).and_raise('doh') expect(page).to have_current_path(fake_socure_document_capture_app_url) visit idv_socure_document_capture_path expect(page).to have_current_path(idv_socure_document_capture_path) @@ -91,8 +105,42 @@ end end + context 'shows the correct attempts on error pages' do + before do + stub_docv_verification_data_fail_with( + docv_transaction_token: @docv_transaction_token, + errors: ['XXXX'], + ) + end + + it 'remaining attempts displayed is properly decremented' do + socure_docv_upload_documents( + docv_transaction_token: @docv_transaction_token, + ) + visit idv_socure_document_capture_update_path + expect(page).to have_content( + strip_tags( + t( + 'doc_auth.rate_limit_warning.plural_html', + remaining_attempts: max_attempts - 1, + ), + ), + ) + + visit idv_socure_document_capture_path + socure_docv_upload_documents( + docv_transaction_token: @docv_transaction_token, + ) + visit idv_socure_document_capture_update_path + expect(page).to have_content(strip_tags(t('doc_auth.rate_limit_warning.singular_html'))) + end + end + context 'reuses valid capture app urls when appropriate', allow_browser_log: true do context 'successfully erases capture app url when flow is complete' do + before do + expect(DocAuth::Socure::WebhookRepeater).not_to receive(:new) + end it 'proceeds to the next page with valid info' do document_capture_session = DocumentCaptureSession.find_by(user_id: @user.id) expect(document_capture_session.socure_docv_capture_app_url) @@ -199,7 +247,7 @@ expect(DocAuthLog.find_by(user_id: @user.id).state).to be_nil end - xit 'does track state if state tracking is disabled' do + it 'does track state if state tracking is enabled' do allow(IdentityConfig.store).to receive(:state_tracking_enabled).and_return(true) socure_docv_upload_documents( docv_transaction_token: @docv_transaction_token, @@ -263,7 +311,14 @@ end context 'standard mobile flow' do + let(:socure_docv_webhook_repeat_endpoints) do # repeat webhooks + ['https://1.example.test/thepath', 'https://2.example.test/thepath'] + end + it 'proceeds to the next page with valid info' do + expect(SocureDocvRepeatWebhookJob).to receive(:perform_later) + .exactly(6 * socure_docv_webhook_repeat_endpoints.length).times.and_call_original + perform_in_browser(:mobile) do visit_idp_from_oidc_sp_with_ial2 @user = sign_in_and_2fa_user diff --git a/spec/features/idv/end_to_end_idv_spec.rb b/spec/features/idv/end_to_end_idv_spec.rb index eef9d8baadd..40717b18abb 100644 --- a/spec/features/idv/end_to_end_idv_spec.rb +++ b/spec/features/idv/end_to_end_idv_spec.rb @@ -58,25 +58,32 @@ user = sign_up_and_2fa_ial1_user complete_welcome_step + expect(page).to have_current_path(idv_agreement_path) test_go_back_from_agreement complete_agreement_step + expect(page).to have_current_path(idv_hybrid_handoff_path) test_go_back_from_hybrid_handoff complete_hybrid_handoff_step # upload photos + expect(page).to have_current_path(idv_document_capture_path) test_go_back_from_document_capture complete_document_capture_step + expect(page).to have_current_path(idv_ssn_path) test_go_back_from_ssn_page complete_ssn_step + expect(page).to have_current_path(idv_verify_info_path) test_go_back_from_verify_info complete_verify_step + expect(page).to have_current_path(idv_phone_path) test_go_back_from_phone complete_otp_verification_page(user) + expect(page).to have_current_path(idv_enter_password_path) test_go_back_from_enter_password complete_enter_password_step(user) @@ -93,6 +100,7 @@ complete_all_doc_auth_steps enter_gpo_flow + expect(page).to have_current_path(idv_request_letter_path) test_go_back_from_request_letter complete_request_letter complete_enter_password_step(user) @@ -350,12 +358,12 @@ def validate_letter_enqueued_page end def validate_personal_key_page - expect(current_path).to eq idv_personal_key_path + expect(page).to have_current_path idv_personal_key_path # Clicking acknowledge checkbox is required to continue click_continue expect(page).to have_content(t('forms.validation.required_checkbox')) - expect(current_path).to eq(idv_personal_key_path) + expect(page).to have_current_path(idv_personal_key_path) expect(page).to have_content(t('forms.personal_key_partial.acknowledgement.header')) expect(page).to have_content(t('forms.personal_key_partial.acknowledgement.text')) @@ -379,7 +387,7 @@ def validate_personal_key_page def try_to_skip_ahead_before_signing_in visit idv_enter_password_path - expect(current_path).to eq(root_path) + expect(page).to have_current_path(root_path) end def try_to_skip_ahead_from_welcome @@ -418,9 +426,9 @@ def visit_by_mail_and_return def test_go_back_from_agreement go_back - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) complete_welcome_step - expect(current_path).to eq(idv_agreement_path) + expect(page).to have_current_path(idv_agreement_path) expect(page).not_to have_checked_field( t('doc_auth.instructions.consent', app_name: APP_NAME), visible: :all, @@ -435,7 +443,7 @@ def test_go_back_from_hybrid_handoff visible: :all, ) visit idv_welcome_path - expect(current_path).to eql(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) complete_welcome_step expect(page).to have_current_path(idv_agreement_path) expect(page).not_to have_checked_field( @@ -447,6 +455,7 @@ def test_go_back_from_hybrid_handoff def test_go_back_from_document_capture go_back + expect(page).to have_current_path(idv_hybrid_handoff_path) go_back expect(page).to have_current_path(idv_agreement_path) expect(page).to have_checked_field( diff --git a/spec/features/idv/get_proofing_results_job_scenarios_spec.rb b/spec/features/idv/get_proofing_results_job_scenarios_spec.rb index 610e08c0614..5b8dd20a4c5 100644 --- a/spec/features/idv/get_proofing_results_job_scenarios_spec.rb +++ b/spec/features/idv/get_proofing_results_job_scenarios_spec.rb @@ -50,7 +50,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "cancelled" expect(@user.in_person_enrollments.first).to have_attributes( status: 'cancelled', @@ -85,7 +85,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "cancelled" expect(@user.in_person_enrollments.first).to have_attributes( status: 'cancelled', @@ -129,7 +129,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "cancelled" expect(@user.in_person_enrollments.first).to have_attributes( status: 'cancelled', @@ -164,7 +164,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "cancelled" expect(@user.in_person_enrollments.first).to have_attributes( status: 'cancelled', @@ -225,7 +225,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "passed" expect(@user.in_person_enrollments.first).to have_attributes( status: 'passed', @@ -286,7 +286,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "failed|cancelled|expired" expect(@user.in_person_enrollments.first).to have_attributes( status: status, @@ -346,13 +346,13 @@ # When the user logs in login(@user, @new_password) # Then the user is taken to the /account/reactivate/start page - expect(current_path).to eq(reactivate_account_path) + expect(page).to have_current_path(reactivate_account_path) # When the user attempts to reactivate account without their personal key account_reactivation_with_personal_key(@user, @new_password) # Then the user is taken to the /sign_up/completed page - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) # And the user has an InPersonEnrollment with status "passed" expect(@user.in_person_enrollments.first).to have_attributes( status: 'passed', @@ -411,13 +411,13 @@ # When the user logs in login(@user, @new_password) # Then the user is taken to the /account/reactivate/start page - expect(current_path).to eq(reactivate_account_path) + expect(page).to have_current_path(reactivate_account_path) # When the user attempts to reactivate account without their personal key account_reactivation_without_personal_key # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "passed" expect(@user.in_person_enrollments.first).to have_attributes( status: 'passed', @@ -478,7 +478,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "failed|cancelled|expired" expect(@user.in_person_enrollments.first).to have_attributes( status: status, @@ -536,7 +536,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "cancelled" expect(@user.in_person_enrollments.first).to have_attributes( status: 'cancelled', @@ -577,7 +577,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "cancelled" expect(@user.in_person_enrollments.first).to have_attributes( status: 'cancelled', @@ -656,7 +656,7 @@ login(@user, @new_password) # Then the user is taken to the /verify/welcome page - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) # And the user has an InPersonEnrollment with status "passed" expect(@user.in_person_enrollments.first).to have_attributes( status: 'passed', diff --git a/spec/features/idv/hybrid_mobile/hybrid_mobile_spec.rb b/spec/features/idv/hybrid_mobile/hybrid_mobile_spec.rb index fe21fec28d4..c948d6e9dbf 100644 --- a/spec/features/idv/hybrid_mobile/hybrid_mobile_spec.rb +++ b/spec/features/idv/hybrid_mobile/hybrid_mobile_spec.rb @@ -329,7 +329,7 @@ warning_link_text = t('doc_auth.headings.capture_scan_warning_link') click_link warning_link_text - expect(current_path).to eq(idv_hybrid_handoff_path) + expect(page).to have_current_path(idv_hybrid_handoff_path, ignore_query: true) clear_and_fill_in(:doc_auth_phone, phone_number) click_send_link end @@ -387,7 +387,7 @@ warning_link_text = t('doc_auth.headings.capture_scan_warning_link') click_link warning_link_text - expect(current_path).to eq(idv_hybrid_handoff_path) + expect(page).to have_current_path(idv_hybrid_handoff_path, ignore_query: true) clear_and_fill_in(:doc_auth_phone, phone_number) click_send_link end diff --git a/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb b/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb index f96d46d215c..6b61c0887a8 100644 --- a/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb +++ b/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb @@ -11,6 +11,7 @@ let(:fake_socure_docv_document_request_endpoint) { 'https://fake-socure.test/document-request' } let(:socure_docv_verification_data_test_mode) { false } let(:fake_analytics) { FakeAnalytics.new } + let(:socure_docv_webhook_repeat_endpoints) { [] } before do allow(FeatureManagement).to receive(:doc_capture_polling_enabled?).and_return(true) @@ -21,6 +22,9 @@ allow(IdentityConfig.store).to receive(:ruby_workers_idv_enabled).and_return(false) allow(IdentityConfig.store).to receive(:socure_docv_document_request_endpoint) .and_return(fake_socure_docv_document_request_endpoint) + allow(IdentityConfig.store).to receive(:socure_docv_webhook_repeat_endpoints) + .and_return(socure_docv_webhook_repeat_endpoints) + socure_docv_webhook_repeat_endpoints.each { |endpoint| stub_request(:post, endpoint) } allow(Telephony).to receive(:send_doc_auth_link).and_wrap_original do |impl, config| @sms_link = config[:link] impl.call(**config) @@ -36,6 +40,7 @@ @pass_stub = stub_docv_verification_data_pass(docv_transaction_token: @docv_transaction_token) end it 'proofs and hands off to mobile', js: true do + expect(SocureDocvRepeatWebhookJob).not_to receive(:perform_later) user = nil perform_in_browser(:desktop) do @@ -133,6 +138,7 @@ end it 'shows the waiting screen correctly after cancelling from mobile and restarting', js: true do + expect(SocureDocvRepeatWebhookJob).not_to receive(:perform_later) user = nil perform_in_browser(:desktop) do @@ -165,9 +171,11 @@ context 'user is rate limited on mobile' do let(:max_attempts) { IdentityConfig.store.doc_auth_max_attempts } + let(:socure_docv_webhook_repeat_endpoints) do # repeat webhooks + ['https://1.example.test/thepath', 'https://2.example.test/thepath'] + end before do - allow(IdentityConfig.store).to receive(:doc_auth_max_attempts).and_return(max_attempts) DocAuth::Mock::DocAuthMockClient.mock_response!( method: :post_front_image, response: DocAuth::Response.new( @@ -178,6 +186,10 @@ end it 'shows capture complete on mobile and error page on desktop', js: true do + expect(SocureDocvRepeatWebhookJob).to receive(:perform_later) + .exactly(6 * max_attempts * socure_docv_webhook_repeat_endpoints.length) + .times.and_call_original + user = nil perform_in_browser(:desktop) do @@ -212,49 +224,65 @@ end end - it 'prefills the phone number used on the phone step if the user has no MFA phone', :js do - user = create(:user, :with_authentication_app) - - perform_in_browser(:desktop) do - start_idv_from_sp(facial_match_required: false) - sign_in_and_2fa_user(user) + context 'if the user has no MFA phone' do + let(:socure_docv_webhook_repeat_endpoints) do # repeat webhooks + ['https://1.example.test/thepath', 'https://2.example.test/thepath'] + end - complete_doc_auth_steps_before_hybrid_handoff_step - clear_and_fill_in(:doc_auth_phone, phone_number) - click_send_link + before do + # recovers when fails to repeat webhook to an endpoint + allow_any_instance_of(DocAuth::Socure::WebhookRepeater) + .to receive(:send_http_post_request).and_raise('doh') end - expect(@sms_link).to be_present + it 'prefills the phone number used on the phone step', :js do + expect(SocureDocvRepeatWebhookJob).to receive(:perform_later) + .exactly(6 * socure_docv_webhook_repeat_endpoints.length) + .times.and_call_original - perform_in_browser(:mobile) do - visit @sms_link + user = create(:user, :with_authentication_app) - expect(page).to have_current_path(idv_hybrid_mobile_socure_document_capture_url) - click_idv_continue - expect(page).to have_current_path(fake_socure_document_capture_app_url) - socure_docv_upload_documents(docv_transaction_token: @docv_transaction_token) - visit idv_hybrid_mobile_socure_document_capture_update_url + perform_in_browser(:desktop) do + start_idv_from_sp(facial_match_required: false) + sign_in_and_2fa_user(user) - expect(page).to have_current_path(idv_hybrid_mobile_capture_complete_url) - expect(page).to have_text(t('doc_auth.instructions.switch_back')) - end + complete_doc_auth_steps_before_hybrid_handoff_step + clear_and_fill_in(:doc_auth_phone, phone_number) + click_send_link + end - perform_in_browser(:desktop) do - expect(page).to have_current_path(idv_ssn_path, wait: 10) + expect(@sms_link).to be_present - fill_out_ssn_form_ok - click_idv_continue + perform_in_browser(:mobile) do + visit @sms_link - expect(page).to have_content(t('headings.verify')) - complete_verify_step + expect(page).to have_current_path(idv_hybrid_mobile_socure_document_capture_url) + click_idv_continue + expect(page).to have_current_path(fake_socure_document_capture_app_url) + socure_docv_upload_documents(docv_transaction_token: @docv_transaction_token) + visit idv_hybrid_mobile_socure_document_capture_update_url - prefilled_phone = page.find(id: 'idv_phone_form_phone').value + expect(page).to have_current_path(idv_hybrid_mobile_capture_complete_url) + expect(page).to have_text(t('doc_auth.instructions.switch_back')) + end - expect( - PhoneFormatter.format(prefilled_phone), - ).to eq( - PhoneFormatter.format(phone_number), - ) + perform_in_browser(:desktop) do + expect(page).to have_current_path(idv_ssn_path, wait: 10) + + fill_out_ssn_form_ok + click_idv_continue + + expect(page).to have_content(t('headings.verify')) + complete_verify_step + + prefilled_phone = page.find(id: 'idv_phone_form_phone').value + + expect( + PhoneFormatter.format(prefilled_phone), + ).to eq( + PhoneFormatter.format(phone_number), + ) + end end end @@ -303,8 +331,20 @@ context 'when an invalid test token is used' do let(:invalid_token) { 'invalid-token' } + let(:socure_docv_webhook_repeat_endpoints) do # repeat webhooks + ['https://1.example.test/thepath', 'https://2.example.test/thepath'] + end + + before do + # recovers when fails to repeat webhook + allow_any_instance_of(DocAuth::Socure::WebhookRepeater) + .to receive(:send_http_post_request).and_raise('doh') + end it 'waits to fetch verificationdata using docv capture session token', js: true do + expect(SocureDocvRepeatWebhookJob).to receive(:perform_later) + .exactly(6 * socure_docv_webhook_repeat_endpoints.length).times.and_call_original + user = nil perform_in_browser(:desktop) do diff --git a/spec/features/idv/outage_spec.rb b/spec/features/idv/outage_spec.rb index 918382a504b..b6e71a21aff 100644 --- a/spec/features/idv/outage_spec.rb +++ b/spec/features/idv/outage_spec.rb @@ -68,24 +68,24 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) it 'takes the user through the mail only flow, allowing hybrid', js: true do sign_in_with_idv_required(user: user) - expect(current_path).to eq idv_mail_only_warning_path + expect(page).to have_current_path idv_mail_only_warning_path click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path complete_welcome_step complete_agreement_step # Still offer the option for hybrid flow - expect(current_path).to eq idv_hybrid_handoff_path + expect(page).to have_current_path idv_hybrid_handoff_path complete_hybrid_handoff_step complete_document_capture_step complete_ssn_step complete_verify_step - expect(current_path).to eq idv_request_letter_path + expect(page).to have_current_path idv_request_letter_path end end @@ -95,13 +95,13 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) it 'shows mail only warning page before idv welcome page', js: true do sign_in_with_idv_required(user: user) - expect(current_path).to eq idv_mail_only_warning_path + expect(page).to have_current_path idv_mail_only_warning_path complete_doc_auth_steps_before_document_capture_step click_on t('links.cancel') click_on t('idv.cancel.actions.start_over') - expect(current_path).to eq idv_mail_only_warning_path + expect(page).to have_current_path idv_mail_only_warning_path end end @@ -111,11 +111,11 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user) - expect(current_path).to eq idv_mail_only_warning_path + expect(page).to have_current_path idv_mail_only_warning_path click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end end @@ -126,7 +126,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user) - expect(current_path).to eq vendor_outage_path + expect(page).to have_current_path vendor_outage_path end end @@ -140,11 +140,11 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user, sms_or_totp: :totp) - expect(current_path).to eq idv_mail_only_warning_path + expect(page).to have_current_path idv_mail_only_warning_path click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end it 'returns to the correct page when clicking to exit' do @@ -161,7 +161,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) click_idv_continue complete_agreement_step - expect(current_path).to eq idv_document_capture_path + expect(page).to have_current_path idv_document_capture_path end end end @@ -174,11 +174,11 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) it 'shows mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user, sms_or_totp: :sms) - expect(current_path).to eq idv_mail_only_warning_path + expect(page).to have_current_path idv_mail_only_warning_path click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end it 'still allows the hybrid handoff screen' do @@ -187,7 +187,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) click_idv_continue complete_agreement_step - expect(current_path).to eq idv_hybrid_handoff_path + expect(page).to have_current_path idv_hybrid_handoff_path end end @@ -198,7 +198,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) it 'does not show the mail only warning page before idv welcome page' do sign_in_with_idv_required(user: user, sms_or_totp: :sms) - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end it 'does not show the hybrid handoff screen' do @@ -207,7 +207,7 @@ def sign_in_with_idv_required(user:, sms_or_totp: :sms) click_idv_continue complete_agreement_step - expect(current_path).to eq idv_document_capture_path + expect(page).to have_current_path idv_document_capture_path end end diff --git a/spec/features/idv/pending_profile_password_reset_spec.rb b/spec/features/idv/pending_profile_password_reset_spec.rb index fcbe3c719f1..e05499d4111 100644 --- a/spec/features/idv/pending_profile_password_reset_spec.rb +++ b/spec/features/idv/pending_profile_password_reset_spec.rb @@ -26,7 +26,7 @@ sign_in_live_with_2fa(user) expect(page).to have_content t('doc_auth.headings.welcome', sp_name: sp_name) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) expect(user.reload.active_or_pending_profile).to be_nil end @@ -50,7 +50,7 @@ sign_in_live_with_2fa(user) expect(page).to have_content(t('doc_auth.headings.welcome', sp_name: sp_name)) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) expect(user.reload.active_or_pending_profile).to be_nil end @@ -72,7 +72,7 @@ sign_in_live_with_2fa(user) expect(page).to have_content(t('doc_auth.headings.welcome', sp_name: sp_name)) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) expect(user.reload.active_or_pending_profile).to be_nil end diff --git a/spec/features/idv/phone_errors_spec.rb b/spec/features/idv/phone_errors_spec.rb index 6313e740354..d713eff8290 100644 --- a/spec/features/idv/phone_errors_spec.rb +++ b/spec/features/idv/phone_errors_spec.rb @@ -25,37 +25,37 @@ def verify_phone_submitted(phone_errors_url, phone_errors_path) visit(phone_errors_url) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) complete_welcome_step visit(phone_errors_url) - expect(current_path).to eq(idv_agreement_path) + expect(page).to have_current_path(idv_agreement_path) complete_agreement_step visit(phone_errors_url) - expect(current_path).to eq(idv_hybrid_handoff_path) + expect(page).to have_current_path(idv_hybrid_handoff_path) complete_hybrid_handoff_step # upload photos visit(phone_errors_url) - expect(current_path).to eq(idv_document_capture_path) + expect(page).to have_current_path(idv_document_capture_path) complete_document_capture_step visit(phone_errors_url) - expect(current_path).to eq(idv_ssn_path) + expect(page).to have_current_path(idv_ssn_path) complete_ssn_step visit(phone_errors_url) - expect(current_path).to eq(idv_verify_info_path) + expect(page).to have_current_path(idv_verify_info_path) complete_verify_step visit(phone_errors_url) - expect(current_path).to eq(idv_phone_path) + expect(page).to have_current_path(idv_phone_path) fill_out_phone_form_fail click_idv_send_security_code - expect(current_path).to eq(idv_phone_errors_warning_path) + expect(page).to have_current_path(idv_phone_errors_warning_path) visit(phone_errors_url) - expect(current_path).to eq(phone_errors_path) + expect(page).to have_current_path(phone_errors_path) end end diff --git a/spec/features/idv/phone_otp_rate_limiting_spec.rb b/spec/features/idv/phone_otp_rate_limiting_spec.rb index 35d9426b8ef..c19295ac705 100644 --- a/spec/features/idv/phone_otp_rate_limiting_spec.rb +++ b/spec/features/idv/phone_otp_rate_limiting_spec.rb @@ -78,7 +78,7 @@ def expect_rate_limit_to_expire(user) click_submit_default expect(page).to have_content(t('idv.titles.session.enter_password', app_name: APP_NAME)) - expect(current_path).to eq(idv_enter_password_path) + expect(page).to have_current_path(idv_enter_password_path) end end end diff --git a/spec/features/idv/proof_address_rate_limit_spec.rb b/spec/features/idv/proof_address_rate_limit_spec.rb index f1605506b0e..1a144cbd441 100644 --- a/spec/features/idv/proof_address_rate_limit_spec.rb +++ b/spec/features/idv/proof_address_rate_limit_spec.rb @@ -12,11 +12,11 @@ start_idv_from_sp complete_idv_steps_before_phone_step(user) - expect(current_path).to eq(idv_phone_errors_failure_path) + expect(page).to have_current_path(idv_phone_errors_failure_path) # Cancel is available click_on 'Cancel' - expect(current_path).to eq(idv_cancel_path) + expect(page).to have_current_path(idv_cancel_path, ignore_query: true) click_on(t('idv.cancel.actions.keep_going')) # Can continue with Verify by mail @@ -24,7 +24,7 @@ click_on t('idv.buttons.mail.send') expect(page).to have_content(t('idv.titles.session.enter_password', app_name: APP_NAME)) - expect(current_path).to eq(idv_enter_password_path) + expect(page).to have_current_path(idv_enter_password_path) fill_in 'Password', with: user.password click_idv_continue expect(page).to have_current_path(idv_letter_enqueued_path) @@ -52,12 +52,12 @@ click_idv_send_security_code # There should be no option to verify by mail on the warning page - expect(current_path).to eq(idv_phone_errors_warning_path) + expect(page).to have_current_path(idv_phone_errors_warning_path) expect(page).to_not have_content(t('idv.failure.phone.warning.gpo.button')) # Visiting the letter request URL should redirect to phone visit idv_request_letter_path - expect(current_path).to eq(idv_phone_path) + expect(page).to have_current_path(idv_phone_path) fill_out_phone_form_ok click_idv_send_security_code @@ -65,10 +65,10 @@ click_submit_default expect(page).to have_content(t('idv.titles.session.enter_password', app_name: APP_NAME)) - expect(current_path).to eq(idv_enter_password_path) + expect(page).to have_current_path(idv_enter_password_path) fill_in 'Password', with: user.password click_idv_continue - expect(current_path).to eq(idv_personal_key_path) + expect(page).to have_current_path(idv_personal_key_path) expect(user.reload.active_profile.present?).to eq(true) end end @@ -87,12 +87,12 @@ start_idv_from_sp sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_phone_errors_failure_path) + expect(page).to have_current_path(idv_phone_errors_failure_path) expect(page).to_not have_content(t('idv.failure.phone.warning.gpo.button')) # Visiting the letter request URL should redirect to phone failure visit idv_request_letter_path - expect(current_path).to eq(idv_phone_errors_failure_path) + expect(page).to have_current_path(idv_phone_errors_failure_path) end end end diff --git a/spec/features/idv/proofing_components_spec.rb b/spec/features/idv/proofing_components_spec.rb index 70268b77ed1..63d4f16c426 100644 --- a/spec/features/idv/proofing_components_spec.rb +++ b/spec/features/idv/proofing_components_spec.rb @@ -16,7 +16,7 @@ visit_idp_from_sp_with_ial2(:oidc) register_user(email) - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path complete_all_doc_auth_steps_before_password_step fill_in 'Password', with: Features::SessionHelper::VALID_PASSWORD diff --git a/spec/features/idv/puerto_rican_address_spec.rb b/spec/features/idv/puerto_rican_address_spec.rb index 8bb24149a5b..ecc50c1eb0e 100644 --- a/spec/features/idv/puerto_rican_address_spec.rb +++ b/spec/features/idv/puerto_rican_address_spec.rb @@ -14,12 +14,12 @@ complete_ssn_step expect(page).to have_content(t('doc_auth.headings.address')) - expect(current_path).to eq(idv_address_path) + expect(page).to have_current_path(idv_address_path) click_button t('forms.buttons.submit.update') expect(page).to have_content(t('headings.verify')) - expect(current_path).to eq(idv_verify_info_path) + expect(page).to have_current_path(idv_verify_info_path) end it 'does not redirect to the user to the address step after they update their SSN' do @@ -27,7 +27,7 @@ click_button t('forms.buttons.submit.update') expect(page).to have_content(t('headings.verify')) - expect(current_path).to eq(idv_verify_info_path) + expect(page).to have_current_path(idv_verify_info_path) click_link t('idv.buttons.change_ssn_label') diff --git a/spec/features/idv/sp_follow_up_spec.rb b/spec/features/idv/sp_follow_up_spec.rb index a6e9f39b3bc..ec3512f9f14 100644 --- a/spec/features/idv/sp_follow_up_spec.rb +++ b/spec/features/idv/sp_follow_up_spec.rb @@ -18,7 +18,7 @@ sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_verify_by_mail_enter_code_path) + expect(page).to have_current_path(idv_verify_by_mail_enter_code_path) fill_in t('idv.gpo.form.otp_label'), with: otp click_button t('idv.gpo.form.submit') @@ -63,13 +63,13 @@ sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_verify_by_mail_enter_code_path) + expect(page).to have_current_path(idv_verify_by_mail_enter_code_path) fill_in t('idv.gpo.form.otp_label'), with: otp click_button t('idv.gpo.form.submit') acknowledge_and_confirm_personal_key - expect(current_path).to eq(idv_sp_follow_up_path) + expect(page).to have_current_path(idv_sp_follow_up_path) click_on t('idv.by_mail.sp_follow_up.connect_account') expect(current_url).to eq(post_idv_follow_up_url) @@ -91,13 +91,13 @@ sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_verify_by_mail_enter_code_path) + expect(page).to have_current_path(idv_verify_by_mail_enter_code_path) fill_in t('idv.gpo.form.otp_label'), with: otp click_button t('idv.gpo.form.submit') acknowledge_and_confirm_personal_key - expect(current_path).to eq(idv_sp_follow_up_path) + expect(page).to have_current_path(idv_sp_follow_up_path) click_on t('idv.by_mail.sp_follow_up.go_to_account') expect(current_url).to eq(account_url) diff --git a/spec/features/idv/steps/enter_code_step_spec.rb b/spec/features/idv/steps/enter_code_step_spec.rb index 379558fc413..e34db2a314a 100644 --- a/spec/features/idv/steps/enter_code_step_spec.rb +++ b/spec/features/idv/steps/enter_code_step_spec.rb @@ -93,7 +93,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).to have_css('h1', text: t('idv.gpo.title')) fill_in t('idv.gpo.form.otp_label'), with: 'incorrect1' @@ -107,7 +107,7 @@ it 'renders an alternate ui that remains after failed submission', :js do visit idv_verify_by_mail_enter_code_url(did_not_receive_letter: 1) verify_no_rate_limit_banner - expect(current_path).to eql(new_user_session_path) + expect(page).to have_current_path(new_user_session_path) fill_in_credentials_and_submit(user.email, user.password) continue_as(user.email, user.password) @@ -115,13 +115,13 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path(idv_verify_by_mail_enter_code_path, ignore_query: true) expect(page).to have_css('h1', text: t('idv.gpo.did_not_receive_letter.title')) fill_in t('idv.gpo.form.otp_label'), with: 'incorrect1' click_button t('idv.gpo.form.submit') - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).to have_css('h1', text: t('idv.gpo.did_not_receive_letter.title')) expect(page).to have_content(t('errors.messages.confirmation_code_incorrect')) end @@ -135,7 +135,7 @@ it 'shows the user a personal key after verification' do sign_in_live_with_2fa(user) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path verify_no_rate_limit_banner expect(page).to have_content t('idv.messages.gpo.resend') @@ -163,7 +163,7 @@ it 'allows a user to verify their account for an existing pending profile' do sign_in_live_with_2fa(user) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).to have_content t('idv.messages.gpo.resend') verify_no_rate_limit_banner @@ -178,7 +178,7 @@ it 'allows a user to cancel and start over within the banner' do sign_in_live_with_2fa(user) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).to have_content t('idv.gpo.intro') expect(page).to have_content( strip_tags( @@ -193,11 +193,11 @@ click_on t('idv.gpo.address_accordion.cta_link') - expect(current_path).to eq idv_confirm_start_over_path + expect(page).to have_current_path idv_confirm_start_over_path click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end end @@ -209,16 +209,16 @@ ) sign_in_live_with_2fa(user) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path verify_rate_limit_banner_present(another_gpo_confirmation_code.updated_at) click_on t('idv.gpo.address_accordion.cta_link') - expect(current_path).to eq idv_confirm_start_over_path + expect(page).to have_current_path idv_confirm_start_over_path click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end context 'user is rate limited', :js do @@ -235,7 +235,7 @@ fill_in t('idv.gpo.form.otp_label'), with: wrong_otp click_button t('idv.gpo.form.submit') - expect(current_path).to eq(idv_enter_code_rate_limited_path) + expect(page).to have_current_path(idv_enter_code_rate_limited_path) end end @@ -247,10 +247,10 @@ click_on t('idv.gpo.address_accordion.title') click_on t('idv.gpo.address_accordion.cta_link') - expect(current_path).to eq idv_confirm_start_over_path + expect(page).to have_current_path idv_confirm_start_over_path click_idv_continue - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end end diff --git a/spec/features/idv/steps/enter_password_step_spec.rb b/spec/features/idv/steps/enter_password_step_spec.rb index c76b9a93691..577934ebff6 100644 --- a/spec/features/idv/steps/enter_password_step_spec.rb +++ b/spec/features/idv/steps/enter_password_step_spec.rb @@ -31,7 +31,7 @@ click_continue expect(page).to have_content(t('idv.titles.come_back_later')) - expect(current_path).to eq idv_letter_enqueued_path + expect(page).to have_current_path idv_letter_enqueued_path end context 'with an sp' do @@ -94,14 +94,14 @@ def sends_letter_creates_unverified_profile_sends_email it 'allows the user to submit password and proceed to obtain a personal key' do visit(idv_hybrid_handoff_url(redo: true)) - expect(current_path).to eq idv_hybrid_handoff_path + expect(page).to have_current_path(idv_hybrid_handoff_path(redo: true)) complete_hybrid_handoff_step complete_document_capture_step complete_ssn_step complete_verify_step complete_phone_step(user) complete_enter_password_step(user) - expect(current_path).to eq idv_personal_key_path + expect(page).to have_current_path idv_personal_key_path end end end diff --git a/spec/features/idv/steps/forgot_password_step_spec.rb b/spec/features/idv/steps/forgot_password_step_spec.rb index 91d8f18986e..772570a3713 100644 --- a/spec/features/idv/steps/forgot_password_step_spec.rb +++ b/spec/features/idv/steps/forgot_password_step_spec.rb @@ -9,7 +9,7 @@ click_link t('idv.forgot_password.link_text') - expect(page.current_path).to eq(idv_forgot_password_path) + expect(page).to have_current_path(idv_forgot_password_path) end it 'goes back to the enter password page from the forgot password page' do @@ -19,7 +19,7 @@ click_link t('idv.forgot_password.link_text') click_link t('idv.forgot_password.try_again') - expect(page.current_path).to eq(idv_enter_password_path) + expect(page).to have_current_path(idv_enter_password_path) end it 'allows the user to reset their password' do @@ -29,11 +29,11 @@ click_link t('idv.forgot_password.link_text') click_button t('idv.forgot_password.reset_password') - expect(page.current_path).to eq(forgot_password_path) + expect(page).to have_current_path(forgot_password_path, ignore_query: true) open_last_email click_email_link_matching(/reset_password_token/) - expect(current_path).to eq edit_user_password_path + expect(page).to have_current_path edit_user_password_path end end diff --git a/spec/features/idv/steps/phone_otp_verification_step_spec.rb b/spec/features/idv/steps/phone_otp_verification_step_spec.rb index 5b397d0fcfd..da02a5facdd 100644 --- a/spec/features/idv/steps/phone_otp_verification_step_spec.rb +++ b/spec/features/idv/steps/phone_otp_verification_step_spec.rb @@ -11,14 +11,14 @@ # Attempt to bypass the step visit idv_enter_password_path - expect(current_path).to eq(idv_otp_verification_path) + expect(page).to have_current_path(idv_otp_verification_path) # Enter an incorrect otp fill_in 'code', with: '000000' click_submit_default expect(page).to have_content(t('two_factor_authentication.invalid_otp')) - expect(current_path).to eq(idv_otp_verification_path) + expect(page).to have_current_path(idv_otp_verification_path) # Enter the correct code fill_in_code_with_last_phone_otp @@ -52,7 +52,7 @@ click_on t('links.two_factor_authentication.send_another_code') expect(Telephony::Test::Message.messages.count).to eq(sent_message_count + 1) - expect(current_path).to eq(idv_otp_verification_path) + expect(page).to have_current_path(idv_otp_verification_path) fill_in_code_with_last_phone_otp click_submit_default diff --git a/spec/features/idv/threat_metrix_pending_spec.rb b/spec/features/idv/threat_metrix_pending_spec.rb index 3bd790c6fd0..0488a622da3 100644 --- a/spec/features/idv/threat_metrix_pending_spec.rb +++ b/spec/features/idv/threat_metrix_pending_spec.rb @@ -58,7 +58,7 @@ sign_in_live_with_2fa(user) click_agree_and_continue - expect(current_path).to eq('/auth/result') + expect(page).to have_current_path('/auth/result', ignore_query: true) end scenario 'users rejected from fraud review cannot perform idv' do @@ -83,7 +83,7 @@ sign_in_live_with_2fa(user) click_agree_and_continue - expect(current_path).to eq('/auth/result') + expect(page).to have_current_path('/auth/result', ignore_query: true) end scenario 'users ThreatMetrix Pass, it logs idv_tmx_fraud_check event' do diff --git a/spec/features/idv/uak_password_spec.rb b/spec/features/idv/uak_password_spec.rb index 61bdbd335ee..b457285d04e 100644 --- a/spec/features/idv/uak_password_spec.rb +++ b/spec/features/idv/uak_password_spec.rb @@ -18,6 +18,10 @@ click_agree_and_continue - expect(current_url).to start_with('http://localhost:7654/auth/result') + expect(page).to have_current_path( + 'http://localhost:7654/auth/result', + url: true, + ignore_query: true, + ) end end diff --git a/spec/features/idv/verify_by_mail_pending_spec.rb b/spec/features/idv/verify_by_mail_pending_spec.rb index c49aeb45775..130c5918153 100644 --- a/spec/features/idv/verify_by_mail_pending_spec.rb +++ b/spec/features/idv/verify_by_mail_pending_spec.rb @@ -11,17 +11,17 @@ start_idv_from_sp(facial_match_required: false) sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_verify_by_mail_enter_code_path) + expect(page).to have_current_path(idv_verify_by_mail_enter_code_path) # Attempting to start IdV should require enter-code to be completed visit idv_welcome_path - expect(current_path).to eq(idv_verify_by_mail_enter_code_path) + expect(page).to have_current_path(idv_verify_by_mail_enter_code_path) # Cancelling redirects to IdV flow start click_on t('idv.gpo.address_accordion.cta_link') click_idv_continue - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) end it 'does not require them to enter their code if they are upgrading to facial match' do @@ -34,6 +34,6 @@ # The user is redirected to proofing since their pending profile does not meet # the facial match comparison requirement - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) end end diff --git a/spec/features/load_testing/email_sign_up_spec.rb b/spec/features/load_testing/email_sign_up_spec.rb index 62f3d1039de..4736e385c85 100644 --- a/spec/features/load_testing/email_sign_up_spec.rb +++ b/spec/features/load_testing/email_sign_up_spec.rb @@ -8,7 +8,7 @@ sign_up_with(email) click_link('CONFIRM NOW') - expect(current_path).to eq sign_up_enter_password_path + expect(page).to have_current_path(sign_up_enter_password_path, ignore_query: true) expect(page).to have_content t('devise.confirmations.confirmed_but_must_set_password') end end diff --git a/spec/features/multiple_emails/sp_sign_in_spec.rb b/spec/features/multiple_emails/sp_sign_in_spec.rb index 5b9f6e33992..54c2705713f 100644 --- a/spec/features/multiple_emails/sp_sign_in_spec.rb +++ b/spec/features/multiple_emails/sp_sign_in_spec.rb @@ -38,7 +38,7 @@ click_button(t('help_text.requested_attributes.select_email_link')) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue expect(oidc_decoded_id_token[:email]).to eq(emails.second) end @@ -56,7 +56,7 @@ click_link(t('help_text.requested_attributes.change_email_link')) choose email2.email click_button(t('help_text.requested_attributes.select_email_link')) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default @@ -105,7 +105,7 @@ choose emails.second click_button(t('help_text.requested_attributes.select_email_link')) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default @@ -128,7 +128,7 @@ click_link(t('help_text.requested_attributes.change_email_link')) choose email2.email click_button(t('help_text.requested_attributes.select_email_link')) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default diff --git a/spec/features/new_device_tracking_spec.rb b/spec/features/new_device_tracking_spec.rb index 69a20e0cbb9..d35f6e14f39 100644 --- a/spec/features/new_device_tracking_spec.rb +++ b/spec/features/new_device_tracking_spec.rb @@ -41,7 +41,7 @@ travel_to 16.minutes.from_now do visit root_url - expect(current_path).to eq(new_user_session_path) + expect(page).to have_current_path(new_user_session_path) sign_in_user(user) end @@ -62,7 +62,7 @@ # Notified after session expired, user returned for successful email password and MFA travel_to 38.minutes.from_now do visit root_url - expect(current_path).to eq(new_user_session_path) + expect(page).to have_current_path(new_user_session_path) # Regression: LG-13221: Ensure that the successful authentication email lists failed MFA. sign_in_user(user) diff --git a/spec/features/openid_connect/authorization_confirmation_spec.rb b/spec/features/openid_connect/authorization_confirmation_spec.rb index f95566dcaa4..815acb6efbc 100644 --- a/spec/features/openid_connect/authorization_confirmation_spec.rb +++ b/spec/features/openid_connect/authorization_confirmation_spec.rb @@ -94,13 +94,13 @@ def create_user_and_remember_device sign_in_user(user1) visit_idp_from_ial1_oidc_sp - expect(current_path).to eq(user_authorization_confirmation_path) + expect(page).to have_current_path(user_authorization_confirmation_path) click_button t('user_authorization_confirmation.sign_in') # Simulate clicking the back button by going right back to the original path visit user_authorization_confirmation_path - expect(current_path).to eq(new_user_session_path) + expect(page).to have_current_path(new_user_session_path) end end @@ -115,7 +115,7 @@ 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 + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content t('help_text.requested_attributes.email') expect(page).to have_content email diff --git a/spec/features/openid_connect/openid_connect_spec.rb b/spec/features/openid_connect/openid_connect_spec.rb index 7afa1895245..7a113b24b0f 100644 --- a/spec/features/openid_connect/openid_connect_spec.rb +++ b/spec/features/openid_connect/openid_connect_spec.rb @@ -53,7 +53,7 @@ client_id: 'urn:gov:gsa:openidconnect:test_prompt_login_banned', ) - expect(current_path).to eq(openid_connect_authorize_path) + expect(page).to have_current_path(openid_connect_authorize_path, ignore_query: true) expect(page).to have_content(t('openid_connect.authorization.errors.prompt_invalid')) end @@ -110,7 +110,7 @@ client_id: 'urn:gov:gsa:openidconnect:test_prompt_login_banned', ) - expect(current_path).to eq(openid_connect_authorize_path) + expect(page).to have_current_path(openid_connect_authorize_path, ignore_query: true) expect(page).to have_content(t('openid_connect.authorization.errors.prompt_invalid')) end @@ -1179,7 +1179,7 @@ def oidc_end_client_secret_jwt(vot: nil, prompt: nil, user: nil, redirs_to: nil) expect(URI(oidc_redirect_url).path).to eq(redirs_to) return end - expect(current_path).to eq('/') + expect(page).to have_current_path('/') user ||= create( :profile, :active, :verified, diff --git a/spec/features/openid_connect/vtr_spec.rb b/spec/features/openid_connect/vtr_spec.rb index 24cefe11000..f45259b4ba3 100644 --- a/spec/features/openid_connect/vtr_spec.rb +++ b/spec/features/openid_connect/vtr_spec.rb @@ -107,7 +107,7 @@ sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) end scenario 'sign in with VTR request for idv with facial match requires idv with facial match', @@ -120,7 +120,7 @@ sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) click_continue check t('doc_auth.instructions.consent', app_name: APP_NAME) diff --git a/spec/features/phone/confirmation_spec.rb b/spec/features/phone/confirmation_spec.rb index 737db27c687..5839bd42e58 100644 --- a/spec/features/phone/confirmation_spec.rb +++ b/spec/features/phone/confirmation_spec.rb @@ -28,7 +28,7 @@ def expect_successful_otp_confirmation(delivery_method) def expect_failed_otp_confirmation(_delivery_method) visit account_path - expect(current_path).to eq(authentication_methods_setup_path) + expect(page).to have_current_path(authentication_methods_setup_path) expect(phone_configuration).to be_nil end end @@ -52,7 +52,9 @@ def expect_successful_otp_confirmation(_delivery_method) def expect_failed_otp_confirmation(delivery_method) visit account_path - expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: delivery_method)) + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: delivery_method), + ) end end diff --git a/spec/features/phone/default_phone_selection_spec.rb b/spec/features/phone/default_phone_selection_spec.rb index 23dd10e4e47..5cd111d3bb4 100644 --- a/spec/features/phone/default_phone_selection_spec.rb +++ b/spec/features/phone/default_phone_selection_spec.rb @@ -129,8 +129,10 @@ end def submit_prefilled_otp_code(user, delivery_preference) - expect(current_path) - .to eq login_two_factor_path(otp_delivery_preference: delivery_preference) + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: delivery_preference), + ignore_query: true, + ) fill_in('code', with: user.reload.direct_otp) click_button t('forms.buttons.submit.default') end diff --git a/spec/features/phone/edit_phone_spec.rb b/spec/features/phone/edit_phone_spec.rb index bf47084f1e1..bc99dc48596 100644 --- a/spec/features/phone/edit_phone_spec.rb +++ b/spec/features/phone/edit_phone_spec.rb @@ -9,7 +9,9 @@ visit(manage_phone_path(id: phone_configuration.id)) expect(page).to have_content(t('headings.edit_info.phone')) - expect(current_path).to eq(manage_phone_path(id: phone_configuration.id)) + expect(page).to have_current_path( + manage_phone_path(id: phone_configuration.id), + ) end it "does not allow a user to edit another user's phone number" do diff --git a/spec/features/remember_device/signed_in_sp_expiration_spec.rb b/spec/features/remember_device/signed_in_sp_expiration_spec.rb index 034cde39285..1043f466c4b 100644 --- a/spec/features/remember_device/signed_in_sp_expiration_spec.rb +++ b/spec/features/remember_device/signed_in_sp_expiration_spec.rb @@ -27,7 +27,9 @@ travel_to(5.seconds.from_now) do visit_idp_from_sp_with_ial1_aal2(:oidc) - expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms)) + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: :sms), + ) expect(page).to have_content(t('two_factor_authentication.header_text')) fill_in_code_with_last_phone_otp diff --git a/spec/features/remember_device/sp_expiration_spec.rb b/spec/features/remember_device/sp_expiration_spec.rb index d09effa271b..9c2c7a140ff 100644 --- a/spec/features/remember_device/sp_expiration_spec.rb +++ b/spec/features/remember_device/sp_expiration_spec.rb @@ -31,7 +31,7 @@ def visit_sp(protocol, aal) sign_in_user(user) expect(page).to have_content(t('two_factor_authentication.header_text')) - expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms)) + expect(page).to have_current_path(login_two_factor_path(otp_delivery_preference: :sms)) fill_in_code_with_last_phone_otp protocol == :saml ? click_submit_default_twice : click_submit_default @@ -55,7 +55,7 @@ def visit_sp(protocol, aal) sign_in_user(user) visit_sp(protocol, aal) - expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms)) + expect(page).to have_current_path(login_two_factor_path(otp_delivery_preference: :sms)) expect(page).to have_content(t('two_factor_authentication.header_text')) fill_in_code_with_last_phone_otp @@ -71,7 +71,7 @@ def visit_sp(protocol, aal) sign_in_user(user) expect(page).to have_content(t('two_factor_authentication.header_text')) - expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms)) + expect(page).to have_current_path(login_two_factor_path(otp_delivery_preference: :sms)) fill_in_code_with_last_phone_otp protocol == :saml ? click_submit_default_twice : click_submit_default diff --git a/spec/features/remember_device/webauthn_spec.rb b/spec/features/remember_device/webauthn_spec.rb index c826fca2bec..2f1675b051d 100644 --- a/spec/features/remember_device/webauthn_spec.rb +++ b/spec/features/remember_device/webauthn_spec.rb @@ -130,7 +130,7 @@ def remember_device_and_sign_out_user expect(page) .to have_content t('headings.add_info.phone') - expect(current_path).to eq phone_setup_path + expect(page).to have_current_path phone_setup_path fill_in 'new_phone_form_phone', with: '703-555-1212' click_send_one_time_code diff --git a/spec/features/saml/authorization_confirmation_spec.rb b/spec/features/saml/authorization_confirmation_spec.rb index a9e075f2ad6..e25d78f505f 100644 --- a/spec/features/saml/authorization_confirmation_spec.rb +++ b/spec/features/saml/authorization_confirmation_spec.rb @@ -63,13 +63,13 @@ def create_user_and_remember_device sign_in_user(user1) visit request_url - expect(current_path).to eq(user_authorization_confirmation_path) + expect(page).to have_current_path(user_authorization_confirmation_path) click_button t('user_authorization_confirmation.sign_in') # Simulate clicking the back button by going right back to the original path visit user_authorization_confirmation_path - expect(current_path).to eq(new_user_session_path) + expect(page).to have_current_path(new_user_session_path) end it 'does not render the confirmation screen on a return visit to the SP by default' do @@ -89,7 +89,7 @@ def create_user_and_remember_device sign_in_user(user1) visit user_authorization_confirmation_path - expect(current_path).to eq(account_path) + expect(page).to have_current_path(account_path) end end @@ -106,7 +106,7 @@ 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 + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content t('help_text.requested_attributes.email') expect(page).to have_content email diff --git a/spec/features/saml/ial1_sso_spec.rb b/spec/features/saml/ial1_sso_spec.rb index e2ca596dfe9..bc73dbf0abe 100644 --- a/spec/features/saml/ial1_sso_spec.rb +++ b/spec/features/saml/ial1_sso_spec.rb @@ -15,7 +15,7 @@ perform_in_browser(:two) do confirm_email_in_a_different_browser(email) - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path 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') @@ -43,7 +43,7 @@ expect(current_url).to eq complete_saml_url visit root_path - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end it 'shows user the start page without accordion' do @@ -152,7 +152,7 @@ visit saml_authn_request_url - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') end end @@ -162,7 +162,7 @@ visit saml_authn_request_url - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end end diff --git a/spec/features/saml/ial2_sso_spec.rb b/spec/features/saml/ial2_sso_spec.rb index 5c772f42fa7..f5573dbe36b 100644 --- a/spec/features/saml/ial2_sso_spec.rb +++ b/spec/features/saml/ial2_sso_spec.rb @@ -61,7 +61,7 @@ def sign_out_user visit saml_ial2_request_url - expect(current_path).to match new_user_session_path + expect(page).to have_current_path(new_user_session_path) expect(page).to have_content(sp_content) end @@ -101,7 +101,7 @@ def sign_out_user visit account_path click_link(t('account.index.verification.reactivate_button')) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).not_to have_link(t('idv.messages.gpo.resend')) end @@ -114,7 +114,7 @@ def sign_out_user sign_in_live_with_2fa(user) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).not_to have_link(t('idv.messages.gpo.resend')) end end @@ -132,16 +132,16 @@ def sign_out_user sign_in_live_with_2fa(user) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path click_link(t('idv.messages.gpo.resend')) expect(user.events.account_verified.size).to be(0) - expect(current_path).to eq(idv_resend_letter_path) + expect(page).to have_current_path(idv_resend_letter_path) click_button(t('idv.gpo.request_another_letter.button')) - expect(current_path).to eq(idv_letter_enqueued_path) + expect(page).to have_current_path(idv_letter_enqueued_path) end end end @@ -158,7 +158,7 @@ def sign_out_user ) visit sign_up_completed_path - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path end end end diff --git a/spec/features/saml/saml_logout_spec.rb b/spec/features/saml/saml_logout_spec.rb index da14da53c42..ff0fdc5270c 100644 --- a/spec/features/saml/saml_logout_spec.rb +++ b/spec/features/saml/saml_logout_spec.rb @@ -19,7 +19,7 @@ # Sign out of the IDP visit account_path first(:button, t('links.sign_out')).click - expect(current_path).to eq root_path + expect(page).to have_current_path root_path # SAML logout request visit_saml_logout_request_url( @@ -84,7 +84,7 @@ # The user should be signed out visit account_path - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end end @@ -102,7 +102,7 @@ # The user should be signed out visit account_path - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end end @@ -132,7 +132,7 @@ # The user should be signed out visit account_path - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end end end @@ -151,7 +151,10 @@ }, ) - expect(current_path).to eq(api_saml_logout_path(path_year: SamlAuthHelper::PATH_YEAR)) + expect(page).to have_current_path( + api_saml_logout_path(path_year: SamlAuthHelper::PATH_YEAR), + ignore_query: true, + ) expect(page.driver.status_code).to eq(400) # The user should be signed in diff --git a/spec/features/saml/saml_spec.rb b/spec/features/saml/saml_spec.rb index d8e5ab221ff..2e3262ff730 100644 --- a/spec/features/saml/saml_spec.rb +++ b/spec/features/saml/saml_spec.rb @@ -53,14 +53,14 @@ it 'directs users to the start page' do visit_saml_authn_request_url - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path end it 'prompts the user to enter OTP' do sign_in_before_2fa(user) visit_saml_authn_request_url - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') end end @@ -71,7 +71,7 @@ end it 'prompts the user to set up 2FA' do - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end it 'prompts the user to confirm phone after setting up 2FA' do @@ -79,7 +79,10 @@ fill_in 'new_phone_form_phone', with: '202-555-1212' click_send_one_time_code - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: 'sms'), + ignore_query: true, + ) end end @@ -223,7 +226,7 @@ it 'redirects to root' do travel(Devise.timeout_in + 1.second) do visit api_saml_logout_url(path_year: SamlAuthHelper::PATH_YEAR) - expect(page.current_path).to eq('/') + expect(page).to have_current_path('/') end end end @@ -381,6 +384,7 @@ visit_idp_from_sp_with_ial1(:saml) sign_in_live_with_2fa(user) click_submit_default_twice + expect(page).to have_current_path(test_saml_decode_assertion_path) xmldoc = SamlResponseDoc.new('feature', 'response_assertion') expect(xmldoc.attribute_value_for(:ial)).to eq( Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF, diff --git a/spec/features/saml/vtr_spec.rb b/spec/features/saml/vtr_spec.rb index a22bf2781ac..80ec2cc1277 100644 --- a/spec/features/saml/vtr_spec.rb +++ b/spec/features/saml/vtr_spec.rb @@ -212,7 +212,7 @@ def expect_successful_saml_redirect if javascript_enabled? - expect(current_path).to eq(test_saml_decode_assertion_path) + expect(page).to have_current_path(test_saml_decode_assertion_path) else expect(page).to have_current_path( api_saml_finalauthpost_path(path_year: SamlAuthHelper::PATH_YEAR), diff --git a/spec/features/session/decryption_spec.rb b/spec/features/session/decryption_spec.rb index 6e63e80a5d1..d772f41292c 100644 --- a/spec/features/session/decryption_spec.rb +++ b/spec/features/session/decryption_spec.rb @@ -14,7 +14,7 @@ visit account_path # Should redirect to root since the user has been logged out - expect(current_path).to eq(root_path) + expect(page).to have_current_path(root_path) end end end diff --git a/spec/features/sign_in/banned_users_spec.rb b/spec/features/sign_in/banned_users_spec.rb index aecb624ae3a..1b93b0f1a7f 100644 --- a/spec/features/sign_in/banned_users_spec.rb +++ b/spec/features/sign_in/banned_users_spec.rb @@ -30,7 +30,7 @@ SignInRestriction.create(user: user, service_provider: 'http://localhost:3000') sign_in_live_with_2fa(user) - expect(current_path).to eq(account_path) + expect(page).to have_current_path(account_path) visit_idp_from_sp_with_ial1(:saml) expect_user_to_be_banned @@ -49,7 +49,7 @@ SignInRestriction.create(user: user, service_provider: OidcAuthHelper::OIDC_IAL1_ISSUER) sign_in_live_with_2fa(user) - expect(current_path).to eq(account_path) + expect(page).to have_current_path(account_path) visit_idp_from_sp_with_ial1(:oidc) expect_user_to_be_banned @@ -58,15 +58,15 @@ sign_in_live_with_2fa(user) click_submit_default click_agree_and_continue - expect(current_path).to eq(complete_saml_path) + expect(page).to have_current_path(complete_saml_path) end end def expect_user_to_be_banned - expect(current_path).to eq(banned_user_path) + expect(page).to have_current_path(banned_user_path) expect(page).to have_content(I18n.t('banned_user.title')) visit account_path - expect(current_path).to eq(new_user_session_path) + expect(page).to have_current_path(new_user_session_path) end end diff --git a/spec/features/sign_in/multiple_vot_spec.rb b/spec/features/sign_in/multiple_vot_spec.rb index 9210fae3d17..f0bafff79cf 100644 --- a/spec/features/sign_in/multiple_vot_spec.rb +++ b/spec/features/sign_in/multiple_vot_spec.rb @@ -14,7 +14,7 @@ visit_idp_from_oidc_sp_with_vtr(vtr: ['C1.C2.P1.Pb', 'C1.C2.P1']) sign_in_live_with_2fa(user) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue user_info = OpenidConnectUserInfoPresenter.new(user.identities.last).user_info @@ -29,7 +29,7 @@ visit_idp_from_oidc_sp_with_vtr(vtr: ['C1.C2.P1.Pb', 'C1.C2.P1']) sign_in_live_with_2fa(user) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue user_info = OpenidConnectUserInfoPresenter.new(user.identities.last).user_info @@ -44,13 +44,13 @@ visit_idp_from_oidc_sp_with_vtr(vtr: ['C1.C2.P1.Pb', 'C1.C2.P1']) sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) complete_all_doc_auth_steps_before_password_step(with_selfie: true) fill_in 'Password', with: user.password click_continue acknowledge_and_confirm_personal_key - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue user_info = OpenidConnectUserInfoPresenter.new(user.identities.last).user_info @@ -70,7 +70,7 @@ ) sign_in_live_with_2fa(user) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue user_info = OpenidConnectUserInfoPresenter.new(user.identities.last).user_info @@ -88,7 +88,7 @@ ) sign_in_live_with_2fa(user) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue user_info = OpenidConnectUserInfoPresenter.new(user.identities.last).user_info @@ -109,7 +109,7 @@ user.password = 'new even better password' sign_in_live_with_2fa(user) - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue user_info = OpenidConnectUserInfoPresenter.new(user.identities.last).user_info @@ -141,7 +141,7 @@ sign_in_live_with_2fa(user) click_submit_default - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default @@ -162,7 +162,7 @@ sign_in_live_with_2fa(user) click_submit_default - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default @@ -182,13 +182,13 @@ ) sign_in_live_with_2fa(user) - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) complete_all_doc_auth_steps_before_password_step(with_selfie: true) fill_in 'Password', with: user.password click_continue acknowledge_and_confirm_personal_key - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue xmldoc = SamlResponseDoc.new('feature', 'response_assertion') @@ -217,7 +217,7 @@ sign_in_live_with_2fa(user) click_submit_default - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default @@ -245,7 +245,7 @@ sign_in_live_with_2fa(user) click_submit_default - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default @@ -276,7 +276,7 @@ sign_in_live_with_2fa(user) click_submit_default - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue click_submit_default diff --git a/spec/features/sign_in/setup_piv_cac_after_sign_in_spec.rb b/spec/features/sign_in/setup_piv_cac_after_sign_in_spec.rb index ee2d82a983d..c6c3fd2f761 100644 --- a/spec/features/sign_in/setup_piv_cac_after_sign_in_spec.rb +++ b/spec/features/sign_in/setup_piv_cac_after_sign_in_spec.rb @@ -83,14 +83,14 @@ click_submit_default # Add PIV/CAC after sign-in - expect(current_path).to eq login_add_piv_cac_prompt_path + expect(page).to have_current_path login_add_piv_cac_prompt_path stub_piv_cac_service fill_in 'name', with: 'Card 1' click_on t('forms.piv_cac_setup.submit') follow_piv_cac_redirect expect(page).to have_content(t('notices.piv_cac_configured')) - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path end def perform_steps_to_get_to_add_piv_cac_during_sign_up(sp: :oidc) @@ -100,7 +100,7 @@ def perform_steps_to_get_to_add_piv_cac_during_sign_up(sp: :oidc) fill_in_credentials_and_submit(user.email, user.password) fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq login_add_piv_cac_prompt_path + expect(page).to have_current_path login_add_piv_cac_prompt_path fill_in 'name', with: 'Card 1' end diff --git a/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb b/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb index 5f2796be9ef..659123c2802 100644 --- a/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb +++ b/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb @@ -18,7 +18,7 @@ select_2fa_option('backup_code') expect(page).to have_link(t('components.download_button.label')) - expect(current_path).to eq backup_code_setup_path + expect(page).to have_current_path backup_code_setup_path click_continue click_continue @@ -29,7 +29,7 @@ click_continue expect(page).to have_content(t('notices.backup_codes_configured')) - expect(current_path).to eq confirm_backup_codes_path + expect(page).to have_current_path confirm_backup_codes_path expect(user.backup_code_configurations.count).to eq(BackupCodeGenerator::NUMBER_OF_CODES) click_continue @@ -54,17 +54,17 @@ fill_in :backup_code_verification_form_backup_code, with: codes[index] click_on 'Submit' if index == BackupCodeGenerator::NUMBER_OF_CODES - 1 - expect(current_path).to eq backup_code_refreshed_path + expect(page).to have_current_path backup_code_refreshed_path expect(page).to have_content(t('forms.backup_code.title')) expect(page).to have_content(t('forms.backup_code.last_code')) expect(user.backup_code_configurations.count).to eq(BackupCodeGenerator::NUMBER_OF_CODES) click_continue expect(page).to have_content(t('notices.backup_codes_configured')) - expect(current_path).to eq account_path + expect(page).to have_current_path account_path expect(user.backup_code_configurations.count).to eq(BackupCodeGenerator::NUMBER_OF_CODES) else - expect(current_path).to eq account_path + expect(page).to have_current_path account_path sign_out_user end end @@ -79,7 +79,7 @@ click_continue - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) end context 'when the user needs a backup code reminder' do @@ -93,7 +93,7 @@ fill_in_code_with_last_totp(user) click_submit_default - expect(current_path).to eq backup_code_reminder_path + expect(page).to have_current_path backup_code_reminder_path end end diff --git a/spec/features/two_factor_authentication/change_factor_spec.rb b/spec/features/two_factor_authentication/change_factor_spec.rb index f6905accfbf..e180f945725 100644 --- a/spec/features/two_factor_authentication/change_factor_spec.rb +++ b/spec/features/two_factor_authentication/change_factor_spec.rb @@ -12,11 +12,11 @@ scenario 'editing password' do visit manage_password_path - expect(current_path).to eq login_two_factor_options_path + expect(page).to have_current_path login_two_factor_options_path complete_2fa_confirmation - expect(current_path).to eq manage_password_path + expect(page).to have_current_path manage_password_path end context 'resending OTP code to old phone' do @@ -48,8 +48,9 @@ }, ).once - expect(current_path) - .to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: 'sms'), + ) end end @@ -62,14 +63,14 @@ # Canceling from MFA prompt click_on t('links.cancel') - expect(current_path).to eq account_path + expect(page).to have_current_path account_path # Canceling from MFA selection visit manage_password_path complete_2fa_confirmation_without_entering_otp click_on t('two_factor_authentication.login_options_link_text') click_on t('links.cancel') - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end end end @@ -81,19 +82,19 @@ # Ensure reauthentication context does not prompt incorrectly visit webauthn_setup_path - expect(current_path).to eq login_two_factor_options_path + expect(page).to have_current_path login_two_factor_options_path visit phone_setup_path - expect(current_path).to eq login_two_factor_options_path + expect(page).to have_current_path login_two_factor_options_path find("label[for='two_factor_options_form_selection_sms']").click click_on t('forms.buttons.continue') fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq phone_setup_path + expect(page).to have_current_path phone_setup_path visit phone_setup_path - expect(current_path).to eq phone_setup_path + expect(page).to have_current_path phone_setup_path end end @@ -104,12 +105,12 @@ def complete_2fa_confirmation end def complete_2fa_confirmation_without_entering_otp - expect(current_path).to eq login_two_factor_options_path + expect(page).to have_current_path login_two_factor_options_path find("label[for='two_factor_options_form_selection_sms']").click click_on t('forms.buttons.continue') - expect(current_path).to eq login_two_factor_path( + expect(page).to have_current_path login_two_factor_path( otp_delivery_preference: user.otp_delivery_preference, ) end @@ -123,7 +124,7 @@ def submit_current_password_and_totp fill_in 'Password', with: Features::SessionHelper::VALID_PASSWORD click_button t('forms.buttons.continue') - expect(current_path).to eq login_two_factor_authenticator_path + expect(page).to have_current_path login_two_factor_authenticator_path fill_in 'code', with: generate_totp_code(@secret) click_submit_default diff --git a/spec/features/two_factor_authentication/multiple_mfa_sign_up_spec.rb b/spec/features/two_factor_authentication/multiple_mfa_sign_up_spec.rb index aa751bc08b8..cbe5b566303 100644 --- a/spec/features/two_factor_authentication/multiple_mfa_sign_up_spec.rb +++ b/spec/features/two_factor_authentication/multiple_mfa_sign_up_spec.rb @@ -258,7 +258,7 @@ it 'returns to setup mfa page when user clicks Choose another option' do click_on(t('two_factor_authentication.choose_another_option')) - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path expect(mfa.backup_code_configurations).to be_empty end end diff --git a/spec/features/two_factor_authentication/piv_cac_sign_in_spec.rb b/spec/features/two_factor_authentication/piv_cac_sign_in_spec.rb index 6f00e16973a..f78626d098d 100644 --- a/spec/features/two_factor_authentication/piv_cac_sign_in_spec.rb +++ b/spec/features/two_factor_authentication/piv_cac_sign_in_spec.rb @@ -84,7 +84,7 @@ click_on t('forms.piv_cac_setup.submit') follow_piv_cac_redirect - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue expect(oidc_decoded_id_token[:x509_presented]).to eq(true) diff --git a/spec/features/two_factor_authentication/second_mfa_reminder_spec.rb b/spec/features/two_factor_authentication/second_mfa_reminder_spec.rb index af9cc0a48ff..f72515ceafb 100644 --- a/spec/features/two_factor_authentication/second_mfa_reminder_spec.rb +++ b/spec/features/two_factor_authentication/second_mfa_reminder_spec.rb @@ -40,7 +40,11 @@ click_on t('users.second_mfa_reminder.continue', sp_name: service_provider.friendly_name) - expect(current_url).to start_with(service_provider.redirect_uris.first) + expect(page).to have_current_path( + service_provider.redirect_uris.first, + url: true, + ignore_query: true, + ) end end diff --git a/spec/features/two_factor_authentication/sign_in_spec.rb b/spec/features/two_factor_authentication/sign_in_spec.rb index 932eb1380d3..63ff2dc5a12 100644 --- a/spec/features/two_factor_authentication/sign_in_spec.rb +++ b/spec/features/two_factor_authentication/sign_in_spec.rb @@ -7,7 +7,7 @@ attempt_to_bypass_2fa_setup - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path select_2fa_option('phone') @@ -18,7 +18,7 @@ send_one_time_code_without_entering_phone_number - expect(current_path).to eq phone_setup_path + expect(page).to have_current_path phone_setup_path submit_2fa_setup_form_with_empty_string_phone @@ -31,7 +31,10 @@ submit_2fa_setup_form_with_valid_phone expect(page).to_not have_content t('errors.messages.improbable_phone') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: 'sms'), + ignore_query: true, + ) expect(MfaContext.new(user).phone_configurations).to be_empty expect(user.sms?).to eq true end @@ -47,7 +50,7 @@ fill_in 'new_phone_form_phone', with: unsupported_phone click_send_one_time_code - expect(current_path).to eq phone_setup_path + expect(page).to have_current_path phone_setup_path expect(page).to have_content t( 'two_factor_authentication.otp_delivery_preference.voice_unsupported', location: 'Bahamas', @@ -55,7 +58,7 @@ click_on t('two_factor_authentication.choose_another_option') - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end end @@ -285,19 +288,19 @@ def submit_2fa_setup_form_with_valid_phone user = create(:user, :fully_registered) sign_in_before_2fa(user) - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') expect(page) .to have_content t('two_factor_authentication.header_text') attempt_to_bypass_2fa - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') check 'remember_device' fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end def attempt_to_bypass_2fa @@ -309,7 +312,7 @@ def attempt_to_bypass_2fa sign_in_before_2fa(user) click_link t('links.cancel') - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end scenario 'user does not have to focus on OTP field', js: true do @@ -370,38 +373,38 @@ def attempt_to_bypass_2fa user = user_with_piv_cac sign_in_before_2fa(user) - expect(current_path).to eq login_two_factor_piv_cac_path + expect(page).to have_current_path login_two_factor_piv_cac_path choose_another_security_option('sms') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') visit login_two_factor_piv_cac_path choose_another_security_option('voice') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'voice') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'voice') end it 'allows totp fallback when configured' do user = create(:user, :fully_registered, :with_piv_or_cac, :with_authentication_app) sign_in_before_2fa(user) - expect(current_path).to eq login_two_factor_piv_cac_path + expect(page).to have_current_path login_two_factor_piv_cac_path choose_another_security_option('auth_app') - expect(current_path).to eq login_two_factor_authenticator_path + expect(page).to have_current_path login_two_factor_authenticator_path end scenario 'user can cancel PIV/CAC process' do user = create(:user, :fully_registered, :with_piv_or_cac) sign_in_before_2fa(user) - expect(current_path).to eq login_two_factor_piv_cac_path + expect(page).to have_current_path login_two_factor_piv_cac_path click_link t('links.cancel') - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end scenario 'user uses PIV/CAC as their second factor' do @@ -412,7 +415,7 @@ def attempt_to_bypass_2fa click_on t('forms.piv_cac_mfa.submit') follow_piv_cac_redirect - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end context 'user with Voice preference sends SMS, causing a Telephony error' do @@ -434,7 +437,7 @@ def attempt_to_bypass_2fa sign_in_user(user) - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'voice') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'voice') choose_another_security_option('sms') @@ -451,13 +454,13 @@ def attempt_to_bypass_2fa choose_another_security_option('sms') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') visit login_two_factor_authenticator_path choose_another_security_option('voice') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'voice') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'voice') end scenario 'user can cancel TOTP process' do @@ -465,7 +468,7 @@ def attempt_to_bypass_2fa sign_in_before_2fa(user) click_link t('links.cancel') - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end scenario 'attempting to reuse a TOTP code results in an error' do @@ -479,14 +482,14 @@ def attempt_to_bypass_2fa fill_in 'code', with: otp click_submit_default - expect(current_path).to eq(account_path) + expect(page).to have_current_path(account_path) set_new_browser_session sign_in_user(user) fill_in 'code', with: otp click_submit_default - expect(current_path).to eq login_two_factor_authenticator_path + expect(page).to have_current_path login_two_factor_authenticator_path end end end @@ -503,11 +506,11 @@ def attempt_to_bypass_2fa sign_in_and_2fa_user visit login_two_factor_path(otp_delivery_preference: 'sms') - expect(current_path).to eq account_path + expect(page).to have_current_path account_path visit user_two_factor_authentication_path - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end end @@ -516,7 +519,7 @@ def attempt_to_bypass_2fa user = create(:user, :fully_registered) sign_in_user(user) click_link 'Login.gov' - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: :sms) + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: :sms) end end diff --git a/spec/features/two_factor_authentication/sign_in_via_personal_key_spec.rb b/spec/features/two_factor_authentication/sign_in_via_personal_key_spec.rb index cc0eb9d3ee6..9ef6ff5fd56 100644 --- a/spec/features/two_factor_authentication/sign_in_via_personal_key_spec.rb +++ b/spec/features/two_factor_authentication/sign_in_via_personal_key_spec.rb @@ -14,7 +14,7 @@ enter_personal_key(personal_key: raw_key) click_submit_default expect(user.reload.encrypted_recovery_code_digest).to_not eq old_key - expect(current_path).to eq account_path + expect(page).to have_current_path account_path last_message = Telephony::Test::Message.messages.last expect(last_message.body).to eq t('telephony.personal_key_sign_in_notice', app_name: APP_NAME) diff --git a/spec/features/users/password_recovery_via_recovery_code_spec.rb b/spec/features/users/password_recovery_via_recovery_code_spec.rb index d22c78b04bf..59d88496cfb 100644 --- a/spec/features/users/password_recovery_via_recovery_code_spec.rb +++ b/spec/features/users/password_recovery_via_recovery_code_spec.rb @@ -20,7 +20,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq reactivate_account_path + expect(page).to have_current_path reactivate_account_path reactivate_profile(new_password, personal_key) @@ -39,7 +39,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq(reactivate_account_path) + expect(page).to have_current_path(reactivate_account_path) visit account_path @@ -54,12 +54,16 @@ acknowledge_and_confirm_personal_key click_agree_and_continue - expect(current_url).to start_with('http://localhost:7654/auth/result') + expect(page).to have_current_path( + 'http://localhost:7654/auth/result', + url: true, + ignore_query: true, + ) visit account_path expect(page).to have_content(t('account.index.verification.verified_badge')) - expect(current_path).to eq(account_path) + expect(page).to have_current_path(account_path) end scenario 'resets password, not allowed to use personal key as 2fa', email: true do @@ -86,7 +90,7 @@ click_on t('links.account.reactivate.with_key') click_on t('links.reverify') - expect(current_path).to eq(idv_welcome_path) + expect(page).to have_current_path(idv_welcome_path) end scenario 'resets password, view modal and close it', email: true do @@ -124,12 +128,12 @@ def reactivate_profile(password, personal_key) click_on t('links.account.reactivate.with_key') - expect(current_path).to eq verify_personal_key_path + expect(page).to have_current_path verify_personal_key_path fill_in 'personal_key', with: personal_key click_continue - expect(current_path).to eq verify_password_path + expect(page).to have_current_path verify_password_path fill_in 'Password', with: password click_continue diff --git a/spec/features/users/piv_cac_management_spec.rb b/spec/features/users/piv_cac_management_spec.rb index 8397f36686f..45daa0de75e 100644 --- a/spec/features/users/piv_cac_management_spec.rb +++ b/spec/features/users/piv_cac_management_spec.rb @@ -22,7 +22,7 @@ click_on t('forms.piv_cac_setup.submit') follow_piv_cac_redirect - expect(current_path).to eq account_path + expect(page).to have_current_path account_path visit account_two_factor_authentication_path user.reload expect(page).to have_link(href: edit_piv_cac_path(id: user.piv_cac_configurations.first.id)) @@ -47,7 +47,7 @@ expect(page).to_not have_link(t('account.index.piv_cac_add'), href: setup_piv_cac_url) visit setup_piv_cac_path - expect(current_path).to eq account_two_factor_authentication_path + expect(page).to have_current_path account_two_factor_authentication_path end scenario 'disallows association of a piv/cac with the same name' do @@ -61,7 +61,7 @@ click_on t('forms.piv_cac_setup.submit') follow_piv_cac_redirect - expect(current_path).to eq account_path + expect(page).to have_current_path account_path visit account_two_factor_authentication_path click_link t('account.index.piv_cac_add'), href: setup_piv_cac_url @@ -83,7 +83,7 @@ click_on t('forms.piv_cac_setup.submit') follow_piv_cac_redirect - expect(current_path).to eq setup_piv_cac_error_path + expect(page).to have_current_path(setup_piv_cac_error_path, ignore_query: true) expect(page).to have_link(t('instructions.mfa.piv_cac.try_again'), href: setup_piv_cac_url) expect(page).to have_content( t( @@ -104,7 +104,7 @@ click_on t('forms.piv_cac_setup.submit') follow_piv_cac_redirect - expect(current_path).to eq setup_piv_cac_error_path + expect(page).to have_current_path(setup_piv_cac_error_path, ignore_query: true) expect(page).to have_link( t('instructions.mfa.piv_cac.please_try_again'), href: setup_piv_cac_url, @@ -155,7 +155,9 @@ ), ) - expect(current_path).to eq(edit_piv_cac_path(id: user.piv_cac_configurations.first.id)) + expect(page).to have_current_path( + edit_piv_cac_path(id: user.piv_cac_configurations.first.id), + ) click_button t('two_factor_authentication.piv_cac.delete') expect(page).to have_content(t('two_factor_authentication.piv_cac.deleted')) diff --git a/spec/features/users/profile_recovery_for_gpo_verified_spec.rb b/spec/features/users/profile_recovery_for_gpo_verified_spec.rb index 6a99df19d6e..e90e86ddd4e 100644 --- a/spec/features/users/profile_recovery_for_gpo_verified_spec.rb +++ b/spec/features/users/profile_recovery_for_gpo_verified_spec.rb @@ -28,11 +28,11 @@ click_on t('links.account.reactivate.with_key') - expect(current_path).to eq verify_personal_key_path + expect(page).to have_current_path verify_personal_key_path fill_in 'personal_key', with: personal_key click_continue - expect(current_path).to eq verify_password_path + expect(page).to have_current_path verify_password_path fill_in 'Password', with: new_password click_continue diff --git a/spec/features/users/regenerate_personal_key_spec.rb b/spec/features/users/regenerate_personal_key_spec.rb index e9087371979..d3155b38e10 100644 --- a/spec/features/users/regenerate_personal_key_spec.rb +++ b/spec/features/users/regenerate_personal_key_spec.rb @@ -44,7 +44,7 @@ click_on(t('account.links.regenerate_personal_key'), match: :prefer_exact) # reauthn - expect(current_path).to eq login_two_factor_options_path + expect(page).to have_current_path login_two_factor_options_path find("label[for='two_factor_options_form_selection_sms']").click click_on t('forms.buttons.continue') fill_in_code_with_last_phone_otp diff --git a/spec/features/users/sign_in_spec.rb b/spec/features/users/sign_in_spec.rb index 41a2f2d91a9..982fbc6a6f8 100644 --- a/spec/features/users/sign_in_spec.rb +++ b/spec/features/users/sign_in_spec.rb @@ -45,7 +45,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq(user_please_call_path) + expect(page).to have_current_path(user_please_call_path) end scenario 'user with old terms of use can accept and continue to IAL1 SP' do @@ -165,12 +165,12 @@ sign_in_and_2fa_user visit account_path - expect(current_path).to eq account_path + expect(page).to have_current_path account_path travel(Devise.timeout_in + 1.minute) visit account_path - expect(current_path).to eq root_path + expect(page).to have_current_path root_path travel_back end @@ -231,7 +231,7 @@ click_button(t('notices.timeout_warning.signed_in.sign_out')) expect(page).to have_content t('devise.sessions.signed_out') - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path end end @@ -292,7 +292,7 @@ expect(page).to have_content t('errors.general') fill_in_credentials_and_submit(user.email, user.password) - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') end end @@ -323,19 +323,19 @@ perform_in_browser(:one) do sign_in_live_with_2fa(user) - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end perform_in_browser(:two) do sign_in_live_with_2fa(user) - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end perform_in_browser(:one) do visit account_path - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path expect(page).to have_content(t('devise.failure.session_limited')) expect(analytics.events[:concurrent_session_logout].count).to eq 1 @@ -350,19 +350,19 @@ perform_in_browser(:one) do sign_in_user_with_piv(user) - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end perform_in_browser(:two) do sign_in_user_with_piv(user) - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end perform_in_browser(:one) do visit account_path - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path expect(page).to have_content(t('devise.failure.session_limited')) end end @@ -389,7 +389,7 @@ perform_in_browser(:one) do visit account_path - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path expect(page).to have_content(t('devise.failure.session_limited')) expect_branded_experience end @@ -451,7 +451,7 @@ expect(page) .to have_link t('devise.failure.invalid_link_text', href: link_url) - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end end @@ -463,7 +463,7 @@ fill_in_credentials_and_submit(user.email, user.password) fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end context 'with email and password' do @@ -475,7 +475,7 @@ fill_in_credentials_and_submit(user.email, user.password) click_submit_default - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end end @@ -486,7 +486,7 @@ visit new_user_session_path(request_id: 'invalid') signin_with_piv(user) - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end end end @@ -641,7 +641,7 @@ click_link t('two_factor_authentication.login_options_link_text') click_on t('links.cancel') - expect(current_path).to eq root_path + expect(page).to have_current_path root_path expect(page).to have_content(t('devise.sessions.signed_out')) end end @@ -657,7 +657,7 @@ check 'rules_of_use_form[terms_accepted]' click_button t('forms.buttons.continue') - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') end end @@ -701,7 +701,7 @@ click_agree_and_continue visit_idp_from_oidc_sp_with_loa1_prompt_login - expect(current_path).to eq(bounced_path) + expect(page).to have_current_path(bounced_path) end end @@ -743,7 +743,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content(user.email) click_agree_and_continue @@ -761,7 +761,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content('1**-**-***3') click_agree_and_continue @@ -803,7 +803,7 @@ fill_in_code_with_last_phone_otp click_submit_default_twice - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content(user.email) click_agree_and_continue @@ -832,7 +832,7 @@ click_submit_default click_submit_default - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content('1**-**-***3') click_agree_and_continue @@ -928,7 +928,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq manage_password_path + expect(page).to have_current_path manage_password_path end it 'should redirect user to after_sign_in_path after editing password' do @@ -937,7 +937,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq manage_password_path + expect(page).to have_current_path manage_password_path password = 'salty pickles' fill_in t('forms.passwords.edit.labels.password'), with: password @@ -962,7 +962,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end end end @@ -981,7 +981,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq account_path + expect(page).to have_current_path account_path user.reload expect(user.password_compromised_checked_at).to be_truthy end @@ -999,7 +999,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq account_path + expect(page).to have_current_path account_path user.reload expect(user.password_compromised_checked_at).to be_falsey end @@ -1018,7 +1018,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path select_2fa_option('piv_cac') expect(page).to have_current_path setup_piv_cac_path @@ -1028,7 +1028,7 @@ user = create(:user, :with_phone, :with_piv_or_cac) fill_in_credentials_and_submit(user.email, user.password) - expect(current_path).to eq login_two_factor_piv_cac_path + expect(page).to have_current_path login_two_factor_piv_cac_path end end @@ -1040,7 +1040,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content(user.email) agree_and_continue_button = find_button(t('sign_up.agree_and_continue')) diff --git a/spec/features/users/sign_up_spec.rb b/spec/features/users/sign_up_spec.rb index 5667891a4fc..a61e54b7f5c 100644 --- a/spec/features/users/sign_up_spec.rb +++ b/spec/features/users/sign_up_spec.rb @@ -58,7 +58,7 @@ end it 'redirects user to the home page' do - expect(current_path).to eq root_path + expect(page).to have_current_path root_path end end @@ -69,7 +69,7 @@ end it 'sends them to the cancel page' do - expect(current_path).to eq sign_up_cancel_path + expect(page).to have_current_path sign_up_cancel_path end end @@ -81,7 +81,7 @@ end it 'sends them to the cancel page' do - expect(current_path).to eq sign_up_cancel_path + expect(page).to have_current_path sign_up_cancel_path end end @@ -89,7 +89,7 @@ it 'redirects user to the translated home page' do visit sign_up_email_path(locale: 'es') click_on t('links.cancel') - expect(current_path).to eq '/es' + expect(page).to have_current_path '/es' end end @@ -110,7 +110,7 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq backup_code_setup_path + expect(page).to have_current_path backup_code_setup_path expect(page).to have_link(t('components.download_button.label')) @@ -140,7 +140,7 @@ fill_in 'new_phone_form_phone', with: '225-555-1000' click_send_one_time_code - expect(current_path).to eq(phone_setup_path) + expect(page).to have_current_path(phone_setup_path) expect(page).to have_content(I18n.t('telephony.error.friendly_message.generic')) end @@ -163,7 +163,7 @@ timeout: '(10|9) minutes', ) - expect(current_path).to eq(authentication_methods_setup_path) + expect(page).to have_current_path(authentication_methods_setup_path) expect(page).to have_content(/#{rate_limited_message}/) end @@ -398,12 +398,12 @@ def clipboard_text ) click_button t('forms.buttons.continue') - expect(current_path).to eq rules_of_use_path + expect(page).to have_current_path rules_of_use_path check 'rules_of_use_form[terms_accepted]' freeze_time do click_button t('forms.buttons.continue') - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path expect(user.reload.accepted_terms_at).to eq Time.zone.now end end @@ -493,7 +493,7 @@ def clipboard_text it 'returns them to the homepage' do click_link APP_NAME, href: new_user_session_path - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path end end @@ -506,7 +506,7 @@ def clipboard_text it 'returns them to the MFA setup screen' do click_link APP_NAME, href: new_user_session_path - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end end end @@ -519,17 +519,17 @@ def clipboard_text it 'should land user on piv cac suggestion page' do confirm_email(email) submit_form_with_valid_password - expect(current_path).to eq login_piv_cac_recommended_path + expect(page).to have_current_path login_piv_cac_recommended_path end context 'when the user chooses to skip adding piv' do it 'should land on mfa screen' do confirm_email(email) submit_form_with_valid_password - expect(current_path).to eq login_piv_cac_recommended_path + expect(page).to have_current_path login_piv_cac_recommended_path click_button t('two_factor_authentication.piv_cac_upsell.choose_other_method') - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end end @@ -537,10 +537,10 @@ def clipboard_text it 'should land on piv add screen' do confirm_email(email) submit_form_with_valid_password - expect(current_path).to eq login_piv_cac_recommended_path + expect(page).to have_current_path login_piv_cac_recommended_path click_button t('two_factor_authentication.piv_cac_upsell.add_piv') - expect(current_path).to eq setup_piv_cac_path + expect(page).to have_current_path setup_piv_cac_path end end end @@ -550,17 +550,17 @@ def clipboard_text it 'should land user on piv cac suggestion page' do confirm_email(email) submit_form_with_valid_password - expect(current_path).to eq login_piv_cac_recommended_path + expect(page).to have_current_path login_piv_cac_recommended_path end context 'when the user chooses to skip adding piv' do it 'should land on mfa screen' do confirm_email(email) submit_form_with_valid_password - expect(current_path).to eq login_piv_cac_recommended_path + expect(page).to have_current_path login_piv_cac_recommended_path click_button t('two_factor_authentication.piv_cac_upsell.choose_other_method') - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end end @@ -568,10 +568,10 @@ def clipboard_text it 'should land on piv add screen' do confirm_email(email) submit_form_with_valid_password - expect(current_path).to eq login_piv_cac_recommended_path + expect(page).to have_current_path login_piv_cac_recommended_path click_button t('two_factor_authentication.piv_cac_upsell.add_piv') - expect(current_path).to eq setup_piv_cac_path + expect(page).to have_current_path setup_piv_cac_path end end end @@ -581,7 +581,7 @@ def clipboard_text it 'should skip piv cac recommendation page' do confirm_email(email) submit_form_with_valid_password - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end end end diff --git a/spec/features/users/totp_management_spec.rb b/spec/features/users/totp_management_spec.rb index 8eb78e84398..2025f3c776b 100644 --- a/spec/features/users/totp_management_spec.rb +++ b/spec/features/users/totp_management_spec.rb @@ -22,7 +22,7 @@ ), ) - expect(current_path).to eq(edit_auth_app_path(id: auth_app_config.id)) + expect(page).to have_current_path(edit_auth_app_path(id: auth_app_config.id)) click_button t('two_factor_authentication.auth_app.delete') @@ -47,7 +47,7 @@ ), ) - expect(current_path).to eq(edit_auth_app_path(id: auth_app_configuration.id)) + expect(page).to have_current_path(edit_auth_app_path(id: auth_app_configuration.id)) expect(page).to have_field( t('two_factor_authentication.auth_app.nickname'), with: name, @@ -79,7 +79,7 @@ ), ) - expect(current_path).to eq(edit_auth_app_path(id: existing_auth_app_configuration.id)) + expect(page).to have_current_path(edit_auth_app_path(id: existing_auth_app_configuration.id)) expect(page).to have_field( t('two_factor_authentication.auth_app.nickname'), with: name, @@ -90,7 +90,7 @@ click_button t('two_factor_authentication.auth_app.change_nickname') - expect(current_path).to eq(edit_auth_app_path(id: existing_auth_app_configuration.id)) + expect(page).to have_current_path(edit_auth_app_path(id: existing_auth_app_configuration.id)) expect(page).to have_content(t('errors.manage_authenticator.unique_name_error')) end diff --git a/spec/features/users/user_profile_spec.rb b/spec/features/users/user_profile_spec.rb index 5340eead14e..749ce13f9fb 100644 --- a/spec/features/users/user_profile_spec.rb +++ b/spec/features/users/user_profile_spec.rb @@ -36,7 +36,7 @@ fill_in(t('idv.form.password'), with: Features::SessionHelper::VALID_PASSWORD) click_button t('users.delete.actions.delete') expect(page).to have_content t('devise.registrations.destroyed') - expect(current_path).to eq root_path + expect(page).to have_current_path root_path expect(User.count).to eq 0 expect(AgencyIdentity.count).to eq 0 end @@ -84,7 +84,7 @@ fill_in(t('idv.form.password'), with: profile.user.password) click_button t('users.delete.actions.delete') expect(page).to have_content t('devise.registrations.destroyed') - expect(current_path).to eq root_path + expect(page).to have_current_path root_path expect(User.count).to eq 0 expect(Profile.count).to eq 0 end @@ -132,7 +132,7 @@ click_button 'Update' - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end context 'IAL2 user' do @@ -155,7 +155,7 @@ click_continue - expect(current_path).to eq(account_path) + expect(page).to have_current_path(account_path) end it 'allows the user reactivate their profile by reverifying', :js do @@ -173,11 +173,15 @@ click_idv_continue acknowledge_and_confirm_personal_key - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue - expect(current_url).to start_with('http://localhost:7654/auth/result') + expect(page).to have_current_path( + 'http://localhost:7654/auth/result', + url: true, + ignore_query: true, + ) end end end @@ -191,7 +195,7 @@ click_on t('account.navigation.menu') click_link t('account.navigation.history') - expect(current_path).to eq(account_history_path) + expect(page).to have_current_path(account_history_path) end end diff --git a/spec/features/users/verify_profile_spec.rb b/spec/features/users/verify_profile_spec.rb index c1a0ff7cf4d..31a7768efa6 100644 --- a/spec/features/users/verify_profile_spec.rb +++ b/spec/features/users/verify_profile_spec.rb @@ -43,7 +43,7 @@ click_button t('idv.gpo.form.submit') expect(page).to have_content t('errors.messages.gpo_otp_expired_and_cannot_request_another') - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path end scenario 'wrong OTP used' do @@ -51,7 +51,7 @@ fill_in t('idv.gpo.form.otp_label'), with: 'the wrong code' click_button t('idv.gpo.form.submit') - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).to have_content(t('errors.messages.confirmation_code_incorrect')) expect(page.body).to_not match('the wrong code') end diff --git a/spec/features/visitors/i18n_spec.rb b/spec/features/visitors/i18n_spec.rb index f02559428b2..3168880aa46 100644 --- a/spec/features/visitors/i18n_spec.rb +++ b/spec/features/visitors/i18n_spec.rb @@ -119,7 +119,7 @@ click_submit_default end - expect(current_path).to eq idv_welcome_path(locale: :es) + expect(page).to have_current_path idv_welcome_path(locale: :es) expect(page.document.find('html')['lang']).to eq('es') end end diff --git a/spec/features/visitors/password_recovery_spec.rb b/spec/features/visitors/password_recovery_spec.rb index 8f223c34bd7..3f1bed3114d 100644 --- a/spec/features/visitors/password_recovery_spec.rb +++ b/spec/features/visitors/password_recovery_spec.rb @@ -19,7 +19,7 @@ click_button t('forms.buttons.continue') - expect(current_path).to eq forgot_password_path + expect(page).to have_current_path forgot_password_path expect(last_email.subject).to eq t('user_mailer.reset_password_instructions.subject') expect(last_email.html_part.body).to include MarketingSite.help_url @@ -33,7 +33,7 @@ open_last_email click_email_link_matching(/reset_password_token/) - expect(current_path).to eq edit_user_password_path + expect(page).to have_current_path edit_user_password_path end end @@ -85,13 +85,13 @@ fill_in t('components.password_confirmation.confirm_label'), with: password click_button t('forms.passwords.edit.buttons.submit') - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path end it 'prompts user to set up their 2FA options after signing back in' do reset_password_and_sign_back_in(@user) - expect(current_path).to eq authentication_methods_setup_path + expect(page).to have_current_path authentication_methods_setup_path end end @@ -105,7 +105,7 @@ end it 'redirects to new user password form' do - expect(current_path).to eq new_user_password_path + expect(page).to have_current_path new_user_password_path end it 'displays a flash error message' do @@ -130,7 +130,7 @@ fill_in 'code', with: @user.reload.direct_otp click_button t('forms.buttons.submit.default') - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end end @@ -157,7 +157,7 @@ end it 'lands on the reset password page' do - expect(current_path).to eq edit_user_password_path + expect(page).to have_current_path edit_user_password_path end context 'when password form values are valid' do @@ -177,7 +177,7 @@ ).to eq('password_changed') visit account_path - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path end it 'allows the user to continue to the service provider' do @@ -234,7 +234,7 @@ click_button t('forms.passwords.edit.buttons.submit') signin(@user.email, '1234') - expect(current_path).to eq new_user_session_path + expect(page).to have_current_path new_user_session_path end it 'allows multiple attempts with invalid password' do @@ -276,7 +276,7 @@ expect(page).to have_content t('devise.passwords.token_expired') - expect(current_path).to eq new_user_password_path + expect(page).to have_current_path new_user_password_path end it 'rate limits reset passwords requests' do diff --git a/spec/features/visitors/sign_up_with_email_spec.rb b/spec/features/visitors/sign_up_with_email_spec.rb index 7633a1aecc6..4228e03df5d 100644 --- a/spec/features/visitors/sign_up_with_email_spec.rb +++ b/spec/features/visitors/sign_up_with_email_spec.rb @@ -57,7 +57,7 @@ sign_up_and_2fa_ial1_user expect(Funnel::Registration::TotalRegisteredCount.call).to eq(1) - expect(current_path).to eq account_path + expect(page).to have_current_path account_path end it 'returns a bad request if the email contains invalid bytes' do diff --git a/spec/features/webauthn/hidden_spec.rb b/spec/features/webauthn/hidden_spec.rb index 9af74c27f11..e7bf4940eda 100644 --- a/spec/features/webauthn/hidden_spec.rb +++ b/spec/features/webauthn/hidden_spec.rb @@ -130,7 +130,7 @@ fill_in_credentials_and_submit(user.email, user.password) # Redirected to options page - expect(current_path).to eq(login_two_factor_options_path) + expect(page).to have_current_path(login_two_factor_options_path) # Can choose authenticator expect(webauthn_option_hidden?).to eq(false) @@ -150,7 +150,7 @@ fill_in_credentials_and_submit(user.email, user.password) # Redirected to default MFA method - expect(current_path).to eq(login_two_factor_piv_cac_path) + expect(page).to have_current_path(login_two_factor_piv_cac_path) # Can change to authenticator if they choose click_on t('two_factor_authentication.login_options_link_text') diff --git a/spec/features/webauthn/management_spec.rb b/spec/features/webauthn/management_spec.rb index 2571c955407..ed6bd005892 100644 --- a/spec/features/webauthn/management_spec.rb +++ b/spec/features/webauthn/management_spec.rb @@ -24,7 +24,7 @@ def expect_webauthn_setup_error 'errors.webauthn_setup.general_error_html', link_html: t('errors.webauthn_setup.additional_methods_link'), ) - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path end def visit_webauthn_platform_setup @@ -44,7 +44,7 @@ def expect_webauthn_platform_setup_success def expect_webauthn_platform_setup_error expect(page).to have_content t('errors.webauthn_platform_setup.general_error') - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path end context 'with webauthn roaming associations' do @@ -91,7 +91,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) click_button t('two_factor_authentication.webauthn_roaming.delete') @@ -116,7 +116,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) expect(page).to have_field( t('two_factor_authentication.webauthn_roaming.nickname'), with: name, @@ -146,7 +146,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) click_link t('links.cancel') @@ -170,7 +170,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) click_button t('two_factor_authentication.webauthn_roaming.delete') @@ -195,7 +195,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) expect(page).to have_field( t('two_factor_authentication.webauthn_roaming.nickname'), with: name, @@ -205,7 +205,7 @@ def expect_webauthn_platform_setup_error click_button t('two_factor_authentication.webauthn_roaming.change_nickname') - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) expect(page).to have_field( t('two_factor_authentication.webauthn_roaming.nickname'), with: 'existing', @@ -221,15 +221,15 @@ def expect_webauthn_platform_setup_error sign_in_and_2fa_user(user) visit account_two_factor_authentication_path - expect(current_path).to eq account_two_factor_authentication_path + expect(page).to have_current_path account_two_factor_authentication_path first(:link, t('account.index.webauthn_add'), href: webauthn_setup_path).click - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path fill_in_nickname_and_click_continue(nickname: webauthn_config.name) mock_press_button_on_hardware_key_on_setup - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path expect(page).to have_content t('errors.webauthn_setup.unique_name') end @@ -401,7 +401,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) click_button t('two_factor_authentication.webauthn_platform.delete') @@ -426,7 +426,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) expect(page).to have_field( t('two_factor_authentication.webauthn_platform.nickname'), with: name, @@ -456,7 +456,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) click_link t('links.cancel') @@ -480,7 +480,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) click_button t('two_factor_authentication.webauthn_platform.delete') @@ -505,7 +505,7 @@ def expect_webauthn_platform_setup_error ].join(': '), ) - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) expect(page).to have_field( t('two_factor_authentication.webauthn_platform.nickname'), with: name, @@ -515,7 +515,7 @@ def expect_webauthn_platform_setup_error click_button t('two_factor_authentication.webauthn_platform.change_nickname') - expect(current_path).to eq(edit_webauthn_path(id: webauthn_config.id)) + expect(page).to have_current_path(edit_webauthn_path(id: webauthn_config.id)) expect(page).to have_field( t('two_factor_authentication.webauthn_platform.nickname'), with: 'existing', @@ -531,15 +531,15 @@ def expect_webauthn_platform_setup_error sign_in_and_2fa_user(user) visit account_two_factor_authentication_path - expect(current_path).to eq account_two_factor_authentication_path + expect(page).to have_current_path account_two_factor_authentication_path first(:link, t('account.index.webauthn_add'), href: webauthn_setup_path).click - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path fill_in_nickname_and_click_continue(nickname: webauthn_config.name) mock_press_button_on_hardware_key_on_setup - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path expect(page).to have_content t('errors.webauthn_setup.unique_name') end diff --git a/spec/features/webauthn/sign_in_spec.rb b/spec/features/webauthn/sign_in_spec.rb index 5d1f8b0bd28..78d1e602bcb 100644 --- a/spec/features/webauthn/sign_in_spec.rb +++ b/spec/features/webauthn/sign_in_spec.rb @@ -97,11 +97,11 @@ end it 'redirects to options page on sign in' do - expect(current_path).to eq(login_two_factor_options_path) + expect(page).to have_current_path(login_two_factor_options_path) end it 'allows user to go to options page and still select webauthn as their option' do - expect(current_path).to eq(login_two_factor_options_path) + expect(page).to have_current_path(login_two_factor_options_path) select_2fa_option('webauthn_platform', visible: :all) click_continue expect(current_url).to eq(login_two_factor_webauthn_url(platform: true)) diff --git a/spec/features/webauthn/sign_up_spec.rb b/spec/features/webauthn/sign_up_spec.rb index a2a68ffe5a5..78829f1de74 100644 --- a/spec/features/webauthn/sign_up_spec.rb +++ b/spec/features/webauthn/sign_up_spec.rb @@ -33,13 +33,13 @@ def expect_webauthn_setup_error visit_idp_from_ial1_oidc_sp_requesting_phishing_resistant(prompt: 'select_account') select_2fa_option('webauthn', visible: :all) - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path fill_in_nickname_and_click_continue mock_press_button_on_hardware_key_on_setup skip_second_mfa_prompt - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) end end end diff --git a/spec/forms/select_email_form_spec.rb b/spec/forms/select_email_form_spec.rb index 9775d56ed8c..cc63aaabd3c 100644 --- a/spec/forms/select_email_form_spec.rb +++ b/spec/forms/select_email_form_spec.rb @@ -29,14 +29,28 @@ end context 'with an invalid email id' do - let(:selected_email_id) { '' } + context 'with a blank email id' do + let(:selected_email_id) { '' } - it 'is unsuccessful' do - expect(response.to_h).to eq( - success: false, - error_details: { selected_email_id: { not_found: true } }, - selected_email_id: nil, - ) + it 'is unsuccessful' do + expect(response.to_h).to eq( + success: false, + error_details: { selected_email_id: { blank: true, not_found: true } }, + selected_email_id: nil, + ) + end + end + + context 'with a non-existing email id' do + let(:selected_email_id) { 9000 } + + it 'is unsuccessful' do + expect(response.to_h).to eq( + success: false, + error_details: { selected_email_id: { not_found: true } }, + selected_email_id: 9000, + ) + end end context 'with present value that does not convert to numeric' do @@ -45,7 +59,7 @@ it 'is unsuccessful without raising exception' do expect(response.to_h).to eq( success: false, - error_details: { selected_email_id: { not_found: true } }, + error_details: { selected_email_id: { not_found: true, blank: true } }, selected_email_id: nil, ) end diff --git a/spec/javascript/packages/document-capture/hooks/use-async-spec.jsx b/spec/javascript/packages/document-capture/hooks/use-async-spec.jsx index a1b750a9cb7..4149251c335 100644 --- a/spec/javascript/packages/document-capture/hooks/use-async-spec.jsx +++ b/spec/javascript/packages/document-capture/hooks/use-async-spec.jsx @@ -23,19 +23,8 @@ describe('document-capture/hooks/use-async', () => { } it('returns suspense resource that renders fallback', async () => { - let resolve; - const createPromise = sinon - .stub() - .onCall(0) - .returns( - new Promise((_resolve) => { - resolve = () => { - _resolve(); - }; - }), - ) - .onCall(1) - .throws(); + const { promise, resolve } = Promise.withResolvers(); + const createPromise = sinon.stub().onCall(0).returns(promise).onCall(1).throws(); const { container, findByText } = render(); @@ -47,25 +36,14 @@ describe('document-capture/hooks/use-async', () => { }); it('returns suspense resource that renders error fallback', async () => { - let reject; - const createPromise = sinon - .stub() - .onCall(0) - .returns( - new Promise((_resolve, _reject) => { - reject = () => { - _reject(new Error()); - }; - }), - ) - .onCall(1) - .throws(); + const { promise, reject } = Promise.withResolvers(); + const createPromise = sinon.stub().onCall(0).returns(promise).onCall(1).throws(); const { container, findByText } = render(); expect(container.textContent).to.equal('Loading'); - reject(); + reject(new Error()); expect(await findByText('Error')).to.be.ok(); expect(console).to.have.loggedError(); diff --git a/spec/jobs/socure_docv_repeat_webhook_job_spec.rb b/spec/jobs/socure_docv_repeat_webhook_job_spec.rb new file mode 100644 index 00000000000..604b6f5ca4c --- /dev/null +++ b/spec/jobs/socure_docv_repeat_webhook_job_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe SocureDocvRepeatWebhookJob do + let(:job) { described_class.new } + let(:headers) do + { + Authorization: 'auhtoriztion-header', + 'Content-Type': 'application/json', + } + end + let(:endpoint) { 'https://example.test/endpoint' } + let(:body) do + { + event: { + created: '2020-01-01T00:00:00Z', + customerUserId: 'customer-user-id', + eventType: 'REPEATED_EVENT', + docvTransactionToken: 'rando-token', + referenceId: 'reference-id', + }, + } + end + + before do + stub_request(:post, endpoint) + .with(body:, headers:) + end + + describe '#perform' do + subject(:perform) do + job.perform(body:, headers:, endpoint:) + end + + it 'repeats the webhook' do + expect(Faraday).to receive(:new).and_call_original + expect(NewRelic::Agent).not_to receive(:notice_error) + + perform + end + + context 'failed endpoint repeat' do + before do + allow_any_instance_of(DocAuth::Socure::WebhookRepeater) + .to receive(:send_http_post_request).with(endpoint).and_raise('uh-oh') + end + + it 'sends message to New Relic' do + expect(NewRelic::Agent).to receive(:notice_error) do |*args| + expect(args.first).to be_a_kind_of(RuntimeError) + expect(args.last).to eq( + { + custom_params: { + event: 'Failed to repeat webhook', + endpoint:, + body:, + }, + }, + ) + end + + perform + end + end + end +end diff --git a/spec/lib/linters/mail_later_linter_spec.rb b/spec/lib/linters/mail_later_linter_spec.rb index 3cc51f7bb26..6a00ae279fd 100644 --- a/spec/lib/linters/mail_later_linter_spec.rb +++ b/spec/lib/linters/mail_later_linter_spec.rb @@ -33,6 +33,14 @@ RUBY end + it 'registers offense when calling .with(...).deliver_now method with variable mailer' do + expect_offense(<<~RUBY) + mailer = UserMailer.with(user) + mailer.send_email(params).deliver_later + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ IdentityIdp/MailLaterLinter: Please send mail using deliver_now_or_later instead + RUBY + end + it 'does not register offenses for the ReportMailer' do expect_no_offenses(<<~RUBY) ReportMailer.send_email(foobar).deliver_now diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb index 297b4c5a7f9..66edf8f05ee 100644 --- a/spec/mailers/previews/user_mailer_preview.rb +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -243,11 +243,8 @@ def in_person_failed_fraud ) end - def in_person_please_call - UserMailer.with(user: user, email_address: email_address_record).in_person_please_call( - enrollment: in_person_enrollment_id_ipp, - visited_location_name: in_person_visited_location_name, - ) + def idv_please_call + UserMailer.with(user: user, email_address: email_address_record).idv_please_call end def account_rejected diff --git a/spec/mailers/previews/user_mailer_preview_spec.rb b/spec/mailers/previews/user_mailer_preview_spec.rb index fcc2bda9e53..d533387f9e5 100644 --- a/spec/mailers/previews/user_mailer_preview_spec.rb +++ b/spec/mailers/previews/user_mailer_preview_spec.rb @@ -2,7 +2,7 @@ require_relative './user_mailer_preview' RSpec.describe UserMailerPreview do - it_behaves_like 'a mailer preview' + it_behaves_like 'a mailer preview', preview_methods_that_can_be_missing: [:in_person_please_call] it 'uses user and email records that cannot be saved' do expect(User.count).to eq(0) diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 8e273ac41ef..887009af5cb 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -799,6 +799,23 @@ def expect_email_body_to_have_help_and_contact_links end end + describe '#idv_please_call' do + let(:mail) do + UserMailer.with(user: user, email_address: email_address).idv_please_call + end + + it_behaves_like 'a system email' + it_behaves_like 'an email that respects user email locale preference' + + it 'renders the idv_please_call template' do + expect_any_instance_of(ActionMailer::Base).to receive(:mail) + .with(hash_including(template_name: 'idv_please_call')) + .and_call_original + + mail.deliver_later + end + end + context 'in person emails' do let(:current_address_matches_id) { false } let!(:enrollment) do @@ -1306,6 +1323,14 @@ def expect_email_body_to_have_help_and_contact_links it_behaves_like 'a system email' it_behaves_like 'an email that respects user email locale preference' + it 'renders the idv_please_call template' do + expect_any_instance_of(ActionMailer::Base).to receive(:mail) + .with(hash_including(template_name: 'idv_please_call')) + .and_call_original + + mail.deliver_later + end + context 'when the keyword argument visited_location_name is missing' do let(:mail) do UserMailer.with(user: user, email_address: email_address).in_person_please_call( @@ -1440,6 +1465,13 @@ def expect_email_body_to_have_help_and_contact_links end describe '#deliver_later' do + it 'queues email without raising' do + # rubocop:disable IdentityIdp/MailLaterLinter + mailer = UserMailer.with(user:, email_address: user.email_addresses.first) + mailer.suspended_create_account.deliver_later + # rubocop:enable IdentityIdp/MailLaterLinter + end + it 'does not queue email if it potentially contains sensitive value' do user = create(:user) mailer = UserMailer.with( diff --git a/spec/services/idv/analytics_events_enhancer_spec.rb b/spec/services/idv/analytics_events_enhancer_spec.rb index a553f623b4e..8cd8994461c 100644 --- a/spec/services/idv/analytics_events_enhancer_spec.rb +++ b/spec/services/idv/analytics_events_enhancer_spec.rb @@ -211,4 +211,33 @@ def track_event(_event, **kwargs) end end end + + describe 'valid configuration' do + let(:explicitly_ignored_methods) do + described_class.const_get(:IGNORED_METHODS).sort + end + + let(:explicitly_enhanced_methods) do + described_class.const_get(:METHODS_WITH_PROFILE_HISTORY).sort + end + + let(:explicitly_referenced_methods) do + [*explicitly_ignored_methods, *explicitly_enhanced_methods].sort + end + + let(:idv_event_methods) do + AnalyticsEvents.instance_methods(false) + .filter { |n| n.start_with?('idv_') } + .sort + end + + it 'only references known AnalyticsEvents methods' do + found_methods = (idv_event_methods & explicitly_referenced_methods).sort + expect(found_methods).to eq(explicitly_referenced_methods) + end + + it 'does not both ignore and enhance the same method' do + expect(explicitly_ignored_methods).to_not include(*explicitly_enhanced_methods) + end + end end diff --git a/spec/services/user_alerts/alert_user_about_account_verified_spec.rb b/spec/services/user_alerts/alert_user_about_account_verified_spec.rb index 47dd8f362fa..c956abd7ba1 100644 --- a/spec/services/user_alerts/alert_user_about_account_verified_spec.rb +++ b/spec/services/user_alerts/alert_user_about_account_verified_spec.rb @@ -38,7 +38,9 @@ expect_delivered_email( to: [user.confirmed_email_addresses.first.email], subject: t('user_mailer.account_verified.subject', app_name: APP_NAME), - body: ['', 'localhost:3000'], + body: [ + 'http://www.example.com/redirect/return_to_sp/account_verified_cta', + ], ) end end @@ -50,7 +52,9 @@ described_class.call(profile: profile) email_body = last_email.text_part.decoded.squish - expect(email_body).to_not include('
') + expect(email_body).to_not include( + 'http://www.example.com/redirect/return_to_sp/account_verified_cta', + ) end end @@ -69,7 +73,7 @@ expect_delivered_email( to: [user.confirmed_email_addresses.first.email], subject: t('user_mailer.account_verified.subject', app_name: APP_NAME), - body: ['
', 'http://example.com'], + body: ['http://example.com'], ) end end diff --git a/spec/support/fake_analytics.rb b/spec/support/fake_analytics.rb index ce3ee4b6170..0ec98262613 100644 --- a/spec/support/fake_analytics.rb +++ b/spec/support/fake_analytics.rb @@ -1,3 +1,5 @@ +require 'analytics_events_documenter' + class FakeAnalytics < Analytics PiiDetected = Class.new(StandardError).freeze @@ -73,6 +75,10 @@ def track_event(event, original_attributes = {}) module UndocumentedParamsChecker mattr_accessor :asts mattr_accessor :docstrings + DOCUMENTATION_OPTIONAL_PARAMS = [ + :user_id, + *AnalyticsEventsDocumenter::DOCUMENTATION_OPTIONAL_PARAMS.map(&:to_sym), + ].uniq.freeze def track_event(event, original_attributes = {}) method_name = caller @@ -91,9 +97,9 @@ def track_event(event, original_attributes = {}) .map(&:last) extra_keywords = original_attributes.keys \ - - [:pii_like_keypaths, :user_id] \ - - param_names \ - - option_param_names(analytics_method) + - DOCUMENTATION_OPTIONAL_PARAMS \ + - param_names \ + - option_param_names(analytics_method) if extra_keywords.present? raise UndocumentedParams, <<~ERROR diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb index cd948410a74..9fc4318a822 100644 --- a/spec/support/features/doc_auth_helper.rb +++ b/spec/support/features/doc_auth_helper.rb @@ -111,6 +111,7 @@ def complete_document_capture_step(with_selfie: false) if with_selfie attach_liveness_images else + expect(page).to have_current_path(idv_document_capture_path) attach_images end diff --git a/spec/support/features/idv_helper.rb b/spec/support/features/idv_helper.rb index 54960c5bfdd..f78beb2e596 100644 --- a/spec/support/features/idv_helper.rb +++ b/spec/support/features/idv_helper.rb @@ -199,7 +199,7 @@ def visit_idp_from_saml_sp_with_loa3 def validate_idv_completed_page(user) expect(user.identity_verified?).to be(true) - expect(current_path).to eq sign_up_completed_path + expect(page).to have_current_path sign_up_completed_path expect(page).to have_content t( 'titles.sign_up.completion_ial2', sp: 'Test SP', @@ -207,6 +207,10 @@ def validate_idv_completed_page(user) end def validate_return_to_sp - expect(current_url).to start_with('http://localhost:7654/auth/result') + expect(page).to have_current_path( + 'http://localhost:7654/auth/result', + url: true, + ignore_query: true, + ) end end diff --git a/spec/support/features/session_helper.rb b/spec/support/features/session_helper.rb index 897f117a3f0..123748bd7b9 100644 --- a/spec/support/features/session_helper.rb +++ b/spec/support/features/session_helper.rb @@ -21,7 +21,7 @@ def choose_another_security_option(option) click_link t('two_factor_authentication.login_options_link_text') - expect(current_path).to eq login_two_factor_options_path + expect(page).to have_current_path login_two_factor_options_path select_2fa_option(option) end @@ -602,7 +602,7 @@ def fill_forgot_password_form(user) fill_in t('account.index.email'), with: user.email click_button t('forms.buttons.continue') - expect(current_path).to eq forgot_password_path + expect(page).to have_current_path forgot_password_path end def click_reset_password_link_from_email @@ -617,7 +617,7 @@ def click_reset_password_link_from_email open_last_email click_email_link_matching(/reset_password_token/) - expect(current_path).to eq edit_user_password_path + expect(page).to have_current_path edit_user_password_path end def expect_branded_experience diff --git a/spec/support/idv_examples/sp_handoff.rb b/spec/support/idv_examples/sp_handoff.rb index 868f999ad5a..71786093558 100644 --- a/spec/support/idv_examples/sp_handoff.rb +++ b/spec/support/idv_examples/sp_handoff.rb @@ -13,7 +13,7 @@ visit_idp_from_sp_with_ial2(sp) register_user(email) - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path complete_all_doc_auth_steps_before_password_step fill_in 'Password', with: Features::SessionHelper::VALID_PASSWORD @@ -43,7 +43,7 @@ fill_in_code_with_last_totp(user) click_submit_default - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path complete_all_doc_auth_steps_before_password_step fill_in 'Password', with: user.password @@ -171,7 +171,7 @@ def expect_successful_saml_handoff expect(AgencyIdentity.where(user_id: user.id, agency_id: 2).first.uuid).to eq(xmldoc.uuid) if javascript_enabled? - expect(current_path).to eq test_saml_decode_assertion_path + expect(page).to have_current_path test_saml_decode_assertion_path else expect(current_url).to eq @saml_authn_request end diff --git a/spec/support/idv_examples/sp_requested_attributes.rb b/spec/support/idv_examples/sp_requested_attributes.rb index ac7641780bb..67cf7cf22ec 100644 --- a/spec/support/idv_examples/sp_requested_attributes.rb +++ b/spec/support/idv_examples/sp_requested_attributes.rb @@ -13,14 +13,14 @@ fill_in_code_with_last_phone_otp click_submit_default - expect(current_path).to eq idv_welcome_path + expect(page).to have_current_path idv_welcome_path complete_all_doc_auth_steps_before_password_step fill_in 'Password', with: user.password click_continue acknowledge_and_confirm_personal_key - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) expect(page).to have_content t('help_text.requested_attributes.email') expect(page).to have_content user.email @@ -84,7 +84,7 @@ fill_in_code_with_last_phone_otp sp == :saml ? click_submit_default_twice : click_submit_default - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) expect(page).to have_content t('help_text.requested_attributes.email') expect(page).to have_content user.email diff --git a/spec/support/idv_examples/verification_code_entry.rb b/spec/support/idv_examples/verification_code_entry.rb index 6a8ef4a4ec5..953c9481adb 100644 --- a/spec/support/idv_examples/verification_code_entry.rb +++ b/spec/support/idv_examples/verification_code_entry.rb @@ -4,7 +4,7 @@ it 'prompts for verification code at sign in' do sign_in_live_with_2fa(user) - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).to have_content t('idv.messages.gpo.resend') gpo_confirmation_code @@ -35,7 +35,7 @@ fill_in t('idv.gpo.form.otp_label'), with: otp click_button t('idv.gpo.form.submit') - expect(current_path).to eq idv_verify_by_mail_enter_code_path + expect(page).to have_current_path idv_verify_by_mail_enter_code_path expect(page).to have_content t('errors.messages.gpo_otp_expired_and_cannot_request_another') user.reload @@ -59,7 +59,7 @@ expect(GpoConfirmation.count).to eq(1) expect(GpoConfirmationCode.count).to eq(2) - expect(current_path).to eq idv_letter_enqueued_path + expect(page).to have_current_path idv_letter_enqueued_path confirmation_code = GpoConfirmationCode.first otp_fingerprint = Pii::Fingerprinter.fingerprint(otp) diff --git a/spec/support/mailer_helper.rb b/spec/support/mailer_helper.rb index eb264b0adca..e28e65b22cf 100644 --- a/spec/support/mailer_helper.rb +++ b/spec/support/mailer_helper.rb @@ -15,26 +15,106 @@ def strip_tags(str) ActionController::Base.helpers.strip_tags(str) end + # @param [String,String[],nil] to The email address(es) the message must've been sent to. + # @param [String,nil] subject The subject the email must've had + # @param [String[],nil] Array of substrings that must appear in body. def expect_delivered_email(to: nil, subject: nil, body: nil) - email = ActionMailer::Base.deliveries.find do |sent_mail| - next unless to.present? && sent_mail.to == to - next unless subject.present? && sent_mail.subject == subject - if body.present? - delivered_body = sent_mail.text_part.decoded.squish - body.to_a.each do |expected_body| - next unless delivered_body.include?(expected_body) - end - end - true - end + email = find_sent_email(to:, subject:, body:) error_message = <<~ERROR Unable to find email matching args: to: #{to} subject: #{subject} body: #{body} - Sent mails: #{ActionMailer::Base.deliveries} + Sent mails: + #{summarize_all_deliveries(to:, subject:, body:).indent(2)} ERROR + expect(email).to_not be(nil), error_message end + + # @param [String,nil] to If provided, the email address the message must've been sent to + # @param [String,nil] subject If provided, the subject the email must've had + # @param [String[],nil] Array of substrings that must appear in body. + def expect_email_not_delivered(to: nil, subject: nil, body: nil) + email = find_sent_email(to:, subject:, body:) + + error_message = <<~ERROR + Found an email matching the below (but shouldn't have): + to: #{to} + subject: #{subject} + body: #{body} + Sent mails: + #{summarize_all_deliveries(to:, subject:, body:).indent(2)} + ERROR + + expect(email).to be(nil), error_message + end + + private + + def body_matches(email:, body:) + return true if body.nil? + + delivered_body = email.text_part.decoded.squish + + Array.wrap(body).all? do |expected_substring| + delivered_body.include?(expected_substring) + end + end + + def to_matches(email:, to:) + return true if to.nil? + + to = Array.wrap(to).to_set + + (email.to.to_set - to).empty? + end + + def find_sent_email( + to:, + subject:, + body: + ) + ActionMailer::Base.deliveries.find do |email| + to_ok = to_matches(email:, to:) + subject_ok = subject.nil? || email.subject == subject + body_ok = body_matches(email:, body:) + + to_ok && subject_ok && body_ok + end + end + + def summarize_delivery( + email:, + to:, + subject:, + body: + ) + body_text = email.text_part.decoded.squish + + body_summary = body.presence && Array.wrap(body).map do |substring| + found = body_text.include?(substring) + "- #{substring.inspect} (#{found ? 'found' : 'not found'})" + end.join("\n") + + to_ok = to_matches(email:, to:) + subject_ok = subject.nil? || subject == email.subject + + [ + "To: #{email.to}#{to_ok ? '' : ' (did not match)'}", + "Subject: #{email.subject}#{subject_ok ? '' : ' (did not match)'}", + body.presence && "Body:\n#{body_summary.indent(2)}", + ].compact.join("\n") + end + + def summarize_all_deliveries(query) + ActionMailer::Base.deliveries.map do |email| + summary = summarize_delivery(email:, **query) + [ + "- #{summary.lines.first.chomp}", + *summary.lines.drop(1).map { |l| l.chomp.indent(2) }, + ].join("\n") + end.join("\n") + end end diff --git a/spec/support/mailer_helper_spec.rb b/spec/support/mailer_helper_spec.rb new file mode 100644 index 00000000000..dbec5de7d64 --- /dev/null +++ b/spec/support/mailer_helper_spec.rb @@ -0,0 +1,383 @@ +require 'rails_helper' + +RSpec.describe 'mailer_helper' do + def mail_double(to:, subject:, body:) + instance_double( + Mail::Message, + to:, + subject:, + text_part: instance_double( + Mail::Part, + decoded: body, + ), + ) + end + + let(:all_deliveries) do + [ + mail_double( + to: ['user@example.com'], + subject: 'Test subject 1', + body: 'Hello world!', + ), + ] + end + + before do + allow(ActionMailer::Base).to receive(:deliveries).and_return(all_deliveries) + end + + describe '#expect_delivered_email' do + context 'when searching by to' do + context 'and found' do + it 'does not raise' do + expect do + expect_delivered_email(to: 'user@example.com') + end.not_to raise_error + end + end + context 'and not found' do + it 'raises an appropriate error' do + expect do + expect_delivered_email(to: 'otheruser@example.com') + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Unable to find email matching args: + to: otheruser@example.com + subject: + body: + Sent mails: + - To: [\"user@example.com\"] (did not match) + Subject: Test subject 1 + END + ) + end, + ) + end + end + end + + context 'when searching by subject' do + context 'and found' do + it 'does not raise' do + expect do + expect_delivered_email(subject: 'Test subject 1') + end.not_to raise_error + end + context 'and not found' do + it 'raises an appropriate error' do + expect do + expect_delivered_email(subject: 'Another unrelated subject') + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Unable to find email matching args: + to: + subject: Another unrelated subject + body: + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 (did not match) + END + ) + end, + ) + end + end + end + end + + context 'when searching by body' do + context 'with string' do + context 'when found' do + it 'does not raise' do + expect do + expect_delivered_email( + body: 'Hello', + ) + end.not_to raise_error + end + end + context 'and not found' do + it 'raises an appropriate error' do + expect do + expect_delivered_email(body: 'Hellow') + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Unable to find email matching args: + to: + subject: + body: Hellow + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 + Body: + - "Hellow" (not found) + END + ) + end, + ) + end + end + end + context 'with array' do + context 'when found' do + it 'does not raise' do + expect do + expect_delivered_email( + body: ['Hello', 'world'], + ) + end.not_to raise_error + end + end + context 'and not found' do + it 'raises an appropriate error' do + expect do + expect_delivered_email(body: ['Hellow', 'world']) + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Unable to find email matching args: + to: + subject: + body: ["Hellow", "world"] + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 + Body: + - "Hellow" (not found) + - "world" (found) + END + ) + end, + ) + end + end + end + end + + context 'when searching by to + subject + body' do + context 'and found' do + it 'does not raise' do + expect do + expect_delivered_email( + to: 'user@example.com', + subject: 'Test subject 1', + body: 'Hello', + ) + end.not_to raise_error + end + context 'and to does not match any' do + it 'raises an appropriate error' do + expect do + expect_delivered_email( + to: 'otheruser@example.com', + subject: 'Unrelated subject', + body: 'Hellow', + ) + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Unable to find email matching args: + to: otheruser@example.com + subject: Unrelated subject + body: Hellow + Sent mails: + - To: [\"user@example.com\"] (did not match) + Subject: Test subject 1 (did not match) + Body: + - "Hellow" (not found) + END + ) + end, + ) + end + end + end + end + end + + describe '#expect_email_not_delivered' do + context 'when searching by to' do + context 'and not found' do + it 'does not raise' do + expect do + expect_email_not_delivered(to: 'otheruser@example.com') + end.not_to raise_error + end + end + context 'and found' do + it 'raises an appropriate error' do + expect do + expect_email_not_delivered(to: 'user@example.com') + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Found an email matching the below (but shouldn't have): + to: user@example.com + subject: + body: + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 + END + ) + end, + ) + end + end + end + + context 'when searching by subject' do + context 'and not found' do + it 'does not raise' do + expect do + expect_email_not_delivered(subject: 'Another unrelated subject') + end.not_to raise_error + end + context 'and found' do + it 'raises an appropriate error' do + expect do + expect_email_not_delivered(subject: 'Test subject 1') + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Found an email matching the below (but shouldn't have): + to: + subject: Test subject 1 + body: + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 + END + ) + end, + ) + end + end + end + end + + context 'when searching by body' do + context 'with string' do + context 'when not found' do + it 'does not raise' do + expect do + expect_email_not_delivered( + body: 'Hellow', + ) + end.not_to raise_error + end + end + context 'when found' do + it 'raises an appropriate error' do + expect do + expect_email_not_delivered(body: 'Hello') + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Found an email matching the below (but shouldn't have): + to: + subject: + body: Hello + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 + Body: + - "Hello" (found) + END + ) + end, + ) + end + end + end + context 'with array' do + context 'when not found' do + it 'does not raise' do + expect do + expect_email_not_delivered( + body: ['Hellow', 'world'], + ) + end.not_to raise_error + end + end + context 'and found' do + it 'raises an appropriate error' do + expect do + expect_email_not_delivered(body: ['Hello', 'world']) + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Found an email matching the below (but shouldn't have): + to: + subject: + body: ["Hello", "world"] + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 + Body: + - "Hello" (found) + - "world" (found) + END + ) + end, + ) + end + end + end + end + + context 'when searching by to + subject + body' do + context 'and not found' do + it 'does not raise' do + expect do + expect_email_not_delivered( + to: 'otheruser@example.com', + subject: 'Unrelated subject', + body: 'Hellow', + ) + end.not_to raise_error + end + context 'and it matches' do + it 'raises an appropriate error' do + expect do + expect_email_not_delivered( + to: 'user@example.com', + subject: 'Test subject 1', + body: 'Hello', + ) + end.to raise_error( + satisfy do |err| + expect(err.message).to eql( + <<~END, + Found an email matching the below (but shouldn't have): + to: user@example.com + subject: Test subject 1 + body: Hello + Sent mails: + - To: [\"user@example.com\"] + Subject: Test subject 1 + Body: + - "Hello" (found) + END + ) + end, + ) + end + end + end + end + end +end diff --git a/spec/support/shared_examples/account_creation.rb b/spec/support/shared_examples/account_creation.rb index cac5c3a31c5..6ac469d7354 100644 --- a/spec/support/shared_examples/account_creation.rb +++ b/spec/support/shared_examples/account_creation.rb @@ -46,7 +46,9 @@ acknowledge_and_confirm_personal_key click_agree_and_continue - expect(current_path).to eq test_saml_decode_assertion_path if sp == :saml + if sp == :saml + expect(page).to have_current_path test_saml_decode_assertion_path + end if sp == :oidc redirect_uri = URI(current_url) @@ -92,7 +94,9 @@ acknowledge_and_confirm_personal_key click_agree_and_continue - expect(current_path).to eq test_saml_decode_assertion_path if sp == :saml + if sp == :saml + expect(page).to have_current_path test_saml_decode_assertion_path + end if sp == :oidc redirect_uri = URI(current_url) diff --git a/spec/support/shared_examples/mailer_preview.rb b/spec/support/shared_examples/mailer_preview.rb index 04918203c96..4f359c1f43b 100644 --- a/spec/support/shared_examples/mailer_preview.rb +++ b/spec/support/shared_examples/mailer_preview.rb @@ -1,10 +1,10 @@ -RSpec.shared_examples 'a mailer preview' do +RSpec.shared_examples 'a mailer preview' do |preview_methods_that_can_be_missing: []| let(:mailer_class) { described_class.class_name.gsub(/Preview$/, '').constantize } it 'has a preview method for each mailer method' do mailer_methods = mailer_class.instance_methods(false) preview_methods = described_class.instance_methods(false) - expect(mailer_methods - preview_methods).to be_empty + expect(mailer_methods - preview_methods).to eql(preview_methods_that_can_be_missing) end described_class.instance_methods(false).each do |mailer_method| diff --git a/spec/support/shared_examples/phone/rate_limiting.rb b/spec/support/shared_examples/phone/rate_limiting.rb index fdc50481233..0d6b2d0c2a4 100644 --- a/spec/support/shared_examples/phone/rate_limiting.rb +++ b/spec/support/shared_examples/phone/rate_limiting.rb @@ -71,7 +71,9 @@ ), ) end - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: delivery_method) + expect(page).to have_current_path( + login_two_factor_path(otp_delivery_preference: delivery_method), + ) end fill_in :code, with: '123456' click_submit_default diff --git a/spec/support/shared_examples/sign_in.rb b/spec/support/shared_examples/sign_in.rb index b84aa6054e9..013e9ad5172 100644 --- a/spec/support/shared_examples/sign_in.rb +++ b/spec/support/shared_examples/sign_in.rb @@ -164,7 +164,7 @@ click_submit_default click_submit_default if current_path == complete_saml_path - expect(current_path).to eq reactivate_account_path + expect(page).to have_current_path reactivate_account_path reactivate_profile(new_password, user.personal_key) @@ -378,9 +378,9 @@ def user_with_broken_personal_key(scenario) ), ) if successful_sign_in - expect(current_path).to eq login_two_factor_path(otp_delivery_preference: 'sms') + expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms') else - expect(current_path).to eq sign_in_security_check_failed_path + expect(page).to have_current_path sign_in_security_check_failed_path end end end diff --git a/spec/support/shared_examples/webauthn_setup.rb b/spec/support/shared_examples/webauthn_setup.rb index 229153b4564..9070dec2f81 100644 --- a/spec/support/shared_examples/webauthn_setup.rb +++ b/spec/support/shared_examples/webauthn_setup.rb @@ -3,7 +3,7 @@ mock_webauthn_setup_challenge visit_webauthn_setup - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path fill_in_nickname_and_click_continue mock_press_button_on_hardware_key_on_setup @@ -32,7 +32,7 @@ mock_webauthn_setup_challenge visit_webauthn_setup - expect(current_path).to eq webauthn_setup_path + expect(page).to have_current_path webauthn_setup_path mock_submit_without_pressing_button_on_hardware_key_on_setup diff --git a/spec/support/sp_auth_helper.rb b/spec/support/sp_auth_helper.rb index e36369a218e..e08fb32c50f 100644 --- a/spec/support/sp_auth_helper.rb +++ b/spec/support/sp_auth_helper.rb @@ -43,7 +43,7 @@ def create_in_person_ial2_account_go_back_to_sp_and_sign_out(sp) fill_in_code_with_last_totp(user) click_submit_default - expect(current_path).to eq(sign_up_completed_path) + expect(page).to have_current_path(sign_up_completed_path) click_agree_and_continue visit sign_out_url diff --git a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb index 152365c4d20..4379ef66113 100644 --- a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb +++ b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb @@ -29,7 +29,7 @@ is_enhanced_ipp: is_enhanced_ipp, ) end - let(:step_indicator_steps) { Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS } + let(:step_indicator_steps) { Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS_IPP } let(:sp_event_name) { 'IdV: user clicked sp link on ready to verify page' } let(:help_event_name) { 'IdV: user clicked what to bring link on ready to verify page' } diff --git a/spec/views/idv/shared/ssn.html.erb_spec.rb b/spec/views/idv/shared/ssn.html.erb_spec.rb index c951b33ba9f..e0bff6b6f6d 100644 --- a/spec/views/idv/shared/ssn.html.erb_spec.rb +++ b/spec/views/idv/shared/ssn.html.erb_spec.rb @@ -30,7 +30,7 @@ :ssn_presenter, Idv::SsnPresenter.new( sp_name: sp_name, ssn_form: Idv::SsnFormatForm.new(nil), - step_indicator_steps: Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS + step_indicator_steps: Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS ), ) render template: 'idv/shared/ssn', locals: { diff --git a/tsconfig.json b/tsconfig.json index 574fa031bf1..e1e8484ae35 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,7 @@ "exclude": [ "**/fixtures", "spec/**/*.spec.js", + "app/javascript/packs/digital-analytics-program.ts", "app/javascript/packages/analytics/digital-analytics-program*.js" ] } diff --git a/typings/clipboard-polyfill/overwrite-globals.d.ts b/typings/clipboard-polyfill/overwrite-globals.d.ts deleted file mode 100644 index cb0ff5c3b54..00000000000 --- a/typings/clipboard-polyfill/overwrite-globals.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/webpack.config.js b/webpack.config.js index d0492128dd9..eb46a9bd0b1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,6 @@ const { parse, resolve } = require('path'); const url = require('url'); -const { sync: glob } = require('fast-glob'); +const { globSync: glob } = require('fs'); const WebpackAssetsManifest = require('webpack-assets-manifest'); const RailsI18nWebpackPlugin = require('@18f/identity-rails-i18n-webpack-plugin'); const RailsAssetsWebpackPlugin = require('@18f/identity-assets/webpack-plugin'); diff --git a/yarn.lock b/yarn.lock index ec103eca0b4..ca61d2a5cc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1418,10 +1418,26 @@ "@types/chai" "*" "@types/chai-as-promised" "*" -"@types/estree@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/eslint-scope@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584" + integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== "@types/grecaptcha@^3.0.4": version "3.0.4" @@ -1447,7 +1463,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -1462,10 +1478,10 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.0.tgz#3d9018c575f0e3f7386c1de80ee66cc21fbb7a52" integrity sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg== -"@types/node@*", "@types/node@^22.10.1": - version "22.10.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.1.tgz#41ffeee127b8975a05f8c4f83fb89bcb2987d766" - integrity sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ== +"@types/node@*", "@types/node@^22.10.2": + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== dependencies: undici-types "~6.20.0" @@ -1708,125 +1724,125 @@ receptor "1.0.0" resolve-id-refs "0.1.0" -"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" - integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== +"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" + integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-numbers" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== +"@webassemblyjs/floating-point-hex-parser@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz#fcca1eeddb1cc4e7b6eed4fc7956d6813b21b9fb" + integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA== -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== +"@webassemblyjs/helper-api-error@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz#e0a16152248bc38daee76dd7e21f15c5ef3ab1e7" + integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ== -"@webassemblyjs/helper-buffer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" - integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== +"@webassemblyjs/helper-buffer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz#822a9bc603166531f7d5df84e67b5bf99b72b96b" + integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA== -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== +"@webassemblyjs/helper-numbers@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz#dbd932548e7119f4b8a7877fd5a8d20e63490b2d" + integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/floating-point-hex-parser" "1.13.2" + "@webassemblyjs/helper-api-error" "1.13.2" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== +"@webassemblyjs/helper-wasm-bytecode@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz#e556108758f448aae84c850e593ce18a0eb31e0b" + integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA== -"@webassemblyjs/helper-wasm-section@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" - integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== +"@webassemblyjs/helper-wasm-section@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz#9629dda9c4430eab54b591053d6dc6f3ba050348" + integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw== dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/wasm-gen" "1.14.1" -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== +"@webassemblyjs/ieee754@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz#1c5eaace1d606ada2c7fd7045ea9356c59ee0dba" + integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== +"@webassemblyjs/leb128@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz#57c5c3deb0105d02ce25fa3fd74f4ebc9fd0bbb0" + integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== - -"@webassemblyjs/wasm-edit@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" - integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-opt" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - "@webassemblyjs/wast-printer" "1.12.1" - -"@webassemblyjs/wasm-gen@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" - integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" - integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - -"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" - integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" - integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== - dependencies: - "@webassemblyjs/ast" "1.12.1" +"@webassemblyjs/utf8@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1" + integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== + +"@webassemblyjs/wasm-edit@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597" + integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/helper-wasm-section" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-opt" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + "@webassemblyjs/wast-printer" "1.14.1" + +"@webassemblyjs/wasm-gen@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz#991e7f0c090cb0bb62bbac882076e3d219da9570" + integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" + +"@webassemblyjs/wasm-opt@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz#e6f71ed7ccae46781c206017d3c14c50efa8106b" + integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + +"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb" + integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-api-error" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" + +"@webassemblyjs/wast-printer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz#3bb3e9638a8ae5fdaf9610e7a06b4d9f9aa6fe07" + integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw== + dependencies: + "@webassemblyjs/ast" "1.14.1" "@xtuc/long" "4.2.2" "@webpack-cli/configtest@^2.1.1": @@ -1864,20 +1880,15 @@ abab@^2.0.6: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -acorn-import-attributes@^1.9.5: - version "1.9.5" - resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" - integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== - acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.7.1, acorn@^8.8.0, acorn@^8.8.2: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.14.0, acorn@^8.8.0, acorn@^8.8.2: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.1" @@ -2182,15 +2193,15 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserslist@^4.21.10, browserslist@^4.21.9, browserslist@^4.22.3: - version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.21.9, browserslist@^4.22.3, browserslist@^4.24.0: + version "4.24.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2" + integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" buffer-builder@^0.2.0: version "0.2.0" @@ -2230,10 +2241,10 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001587: - version "1.0.30001669" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz" - integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w== +caniuse-lite@^1.0.30001688: + version "1.0.30001689" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001689.tgz#67ca960dd5f443903e19949aeacc9d28f6e10910" + integrity sha512-CmeR2VBycfa+5/jOfnp/NpWPGd06nf1XYiefUvhXFfZE4GkRc9jv+eGPS4nT558WS/8lYCzV8SlANCIPvbWP1g== chai-as-promised@^7.1.1: version "7.1.1" @@ -2324,10 +2335,10 @@ cli-width@^4.1.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== -clipboard-polyfill@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/clipboard-polyfill/-/clipboard-polyfill-3.0.3.tgz#159ea0768e20edc7ffda404bd13c54c73de4ff40" - integrity sha512-hts0o01ZkwjA1qHA5gFePzAj/780W7v+eyN3GdaCRyDnapzcPsKRV5aodv77gcr40NDIcyNjNmc+HvfKV+jD0g== +clipboard-polyfill@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/clipboard-polyfill/-/clipboard-polyfill-4.1.1.tgz#eaf074f91c0a55aa4c12fcfd4862d2cfb9a0cab9" + integrity sha512-nbvNLrcX0zviek5QHLFRAaLrx8y/s8+RF2stH43tuS+kP5XlHMrcD0UGBWq43Hwp6WuuK7KefRMP56S45ibZkA== cliui@^7.0.2: version "7.0.4" @@ -2743,10 +2754,10 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -electron-to-chromium@^1.4.668: - version "1.4.724" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.724.tgz#e0a86fe4d3d0e05a4d7b032549d79608078f830d" - integrity sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA== +electron-to-chromium@^1.5.73: + version "1.5.73" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.73.tgz#f32956ce40947fa3c8606726a96cd8fb5bb5f720" + integrity sha512-8wGNxG9tAG5KhGd3eeA0o6ixhiNdgr0DcHWm85XPCphwZgD1lIEoi6t3VERayWao7SF7AAZTw6oARGJeVjH8Kg== element-closest@^2.0.1: version "2.0.2" @@ -2875,10 +2886,10 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" @@ -4464,10 +4475,10 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -4737,10 +4748,10 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -picocolors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" @@ -5912,10 +5923,10 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typescript@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" - integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +typescript@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" + integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== unbox-primitive@^1.0.2: version "1.0.2" @@ -5965,13 +5976,13 @@ untildify@^4.0.0: resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.2.0" + picocolors "^1.1.0" uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" @@ -6076,18 +6087,18 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.94.0: - version "5.94.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" - integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== - dependencies: - "@types/estree" "^1.0.5" - "@webassemblyjs/ast" "^1.12.1" - "@webassemblyjs/wasm-edit" "^1.12.1" - "@webassemblyjs/wasm-parser" "^1.12.1" - acorn "^8.7.1" - acorn-import-attributes "^1.9.5" - browserslist "^4.21.10" +webpack@^5.97.1: + version "5.97.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.97.1.tgz#972a8320a438b56ff0f1d94ade9e82eac155fa58" + integrity sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg== + dependencies: + "@types/eslint-scope" "^3.7.7" + "@types/estree" "^1.0.6" + "@webassemblyjs/ast" "^1.14.1" + "@webassemblyjs/wasm-edit" "^1.14.1" + "@webassemblyjs/wasm-parser" "^1.14.1" + acorn "^8.14.0" + browserslist "^4.24.0" chrome-trace-event "^1.0.2" enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1"