feat: added app name identifier in segment events (#1277)
* feat: added app name identifier in registration call * feat: added utils for tracking events * refactor: mapped login events * refactor: mapped forgot password events * refactor: mapped reset password events * refactor: mapped register events * fix: fixed unit tests * refactor: mapped progressive prifiling events * fix: fixed unit tests * refactor: added app name in logistration events * refactor: resolved PR reviews and fixed tests
This commit is contained in:
committed by
GitHub
parent
efaa83a1bc
commit
0d603b5fa1
@@ -37,3 +37,4 @@ export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+
|
||||
// things like auto-enrollment upon login and registration.
|
||||
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'register_for_free', 'track', 'is_account_recovery', 'variant', 'host', 'cta'];
|
||||
export const REDIRECT = 'redirect';
|
||||
export const APP_NAME = 'authn_mfe';
|
||||
|
||||
37
src/data/segment/utils.js
Normal file
37
src/data/segment/utils.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
|
||||
import { APP_NAME } from '../constants';
|
||||
|
||||
export const LINK_TIMEOUT = 300;
|
||||
|
||||
/**
|
||||
* Creates an event tracker function that sends a tracking event with the given name and options.
|
||||
*
|
||||
* @param {string} name - The name of the event to be tracked.
|
||||
* @param {object} [options={}] - Additional options to be included with the event.
|
||||
* @returns {function} - A function that, when called, sends the tracking event.
|
||||
*/
|
||||
export const createEventTracker = (name, options = {}) => () => sendTrackEvent(
|
||||
name,
|
||||
{ ...options, app_name: APP_NAME },
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates an event tracker function that sends a tracking event with the given name and options.
|
||||
*
|
||||
* @param {string} name - The name of the event to be tracked.
|
||||
* @param {object} [options={}] - Additional options to be included with the event.
|
||||
* @returns {function} - A function that, when called, sends the tracking event.
|
||||
*/
|
||||
export const createPageEventTracker = (name, options = null) => () => sendPageEvent(
|
||||
name,
|
||||
options,
|
||||
{ app_name: APP_NAME },
|
||||
);
|
||||
|
||||
export const createLinkTracker = (tracker, href) => (e) => {
|
||||
e.preventDefault();
|
||||
tracker();
|
||||
return setTimeout(() => { window.location.href = href; }, LINK_TIMEOUT);
|
||||
};
|
||||
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Form,
|
||||
@@ -25,6 +24,10 @@ import BaseContainer from '../base-container';
|
||||
import { FormGroup } from '../common-components';
|
||||
import { DEFAULT_STATE, LOGIN_PAGE, VALID_EMAIL_REGEX } from '../data/constants';
|
||||
import { updatePathWithQueryParams, windowScrollTo } from '../data/utils';
|
||||
import {
|
||||
trackForgotPasswordPageEvent,
|
||||
trackForgotPasswordPageViewed,
|
||||
} from '../tracking/trackers/forgotpassword';
|
||||
|
||||
const ForgotPasswordPage = (props) => {
|
||||
const platformName = getConfig().SITE_NAME;
|
||||
@@ -41,8 +44,8 @@ const ForgotPasswordPage = (props) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
sendPageEvent('login_and_registration', 'forgot-password');
|
||||
sendTrackEvent('edx.bi.password_reset_form.viewed', { category: 'user-engagement' });
|
||||
trackForgotPasswordPageEvent();
|
||||
trackForgotPasswordPageViewed();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { injectIntl, useIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Form, StatefulButton,
|
||||
@@ -43,6 +42,9 @@ import {
|
||||
updatePathWithQueryParams,
|
||||
} from '../data/utils';
|
||||
import ResetPasswordSuccess from '../reset-password/ResetPasswordSuccess';
|
||||
import {
|
||||
trackForgotPasswordLinkClick, trackLoginPageViewed, trackLoginSuccess,
|
||||
} from '../tracking/trackers/login';
|
||||
|
||||
const LoginPage = (props) => {
|
||||
const {
|
||||
@@ -78,9 +80,15 @@ const LoginPage = (props) => {
|
||||
const tpaHint = getTpaHint();
|
||||
|
||||
useEffect(() => {
|
||||
sendPageEvent('login_and_registration', 'login');
|
||||
trackLoginPageViewed();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (loginResult.success) {
|
||||
trackLoginSuccess();
|
||||
}
|
||||
}, [loginResult]);
|
||||
|
||||
useEffect(() => {
|
||||
const payload = { ...queryParams };
|
||||
if (tpaHint) {
|
||||
@@ -170,9 +178,6 @@ const LoginPage = (props) => {
|
||||
const { name } = event.target;
|
||||
setErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
|
||||
};
|
||||
const trackForgotPasswordLinkClick = () => {
|
||||
sendTrackEvent('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
|
||||
};
|
||||
|
||||
const { provider, skipHintedLogin } = getTpaProvider(tpaHint, providers, secondaryProviders);
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ import { act } from 'react-dom/test-utils';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
import { COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE } from '../../data/constants';
|
||||
import {
|
||||
APP_NAME, COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE,
|
||||
} from '../../data/constants';
|
||||
import { backupLoginFormBegin, dismissPasswordResetBanner, loginRequest } from '../data/actions';
|
||||
import { INTERNAL_SERVER_ERROR } from '../data/constants';
|
||||
import LoginPage from '../LoginPage';
|
||||
@@ -751,7 +753,7 @@ describe('LoginPage', () => {
|
||||
|
||||
it('should send page event when login page is rendered', () => {
|
||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'login');
|
||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'login', { app_name: APP_NAME });
|
||||
});
|
||||
|
||||
it('tests that form is in invalid state when it is submitted', () => {
|
||||
@@ -784,7 +786,7 @@ describe('LoginPage', () => {
|
||||
{ selector: '#forgot-password' },
|
||||
));
|
||||
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.password-reset_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
|
||||
});
|
||||
|
||||
it('should backup the login form state when shouldBackupState is true', () => {
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
tpaProvidersSelector,
|
||||
} from '../common-components/data/selectors';
|
||||
import messages from '../common-components/messages';
|
||||
import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
|
||||
import { APP_NAME, LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
|
||||
import {
|
||||
getTpaHint, getTpaProvider, updatePathWithQueryParams,
|
||||
} from '../data/utils';
|
||||
@@ -56,11 +56,11 @@ const Logistration = (props) => {
|
||||
}, [navigate, disablePublicAccountCreation]);
|
||||
|
||||
const handleInstitutionLogin = (e) => {
|
||||
sendTrackEvent('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
|
||||
sendTrackEvent('edx.bi.institution_login_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
|
||||
if (typeof e === 'string') {
|
||||
sendPageEvent('login_and_registration', e === '/login' ? 'login' : 'register');
|
||||
sendPageEvent('login_and_registration', e === '/login' ? 'login' : 'register', { app_name: APP_NAME });
|
||||
} else {
|
||||
sendPageEvent('login_and_registration', e.target.dataset.eventName);
|
||||
sendPageEvent('login_and_registration', e.target.dataset.eventName, { app_name: APP_NAME });
|
||||
}
|
||||
|
||||
setInstitutionLogin(!institutionLogin);
|
||||
@@ -70,7 +70,7 @@ const Logistration = (props) => {
|
||||
if (tabKey === currentTab) {
|
||||
return;
|
||||
}
|
||||
sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement' });
|
||||
sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement', app_name: APP_NAME });
|
||||
props.clearThirdPartyAuthContextErrorMessage();
|
||||
if (tabKey === LOGIN_PAGE) {
|
||||
props.backupRegistrationForm();
|
||||
|
||||
@@ -11,6 +11,7 @@ import configureStore from 'redux-mock-store';
|
||||
import Logistration from './Logistration';
|
||||
import { clearThirdPartyAuthContextErrorMessage } from '../common-components/data/actions';
|
||||
import {
|
||||
APP_NAME,
|
||||
COMPLETE_STATE, LOGIN_PAGE, REGISTER_PAGE,
|
||||
} from '../data/constants';
|
||||
import { backupLoginForm } from '../login/data/actions';
|
||||
@@ -229,8 +230,8 @@ describe('Logistration', () => {
|
||||
render(reduxWrapper(<IntlLogistration {...props} />));
|
||||
fireEvent.click(screen.getByText('Institution/campus credentials'));
|
||||
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
|
||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'institution_login');
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
|
||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'institution_login', { app_name: APP_NAME });
|
||||
|
||||
mergeConfig({
|
||||
DISABLE_ENTERPRISE_LOGIN: '',
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getConfig, snakeCaseObject } from '@edx/frontend-platform';
|
||||
import { identifyAuthenticatedUser, sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { identifyAuthenticatedUser } from '@edx/frontend-platform/analytics';
|
||||
import {
|
||||
AxiosJwtAuthService,
|
||||
configure as configureAuth,
|
||||
@@ -39,6 +39,13 @@ import {
|
||||
import isOneTrustFunctionalCookieEnabled from '../data/oneTrust';
|
||||
import { getAllPossibleQueryParams, isHostAvailableInQueryParams } from '../data/utils';
|
||||
import { FormFieldRenderer } from '../field-renderer';
|
||||
import {
|
||||
trackDisablePostRegistrationRecommendations,
|
||||
trackProgressiveProfilingPageViewed,
|
||||
trackProgressiveProfilingSkipLinkClick,
|
||||
trackProgressiveProfilingSubmitClick,
|
||||
trackProgressiveProfilingSupportLinkCLick,
|
||||
} from '../tracking/trackers/progressive-profiling';
|
||||
|
||||
const ProgressiveProfiling = (props) => {
|
||||
const { formatMessage } = useIntl();
|
||||
@@ -98,14 +105,13 @@ const ProgressiveProfiling = (props) => {
|
||||
useEffect(() => {
|
||||
if (authenticatedUser?.userId) {
|
||||
identifyAuthenticatedUser(authenticatedUser.userId);
|
||||
sendPageEvent('login_and_registration', 'welcome');
|
||||
trackProgressiveProfilingPageViewed();
|
||||
}
|
||||
}, [authenticatedUser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enablePostRegistrationRecommendations) {
|
||||
sendTrackEvent(
|
||||
'edx.bi.user.recommendations.not.enabled',
|
||||
trackDisablePostRegistrationRecommendations(
|
||||
{ functionalCookiesConsent, page: 'authn_recommendations' },
|
||||
);
|
||||
return;
|
||||
@@ -149,29 +155,23 @@ const ProgressiveProfiling = (props) => {
|
||||
});
|
||||
}
|
||||
props.saveUserProfile(authenticatedUser.username, snakeCaseObject(payload));
|
||||
|
||||
sendTrackEvent(
|
||||
'edx.bi.welcome.page.submit.clicked',
|
||||
{
|
||||
isGenderSelected: !!values.gender,
|
||||
isYearOfBirthSelected: !!values.year_of_birth,
|
||||
isLevelOfEducationSelected: !!values.level_of_education,
|
||||
isWorkExperienceSelected: !!values.work_experience,
|
||||
host: queryParams?.host || '',
|
||||
},
|
||||
);
|
||||
const eventProperties = {
|
||||
isGenderSelected: !!values.gender,
|
||||
isYearOfBirthSelected: !!values.year_of_birth,
|
||||
isLevelOfEducationSelected: !!values.level_of_education,
|
||||
isWorkExperienceSelected: !!values.work_experience,
|
||||
host: queryParams?.host || '',
|
||||
};
|
||||
trackProgressiveProfilingSubmitClick(eventProperties);
|
||||
};
|
||||
|
||||
const handleSkip = (e) => {
|
||||
e.preventDefault();
|
||||
window.history.replaceState(location.state, null, '');
|
||||
setShowModal(true);
|
||||
sendTrackEvent(
|
||||
'edx.bi.welcome.page.skip.link.clicked',
|
||||
{
|
||||
host: queryParams?.host || '',
|
||||
},
|
||||
);
|
||||
trackProgressiveProfilingSkipLinkClick({
|
||||
host: queryParams?.host || '',
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeHandler = (e) => {
|
||||
@@ -242,7 +242,7 @@ const ProgressiveProfiling = (props) => {
|
||||
destination={getConfig().AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK}
|
||||
target="_blank"
|
||||
showLaunchIcon={false}
|
||||
onClick={() => (sendTrackEvent('edx.bi.welcome.page.support.link.clicked'))}
|
||||
onClick={() => (trackProgressiveProfilingSupportLinkCLick())}
|
||||
>
|
||||
{formatMessage(messages['optional.fields.information.link'])}
|
||||
</Hyperlink>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { MemoryRouter, mockNavigate, useLocation } from 'react-router-dom';
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
import {
|
||||
APP_NAME,
|
||||
AUTHN_PROGRESSIVE_PROFILING,
|
||||
COMPLETE_STATE, DEFAULT_REDIRECT_URL,
|
||||
EMBEDDED,
|
||||
@@ -143,8 +144,9 @@ describe('ProgressiveProfilingTests', () => {
|
||||
const modalContentContainer = document.getElementsByClassName('.pgn__modal-content-container');
|
||||
|
||||
expect(modalContentContainer).toBeTruthy();
|
||||
const payload = { host: '', app_name: APP_NAME };
|
||||
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host: '' });
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', payload);
|
||||
});
|
||||
|
||||
// ******** test event functionality ********
|
||||
@@ -165,7 +167,7 @@ describe('ProgressiveProfilingTests', () => {
|
||||
const supportLink = screen.getByRole('link', { name: /learn more about how we use this information/i });
|
||||
fireEvent.click(supportLink);
|
||||
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.support.link.clicked');
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.support.link.clicked', { app_name: APP_NAME });
|
||||
});
|
||||
|
||||
it('should set empty host property value for non-embedded experience', () => {
|
||||
@@ -175,6 +177,7 @@ describe('ProgressiveProfilingTests', () => {
|
||||
isLevelOfEducationSelected: false,
|
||||
isWorkExperienceSelected: false,
|
||||
host: '',
|
||||
app_name: APP_NAME,
|
||||
};
|
||||
delete window.location;
|
||||
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING) };
|
||||
@@ -316,7 +319,7 @@ describe('ProgressiveProfilingTests', () => {
|
||||
const skipLinkButton = screen.getByText('Skip for now');
|
||||
fireEvent.click(skipLinkButton);
|
||||
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host });
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host, app_name: APP_NAME });
|
||||
});
|
||||
|
||||
it('should show spinner while fetching the optional fields', () => {
|
||||
@@ -349,6 +352,7 @@ describe('ProgressiveProfilingTests', () => {
|
||||
isLevelOfEducationSelected: false,
|
||||
isWorkExperienceSelected: false,
|
||||
host: 'http://example.com',
|
||||
app_name: APP_NAME,
|
||||
};
|
||||
delete window.location;
|
||||
window.location = {
|
||||
|
||||
@@ -4,7 +4,6 @@ import React, {
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Form, Spinner, StatefulButton } from '@openedx/paragon';
|
||||
import classNames from 'classnames';
|
||||
@@ -44,11 +43,12 @@ import { getThirdPartyAuthContext as getRegistrationDataFromBackend } from '../c
|
||||
import EnterpriseSSO from '../common-components/EnterpriseSSO';
|
||||
import ThirdPartyAuth from '../common-components/ThirdPartyAuth';
|
||||
import {
|
||||
COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
|
||||
APP_NAME, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
|
||||
} from '../data/constants';
|
||||
import {
|
||||
getAllPossibleQueryParams, getTpaHint, getTpaProvider, isHostAvailableInQueryParams, setCookie,
|
||||
} from '../data/utils';
|
||||
import { trackRegistrationPageViewed, trackRegistrationSuccess } from '../tracking/trackers/register';
|
||||
|
||||
/**
|
||||
* Main Registration Page component
|
||||
@@ -138,7 +138,7 @@ const RegistrationPage = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!formStartTime) {
|
||||
sendPageEvent('login_and_registration', 'register');
|
||||
trackRegistrationPageViewed();
|
||||
const payload = { ...queryParams, is_register_page: true };
|
||||
if (tpaHint) {
|
||||
payload.tpa_hint = tpaHint;
|
||||
@@ -183,7 +183,7 @@ const RegistrationPage = (props) => {
|
||||
useEffect(() => {
|
||||
if (registrationResult.success) {
|
||||
// This event is used by GTM
|
||||
sendTrackEvent('edx.bi.user.account.registered.client', {});
|
||||
trackRegistrationSuccess();
|
||||
|
||||
// This is used by the "User Retention Rate Event" on GTM
|
||||
setCookie(getConfig().USER_RETENTION_COOKIE_NAME, true);
|
||||
@@ -222,7 +222,7 @@ const RegistrationPage = (props) => {
|
||||
|
||||
const registerUser = () => {
|
||||
const totalRegistrationTime = (Date.now() - formStartTime) / 1000;
|
||||
let payload = { ...formFields };
|
||||
let payload = { ...formFields, app_name: APP_NAME };
|
||||
|
||||
if (currentProvider) {
|
||||
delete payload.password;
|
||||
|
||||
@@ -22,7 +22,7 @@ import useAutoGeneratedUsernameExperimentVariation
|
||||
from './data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation';
|
||||
import RegistrationPage from './RegistrationPage';
|
||||
import {
|
||||
AUTHN_PROGRESSIVE_PROFILING, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
|
||||
APP_NAME, AUTHN_PROGRESSIVE_PROFILING, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
|
||||
} from '../data/constants';
|
||||
|
||||
jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||
@@ -190,6 +190,7 @@ describe('RegistrationPage', () => {
|
||||
honor_code: true,
|
||||
totalRegistrationTime: 0,
|
||||
next: '/course/demo-course-url',
|
||||
app_name: APP_NAME,
|
||||
};
|
||||
|
||||
store.dispatch = jest.fn(store.dispatch);
|
||||
@@ -212,6 +213,7 @@ describe('RegistrationPage', () => {
|
||||
honor_code: true,
|
||||
social_auth_provider: 'Apple',
|
||||
totalRegistrationTime: 0,
|
||||
app_name: APP_NAME,
|
||||
};
|
||||
|
||||
store = mockStore({
|
||||
@@ -297,6 +299,7 @@ describe('RegistrationPage', () => {
|
||||
honor_code: true,
|
||||
totalRegistrationTime: 0,
|
||||
marketing_emails_opt_in: true,
|
||||
app_name: APP_NAME,
|
||||
};
|
||||
|
||||
store.dispatch = jest.fn(store.dispatch);
|
||||
@@ -323,6 +326,7 @@ describe('RegistrationPage', () => {
|
||||
country: 'Pakistan',
|
||||
honor_code: true,
|
||||
totalRegistrationTime: 0,
|
||||
app_name: APP_NAME,
|
||||
};
|
||||
|
||||
store.dispatch = jest.fn(store.dispatch);
|
||||
@@ -597,7 +601,7 @@ describe('RegistrationPage', () => {
|
||||
|
||||
it('should send page event when register page is rendered', () => {
|
||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'register');
|
||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'register', { app_name: APP_NAME });
|
||||
});
|
||||
|
||||
it('should send track event when user has successfully registered', () => {
|
||||
@@ -615,7 +619,7 @@ describe('RegistrationPage', () => {
|
||||
delete window.location;
|
||||
window.location = { href: getConfig().BASE_URL };
|
||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.account.registered.client', {});
|
||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.account.registered.client', { app_name: APP_NAME });
|
||||
});
|
||||
|
||||
it('should populate form with pipeline user details', () => {
|
||||
@@ -888,6 +892,7 @@ describe('RegistrationPage', () => {
|
||||
country: 'PK',
|
||||
social_auth_provider: 'Apple',
|
||||
totalRegistrationTime: 0,
|
||||
app_name: APP_NAME,
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import { fireEvent, render } from '@testing-library/react';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
import { APP_NAME } from '../../../data/constants';
|
||||
import { registerNewUser } from '../../data/actions';
|
||||
import { FIELDS } from '../../data/constants';
|
||||
import { NOT_INITIALIZED } from '../../data/optimizelyExperiment/helper';
|
||||
@@ -265,7 +266,7 @@ describe('ConfigurableRegistrationForm', () => {
|
||||
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK' }));
|
||||
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK', app_name: APP_NAME }));
|
||||
});
|
||||
|
||||
it('should show error messages for required fields on empty form submission', () => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent } from '@edx/frontend-platform/analytics';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Form,
|
||||
@@ -19,7 +18,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { resetPassword, validateToken } from './data/actions';
|
||||
import {
|
||||
FORM_SUBMISSION_ERROR, PASSWORD_RESET_ERROR, PASSWORD_VALIDATION_ERROR, TOKEN_STATE,
|
||||
FORM_SUBMISSION_ERROR, PASSWORD_RESET_ERROR, PASSWORD_VALIDATION_ERROR, SUCCESS, TOKEN_STATE,
|
||||
} from './data/constants';
|
||||
import { resetPasswordResultSelector } from './data/selectors';
|
||||
import { validatePassword } from './data/service';
|
||||
@@ -31,6 +30,7 @@ import {
|
||||
LETTER_REGEX, LOGIN_PAGE, NUMBER_REGEX, RESET_PAGE,
|
||||
} from '../data/constants';
|
||||
import { getAllPossibleQueryParams, updatePathWithQueryParams, windowScrollTo } from '../data/utils';
|
||||
import { trackPasswordResetSuccess, trackResetPasswordPageViewed } from '../tracking/trackers/reset-password';
|
||||
|
||||
const ResetPasswordPage = (props) => {
|
||||
const { formatMessage } = useIntl();
|
||||
@@ -44,8 +44,13 @@ const ResetPasswordPage = (props) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
sendPageEvent('login_and_registration', 'reset-password');
|
||||
}, []);
|
||||
if (props.status === TOKEN_STATE.VALID) {
|
||||
trackResetPasswordPageViewed();
|
||||
}
|
||||
if (props.status === SUCCESS) {
|
||||
trackPasswordResetSuccess();
|
||||
}
|
||||
}, [props.status]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.status !== TOKEN_STATE.PENDING && props.status !== PASSWORD_RESET_ERROR) {
|
||||
@@ -144,7 +149,7 @@ const ResetPasswordPage = (props) => {
|
||||
}
|
||||
} else if (props.status === PASSWORD_RESET_ERROR) {
|
||||
navigate(updatePathWithQueryParams(RESET_PAGE));
|
||||
} else if (props.status === 'success') {
|
||||
} else if (props.status === SUCCESS) {
|
||||
navigate(updatePathWithQueryParams(LOGIN_PAGE));
|
||||
} else {
|
||||
return (
|
||||
|
||||
@@ -21,6 +21,7 @@ const token = '1c-bmjdkc-5e60e084cf8113048ca7';
|
||||
|
||||
jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||
sendPageEvent: jest.fn(),
|
||||
sendTrackEvent: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@edx/frontend-platform/auth');
|
||||
|
||||
22
src/tracking/trackers/forgotpassword.js
Normal file
22
src/tracking/trackers/forgotpassword.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
|
||||
|
||||
export const eventNames = {
|
||||
loginAndRegistration: 'login_and_registration',
|
||||
forgotPasswordPageViewed: 'edx.bi.password_reset_form.viewed',
|
||||
};
|
||||
|
||||
export const categories = {
|
||||
userEngagement: 'user-engagement',
|
||||
};
|
||||
|
||||
// Event tracker for forgot password page viewed
|
||||
export const trackForgotPasswordPageViewed = () => createEventTracker(
|
||||
eventNames.forgotPasswordPageViewed,
|
||||
{
|
||||
category: categories.userEngagement,
|
||||
},
|
||||
)();
|
||||
|
||||
export const trackForgotPasswordPageEvent = () => {
|
||||
createPageEventTracker(eventNames.loginAndRegistration, 'forgot-password')();
|
||||
};
|
||||
29
src/tracking/trackers/login.js
Normal file
29
src/tracking/trackers/login.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
|
||||
|
||||
export const eventNames = {
|
||||
forgotPasswordLinkClicked: 'edx.bi.password-reset_form.toggled',
|
||||
loginAndRegistration: 'login_and_registration',
|
||||
registerFormToggled: 'edx.bi.register_form.toggled',
|
||||
loginSuccess: 'edx.bi.user.account.authenticated.client',
|
||||
};
|
||||
|
||||
export const categories = {
|
||||
userEngagement: 'user-engagement',
|
||||
};
|
||||
|
||||
// Event tracker for Forgot Password link click
|
||||
export const trackForgotPasswordLinkClick = () => createEventTracker(
|
||||
eventNames.forgotPasswordLinkClicked,
|
||||
{ category: categories.userEngagement },
|
||||
)();
|
||||
|
||||
// Tracks the login page event.
|
||||
export const trackLoginPageViewed = () => {
|
||||
createPageEventTracker(eventNames.loginAndRegistration, 'login')();
|
||||
};
|
||||
|
||||
// Tracks the login sucess event.
|
||||
export const trackLoginSuccess = () => createEventTracker(
|
||||
eventNames.loginSuccess,
|
||||
{},
|
||||
)();
|
||||
37
src/tracking/trackers/progressive-profiling.js
Normal file
37
src/tracking/trackers/progressive-profiling.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
|
||||
|
||||
export const eventNames = {
|
||||
progressiveProfilingSubmitClick: 'edx.bi.welcome.page.submit.clicked',
|
||||
progressiveProfilingSkipLinkClick: 'edx.bi.welcome.page.skip.link.clicked',
|
||||
disablePostRegistrationRecommendations: 'edx.bi.user.recommendations.not.enabled',
|
||||
progressiveProfilingSupportLinkCLick: 'edx.bi.welcome.page.support.link.clicked',
|
||||
loginAndRegistration: 'login_and_registration',
|
||||
};
|
||||
|
||||
// Event link tracker for Progressive profiling skip button click
|
||||
export const trackProgressiveProfilingSkipLinkClick = evenProperties => createEventTracker(
|
||||
eventNames.progressiveProfilingSkipLinkClick, { ...evenProperties },
|
||||
)();
|
||||
|
||||
// Event tracker for progressive profiling submit button click
|
||||
export const trackProgressiveProfilingSubmitClick = (evenProperties) => createEventTracker(
|
||||
eventNames.progressiveProfilingSubmitClick,
|
||||
{ ...evenProperties },
|
||||
)();
|
||||
|
||||
// Event tracker for progressive profiling submit button click
|
||||
export const trackDisablePostRegistrationRecommendations = (evenProperties) => createEventTracker(
|
||||
eventNames.disablePostRegistrationRecommendations,
|
||||
{ ...evenProperties },
|
||||
)();
|
||||
|
||||
// Tracks the progressive profiling page event.
|
||||
export const trackProgressiveProfilingPageViewed = () => {
|
||||
createPageEventTracker(eventNames.loginAndRegistration, 'welcome')();
|
||||
};
|
||||
|
||||
// Tracks the progressive profiling spport link click.
|
||||
export const trackProgressiveProfilingSupportLinkCLick = () => createEventTracker(
|
||||
eventNames.progressiveProfilingSupportLinkCLick,
|
||||
{},
|
||||
)();
|
||||
22
src/tracking/trackers/register.js
Normal file
22
src/tracking/trackers/register.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
|
||||
|
||||
export const eventNames = {
|
||||
loginAndRegistration: 'login_and_registration',
|
||||
registrationSuccess: 'edx.bi.user.account.registered.client',
|
||||
loginFormToggled: 'edx.bi.login_form.toggled',
|
||||
};
|
||||
|
||||
export const categories = {
|
||||
userEngagement: 'user-engagement',
|
||||
};
|
||||
|
||||
// Event tracker for successful registration
|
||||
export const trackRegistrationSuccess = () => createEventTracker(
|
||||
eventNames.registrationSuccess,
|
||||
{},
|
||||
)();
|
||||
|
||||
// Tracks the progressive profiling page event.
|
||||
export const trackRegistrationPageViewed = () => {
|
||||
createPageEventTracker(eventNames.loginAndRegistration, 'register')();
|
||||
};
|
||||
14
src/tracking/trackers/reset-password.js
Normal file
14
src/tracking/trackers/reset-password.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
|
||||
|
||||
export const eventNames = {
|
||||
loginAndRegistration: 'login_and_registration',
|
||||
resetPasswordSuccess: 'edx.bi.user.password.reset.success',
|
||||
};
|
||||
|
||||
export const trackResetPasswordPageViewed = () => {
|
||||
createPageEventTracker(eventNames.loginAndRegistration, 'reset-password')();
|
||||
};
|
||||
|
||||
export const trackPasswordResetSuccess = () => {
|
||||
createEventTracker(eventNames.resetPasswordSuccess, {})();
|
||||
};
|
||||
37
src/tracking/trackers/tests/forgot-password.test.jsx
Normal file
37
src/tracking/trackers/tests/forgot-password.test.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../../data/segment/utils';
|
||||
import {
|
||||
categories,
|
||||
eventNames,
|
||||
trackForgotPasswordPageEvent,
|
||||
trackForgotPasswordPageViewed,
|
||||
} from '../forgotpassword';
|
||||
|
||||
// Mock createEventTracker function
|
||||
jest.mock('../../../data/segment/utils', () => ({
|
||||
createEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
createPageEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
}));
|
||||
|
||||
describe('Tracking Functions', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fire trackForgotPasswordPageEvent', () => {
|
||||
trackForgotPasswordPageEvent();
|
||||
|
||||
expect(createPageEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.loginAndRegistration,
|
||||
'forgot-password',
|
||||
);
|
||||
});
|
||||
|
||||
it('should fire forgotPasswordPageViewedEvent', () => {
|
||||
trackForgotPasswordPageViewed();
|
||||
|
||||
expect(createEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.forgotPasswordPageViewed,
|
||||
{ category: categories.userEngagement },
|
||||
);
|
||||
});
|
||||
});
|
||||
37
src/tracking/trackers/tests/login.test.jsx
Normal file
37
src/tracking/trackers/tests/login.test.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../../data/segment/utils';
|
||||
import {
|
||||
categories,
|
||||
eventNames,
|
||||
trackForgotPasswordLinkClick,
|
||||
trackLoginPageViewed,
|
||||
} from '../login';
|
||||
|
||||
// Mock createEventTracker function
|
||||
jest.mock('../../../data/segment/utils', () => ({
|
||||
createEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
createPageEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
}));
|
||||
|
||||
describe('Tracking Functions', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('trackForgotPasswordLinkClick function', () => {
|
||||
trackForgotPasswordLinkClick();
|
||||
|
||||
expect(createEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.forgotPasswordLinkClicked,
|
||||
{ category: categories.userEngagement },
|
||||
);
|
||||
});
|
||||
|
||||
it('trackLoginPageEvent function', () => {
|
||||
trackLoginPageViewed();
|
||||
|
||||
expect(createPageEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.loginAndRegistration,
|
||||
'login',
|
||||
);
|
||||
});
|
||||
});
|
||||
37
src/tracking/trackers/tests/progressive-profiling.test.jsx
Normal file
37
src/tracking/trackers/tests/progressive-profiling.test.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../../data/segment/utils';
|
||||
import {
|
||||
eventNames,
|
||||
trackProgressiveProfilingPageViewed,
|
||||
trackProgressiveProfilingSkipLinkClick,
|
||||
} from '../progressive-profiling';
|
||||
|
||||
// Mock createEventTracker function
|
||||
jest.mock('../../../data/segment/utils', () => ({
|
||||
createEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
createPageEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
createLinkTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
}));
|
||||
|
||||
describe('Tracking Functions', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fire trackProgressiveProfilingSkipLinkClickEvent', () => {
|
||||
trackProgressiveProfilingSkipLinkClick();
|
||||
|
||||
expect(createEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.progressiveProfilingSkipLinkClick,
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it('should fire trackProgressiveProfilingPageEvent', () => {
|
||||
trackProgressiveProfilingPageViewed();
|
||||
|
||||
expect(createPageEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.loginAndRegistration,
|
||||
'welcome',
|
||||
);
|
||||
});
|
||||
});
|
||||
36
src/tracking/trackers/tests/register.test.jsx
Normal file
36
src/tracking/trackers/tests/register.test.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { createEventTracker, createPageEventTracker } from '../../../data/segment/utils';
|
||||
import {
|
||||
eventNames,
|
||||
trackRegistrationPageViewed,
|
||||
trackRegistrationSuccess,
|
||||
} from '../register';
|
||||
|
||||
// Mock createEventTracker function
|
||||
jest.mock('../../../data/segment/utils', () => ({
|
||||
createEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
createPageEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
}));
|
||||
|
||||
describe('Tracking Functions', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fire registrationSuccessEvent', () => {
|
||||
trackRegistrationSuccess();
|
||||
|
||||
expect(createEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.registrationSuccess,
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it('should fire trackRegistrationPageEvent', () => {
|
||||
trackRegistrationPageViewed();
|
||||
|
||||
expect(createPageEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.loginAndRegistration,
|
||||
'register',
|
||||
);
|
||||
});
|
||||
});
|
||||
26
src/tracking/trackers/tests/reset-password.test.jsx
Normal file
26
src/tracking/trackers/tests/reset-password.test.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { createPageEventTracker } from '../../../data/segment/utils';
|
||||
import {
|
||||
eventNames,
|
||||
trackResetPasswordPageViewed,
|
||||
} from '../reset-password';
|
||||
|
||||
// Mock createEventTracker function
|
||||
jest.mock('../../../data/segment/utils', () => ({
|
||||
createEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
createPageEventTracker: jest.fn().mockImplementation(() => jest.fn()),
|
||||
}));
|
||||
|
||||
describe('Tracking Functions', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fire trackResettPasswordPageEvent', () => {
|
||||
trackResetPasswordPageViewed();
|
||||
|
||||
expect(createPageEventTracker).toHaveBeenCalledWith(
|
||||
eventNames.loginAndRegistration,
|
||||
'reset-password',
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user