Skip to content

Commit

Permalink
Make Idv::AnalyticsEventsEnhancer opt-out (#10263)
Browse files Browse the repository at this point in the history
* compact common_analytics_attributes

Don't include nil values here

* Refactor proofing_components into its own describe block

* Make AnalyticsEventsEnhancer opt out

Update AnalyticsEventsEnhancer so that it augments any event where the _method name_ starts with `^idv_` UNLESS it has been told not to.

changelog: Internal, Analytics, Add additional data to IdV analytics events by default.
  • Loading branch information
matthinz authored Mar 20, 2024
1 parent ccaf01a commit 0fc7795
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 70 deletions.
164 changes: 124 additions & 40 deletions app/services/idv/analytics_events_enhancer.rb
Original file line number Diff line number Diff line change
@@ -1,56 +1,140 @@
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
].freeze
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
].to_set.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 if IGNORED_METHODS.include?(method_name)

method_name.start_with?('idv_')
end

private

def common_analytics_attributes
{
proofing_components: proofing_components,
}
}.compact
end

def proofing_components
Expand Down
86 changes: 56 additions & 30 deletions spec/services/idv/analytics_events_enhancer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,89 @@
let(:analytics_class) do
Class.new(FakeAnalytics) do
include AnalyticsEvents
include(
Module.new do
def idv_test_method(**extra)
track_event(:idv_test_method, **extra)
end
end,
)
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
it 'enhances idv_ methods by default, but ignores those in IGNORED_METHODS' do
enhancer_source_file = described_class.const_source_location(:IGNORED_METHODS).first

it 'calls analytics method with original and decorated attributes' do
analytics.idv_final(extra: true)
idv_methods = analytics_class.instance_methods.filter { |method| /^idv_/.match?(method) }

expect(analytics.called_kwargs).to eq(extra: true, proofing_components: nil)
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 and decorated attributes' do
analytics.idv_final(extra: true)
it 'calls analytics method with original attributes' do
analytics.idv_test_method(extra: true)

expect(analytics.called_kwargs).to eq(extra: true, proofing_components: nil)
expect(analytics.called_kwargs).to eq(extra: true)
end
end

context 'with proofing component' do
let(:proofing_components) do
ProofingComponent.new(source_check: Idp::Constants::Vendors::AAMVA)
end
describe 'proofing_components' do
let(:proofing_components) { nil }

before do
user.proofing_component = proofing_components
end

it 'calls analytics method with original and decorated attributes' do
analytics.idv_final(extra: true)
context 'without proofing component' do
it 'calls analytics method with original attributes' do
analytics.idv_test_method(extra: true)

expect(analytics.called_kwargs).to match(
extra: true,
proofing_components: kind_of(Idv::ProofingComponentsLogging),
)
expect(analytics.called_kwargs).to match(
extra: true,
)
end
end

context 'with proofing component' do
let(:proofing_components) do
ProofingComponent.new(source_check: Idp::Constants::Vendors::AAMVA)
end

it 'calls analytics method with original attributes and proofing_components' do
analytics.idv_test_method(extra: true)

expect(analytics.called_kwargs).to match(
extra: true,
proofing_components: kind_of(Idv::ProofingComponentsLogging),
)
end
end
end
end

0 comments on commit 0fc7795

Please sign in to comment.