diff --git a/app/services/idv/analytics_events_enhancer.rb b/app/services/idv/analytics_events_enhancer.rb index 834148f9f66..48ee59db676 100644 --- a/app/services/idv/analytics_events_enhancer.rb +++ b/app/services/idv/analytics_events_enhancer.rb @@ -1,48 +1,134 @@ module Idv module AnalyticsEventsEnhancer - DECORATED_METHODS = %i[ - idv_cancellation_confirmed - idv_cancellation_go_back - idv_cancellation_visited - idv_forgot_password - idv_forgot_password_confirmed - idv_final - idv_gpo_address_letter_enqueued - idv_gpo_address_letter_requested - idv_in_person_ready_to_verify_visit - idv_letter_enqueued_visit - idv_personal_key_acknowledgment_toggled - idv_personal_key_downloaded - idv_personal_key_submitted - idv_personal_key_visited - idv_phone_confirmation_form_submitted - idv_phone_confirmation_otp_rate_limit_attempts - idv_phone_confirmation_otp_rate_limit_locked_out - idv_phone_confirmation_otp_rate_limit_sends - idv_phone_confirmation_otp_resent - idv_phone_confirmation_otp_sent - idv_phone_confirmation_otp_submitted - idv_phone_confirmation_otp_visit - idv_phone_confirmation_vendor_submitted - idv_phone_error_visited - idv_phone_of_record_visited - idv_phone_otp_delivery_selection_visit - idv_phone_otp_delivery_selection_submitted - idv_proofing_resolution_result_missing - idv_enter_password_submitted - idv_enter_password_visited - idv_please_call_visited - idv_start_over + IGNORED_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_randomizer_defaulted + idv_doc_auth_redo_ssn_submitted + 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_exit_optional_questions + idv_front_image_added + idv_front_image_clicked + idv_gpo_confirm_start_over_before_letter_visited + idv_gpo_confirm_start_over_visited + 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_cancel_update_state_id + 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_redo_state_id_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 + idv_in_person_usps_proofing_results_job_deadline_passed_email_initiated + idv_in_person_usps_proofing_results_job_email_initiated + idv_in_person_usps_proofing_results_job_enrollment_incomplete + idv_in_person_usps_proofing_results_job_enrollment_updated + idv_in_person_usps_proofing_results_job_exception + idv_in_person_usps_proofing_results_job_please_call_email_initiated + 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_intro_visit + 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_mobile_device_and_camera_check + 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_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 ].freeze - DECORATED_METHODS.each do |method_name| - define_method(method_name) do |**kwargs| - super(**kwargs, **common_analytics_attributes) + def self.included(_mod) + raise 'this mixin is intended to be prepended, not included' + end + + def self.prepended(mod) + mod.instance_methods.each do |method_name| + if should_enhance_method?(method_name) + mod.define_method method_name do |**kwargs| + super(**kwargs, **common_analytics_attributes) + end + end end end - def self.included(_mod) - raise 'this mixin is intended to be prepended, not included' + def self.should_enhance_method?(method_name) + return false unless /^idv_/.match?(method_name) + + return false if IGNORED_METHODS.include?(method_name) + + true end private diff --git a/spec/services/idv/analytics_events_enhancer_spec.rb b/spec/services/idv/analytics_events_enhancer_spec.rb index bc355b339fe..6e81c0b29bf 100644 --- a/spec/services/idv/analytics_events_enhancer_spec.rb +++ b/spec/services/idv/analytics_events_enhancer_spec.rb @@ -7,39 +7,47 @@ include AnalyticsEvents prepend Idv::AnalyticsEventsEnhancer - def idv_final(**kwargs) - @called_kwargs = kwargs - end - - attr_reader :user, :called_kwargs + attr_reader :called_kwargs def initialize(user:) @user = user end + + def track_event(_event, **kwargs) + @called_kwargs = kwargs + end end end let(:analytics) { analytics_class.new(user: user) } - it 'includes decorated methods' do - expect(analytics.methods).to include(*described_class::DECORATED_METHODS) - expect( - analytics.methods. - intersection(described_class::DECORATED_METHODS). - map { |method| analytics.method(method).source_location.first }. - uniq, - ).to eq([Idv::AnalyticsEventsEnhancer.const_source_location(:DECORATED_METHODS).first]) - end + let(:test_method) { :idv_doc_auth_welcome_visited } + + it 'enhances idv_ methods by default, but ignores those in IGNORED_METHODS' do + enhancer_source_file = described_class.const_source_location(:IGNORED_METHODS).first + + idv_methods = analytics_class.instance_methods.filter { |method| /^idv_/.match?(method) } - it 'calls analytics method with original attributes' do - analytics.idv_final(extra: true) - expect(analytics.called_kwargs).to eq(extra: true) + idv_methods.each do |method_name| + method = analytics_class.instance_method(method_name) + method_source_file = method.source_location.first + + should_be_ignored = described_class.const_get(:IGNORED_METHODS).include?(method_name) + if should_be_ignored + expect(method_source_file).not_to eql(enhancer_source_file), + "#{method_name} should not be enhanced" + else + expect( + method_source_file, + ).to eql(enhancer_source_file), "#{method_name} should be enhanced" + end + end end context 'with anonymous analytics user' do let(:user) { AnonymousUser.new } it 'calls analytics method with original attributes' do - analytics.idv_final(extra: true) + analytics.send(test_method, extra: true) expect(analytics.called_kwargs).to eq(extra: true) end @@ -54,7 +62,7 @@ def initialize(user:) context 'without proofing component' do it 'calls analytics method with original attributes' do - analytics.idv_final(extra: true) + analytics.send(test_method, extra: true) expect(analytics.called_kwargs).to match( extra: true, @@ -68,7 +76,7 @@ def initialize(user:) end it 'calls analytics method with original attributes and proofing_components' do - analytics.idv_final(extra: true) + analytics.send(test_method, extra: true) expect(analytics.called_kwargs).to match( extra: true,