Skip to content

Commit

Permalink
Stepper: Handle calypso_signup_actions_complete_step tracking (#94528)
Browse files Browse the repository at this point in the history
  • Loading branch information
chriskmnds authored Sep 20, 2024
1 parent e9b7ca5 commit eb47bbe
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 3 deletions.
6 changes: 5 additions & 1 deletion client/landing/stepper/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const STEPPER_TRACKS_EVENT_STEP_NAV_GO_BACK = 'calypso_signup_step_nav_ba
export const STEPPER_TRACKS_EVENT_STEP_NAV_GO_NEXT = 'calypso_signup_step_nav_next';
export const STEPPER_TRACKS_EVENT_STEP_NAV_GO_TO = 'calypso_signup_step_nav_go_to';
export const STEPPER_TRACKS_EVENT_STEP_NAV_EXIT_FLOW = 'calypso_signup_step_nav_exit_flow';
export const STEPPER_TRACKS_EVENT_STEP_COMPLETE = 'calypso_signup_actions_complete_step';

export const STEPPER_TRACKS_EVENTS_STEP_NAV = < const >[
STEPPER_TRACKS_EVENT_STEP_NAV_SUBMIT,
Expand All @@ -34,4 +35,7 @@ export const STEPPER_TRACKS_EVENTS_STEP_NAV = < const >[
STEPPER_TRACKS_EVENT_STEP_NAV_EXIT_FLOW,
];

export const STEPPER_TRACKS_EVENTS = < const >[ ...STEPPER_TRACKS_EVENTS_STEP_NAV ];
export const STEPPER_TRACKS_EVENTS = < const >[
...STEPPER_TRACKS_EVENTS_STEP_NAV,
STEPPER_TRACKS_EVENT_STEP_COMPLETE,
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { recordTracksEvent } from '@automattic/calypso-analytics';
import { resolveDeviceTypeByViewPort } from '@automattic/viewport';
import { STEPPER_TRACKS_EVENT_STEP_COMPLETE } from 'calypso/landing/stepper/constants';

export interface RecordStepCompleteProps {
flow: string;
step: string;
optionalProps?: Record< string, string | number | null >;
}

const recordStepComplete = ( { flow, step, optionalProps }: RecordStepCompleteProps ) => {
recordTracksEvent( STEPPER_TRACKS_EVENT_STEP_COMPLETE, {
flow,
step,
device: resolveDeviceTypeByViewPort(),
...optionalProps,
} );
};

export default recordStepComplete;
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import { SiteDetails } from '@automattic/data-stores';
import { isAnyHostingFlow } from '@automattic/onboarding';
import { useEffect } from 'react';
import { useEffect, useRef } from '@wordpress/element';
import { getStepOldSlug } from 'calypso/landing/stepper/declarative-flow/helpers/get-step-old-slug';
import { getAssemblerSource } from 'calypso/landing/stepper/declarative-flow/internals/analytics/record-design';
import recordStepComplete, {
type RecordStepCompleteProps,
} from 'calypso/landing/stepper/declarative-flow/internals/analytics/record-step-complete';
import recordStepStart from 'calypso/landing/stepper/declarative-flow/internals/analytics/record-step-start';
import { useIntent } from 'calypso/landing/stepper/hooks/use-intent';
import { useSelectedDesign } from 'calypso/landing/stepper/hooks/use-selected-design';
Expand Down Expand Up @@ -46,6 +49,21 @@ export const useStepRouteTracking = ( {
const { site, siteSlugOrId } = useSiteData();
const isRequestingSelectedSite = useIsRequestingSelectedSite( siteSlugOrId, site );
const hasRequestedSelectedSite = siteSlugOrId ? !! site && ! isRequestingSelectedSite : true;
const stepCompleteEventPropsRef = useRef< RecordStepCompleteProps | null >( null );

/**
* Cleanup effect to record step-complete event when `StepRoute` unmounts.
* This is to ensure that the event is recorded when the user navigates away from the step.
* We only record this if step-start event gets recorded and `stepCompleteEventPropsRef.current` is populated (as a result).
*/
useEffect( () => {
return () => {
if ( stepCompleteEventPropsRef.current ) {
recordStepComplete( stepCompleteEventPropsRef.current );
}
};
// IMPORTANT: Do not add dependencies to this effect, as it should only record when the component unmounts.
}, [] );

useEffect( () => {
// We record the event only when the step is not empty. Additionally, we should not fire this event whenever the intent is changed
Expand All @@ -67,6 +85,13 @@ export const useStepRouteTracking = ( {
...( flowVariantSlug && { flow_variant: flowVariantSlug } ),
} );

// Apply the props to record in the exit/step-complete event. We only record this if start event gets recorded.
stepCompleteEventPropsRef.current = {
flow: flowName,
step: stepSlug,
optionalProps: { intent },
};

const stepOldSlug = getStepOldSlug( stepSlug );

if ( stepOldSlug ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { waitFor } from '@testing-library/react';
import { addQueryArgs } from '@wordpress/url';
import React, { FC, Suspense } from 'react';
import { MemoryRouter } from 'react-router';
import recordStepComplete from 'calypso/landing/stepper/declarative-flow/internals/analytics/record-step-complete';
import recordStepStart from 'calypso/landing/stepper/declarative-flow/internals/analytics/record-step-start';
import { useIntent } from 'calypso/landing/stepper/hooks/use-intent';
import { useSelectedDesign } from 'calypso/landing/stepper/hooks/use-selected-design';
Expand All @@ -17,16 +18,17 @@ import {
import { isUserLoggedIn } from 'calypso/state/current-user/selectors';
import { renderWithProvider } from 'calypso/test-helpers/testing-library';
import StepRoute from '../';
import type { NavigationControls } from '../../../types';
import type {
Flow,
StepperStep,
StepProps,
NavigationControls,
} from 'calypso/landing/stepper/declarative-flow/internals/types';

jest.mock( 'calypso/signup/storageUtils' );
jest.mock( 'calypso/state/current-user/selectors' );
jest.mock( 'calypso/landing/stepper/declarative-flow/internals/analytics/record-step-start' );
jest.mock( 'calypso/landing/stepper/declarative-flow/internals/analytics/record-step-complete' );
jest.mock( 'calypso/landing/stepper/hooks/use-intent' );
jest.mock( 'calypso/landing/stepper/hooks/use-selected-design' );
jest.mock( 'calypso/lib/analytics/page-view' );
Expand Down Expand Up @@ -191,5 +193,32 @@ describe( 'StepRoute', () => {
expect( recordStepStart ).not.toHaveBeenCalled();
expect( recordPageView ).not.toHaveBeenCalled();
} );

it( 'tracks step-complete when the step is unmounted and step-start was previously recorded', () => {
( isUserLoggedIn as jest.Mock ).mockReturnValue( true );
( getSignupCompleteFlowNameAndClear as jest.Mock ).mockReturnValue( 'some-other-flow' );
( getSignupCompleteStepNameAndClear as jest.Mock ).mockReturnValue( 'some-other-step-slug' );
const { unmount } = render( { step: regularStep } );

expect( recordStepComplete ).not.toHaveBeenCalled();
unmount();
expect( recordStepComplete ).toHaveBeenCalledWith( {
step: 'some-step-slug',
flow: 'some-flow',
optionalProps: {
intent: 'build',
},
} );
} );

it( 'skips tracking step-complete when the step is unmounted and step-start was not recorded', () => {
( getSignupCompleteFlowNameAndClear as jest.Mock ).mockReturnValue( 'some-flow' );
( getSignupCompleteStepNameAndClear as jest.Mock ).mockReturnValue( 'some-step-slug' );
const { unmount } = render( { step: regularStep } );

expect( recordStepStart ).not.toHaveBeenCalled();
unmount();
expect( recordStepComplete ).not.toHaveBeenCalled();
} );
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export const FlowRenderer: React.FC< { flow: Flow } > = ( { flow } ) => {
path={ `/${ flow.variantSlug ?? flow.name }/${ step.slug }/:lang?` }
element={
<StepRoute
key={ step.slug }
step={ step }
flow={ flow }
showWooLogo={ isWooExpressFlow( flow.name ) }
Expand Down

0 comments on commit eb47bbe

Please sign in to comment.