diff --git a/app/controllers/event_disavowal_controller.rb b/app/controllers/event_disavowal_controller.rb index 4b1d494d27d..35197b15422 100644 --- a/app/controllers/event_disavowal_controller.rb +++ b/app/controllers/event_disavowal_controller.rb @@ -8,7 +8,6 @@ def new Analytics::EVENT_DISAVOWAL, FormResponse.new( success: true, - errors: {}, extra: EventDisavowal::BuildDisavowedEventAnalyticsAttributes.call(disavowed_event), ).to_h, ) diff --git a/app/controllers/users/personal_keys_controller.rb b/app/controllers/users/personal_keys_controller.rb index ac8c8f59857..58396ff4aeb 100644 --- a/app/controllers/users/personal_keys_controller.rb +++ b/app/controllers/users/personal_keys_controller.rb @@ -65,7 +65,6 @@ def send_new_personal_key_notifications def form_response(emails:, telephony_responses:) FormResponse.new( success: true, - errors: {}, extra: { emails: emails.count, sms_message_ids: telephony_responses.map { |resp| resp.to_h[:message_id] }, diff --git a/app/forms/add_user_email_form.rb b/app/forms/add_user_email_form.rb index 4a12fb2b471..abc8da02fa5 100644 --- a/app/forms/add_user_email_form.rb +++ b/app/forms/add_user_email_form.rb @@ -23,7 +23,7 @@ def submit(user, params) @success = false end - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def email_address_record(email) diff --git a/app/forms/backup_code_setup_form.rb b/app/forms/backup_code_setup_form.rb index 09983a3ab0a..840b61243a5 100644 --- a/app/forms/backup_code_setup_form.rb +++ b/app/forms/backup_code_setup_form.rb @@ -8,7 +8,7 @@ def initialize(user) end def submit - FormResponse.new(success: valid?, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: valid?, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/backup_code_verification_form.rb b/app/forms/backup_code_verification_form.rb index 46a8da3aeb8..db00adbc0e4 100644 --- a/app/forms/backup_code_verification_form.rb +++ b/app/forms/backup_code_verification_form.rb @@ -10,7 +10,6 @@ def submit(params) @backup_code = params[:backup_code] FormResponse.new( success: valid_backup_code?, - errors: {}, extra: extra_analytics_attributes, ) end diff --git a/app/forms/delete_user_email_form.rb b/app/forms/delete_user_email_form.rb index f81b72ca6e8..2097a19e9a1 100644 --- a/app/forms/delete_user_email_form.rb +++ b/app/forms/delete_user_email_form.rb @@ -13,7 +13,7 @@ def initialize(user, email_address) def submit success = valid? && email_address_destroyed notify_subscribers if success - FormResponse.new(success: success, errors: errors.messages) + FormResponse.new(success: success, errors: errors) end private diff --git a/app/forms/edit_phone_form.rb b/app/forms/edit_phone_form.rb index 4ad8512b302..ddd9eb57088 100644 --- a/app/forms/edit_phone_form.rb +++ b/app/forms/edit_phone_form.rb @@ -16,7 +16,7 @@ def submit(params) ingest_submitted_params(params) success = valid? update_phone_configuration if success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def masked_number diff --git a/app/forms/event_disavowal/password_reset_from_disavowal_form.rb b/app/forms/event_disavowal/password_reset_from_disavowal_form.rb index 94d506f4af8..5b214232184 100644 --- a/app/forms/event_disavowal/password_reset_from_disavowal_form.rb +++ b/app/forms/event_disavowal/password_reset_from_disavowal_form.rb @@ -15,7 +15,7 @@ def submit(params) success = valid? handle_valid_password if success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/idv/address_form.rb b/app/forms/idv/address_form.rb index dadb95964a2..4bfcc8cf7f8 100644 --- a/app/forms/idv/address_form.rb +++ b/app/forms/idv/address_form.rb @@ -18,7 +18,7 @@ def initialize(user) def submit(params) consume_params(params) - FormResponse.new(success: valid?, errors: errors.messages) + FormResponse.new(success: valid?, errors: errors) end private diff --git a/app/forms/idv/api_document_verification_form.rb b/app/forms/idv/api_document_verification_form.rb index 215ca19c498..c9cf72292e6 100644 --- a/app/forms/idv/api_document_verification_form.rb +++ b/app/forms/idv/api_document_verification_form.rb @@ -23,7 +23,7 @@ def submit FormResponse.new( success: valid?, - errors: errors.messages, + errors: errors, extra: { remaining_attempts: remaining_attempts, }, diff --git a/app/forms/idv/api_document_verification_status_form.rb b/app/forms/idv/api_document_verification_status_form.rb index ee61ff3c584..f6735c4d103 100644 --- a/app/forms/idv/api_document_verification_status_form.rb +++ b/app/forms/idv/api_document_verification_status_form.rb @@ -14,7 +14,7 @@ def initialize(async_state:, document_capture_session:) def submit FormResponse.new( success: valid?, - errors: errors.messages, + errors: errors, extra: { remaining_attempts: remaining_attempts, }, diff --git a/app/forms/idv/api_image_upload_form.rb b/app/forms/idv/api_image_upload_form.rb index 60a7d16980a..9e0ce1c0f5e 100644 --- a/app/forms/idv/api_image_upload_form.rb +++ b/app/forms/idv/api_image_upload_form.rb @@ -54,7 +54,7 @@ def throttled_else_increment def validate_form response = Idv::DocAuthFormResponse.new( success: valid?, - errors: errors.messages, + errors: errors, extra: extra_attributes, ) diff --git a/app/forms/idv/consent_form.rb b/app/forms/idv/consent_form.rb index 84357ececfb..c2b8ee1e8b1 100644 --- a/app/forms/idv/consent_form.rb +++ b/app/forms/idv/consent_form.rb @@ -7,7 +7,7 @@ class ConsentForm def submit(params) @ial2_consent_given = params[:ial2_consent_given] == 'true' - FormResponse.new(success: valid?, errors: errors.messages) + FormResponse.new(success: valid?, errors: errors) end def ial2_consent_given? diff --git a/app/forms/idv/doc_pii_form.rb b/app/forms/idv/doc_pii_form.rb index 707f6d58527..838fa39c76e 100644 --- a/app/forms/idv/doc_pii_form.rb +++ b/app/forms/idv/doc_pii_form.rb @@ -16,7 +16,7 @@ def initialize(pii) def submit Idv::DocAuthFormResponse.new( success: valid?, - errors: errors.messages, + errors: errors, ) end diff --git a/app/forms/idv/document_capture_form.rb b/app/forms/idv/document_capture_form.rb index b04fad978bf..24d1bc5cca4 100644 --- a/app/forms/idv/document_capture_form.rb +++ b/app/forms/idv/document_capture_form.rb @@ -26,7 +26,7 @@ def self.model_name def submit(params) consume_params(params) - FormResponse.new(success: valid?, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: valid?, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/idv/otp_delivery_method_form.rb b/app/forms/idv/otp_delivery_method_form.rb index af9b20a1f62..cf076bd8e38 100644 --- a/app/forms/idv/otp_delivery_method_form.rb +++ b/app/forms/idv/otp_delivery_method_form.rb @@ -8,7 +8,7 @@ class OtpDeliveryMethodForm def submit(params) self.otp_delivery_preference = params[:otp_delivery_preference] - FormResponse.new(success: valid?, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: valid?, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/idv/phone_confirmation_otp_verification_form.rb b/app/forms/idv/phone_confirmation_otp_verification_form.rb index c03170a9ecf..19016f09e6f 100644 --- a/app/forms/idv/phone_confirmation_otp_verification_form.rb +++ b/app/forms/idv/phone_confirmation_otp_verification_form.rb @@ -15,7 +15,7 @@ def submit(code:) else increment_second_factor_attempts end - FormResponse.new(success: success, errors: {}, extra: extra_analytics_attributes) + FormResponse.new(success: success, extra: extra_analytics_attributes) end private diff --git a/app/forms/idv/phone_form.rb b/app/forms/idv/phone_form.rb index 1ddd7c6ca5c..5a714e052d9 100644 --- a/app/forms/idv/phone_form.rb +++ b/app/forms/idv/phone_form.rb @@ -17,7 +17,7 @@ def submit(params) success = valid? self.phone = params[:phone] unless success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def user_has_multiple_phones? diff --git a/app/forms/idv/ssn_form.rb b/app/forms/idv/ssn_form.rb index be3c3140b78..e9eccf61a4f 100644 --- a/app/forms/idv/ssn_form.rb +++ b/app/forms/idv/ssn_form.rb @@ -22,7 +22,7 @@ def initialize(user) def submit(params) consume_params(params) - FormResponse.new(success: valid?, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: valid?, errors: errors, extra: extra_analytics_attributes) end def ssn_is_unique? diff --git a/app/forms/idv/ssn_format_form.rb b/app/forms/idv/ssn_format_form.rb index b0f0ce15199..422d7557657 100644 --- a/app/forms/idv/ssn_format_form.rb +++ b/app/forms/idv/ssn_format_form.rb @@ -18,7 +18,7 @@ def initialize(user) def submit(params) consume_params(params) - FormResponse.new(success: valid?, errors: errors.messages) + FormResponse.new(success: valid?, errors: errors) end private diff --git a/app/forms/new_phone_form.rb b/app/forms/new_phone_form.rb index 004c2d3690a..85090d89749 100644 --- a/app/forms/new_phone_form.rb +++ b/app/forms/new_phone_form.rb @@ -23,7 +23,7 @@ def submit(params) success = valid? self.phone = submitted_phone unless success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def delivery_preference_sms? diff --git a/app/forms/openid_connect_authorize_form.rb b/app/forms/openid_connect_authorize_form.rb index b84a9f6fbd8..b1b15ab6bc2 100644 --- a/app/forms/openid_connect_authorize_form.rb +++ b/app/forms/openid_connect_authorize_form.rb @@ -57,7 +57,7 @@ def initialize(params) def submit @success = valid? - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def verified_at_requested? diff --git a/app/forms/openid_connect_logout_form.rb b/app/forms/openid_connect_logout_form.rb index 86158c48a49..eb2cf6f74f5 100644 --- a/app/forms/openid_connect_logout_form.rb +++ b/app/forms/openid_connect_logout_form.rb @@ -32,7 +32,7 @@ def submit identity.deactivate if success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/openid_connect_token_form.rb b/app/forms/openid_connect_token_form.rb index 5e50e01f840..c8ec6d43cf2 100644 --- a/app/forms/openid_connect_token_form.rb +++ b/app/forms/openid_connect_token_form.rb @@ -39,7 +39,7 @@ def submit clear_authorization_code if success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def response diff --git a/app/forms/otp_delivery_selection_form.rb b/app/forms/otp_delivery_selection_form.rb index d31ac159890..8a66c75922a 100644 --- a/app/forms/otp_delivery_selection_form.rb +++ b/app/forms/otp_delivery_selection_form.rb @@ -23,7 +23,7 @@ def submit(params) change_otp_delivery_preference_to_sms end - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/otp_verification_form.rb b/app/forms/otp_verification_form.rb index deca633fdb0..1b40719e5ba 100644 --- a/app/forms/otp_verification_form.rb +++ b/app/forms/otp_verification_form.rb @@ -7,7 +7,6 @@ def initialize(user, code) def submit FormResponse.new( success: valid_direct_otp_code?, - errors: {}, extra: extra_analytics_attributes, ) end diff --git a/app/forms/password_form.rb b/app/forms/password_form.rb index 989a55fc2d9..cd8156718dc 100644 --- a/app/forms/password_form.rb +++ b/app/forms/password_form.rb @@ -12,7 +12,7 @@ def submit(params) self.password = submitted_password - FormResponse.new(success: valid?, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: valid?, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/password_reset_email_form.rb b/app/forms/password_reset_email_form.rb index b7a90b14b4a..ae2dddb092d 100644 --- a/app/forms/password_reset_email_form.rb +++ b/app/forms/password_reset_email_form.rb @@ -14,7 +14,7 @@ def resend def submit FormResponse.new( - success: valid?, errors: errors.messages, + success: valid?, errors: errors, extra: extra_analytics_attributes ) end diff --git a/app/forms/personal_key_form.rb b/app/forms/personal_key_form.rb index d4d57d234c5..e30b9345b2d 100644 --- a/app/forms/personal_key_form.rb +++ b/app/forms/personal_key_form.rb @@ -16,7 +16,7 @@ def submit reset_sensitive_fields unless success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/register_user_email_form.rb b/app/forms/register_user_email_form.rb index 203b70af4da..1475d3cbfcd 100644 --- a/app/forms/register_user_email_form.rb +++ b/app/forms/register_user_email_form.rb @@ -43,7 +43,7 @@ def submit(params, instructions = nil) self.success = process_errors(request_id) end - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def email_taken? diff --git a/app/forms/reset_password_form.rb b/app/forms/reset_password_form.rb index a63b666c5e5..24f20255d1a 100644 --- a/app/forms/reset_password_form.rb +++ b/app/forms/reset_password_form.rb @@ -18,7 +18,7 @@ def submit(params) handle_valid_password if success - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/security_event_form.rb b/app/forms/security_event_form.rb index 883b42c7964..73eb62de4da 100644 --- a/app/forms/security_event_form.rb +++ b/app/forms/security_event_form.rb @@ -48,7 +48,7 @@ def submit end end - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def error_code diff --git a/app/forms/totp_setup_form.rb b/app/forms/totp_setup_form.rb index 661424004b1..c9a3acab77f 100644 --- a/app/forms/totp_setup_form.rb +++ b/app/forms/totp_setup_form.rb @@ -19,7 +19,7 @@ def submit process_valid_submission if success - FormResponse.new(success: success, errors: {}, extra: extra_analytics_attributes) + FormResponse.new(success: success, extra: extra_analytics_attributes) end private diff --git a/app/forms/totp_verification_form.rb b/app/forms/totp_verification_form.rb index 8e80b5db8b2..f8485dc1bd7 100644 --- a/app/forms/totp_verification_form.rb +++ b/app/forms/totp_verification_form.rb @@ -8,7 +8,6 @@ def submit cfg = if_valid_totp_code_return_config FormResponse.new( success: cfg.present?, - errors: {}, extra: extra_analytics_attributes(cfg&.id), ) end diff --git a/app/forms/two_factor_authentication/phone_deletion_form.rb b/app/forms/two_factor_authentication/phone_deletion_form.rb index b66d73ea708..90a68980b0e 100644 --- a/app/forms/two_factor_authentication/phone_deletion_form.rb +++ b/app/forms/two_factor_authentication/phone_deletion_form.rb @@ -16,7 +16,7 @@ def initialize(user, configuration) def submit success = configuration.blank? || valid? && configuration_destroyed - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/two_factor_login_options_form.rb b/app/forms/two_factor_login_options_form.rb index b5da0a55ff1..88de98ad66e 100644 --- a/app/forms/two_factor_login_options_form.rb +++ b/app/forms/two_factor_login_options_form.rb @@ -16,7 +16,7 @@ def submit(params) success = valid? - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/forms/two_factor_options_form.rb b/app/forms/two_factor_options_form.rb index 3ca20fe14cc..58957a9bb7c 100644 --- a/app/forms/two_factor_options_form.rb +++ b/app/forms/two_factor_options_form.rb @@ -17,7 +17,7 @@ def submit(params) success = valid? update_otp_delivery_preference_for_user if success && user_needs_updating? - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def selected?(type) diff --git a/app/forms/update_email_language_form.rb b/app/forms/update_email_language_form.rb index e1505252a63..6449154f933 100644 --- a/app/forms/update_email_language_form.rb +++ b/app/forms/update_email_language_form.rb @@ -16,7 +16,7 @@ def submit(params) FormResponse.new( success: valid?, - errors: errors.messages, + errors: errors, ) end end diff --git a/app/forms/update_user_password_form.rb b/app/forms/update_user_password_form.rb index 6acdf01d64d..606706c732d 100644 --- a/app/forms/update_user_password_form.rb +++ b/app/forms/update_user_password_form.rb @@ -13,7 +13,7 @@ def submit(params) self.password = params[:password] success = valid? process_valid_submission if success - FormResponse.new(success: success, errors: errors.messages) + FormResponse.new(success: success, errors: errors) end private diff --git a/app/forms/verify_account_form.rb b/app/forms/verify_account_form.rb index 9441b96797a..485319f2e98 100644 --- a/app/forms/verify_account_form.rb +++ b/app/forms/verify_account_form.rb @@ -21,7 +21,7 @@ def submit else reset_sensitive_fields end - FormResponse.new(success: result, errors: errors.messages) + FormResponse.new(success: result, errors: errors) end protected diff --git a/app/forms/webauthn_setup_form.rb b/app/forms/webauthn_setup_form.rb index 4bdb07dc4a4..b9293487c7a 100644 --- a/app/forms/webauthn_setup_form.rb +++ b/app/forms/webauthn_setup_form.rb @@ -28,7 +28,7 @@ def submit(protocol, params) PushNotification::HttpPush.deliver(event) end - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end # this gives us a hook to override the domain embedded in the attestation test object diff --git a/app/forms/webauthn_verification_form.rb b/app/forms/webauthn_verification_form.rb index 2801899cc6b..d51f5f23bd4 100644 --- a/app/forms/webauthn_verification_form.rb +++ b/app/forms/webauthn_verification_form.rb @@ -25,7 +25,7 @@ def submit(protocol, params) success = valid? && valid_assertion_response?(protocol) FormResponse.new( success: success, - errors: errors.messages, + errors: errors, extra: extra_analytics_attributes, ) end diff --git a/app/forms/webauthn_visit_form.rb b/app/forms/webauthn_visit_form.rb index c27086dae5a..b192975b3c0 100644 --- a/app/forms/webauthn_visit_form.rb +++ b/app/forms/webauthn_visit_form.rb @@ -3,7 +3,7 @@ class WebauthnVisitForm def submit(params) check_params(params) - FormResponse.new(success: errors.empty?, errors: errors.messages) + FormResponse.new(success: errors.empty?, errors: errors) end def check_params(params) diff --git a/app/services/account_reset/cancel.rb b/app/services/account_reset/cancel.rb index 8b6c9917414..aba0aaab092 100644 --- a/app/services/account_reset/cancel.rb +++ b/app/services/account_reset/cancel.rb @@ -16,7 +16,7 @@ def call update_account_reset_request end - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/services/account_reset/create_request.rb b/app/services/account_reset/create_request.rb index 49fc259e924..041b1e12e51 100644 --- a/app/services/account_reset/create_request.rb +++ b/app/services/account_reset/create_request.rb @@ -11,7 +11,6 @@ def call FormResponse.new( success: true, - errors: {}, extra: extra_analytics_attributes, ) end diff --git a/app/services/account_reset/delete_account.rb b/app/services/account_reset/delete_account.rb index 43863e6dd19..521430cd50d 100644 --- a/app/services/account_reset/delete_account.rb +++ b/app/services/account_reset/delete_account.rb @@ -17,7 +17,7 @@ def call handle_successful_submission if success - FormResponse.new(success: success, errors: errors.messages, extra: extra) + FormResponse.new(success: success, errors: errors, extra: extra) end private diff --git a/app/services/account_reset/validate_cancel_token.rb b/app/services/account_reset/validate_cancel_token.rb index 66d79d0ed65..d7e8dd78768 100644 --- a/app/services/account_reset/validate_cancel_token.rb +++ b/app/services/account_reset/validate_cancel_token.rb @@ -10,7 +10,7 @@ def initialize(token) def call @success = valid? - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/services/account_reset/validate_granted_token.rb b/app/services/account_reset/validate_granted_token.rb index 385416032e7..8fd166c12b4 100644 --- a/app/services/account_reset/validate_granted_token.rb +++ b/app/services/account_reset/validate_granted_token.rb @@ -10,7 +10,7 @@ def initialize(token) def call @success = valid? - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/services/capture_doc/validate_document_capture_session.rb b/app/services/capture_doc/validate_document_capture_session.rb index 0592c462c04..4cda3510eb5 100644 --- a/app/services/capture_doc/validate_document_capture_session.rb +++ b/app/services/capture_doc/validate_document_capture_session.rb @@ -10,7 +10,7 @@ def initialize(session_uuid) def call @success = valid? - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/services/email_confirmation_token_validator.rb b/app/services/email_confirmation_token_validator.rb index 63b6d7bc2be..394a91eaeec 100644 --- a/app/services/email_confirmation_token_validator.rb +++ b/app/services/email_confirmation_token_validator.rb @@ -16,7 +16,7 @@ def initialize(email_address, current_user = nil) def submit @success = valid? && @email_address.present? - FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: success, errors: errors, extra: extra_analytics_attributes) end def email_address_already_confirmed? diff --git a/app/services/flow/base_flow.rb b/app/services/flow/base_flow.rb index 76bc767a39f..8b527a7a8ad 100644 --- a/app/services/flow/base_flow.rb +++ b/app/services/flow/base_flow.rb @@ -76,7 +76,7 @@ def form_response(obj, value) end def successful_response - FormResponse.new(success: true, errors: {}) + FormResponse.new(success: true) end delegate :flash, :session, :current_user, :params, :request, :poll_with_meta_refresh, diff --git a/app/services/flow/base_step.rb b/app/services/flow/base_step.rb index bd717862d9a..d33033bff01 100644 --- a/app/services/flow/base_step.rb +++ b/app/services/flow/base_step.rb @@ -47,7 +47,7 @@ def create_response(form_submit_response, call_response) end def form_submit - FormResponse.new(success: true, errors: {}) + FormResponse.new(success: true) end def failure(message, extra = nil) diff --git a/app/services/form_response.rb b/app/services/form_response.rb index da7bed79937..c3a5bbe201d 100644 --- a/app/services/form_response.rb +++ b/app/services/form_response.rb @@ -1,7 +1,8 @@ class FormResponse - def initialize(success:, errors:, extra: {}) + def initialize(success:, errors: {}, extra: {}) @success = success - @errors = errors.to_hash + @errors = errors.is_a?(ActiveModel::Errors) ? errors.messages.to_hash : errors + @error_details = errors.details if errors.is_a?(ActiveModel::Errors) @extra = extra end @@ -12,15 +13,23 @@ def success? end def to_h - { success: success, errors: errors }.merge!(extra) + { success: success, errors: errors }.merge!(extra).tap do |hash| + hash[:error_details] = flatten_details(error_details) if error_details.present? + end end def merge(other) - FormResponse.new( + self.class.new( success: success? && other.success?, - errors: errors.merge(other.errors), + errors: errors.merge(other.errors, &method(:merge_arrays)), extra: extra.merge(other.extra), - ) + ).tap do |merged_response| + own_details = error_details + other_details = other.instance_eval { error_details } if other.is_a?(self.class) + merged_response.instance_eval do + @error_details = Hash(own_details).merge(Hash(other_details), &method(:merge_arrays)) + end + end end def first_error_message @@ -37,5 +46,14 @@ def ==(other) private + def merge_arrays(_key, first, second) + Array(first) + Array(second) + end + + def flatten_details(details) + details.transform_values { |errors| errors.pluck(:error) } + end + attr_reader :success + attr_accessor :error_details end diff --git a/app/services/idv/send_phone_confirmation_otp.rb b/app/services/idv/send_phone_confirmation_otp.rb index 46912a1181f..3d48c769602 100644 --- a/app/services/idv/send_phone_confirmation_otp.rb +++ b/app/services/idv/send_phone_confirmation_otp.rb @@ -31,7 +31,6 @@ def user_locked_out? def too_many_otp_sends_response FormResponse.new( success: false, - errors: {}, extra: extra_analytics_attributes, ) end @@ -67,7 +66,7 @@ def send_otp def otp_sent_response FormResponse.new( - success: telephony_response.success?, errors: {}, extra: extra_analytics_attributes, + success: telephony_response.success?, extra: extra_analytics_attributes, ) end diff --git a/app/services/idv/steps/document_capture_step.rb b/app/services/idv/steps/document_capture_step.rb index 05bc4d3ba96..98abee22d52 100644 --- a/app/services/idv/steps/document_capture_step.rb +++ b/app/services/idv/steps/document_capture_step.rb @@ -126,7 +126,7 @@ def selfie_image end def form_submit - return FormResponse.new(success: true, errors: {}) if request_should_use_stored_result? + return FormResponse.new(success: true) if request_should_use_stored_result? Idv::DocumentCaptureForm. new(liveness_checking_enabled: liveness_checking_enabled?). diff --git a/app/services/password_reset_token_validator.rb b/app/services/password_reset_token_validator.rb index ba608b3f1ea..54f271f4725 100644 --- a/app/services/password_reset_token_validator.rb +++ b/app/services/password_reset_token_validator.rb @@ -9,7 +9,7 @@ def initialize(user) end def submit - FormResponse.new(success: valid?, errors: errors.messages, extra: { user_id: user&.uuid }) + FormResponse.new(success: valid?, errors: errors, extra: { user_id: user&.uuid }) end private diff --git a/app/services/saml_request_validator.rb b/app/services/saml_request_validator.rb index 3c66bdb807e..bade7f40662 100644 --- a/app/services/saml_request_validator.rb +++ b/app/services/saml_request_validator.rb @@ -10,7 +10,7 @@ def call(service_provider:, authn_context:, nameid_format:) self.authn_context = Array(authn_context) self.nameid_format = nameid_format - FormResponse.new(success: valid?, errors: errors.messages, extra: extra_analytics_attributes) + FormResponse.new(success: valid?, errors: errors, extra: extra_analytics_attributes) end private diff --git a/app/services/user_alerts/alert_user_about_personal_key_sign_in.rb b/app/services/user_alerts/alert_user_about_personal_key_sign_in.rb index fbc10d567b4..9bfe7f23713 100644 --- a/app/services/user_alerts/alert_user_about_personal_key_sign_in.rb +++ b/app/services/user_alerts/alert_user_about_personal_key_sign_in.rb @@ -16,7 +16,6 @@ def self.call(user, disavowal_token) def self.form_response(emails:, telephony_responses:) FormResponse.new( success: true, - errors: {}, extra: { emails: emails.count, sms_message_ids: telephony_responses.map { |resp| resp.to_h[:message_id] }, diff --git a/spec/controllers/account_reset/cancel_controller_spec.rb b/spec/controllers/account_reset/cancel_controller_spec.rb index 06e7a8981fa..f4f3f00446c 100644 --- a/spec/controllers/account_reset/cancel_controller_spec.rb +++ b/spec/controllers/account_reset/cancel_controller_spec.rb @@ -31,6 +31,7 @@ analytics_hash = { success: false, errors: { token: [t('errors.account_reset.cancel_token_invalid')] }, + error_details: { token: [t('errors.account_reset.cancel_token_invalid')] }, event: 'cancel', user_id: 'anonymous-uuid', } @@ -47,6 +48,7 @@ analytics_hash = { success: false, errors: { token: [t('errors.account_reset.cancel_token_missing')] }, + error_details: { token: [:blank] }, event: 'cancel', user_id: 'anonymous-uuid', } @@ -93,6 +95,7 @@ event: 'cancel token validation', success: false, errors: { token: [t('errors.account_reset.cancel_token_invalid')] }, + error_details: { token: [t('errors.account_reset.cancel_token_invalid')] }, } expect(@analytics). to receive(:track_event).with(Analytics::ACCOUNT_RESET, properties) diff --git a/spec/controllers/account_reset/delete_account_controller_spec.rb b/spec/controllers/account_reset/delete_account_controller_spec.rb index cc6a4ce822d..d8b28ce232e 100644 --- a/spec/controllers/account_reset/delete_account_controller_spec.rb +++ b/spec/controllers/account_reset/delete_account_controller_spec.rb @@ -37,6 +37,7 @@ event: 'delete', success: false, errors: { token: [t('errors.account_reset.granted_token_invalid')] }, + error_details: { token: [t('errors.account_reset.granted_token_invalid')] }, mfa_method_counts: {}, account_age_in_days: 0, } @@ -56,6 +57,7 @@ event: 'delete', success: false, errors: { token: [t('errors.account_reset.granted_token_missing')] }, + error_details: { token: [:blank] }, mfa_method_counts: {}, account_age_in_days: 0, } @@ -79,6 +81,7 @@ event: 'delete', success: false, errors: { token: [t('errors.account_reset.granted_token_expired')] }, + error_details: { token: [t('errors.account_reset.granted_token_expired')] }, mfa_method_counts: {}, account_age_in_days: 2, } @@ -103,6 +106,7 @@ event: 'granted token validation', success: false, errors: { token: [t('errors.account_reset.granted_token_invalid')] }, + error_details: { token: [t('errors.account_reset.granted_token_invalid')] }, } expect(@analytics). to receive(:track_event).with(Analytics::ACCOUNT_RESET, properties) @@ -124,6 +128,7 @@ event: 'granted token validation', success: false, errors: { token: [t('errors.account_reset.granted_token_expired')] }, + error_details: { token: [t('errors.account_reset.granted_token_expired')] }, } expect(@analytics).to receive(:track_event). with(Analytics::ACCOUNT_RESET, properties) diff --git a/spec/controllers/idv/doc_auth_controller_spec.rb b/spec/controllers/idv/doc_auth_controller_spec.rb index 132568b4550..ecdedea3ef9 100644 --- a/spec/controllers/idv/doc_auth_controller_spec.rb +++ b/spec/controllers/idv/doc_auth_controller_spec.rb @@ -385,6 +385,7 @@ expect(@analytics).to have_received(:track_event).with( 'IdV: ' + "#{Analytics::DOC_AUTH} verify_document_status submitted".downcase, { errors: { pii: [I18n.t('doc_auth.errors.general.no_liveness')] }, + error_details: { pii: [I18n.t('doc_auth.errors.general.no_liveness')] }, success: false, remaining_attempts: IdentityConfig.store.acuant_max_attempts, step: 'verify_document_status', @@ -395,6 +396,7 @@ expect(@analytics).to have_received(:track_event).with( Analytics::DOC_AUTH + ' submitted', { errors: { pii: [I18n.t('doc_auth.errors.general.no_liveness')] }, + error_details: { pii: [I18n.t('doc_auth.errors.general.no_liveness')] }, success: false, remaining_attempts: IdentityConfig.store.acuant_max_attempts, step: 'verify_document_status', diff --git a/spec/controllers/idv/image_uploads_controller_spec.rb b/spec/controllers/idv/image_uploads_controller_spec.rb index 42af8e008c0..ed716dbc93a 100644 --- a/spec/controllers/idv/image_uploads_controller_spec.rb +++ b/spec/controllers/idv/image_uploads_controller_spec.rb @@ -44,6 +44,9 @@ errors: { front: ['Please fill in this field.'], }, + error_details: { + front: [:blank], + }, user_id: user.uuid, remaining_attempts: IdentityConfig.store.acuant_max_attempts - 1, ) @@ -93,6 +96,9 @@ errors: { front: [I18n.t('doc_auth.errors.not_a_file')], }, + error_details: { + front: [I18n.t('doc_auth.errors.not_a_file')], + }, user_id: user.uuid, remaining_attempts: IdentityConfig.store.acuant_max_attempts - 1, ) @@ -176,6 +182,9 @@ errors: { limit: [I18n.t('errors.doc_auth.throttled_heading')], }, + error_details: { + limit: [I18n.t('errors.doc_auth.throttled_heading')], + }, user_id: user.uuid, remaining_attempts: 0, ) @@ -301,6 +310,9 @@ errors: { pii: [I18n.t('doc_auth.errors.alerts.full_name_check')], }, + error_details: { + pii: [I18n.t('doc_auth.errors.alerts.full_name_check')], + }, user_id: user.uuid, remaining_attempts: IdentityConfig.store.acuant_max_attempts - 1, ) @@ -346,6 +358,9 @@ errors: { pii: [I18n.t('doc_auth.errors.general.no_liveness')], }, + error_details: { + pii: [I18n.t('doc_auth.errors.general.no_liveness')], + }, user_id: user.uuid, remaining_attempts: IdentityConfig.store.acuant_max_attempts - 1, ) @@ -391,6 +406,9 @@ errors: { pii: [I18n.t('doc_auth.errors.alerts.birth_date_checks')], }, + error_details: { + pii: [I18n.t('doc_auth.errors.alerts.birth_date_checks')], + }, user_id: user.uuid, remaining_attempts: IdentityConfig.store.acuant_max_attempts - 1, ) diff --git a/spec/controllers/idv/otp_delivery_method_controller_spec.rb b/spec/controllers/idv/otp_delivery_method_controller_spec.rb index 532d0876346..b96087e3bad 100644 --- a/spec/controllers/idv/otp_delivery_method_controller_spec.rb +++ b/spec/controllers/idv/otp_delivery_method_controller_spec.rb @@ -176,6 +176,7 @@ result = { success: false, errors: { otp_delivery_preference: ['is not included in the list'] }, + error_details: { otp_delivery_preference: [:inclusion] }, otp_delivery_preference: '🎷', } diff --git a/spec/controllers/idv/phone_controller_spec.rb b/spec/controllers/idv/phone_controller_spec.rb index 357c84f8d05..d1629238e0f 100644 --- a/spec/controllers/idv/phone_controller_spec.rb +++ b/spec/controllers/idv/phone_controller_spec.rb @@ -133,6 +133,9 @@ errors: { phone: [t('errors.messages.must_have_us_country_code')], }, + error_details: { + phone: [:must_have_us_country_code], + }, country_code: nil, area_code: nil, } diff --git a/spec/controllers/openid_connect/authorization_controller_spec.rb b/spec/controllers/openid_connect/authorization_controller_spec.rb index 27868dc0dc2..8ee86315800 100644 --- a/spec/controllers/openid_connect/authorization_controller_spec.rb +++ b/spec/controllers/openid_connect/authorization_controller_spec.rb @@ -178,6 +178,7 @@ client_id: client_id, unauthorized_scope: true, errors: hash_including(:prompt), + error_details: hash_including(:prompt), user_fully_authenticated: true) expect(@analytics).to_not receive(:track_event).with(Analytics::SP_REDIRECT_INITIATED) @@ -201,6 +202,7 @@ client_id: nil, unauthorized_scope: true, errors: hash_including(:client_id), + error_details: hash_including(:client_id), user_fully_authenticated: true) expect(@analytics).to_not receive(:track_event).with(Analytics::SP_REDIRECT_INITIATED) diff --git a/spec/controllers/openid_connect/logout_controller_spec.rb b/spec/controllers/openid_connect/logout_controller_spec.rb index d187d626640..c5c5f8feb98 100644 --- a/spec/controllers/openid_connect/logout_controller_spec.rb +++ b/spec/controllers/openid_connect/logout_controller_spec.rb @@ -91,6 +91,7 @@ success: false, client_id: service_provider, errors: errors, + error_details: hash_including(*errors.keys), sp_initiated: true, oidc: true) diff --git a/spec/controllers/openid_connect/token_controller_spec.rb b/spec/controllers/openid_connect/token_controller_spec.rb index 38915b9ac4e..04ef9564c10 100644 --- a/spec/controllers/openid_connect/token_controller_spec.rb +++ b/spec/controllers/openid_connect/token_controller_spec.rb @@ -75,7 +75,8 @@ success: false, client_id: client_id, user_id: user.uuid, - errors: hash_including(:grant_type)) + errors: hash_including(:grant_type), + error_details: hash_including(:grant_type)) action end diff --git a/spec/controllers/openid_connect/user_info_controller_spec.rb b/spec/controllers/openid_connect/user_info_controller_spec.rb index 32696d7f0ea..a3750b33bb8 100644 --- a/spec/controllers/openid_connect/user_info_controller_spec.rb +++ b/spec/controllers/openid_connect/user_info_controller_spec.rb @@ -21,7 +21,9 @@ stub_analytics expect(@analytics).to receive(:track_event). with(Analytics::OPENID_CONNECT_BEARER_TOKEN, - success: false, errors: hash_including(:access_token)) + success: false, + errors: hash_including(:access_token), + error_details: hash_including(:access_token)) action end @@ -41,7 +43,9 @@ stub_analytics expect(@analytics).to receive(:track_event). with(Analytics::OPENID_CONNECT_BEARER_TOKEN, - success: false, errors: hash_including(:access_token)) + success: false, + errors: hash_including(:access_token), + error_details: hash_including(:access_token)) action end @@ -60,7 +64,9 @@ stub_analytics expect(@analytics).to receive(:track_event). with(Analytics::OPENID_CONNECT_BEARER_TOKEN, - success: false, errors: hash_including(:access_token)) + success: false, + errors: hash_including(:access_token), + error_details: hash_including(:access_token)) action end diff --git a/spec/controllers/risc/security_events_controller_spec.rb b/spec/controllers/risc/security_events_controller_spec.rb index d22410c3dbe..dae4d633b0e 100644 --- a/spec/controllers/risc/security_events_controller_spec.rb +++ b/spec/controllers/risc/security_events_controller_spec.rb @@ -81,6 +81,7 @@ client_id: service_provider.issuer, error_code: SecurityEventForm::ErrorCodes::JWT_AUD, errors: kind_of(Hash), + error_details: kind_of(Hash), jti: jti, success: false, user_id: user.uuid) diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb index 5a82a611f31..782095b9b16 100644 --- a/spec/controllers/saml_idp_controller_spec.rb +++ b/spec/controllers/saml_idp_controller_spec.rb @@ -300,6 +300,7 @@ def name_id_version(format_urn) analytics_hash = { success: false, errors: { authn_context: [t('errors.messages.unauthorized_authn_context')] }, + error_details: { authn_context: [:unauthorized_authn_context] }, nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT, authn_context: ['http://idmanagement.gov/ns/assurance/loa/5'], service_provider: 'http://localhost:3000', @@ -384,6 +385,7 @@ def name_id_version(format_urn) analytics_hash = { success: false, errors: { service_provider: [t('errors.messages.unauthorized_service_provider')] }, + error_details: { service_provider: [:unauthorized_service_provider] }, nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT, authn_context: request_authn_contexts, service_provider: 'invalid_provider', @@ -414,6 +416,10 @@ def name_id_version(format_urn) service_provider: [t('errors.messages.unauthorized_service_provider')], authn_context: [t('errors.messages.unauthorized_authn_context')], }, + error_details: { + authn_context: [:unauthorized_authn_context], + service_provider: [:unauthorized_service_provider], + }, nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT, authn_context: ['http://idmanagement.gov/ns/assurance/loa/5'], service_provider: 'invalid_provider', @@ -655,6 +661,7 @@ def name_id_version(format_urn) analytics_hash = { success: false, errors: { nameid_format: [t('errors.messages.unauthorized_nameid_format')] }, + error_details: { nameid_format: [:unauthorized_nameid_format] }, nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_EMAIL, authn_context: request_authn_contexts, service_provider: 'http://localhost:3000', diff --git a/spec/controllers/sign_up/email_confirmations_controller_spec.rb b/spec/controllers/sign_up/email_confirmations_controller_spec.rb index 982724ab099..17ac25c62f4 100644 --- a/spec/controllers/sign_up/email_confirmations_controller_spec.rb +++ b/spec/controllers/sign_up/email_confirmations_controller_spec.rb @@ -95,6 +95,7 @@ analytics_hash = { success: false, errors: { confirmation_token: [t('errors.messages.expired')] }, + error_details: { confirmation_token: [:expired] }, user_id: user.uuid, } @@ -118,6 +119,7 @@ analytics_hash = { success: false, errors: { confirmation_token: [t('errors.messages.expired')] }, + error_details: { confirmation_token: [:expired] }, user_id: user.uuid, } diff --git a/spec/controllers/sign_up/passwords_controller_spec.rb b/spec/controllers/sign_up/passwords_controller_spec.rb index f8ab511db83..bbbdf136abf 100644 --- a/spec/controllers/sign_up/passwords_controller_spec.rb +++ b/spec/controllers/sign_up/passwords_controller_spec.rb @@ -46,6 +46,9 @@ errors: { password: ["is too short (minimum is #{Devise.password_length.first} characters)"], }, + error_details: { + password: [:too_short], + }, user_id: user.uuid, request_id_present: false, } diff --git a/spec/controllers/sign_up/registrations_controller_spec.rb b/spec/controllers/sign_up/registrations_controller_spec.rb index c132e6b8a7d..8ec92258d78 100644 --- a/spec/controllers/sign_up/registrations_controller_spec.rb +++ b/spec/controllers/sign_up/registrations_controller_spec.rb @@ -111,6 +111,7 @@ success: false, throttled: false, errors: { email: [t('valid_email.validations.email.invalid')] }, + error_details: { email: [t('valid_email.validations.email.invalid')] }, email_already_exists: false, user_id: 'anonymous-uuid', domain_name: 'invalid', diff --git a/spec/controllers/users/passwords_controller_spec.rb b/spec/controllers/users/passwords_controller_spec.rb index 2ee897512d3..5cb261b0224 100644 --- a/spec/controllers/users/passwords_controller_spec.rb +++ b/spec/controllers/users/passwords_controller_spec.rb @@ -72,14 +72,16 @@ params = { password: 'new' } patch :update, params: { update_user_password_form: params } - errors = { - password: [ - t('errors.messages.too_short.other', count: Devise.password_length.first), - ], - } - - expect(@analytics).to have_received(:track_event). - with(Analytics::PASSWORD_CHANGED, success: false, errors: errors) + expect(@analytics).to have_received(:track_event).with( + Analytics::PASSWORD_CHANGED, + success: false, + errors: { + password: [ + t('errors.messages.too_short.other', count: Devise.password_length.first), + ], + }, + error_details: { password: [:too_short] }, + ) expect(response).to render_template(:edit) end diff --git a/spec/controllers/users/phone_setup_controller_spec.rb b/spec/controllers/users/phone_setup_controller_spec.rb index 328fd9e4e9c..6f8387c1b16 100644 --- a/spec/controllers/users/phone_setup_controller_spec.rb +++ b/spec/controllers/users/phone_setup_controller_spec.rb @@ -47,6 +47,12 @@ t('two_factor_authentication.otp_delivery_preference.phone_unsupported', location: ''), ], }, + error_details: { + phone: [ + :improbable_phone, + t('two_factor_authentication.otp_delivery_preference.phone_unsupported', location: ''), + ], + }, otp_delivery_preference: 'sms', area_code: nil, carrier: 'Test Mobile Carrier', diff --git a/spec/controllers/users/reset_passwords_controller_spec.rb b/spec/controllers/users/reset_passwords_controller_spec.rb index 749311d41d4..fba5a9119dd 100644 --- a/spec/controllers/users/reset_passwords_controller_spec.rb +++ b/spec/controllers/users/reset_passwords_controller_spec.rb @@ -12,6 +12,7 @@ analytics_hash = { success: false, errors: { user: ['invalid_token'] }, + error_details: { user: [:blank] }, user_id: nil, } @@ -37,6 +38,7 @@ analytics_hash = { success: false, errors: { user: ['token_expired'] }, + error_details: { user: ['token_expired'] }, user_id: '123', } @@ -100,6 +102,10 @@ password: ["is too short (minimum is #{Devise.password_length.first} characters)"], reset_password_token: ['token_expired'], }, + error_details: { + password: [:too_short], + reset_password_token: ['token_expired'], + }, user_id: user.uuid, profile_deactivated: false, } @@ -130,6 +136,9 @@ errors: { password: ["is too short (minimum is #{Devise.password_length.first} characters)"], }, + error_details: { + password: [:too_short], + }, user_id: user.uuid, profile_deactivated: false, } @@ -410,6 +419,7 @@ analytics_hash = { success: false, errors: { email: [t('valid_email.validations.email.invalid')] }, + error_details: { email: [t('valid_email.validations.email.invalid')] }, user_id: 'nonexistent-uuid', confirmed: false, active_profile: false, diff --git a/spec/controllers/users/verify_account_controller_spec.rb b/spec/controllers/users/verify_account_controller_spec.rb index 6bbba31a6c8..bbcf565e008 100644 --- a/spec/controllers/users/verify_account_controller_spec.rb +++ b/spec/controllers/users/verify_account_controller_spec.rb @@ -112,7 +112,9 @@ it 'redirects to the index page to show errors' do expect(@analytics).to receive(:track_event).with( Analytics::ACCOUNT_VERIFICATION_SUBMITTED, - success: false, errors: { otp: [t('errors.messages.confirmation_code_incorrect')]}, + success: false, + errors: { otp: [t('errors.messages.confirmation_code_incorrect')]}, + error_details: { otp: [:confirmation_code_incorrect]}, ) action @@ -129,7 +131,9 @@ expect(@analytics).to receive(:track_event).with( Analytics::ACCOUNT_VERIFICATION_SUBMITTED, - success: false, errors: { otp: [t('errors.messages.confirmation_code_incorrect')]}, + success: false, + errors: { otp: [t('errors.messages.confirmation_code_incorrect')]}, + error_details: { otp: [:confirmation_code_incorrect]}, ).exactly(max_attempts).times expect(@analytics).to receive(:track_event).with( diff --git a/spec/forms/openid_connect_authorize_form_spec.rb b/spec/forms/openid_connect_authorize_form_spec.rb index 9ae2a4ac592..c124087fbda 100644 --- a/spec/forms/openid_connect_authorize_form_spec.rb +++ b/spec/forms/openid_connect_authorize_form_spec.rb @@ -39,18 +39,13 @@ context 'with valid params' do it 'is successful' do - allow(FormResponse).to receive(:new) - - form.submit - - extra_attributes = { + expect(result.to_h).to eq( + success: true, + errors: {}, client_id: client_id, redirect_uri: nil, unauthorized_scope: true, - } - - expect(FormResponse).to have_received(:new). - with(success: true, errors: {}, extra: extra_attributes) + ) end end @@ -59,20 +54,15 @@ let(:response_type) { nil } it 'is unsuccessful and has error messages' do - form_response = instance_double(FormResponse) - - extra_attributes = { + expect(result.to_h).to eq( + success: false, + errors: { response_type: ['is not included in the list'] }, + error_details: { response_type: [:inclusion] }, client_id: client_id, redirect_uri: "#{redirect_uri}?error=invalid_request&error_description=" \ "Response+type+is+not+included+in+the+list&state=#{state}", unauthorized_scope: true, - } - - errors = { response_type: ['is not included in the list'] } - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra_attributes).and_return(form_response) - expect(result).to eq form_response + ) end end end diff --git a/spec/forms/openid_connect_token_form_spec.rb b/spec/forms/openid_connect_token_form_spec.rb index 401620cb42f..f238b840dd4 100644 --- a/spec/forms/openid_connect_token_form_spec.rb +++ b/spec/forms/openid_connect_token_form_spec.rb @@ -383,14 +383,14 @@ describe '#submit' do context 'with valid params' do it 'returns FormResponse with success: true' do - response = instance_double(FormResponse) - allow(FormResponse).to receive(:new).and_return(response) - submission = form.submit - expect(submission).to eq response - expect(FormResponse).to have_received(:new). - with(success: true, errors: {}, extra: { client_id: client_id, user_id: user.uuid }) + expect(submission.to_h).to eq( + success: true, + errors: {}, + client_id: client_id, + user_id: user.uuid, + ) end end @@ -398,15 +398,15 @@ let(:code) { nil } it 'returns FormResponse with success: false' do - response = instance_double(FormResponse) - allow(FormResponse).to receive(:new).and_return(response) - submission = form.submit - expect(submission).to eq response - expect(FormResponse).to have_received(:new). - with(success: false, errors: form.errors.messages, extra: { client_id: nil, - user_id: nil }) + expect(submission.to_h).to include( + success: false, + errors: form.errors.messages, + error_details: hash_including(*form.errors.keys), + client_id: nil, + user_id: nil, + ) end end end diff --git a/spec/forms/otp_delivery_selection_form_spec.rb b/spec/forms/otp_delivery_selection_form_spec.rb index d18d4246929..a8744236c74 100644 --- a/spec/forms/otp_delivery_selection_form_spec.rb +++ b/spec/forms/otp_delivery_selection_form_spec.rb @@ -30,11 +30,11 @@ context: 'authentication', } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(subject.submit(otp_delivery_preference: 'sms', resend: true)).to eq result + expect(subject.submit(otp_delivery_preference: 'sms', resend: true).to_h).to eq( + success: true, + errors: {}, + **extra, + ) end end @@ -53,16 +53,18 @@ context: 'authentication', } - result = instance_double(FormResponse) subject = OtpDeliverySelectionForm.new( build_stubbed(:user), nil, 'authentication', ) - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(subject.submit(otp_delivery_preference: 'foo')).to eq result + expect(subject.submit(otp_delivery_preference: 'foo').to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end diff --git a/spec/forms/otp_verification_form_spec.rb b/spec/forms/otp_verification_form_spec.rb index cb30289d402..9350e9aad95 100644 --- a/spec/forms/otp_verification_form_spec.rb +++ b/spec/forms/otp_verification_form_spec.rb @@ -7,14 +7,14 @@ user = build_stubbed(:user) code = '123456' form = OtpVerificationForm.new(user, code) - result = instance_double(FormResponse) allow(user).to receive(:authenticate_direct_otp).with(code).and_return(true) - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: { multi_factor_auth_method: 'otp_code' }). - and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to eq( + success: true, + errors: {}, + multi_factor_auth_method: 'otp_code', + ) end end @@ -23,12 +23,12 @@ user = build_stubbed(:user) code = '123456' form = OtpVerificationForm.new(user, code) - result = instance_double(FormResponse) - expect(FormResponse).to receive(:new). - with(success: false, errors: {}, extra: { multi_factor_auth_method: 'otp_code' }). - and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to eq( + success: false, + errors: {}, + multi_factor_auth_method: 'otp_code', + ) end end diff --git a/spec/forms/password_reset_email_form_spec.rb b/spec/forms/password_reset_email_form_spec.rb index fc8d98d82b0..887e0829a33 100644 --- a/spec/forms/password_reset_email_form_spec.rb +++ b/spec/forms/password_reset_email_form_spec.rb @@ -12,34 +12,26 @@ user = create(:user, :signed_up, email: 'test1@test.com') subject = PasswordResetEmailForm.new('Test1@test.com') - extra = { + expect(subject.submit.to_h).to eq( + success: true, + errors: {}, user_id: user.uuid, confirmed: true, active_profile: false, - } - - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(subject.submit).to eq result + ) expect(subject).to respond_to(:resend) end end context 'when email is valid and user does not exist' do it 'returns hash with properties about the event and the nonexistent user' do - extra = { + expect(subject.submit.to_h).to eq( + success: true, + errors: {}, user_id: 'nonexistent-uuid', confirmed: false, active_profile: false, - } - - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(subject.submit).to eq result + ) end end @@ -49,17 +41,14 @@ errors = { email: [t('valid_email.validations.email.invalid')] } - extra = { + expect(subject.submit.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), user_id: 'nonexistent-uuid', confirmed: false, active_profile: false, - } - - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(subject.submit).to eq result + ) end end end diff --git a/spec/forms/personal_key_form_spec.rb b/spec/forms/personal_key_form_spec.rb index 83120fc7bb9..40af570aa89 100644 --- a/spec/forms/personal_key_form_spec.rb +++ b/spec/forms/personal_key_form_spec.rb @@ -9,12 +9,13 @@ old_code = user.reload.encrypted_recovery_code_digest form = PersonalKeyForm.new(user, raw_code) - result = instance_double(FormResponse) extra = { multi_factor_auth_method: 'personal key' } - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to eq( + success: true, + errors: {}, + **extra, + ) expect(user.reload.encrypted_recovery_code_digest).to eq old_code end end @@ -25,12 +26,14 @@ errors = { personal_key: ['Incorrect personal key'] } form = PersonalKeyForm.new(user, 'foo') - result = instance_double(FormResponse) extra = { multi_factor_auth_method: 'personal key' } - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) expect(user.encrypted_recovery_code_digest).to_not be_nil expect(form.personal_key).to be_nil end diff --git a/spec/forms/register_user_email_form_spec.rb b/spec/forms/register_user_email_form_spec.rb index a8de431837b..bf60ae303c6 100644 --- a/spec/forms/register_user_email_form_spec.rb +++ b/spec/forms/register_user_email_form_spec.rb @@ -23,11 +23,11 @@ domain_name: 'gmail.com', } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(subject.submit(email: 'TAKEN@gmail.com')).to eq result + expect(subject.submit(email: 'TAKEN@gmail.com').to_h).to eq( + success: true, + errors: {}, + **extra, + ) expect(subject.email).to eq 'taken@gmail.com' expect(mailer).to have_received(:deliver_now) end @@ -64,11 +64,11 @@ domain_name: 'test.com', } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(subject.submit(email: user.email)).to eq result + expect(subject.submit(email: user.email).to_h).to eq( + success: true, + errors: {}, + **extra, + ) end it 'creates throttle events after reaching throttle limit' do @@ -106,8 +106,6 @@ context 'when email is not already taken' do it 'is valid' do - result = instance_double(FormResponse) - allow(FormResponse).to receive(:new).and_return(result) submit_form = subject.submit(email: 'not_taken@gmail.com') extra = { email_already_exists: false, @@ -116,9 +114,11 @@ domain_name: 'gmail.com', } - expect(FormResponse).to have_received(:new). - with(success: true, errors: {}, extra: extra) - expect(submit_form).to eq result + expect(submit_form.to_h).to eq( + success: true, + errors: {}, + **extra, + ) end it 'saves the user email_language for a valid form' do @@ -142,19 +142,18 @@ domain_name: 'invalid_email', } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(subject.submit(email: 'invalid_email')).to eq result + expect(subject.submit(email: 'invalid_email').to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end context 'when request_id is invalid' do it 'returns unsuccessful and adds an error to the form object' do errors = { email: [t('sign_up.email.invalid_request')] } - result = instance_double(FormResponse) - allow(FormResponse).to receive(:new).and_return(result) submit_form = subject.submit(email: 'not_taken@gmail.com', request_id: 'fake_id') extra = { domain_name: 'gmail.com', @@ -163,9 +162,12 @@ user_id: 'anonymous-uuid', } - expect(FormResponse).to have_received(:new). - with(errors: errors, extra: extra, success: false) - expect(submit_form).to eq result + expect(submit_form.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -178,8 +180,6 @@ uuid: SecureRandom.uuid, ) request_id = sp_request.uuid - result = instance_double(FormResponse) - allow(FormResponse).to receive(:new).and_return(result) submit_form = subject.submit(email: 'not_taken@gmail.com', request_id: request_id) extra = { domain_name: 'gmail.com', @@ -188,16 +188,16 @@ user_id: User.find_with_email('not_taken@gmail.com').uuid, } - expect(FormResponse).to have_received(:new). - with(errors: {}, extra: extra, success: true) - expect(submit_form).to eq result + expect(submit_form.to_h).to eq( + success: true, + errors: {}, + **extra, + ) end end context 'when request_id is blank' do it 'returns success with no errors' do - result = instance_double(FormResponse) - allow(FormResponse).to receive(:new).and_return(result) submit_form = subject.submit(email: 'not_taken@gmail.com', request_id: nil) extra = { domain_name: 'gmail.com', @@ -206,9 +206,11 @@ user_id: User.find_with_email('not_taken@gmail.com').uuid, } - expect(FormResponse).to have_received(:new). - with(errors: {}, extra: extra, success: true) - expect(submit_form).to eq result + expect(submit_form.to_h).to eq( + success: true, + errors: {}, + **extra, + ) end end end diff --git a/spec/forms/reset_password_form_spec.rb b/spec/forms/reset_password_form_spec.rb index 94eaa101f31..e197e3b304d 100644 --- a/spec/forms/reset_password_form_spec.rb +++ b/spec/forms/reset_password_form_spec.rb @@ -19,11 +19,12 @@ extra = { user_id: '123', profile_deactivated: false } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(form.submit(password: password)).to eq result + expect(form.submit(password: password).to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -42,11 +43,12 @@ extra = { user_id: '123', profile_deactivated: false } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(form.submit(password: password)).to eq result + expect(form.submit(password: password).to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -58,15 +60,16 @@ form = ResetPasswordForm.new(user) password = 'valid password' extra = { user_id: '123', profile_deactivated: false } - result = instance_double(FormResponse) user_updater = instance_double(UpdateUser) allow(UpdateUser).to receive(:new). with(user: user, attributes: { password: password }).and_return(user_updater) expect(user_updater).to receive(:call) - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(form.submit(password: password)).to eq result + expect(form.submit(password: password).to_h).to eq( + success: true, + errors: {}, + **extra, + ) end end @@ -86,11 +89,12 @@ extra = { user_id: '123', profile_deactivated: false } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(form.submit(password: password)).to eq result + expect(form.submit(password: password).to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -105,11 +109,12 @@ extra = { user_id: nil, profile_deactivated: false } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(form.submit(password: 'a good and powerful password')).to eq result + expect(form.submit(password: 'a good and powerful password').to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end diff --git a/spec/forms/totp_setup_form_spec.rb b/spec/forms/totp_setup_form_spec.rb index 5fb7cadc94d..3f53491f463 100644 --- a/spec/forms/totp_setup_form_spec.rb +++ b/spec/forms/totp_setup_form_spec.rb @@ -9,16 +9,17 @@ context 'when TOTP code is valid' do it 'returns FormResponse with success: true' do form = TotpSetupForm.new(user, secret, code) - result = instance_double(FormResponse) extra = { totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: next_auth_app_id, } - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to eq( + success: true, + errors: {}, + **extra, + ) expect(user.auth_app_configurations.any?).to eq true end @@ -34,16 +35,17 @@ context 'when TOTP code is invalid' do it 'returns FormResponse with success: false' do form = TotpSetupForm.new(user, secret, 'kode') - result = instance_double(FormResponse) extra = { totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: nil, } - expect(FormResponse).to receive(:new). - with(success: false, errors: {}, extra: extra).and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to include( + success: false, + errors: {}, + **extra, + ) expect(user.auth_app_configurations.any?).to eq false end end @@ -53,16 +55,17 @@ context 'when the secret key is not present' do it 'returns FormResponse with success: false' do form = TotpSetupForm.new(user, nil, 'kode') - result = instance_double(FormResponse) extra = { totp_secret_present: false, multi_factor_auth_method: 'totp', auth_app_configuration_id: nil, } - expect(FormResponse).to receive(:new). - with(success: false, errors: {}, extra: extra).and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to include( + success: false, + errors: {}, + **extra, + ) expect(user.auth_app_configurations.any?).to eq false end end diff --git a/spec/forms/totp_verification_form_spec.rb b/spec/forms/totp_verification_form_spec.rb index 26e14891a78..2e18ac33fc6 100644 --- a/spec/forms/totp_verification_form_spec.rb +++ b/spec/forms/totp_verification_form_spec.rb @@ -7,16 +7,16 @@ user = create(:user, :with_authentication_app) code = '123456' form = TotpVerificationForm.new(user, code) - result = instance_double(FormResponse) cfg = user.auth_app_configurations.first allow(Db::AuthAppConfiguration).to receive(:authenticate).and_return(cfg) - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: { multi_factor_auth_method: 'totp', - auth_app_configuration_id: cfg.id }). - and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to eq( + success: true, + errors: {}, + multi_factor_auth_method: 'totp', + auth_app_configuration_id: cfg.id, + ) end end @@ -25,15 +25,15 @@ user = build_stubbed(:user) code = '123456' form = TotpVerificationForm.new(user, code) - result = instance_double(FormResponse) allow(user).to receive(:authenticate_totp).and_return(false) - expect(FormResponse).to receive(:new). - with(success: false, errors: {}, extra: { multi_factor_auth_method: 'totp', - auth_app_configuration_id: nil }). - and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to eq( + success: false, + errors: {}, + multi_factor_auth_method: 'totp', + auth_app_configuration_id: nil, + ) end end @@ -44,14 +44,14 @@ invalid_codes.each do |code| form = TotpVerificationForm.new(user, code) - result = instance_double(FormResponse) allow(user).to receive(:authenticate_totp).with(code).and_return(true) - expect(FormResponse).to receive(:new). - with(success: false, errors: {}, extra: { multi_factor_auth_method: 'totp', - auth_app_configuration_id: nil }). - and_return(result) - expect(form.submit).to eq result + expect(form.submit.to_h).to eq( + success: false, + errors: {}, + multi_factor_auth_method: 'totp', + auth_app_configuration_id: nil, + ) end end end diff --git a/spec/forms/two_factor_login_options_form_spec.rb b/spec/forms/two_factor_login_options_form_spec.rb index 8c46510e90d..b772539e731 100644 --- a/spec/forms/two_factor_login_options_form_spec.rb +++ b/spec/forms/two_factor_login_options_form_spec.rb @@ -14,11 +14,11 @@ selection: 'sms', } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra).and_return(result) - expect(subject.submit(selection: 'sms')).to eq result + expect(subject.submit(selection: 'sms').to_h).to eq( + success: true, + errors: {}, + **extra, + ) end end @@ -32,11 +32,12 @@ selection: 'foo', } - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: false, errors: errors, extra: extra).and_return(result) - expect(subject.submit(selection: 'foo')).to eq result + expect(subject.submit(selection: 'foo').to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end end diff --git a/spec/forms/update_user_password_form_spec.rb b/spec/forms/update_user_password_form_spec.rb index 9017ecd9331..9e430f6e56f 100644 --- a/spec/forms/update_user_password_form_spec.rb +++ b/spec/forms/update_user_password_form_spec.rb @@ -20,24 +20,24 @@ errors = { password: [t('errors.messages.too_short.other', count: Devise.password_length.first)], } - result = instance_double(FormResponse) - expect(FormResponse).to receive(:new). - with(success: false, errors: errors).and_return(result) expect(UpdateUser).not_to receive(:new) expect(EmailNotifier).not_to receive(:new) expect(ActiveProfileEncryptor).not_to receive(:new) - expect(subject.submit(params)).to eq result + expect(subject.submit(params).to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + ) end end context 'when the password is valid' do it 'returns FormResponse with success: true' do - result = instance_double(FormResponse) - - expect(FormResponse).to receive(:new). - with(success: true, errors: {}).and_return(result) - expect(subject.submit(params)).to eq result + expect(subject.submit(params).to_h).to eq( + success: true, + errors: {}, + ) end it 'updates the user' do diff --git a/spec/forms/webauthn_setup_form_spec.rb b/spec/forms/webauthn_setup_form_spec.rb index bc59d7aa352..a8108cf7126 100644 --- a/spec/forms/webauthn_setup_form_spec.rb +++ b/spec/forms/webauthn_setup_form_spec.rb @@ -11,7 +11,6 @@ context 'when the input is valid' do it 'returns FormResponse with success: true' do allow(IdentityConfig.store).to receive(:domain_name).and_return('localhost:3000') - result = instance_double(FormResponse) params = { attestation_object: attestation_object, client_data_json: setup_client_data_json, @@ -22,9 +21,11 @@ multi_factor_auth_method: 'webauthn', } - expect(FormResponse).to receive(:new). - with(success: true, errors: {}, extra: extra_attributes).and_return(result) - expect(subject.submit(protocol, params)).to eq result + expect(subject.submit(protocol, params).to_h).to eq( + success: true, + errors: {}, + **extra_attributes, + ) end it 'sends a recovery information changed event' do @@ -44,7 +45,6 @@ context 'when the input is invalid' do it 'returns FormResponse with success: false' do - result = instance_double(FormResponse) params = { attestation_object: attestation_object, client_data_json: setup_client_data_json, @@ -55,16 +55,17 @@ multi_factor_auth_method: 'webauthn', } - expect(FormResponse).to receive(:new). - with(success: false, errors: {}, extra: extra_attributes).and_return(result) - expect(subject.submit(protocol, params)).to eq result + expect(subject.submit(protocol, params).to_h).to eq( + success: false, + errors: {}, + **extra_attributes, + ) end it 'returns false with an error when the attestation response raises an error' do allow(IdentityConfig.store).to receive(:domain_name).and_return('localhost:3000') allow(WebAuthn::AttestationStatement).to receive(:from).and_raise(StandardError) - result = instance_double(FormResponse) params = { attestation_object: attestation_object, client_data_json: setup_client_data_json, @@ -75,10 +76,12 @@ multi_factor_auth_method: 'webauthn', } - expect(FormResponse).to receive(:new). - with(success: false, extra: extra_attributes, errors: - { name: [I18n.t('errors.webauthn_setup.attestation_error')] }).and_return(result) - expect(subject.submit(protocol, params)).to eq result + expect(subject.submit(protocol, params).to_h).to eq( + success: false, + errors: { name: [I18n.t('errors.webauthn_setup.attestation_error')] }, + error_details: { name: [I18n.t('errors.webauthn_setup.attestation_error')] }, + **extra_attributes, + ) end end end diff --git a/spec/forms/webauthn_visit_form_spec.rb b/spec/forms/webauthn_visit_form_spec.rb index 248f61fdf28..00f71aced80 100644 --- a/spec/forms/webauthn_visit_form_spec.rb +++ b/spec/forms/webauthn_visit_form_spec.rb @@ -5,43 +5,46 @@ describe '#submit' do it 'returns FormResponse with success: true if there are no errors' do - result = instance_double(FormResponse) params = {} - expect(FormResponse).to receive(:new). - with(success: true, errors: {}).and_return(result) - expect(subject.submit(params)).to eq result + expect(subject.submit(params).to_h).to eq( + success: true, + errors: {}, + ) end context 'when there are errors' do it 'returns FormResponse with success: false with InvalidStateError' do - result = instance_double(FormResponse) params = { error: 'InvalidStateError' } errors = { InvalidStateError: [I18n.t('errors.webauthn_setup.already_registered')] } - expect(FormResponse).to receive(:new). - with(success: false, errors: errors).and_return(result) - expect(subject.submit(params)).to eq result + expect(subject.submit(params).to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + ) end it 'returns FormResponse with success: false with NotSupportedError' do - result = instance_double(FormResponse) params = { error: 'NotSupportedError' } errors = { NotSupportedError: [I18n.t('errors.webauthn_setup.not_supported')] } - expect(FormResponse).to receive(:new). - with(success: false, errors: errors).and_return(result) - expect(subject.submit(params)).to eq result + expect(subject.submit(params).to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + ) end it 'returns FormResponse with success: false with an unrecognized error' do - result = instance_double(FormResponse) params = { error: 'foo' } errors = { foo: [I18n.t('errors.webauthn_setup.general_error')] } - expect(FormResponse).to receive(:new). - with(success: false, errors: errors).and_return(result) - expect(subject.submit(params)).to eq result + expect(subject.submit(params).to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + ) end end end diff --git a/spec/services/form_response_spec.rb b/spec/services/form_response_spec.rb index 3d649c27bbf..49fbf9333d8 100644 --- a/spec/services/form_response_spec.rb +++ b/spec/services/form_response_spec.rb @@ -1,17 +1,6 @@ require 'rails_helper' describe FormResponse do - describe '.new' do - it 'raises an error if errors is not a Hash' do - errors = ['bar', [{ foo: 'bar' }], ['foobar']] - - errors.each do |error| - expect { FormResponse.new(success: true, errors: error) }. - to raise_error NoMethodError - end - end - end - describe '#success?' do context 'when the success argument is true' do it 'returns true' do @@ -31,21 +20,36 @@ end describe '#errors' do - it 'returns the value of the errors argument' do - errors = { foo: 'bar' } - response = FormResponse.new(success: true, errors: errors) + context 'initialized with hash' do + it 'returns the value of the errors argument' do + errors = { foo: 'bar' } + response = FormResponse.new(success: true, errors: errors) + + expect(response.errors).to eq errors + end + end + + context 'initialized with ActiveModel::Errors' do + it 'returns the messages value of the errors argument' do + errors = ActiveModel::Errors.new(build_stubbed(:user)) + errors.add(:email_language, :blank, message: 'Language cannot be blank') + response = FormResponse.new(success: false, errors: errors) - expect(response.errors).to eq errors + expect(response.errors).to eq errors.messages + end end end describe '#merge' do it 'merges the extra analytics' do - response1 = FormResponse.new(success: true, errors: {}, extra: { step: 'foo' }) - response2 = IdentityDocAuth::Response.new(success: true, extra: { is_fallback_link: true }) + response1 = FormResponse.new(success: true, errors: {}, extra: { step: 'foo', order: [1, 2] }) + response2 = IdentityDocAuth::Response.new( + success: true, + extra: { is_fallback_link: true, order: [2, 1] }, + ) combined_response = response1.merge(response2) - expect(combined_response.extra).to eq({ step: 'foo', is_fallback_link: true }) + expect(combined_response.extra).to eq({ step: 'foo', is_fallback_link: true, order: [2, 1] }) end it 'merges errors' do @@ -56,6 +60,42 @@ expect(combined_response.errors).to eq(front: 'error', back: 'error') end + it 'merges multiple errors for key' do + response1 = FormResponse.new(success: false, errors: { front: 'front-error-1' }) + response2 = IdentityDocAuth::Response.new(success: true, errors: { front: ['front-error-2'] }) + + combined_response = response1.merge(response2) + expect(combined_response.errors).to eq(front: ['front-error-1', 'front-error-2']) + end + + it 'merges error details' do + errors1 = ActiveModel::Errors.new(build_stubbed(:user)) + errors1.add(:email_language, :blank, message: 'Language cannot be blank') + errors2 = ActiveModel::Errors.new(build_stubbed(:user)) + errors2.add(:email_language, :invalid, message: 'Language is not valid') + + response1 = FormResponse.new(success: false, errors: errors1) + response2 = FormResponse.new(success: false, errors: errors2) + + combined_response = response1.merge(response2) + expect(combined_response.to_h[:error_details]).to eq(email_language: [:blank, :invalid]) + end + + it 'merges hash and ActiveModel::Errors' do + errors1 = ActiveModel::Errors.new(build_stubbed(:user)) + errors1.add(:email_language, :blank, message: 'Language cannot be blank') + errors2 = { email_language: 'Language is not valid' } + + response1 = FormResponse.new(success: false, errors: errors1) + response2 = FormResponse.new(success: false, errors: errors2) + + combined_response = response1.merge(response2) + expect(combined_response.errors).to eq( + email_language: ['Language cannot be blank', 'Language is not valid'], + ) + expect(combined_response.to_h[:error_details]).to eq(email_language: [:blank]) + end + it 'returns true if one is false and one is true' do response1 = FormResponse.new(success: false, errors: {}) response2 = IdentityDocAuth::Response.new(success: true) @@ -94,6 +134,49 @@ expect(response.to_h).to eq response_hash end end + + context 'when errors is an ActiveModel::Errors' do + it 'returns a hash with success, errors, and error_details keys' do + errors = ActiveModel::Errors.new(build_stubbed(:user)) + errors.add(:email_language, :blank, message: 'Language cannot be blank') + response = FormResponse.new(success: false, errors: errors) + response_hash = { + success: false, + errors: { + email_language: ['Language cannot be blank'], + }, + error_details: { + email_language: [:blank], + }, + } + + expect(response.to_h).to eq response_hash + end + + it 'omits details if errors are empty' do + errors = ActiveModel::Errors.new(build_stubbed(:user)) + response = FormResponse.new(success: true, errors: errors) + response_hash = { + success: true, + errors: {}, + } + + expect(response.to_h).to eq response_hash + end + + it 'omits details if merged errors are empty' do + errors = ActiveModel::Errors.new(build_stubbed(:user)) + response1 = FormResponse.new(success: true, errors: errors) + response2 = FormResponse.new(success: true, errors: errors) + combined_response = response1.merge(response2) + response_hash = { + success: true, + errors: {}, + } + + expect(combined_response.to_h).to eq response_hash + end + end end describe '#extra' do diff --git a/spec/services/saml_request_validator_spec.rb b/spec/services/saml_request_validator_spec.rb index 0c9f0e3ef88..c2a61802555 100644 --- a/spec/services/saml_request_validator_spec.rb +++ b/spec/services/saml_request_validator_spec.rb @@ -7,21 +7,23 @@ sp = ServiceProvider.from_issuer('http://localhost:3000') authn_context = [Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, nameid_format: name_id_format, } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: true, errors: {}, extra: extra) + expect(response.to_h).to include( + success: true, + errors: {}, + **extra, + ) end end @@ -30,7 +32,6 @@ sp = ServiceProvider.from_issuer('foo') authn_context = [Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, @@ -40,14 +41,18 @@ service_provider: [t('errors.messages.unauthorized_service_provider')], } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: false, errors: errors, extra: extra) + expect(response.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -56,7 +61,6 @@ sp = ServiceProvider.from_issuer('http://localhost:3000') authn_context = [Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_EMAIL - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, @@ -66,14 +70,18 @@ nameid_format: [t('errors.messages.unauthorized_nameid_format')], } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: false, errors: errors, extra: extra) + expect(response.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -82,21 +90,23 @@ sp = ServiceProvider.from_issuer('https://rp1.serviceprovider.com/auth/saml/metadata') authn_context = [Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_EMAIL - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, nameid_format: name_id_format, } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: true, errors: {}, extra: extra) + expect(response.to_h).to include( + success: true, + errors: {}, + **extra, + ) end it 'returns FormResponse with success: true for ial2 on ial:2 sp' do @@ -104,21 +114,23 @@ sp.ial = 2 authn_context = [Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_EMAIL - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, nameid_format: name_id_format, } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: true, errors: {}, extra: extra) + expect(response.to_h).to include( + success: true, + errors: {}, + **extra, + ) end end @@ -127,7 +139,6 @@ sp = ServiceProvider.from_issuer('http://localhost:3000') authn_context = ['IAL1'] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, @@ -137,14 +148,18 @@ authn_context: [t('errors.messages.unauthorized_authn_context')], } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: false, errors: errors, extra: extra) + expect(response.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end it 'returns FormResponse with success: false for ial2 on an ial:1 sp' do @@ -152,7 +167,6 @@ sp.ial = 1 authn_context = [Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, @@ -162,14 +176,18 @@ authn_context: [t('errors.messages.unauthorized_authn_context')], } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: false, errors: errors, extra: extra) + expect(response.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -178,7 +196,6 @@ sp = ServiceProvider.from_issuer('foo') authn_context = ['IAL1'] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, @@ -189,14 +206,18 @@ service_provider: [t('errors.messages.unauthorized_service_provider')], } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: false, errors: errors, extra: extra) + expect(response.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end @@ -205,7 +226,6 @@ sp = ServiceProvider.from_issuer('http://localhost:3000') authn_context = [Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF] name_id_format = Saml::Idp::Constants::NAME_ID_FORMAT_EMAIL - allow(FormResponse).to receive(:new) extra = { authn_context: authn_context, service_provider: sp.issuer, @@ -215,14 +235,18 @@ nameid_format: [t('errors.messages.unauthorized_nameid_format')], } - SamlRequestValidator.new.call( + response = SamlRequestValidator.new.call( service_provider: sp, authn_context: authn_context, nameid_format: name_id_format, ) - expect(FormResponse).to have_received(:new). - with(success: false, errors: errors, extra: extra) + expect(response.to_h).to include( + success: false, + errors: errors, + error_details: hash_including(*errors.keys), + **extra, + ) end end end