diff --git a/.env b/.env index 9d2c9658..3e70f47c 100644 --- a/.env +++ b/.env @@ -16,6 +16,9 @@ SITE_NAME=null INFO_EMAIL='' # ***** Cookies ***** USER_RETENTION_COOKIE_NAME=null +# ***** Cohesion Keys ***** +COHESION_WRITE_KEY='' +COHESION_SOURCE_KEY='' # ***** Links ***** LOGIN_ISSUE_SUPPORT_LINK='' AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK=null diff --git a/.env.development b/.env.development index e085d5e3..5134d1c2 100644 --- a/.env.development +++ b/.env.development @@ -25,6 +25,9 @@ ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN='true' # ***** Cookies ***** SESSION_COOKIE_DOMAIN='localhost' USER_INFO_COOKIE_NAME='edx-user-info' +# ***** Cohesion Keys ***** +COHESION_WRITE_KEY='' +COHESION_SOURCE_KEY='' # ***** Links ***** LOGIN_ISSUE_SUPPORT_LINK='http://localhost:18000/login-issue-support-url' TOS_AND_HONOR_CODE='http://localhost:18000/honor' diff --git a/.env.test b/.env.test index a6546d69..592df8a6 100644 --- a/.env.test +++ b/.env.test @@ -18,3 +18,5 @@ SEGMENT_KEY='' SITE_NAME='Your Platform Name Here' APP_ID='' MFE_CONFIG_API_URL='' +COHESION_WRITE_KEY='' +COHESION_SOURCE_KEY='' diff --git a/.eslintignore b/.eslintignore index 8346f2f1..8f123893 100755 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,4 @@ docs node_modules/ __mocks__/ __snapshots__/ +src/cohesion/index.js diff --git a/public/index.html b/public/index.html index 2c851c7b..5ce7bb9e 100644 --- a/public/index.html +++ b/public/index.html @@ -1,25 +1,44 @@ - + - <%= (process.env.SITE_NAME && process.env.SITE_NAME != 'null') ? 'Authentication | ' + process.env.SITE_NAME : 'Authentication' %> - - - - - <% if (process.env.OPTIMIZELY_URL) { %> - - <% } else if (process.env.OPTIMIZELY_PROJECT_ID) { %> - - <% } %> + + <%= (process.env.SITE_NAME && process.env.SITE_NAME !='null' ) ? + 'Authentication | ' + process.env.SITE_NAME : 'Authentication' %> + + + + + + + <% if (process.env.OPTIMIZELY_URL) { %> + + <% } else if (process.env.OPTIMIZELY_PROJECT_ID) { %> + + <% } %> +
diff --git a/src/cohesion/cohesion.scss b/src/cohesion/cohesion.scss new file mode 100644 index 00000000..7cfbaf75 --- /dev/null +++ b/src/cohesion/cohesion.scss @@ -0,0 +1,4 @@ +.preampjs [data-preamp], +.fusejs [data-fuse] { + opacity: 0 !important; +} diff --git a/src/cohesion/constants.js b/src/cohesion/constants.js new file mode 100644 index 00000000..9253f0f5 --- /dev/null +++ b/src/cohesion/constants.js @@ -0,0 +1,22 @@ +export const PAGE_TYPES = { + ACCOUNT_CREATION: 'account-creation', + SIGN_IN: 'sign-in', +}; + +export const ELEMENT_TYPES = { + BUTTON: 'BUTTON', +}; + +export const EVENT_TYPES = { ElementClicked: 'redventures.usertracking.v3.ElementClicked' }; + +export const ELEMENT_TEXT = { + CREATE_ACCOUNT: 'create-account', + OPT_IN_TEXT: 'I agree that edx may send me marketing messages', + SIGN_IN: 'Sign In', +}; + +export const ELEMENT_NAME = { + SIGN_IN: PAGE_TYPES.SIGN_IN, + OPT_OUT: 'opt-out', + CREATE_ACCOUNT: 'Create an account for free', +}; diff --git a/src/cohesion/data/actions.js b/src/cohesion/data/actions.js new file mode 100644 index 00000000..809df583 --- /dev/null +++ b/src/cohesion/data/actions.js @@ -0,0 +1,6 @@ +export const SET_COHESION_EVENT_ELEMENT_STATES = 'SET_COHESION_EVENT_ELEMENT_STATES'; + +export const setCohesionEventStates = (eventData) => ({ + type: SET_COHESION_EVENT_ELEMENT_STATES, + payload: eventData, +}); diff --git a/src/cohesion/data/reducers.js b/src/cohesion/data/reducers.js new file mode 100644 index 00000000..4b8fa693 --- /dev/null +++ b/src/cohesion/data/reducers.js @@ -0,0 +1,17 @@ +import { SET_COHESION_EVENT_ELEMENT_STATES } from './actions'; + +export const storeName = 'cohesion'; + +export const defaultState = { + eventData: {}, +}; + +export const reducer = (state = defaultState, action = {}) => { + if (action.type === SET_COHESION_EVENT_ELEMENT_STATES) { + return { + ...state, + eventData: action.payload, + }; + } + return state; +}; diff --git a/src/cohesion/index.js b/src/cohesion/index.js new file mode 100644 index 00000000..2239527f --- /dev/null +++ b/src/cohesion/index.js @@ -0,0 +1,52 @@ +module.exports = () => { + if (process.env.COHESION_WRITE_KEY && process.env.COHESION_SOURCE_KEY) { + !(function (co, h, e, s, i, o, n) { + const d = "documentElement"; + const a = "className"; + h[d][a] += " preampjs fusejs"; + n.k = e; + co._Cohesion = n; + co._Preamp = { k: s, start: new Date() }; + co._Fuse = { k: i }; + co._Tagular = { k: o }; + [e, s, i, o].map((x) => { + co[x] = + co[x] || + function () { + (co[x].q = co[x].q || []).push([].slice.call(arguments)); + }; + }); + const b = function () { + const u = h[d][a]; + h[d][a] = u.replace(/ ?preampjs| ?fusejs/g, ""); + }; + h.addEventListener("DOMContentLoaded", () => { + co.setTimeout(b, 3e3); + co._Preamp.docReady = co._Fuse.docReady = !0; + }); + const z = h.createElement("script"); + z.async = 1; + z.src = "https://cdn.cohesionapps.com/cohesion/cohesion-latest.min.js"; + z.onerror = function () { + const ce = "error"; + const f = "function"; + for (const o of co[e].q || []) { + o[0] === ce && typeof o[1] === f && o[1](); + } + co[e] = function (n, cb) { + n === ce && typeof cb === f && cb(); + }; + b(); + }; + h.head.appendChild(z); + })(window, document, "cohesion", "preamp", "fuse", "tagular", { + tagular: { + writeKey: process.env.COHESION_WRITE_KEY, + sourceKey: process.env.COHESION_SOURCE_KEY, + taggy: { + enabled: true, + }, + }, + }); + } +}; diff --git a/src/cohesion/trackers.js b/src/cohesion/trackers.js new file mode 100644 index 00000000..0144bb94 --- /dev/null +++ b/src/cohesion/trackers.js @@ -0,0 +1,24 @@ +import { EVENT_TYPES } from './constants'; + +/** + * Tracks cohesion events by setting the page type and tracking a click event. + * + * @param {string} pageType - The type of page where the event occurred. + * @param {string} elementType - The type of the web element (e.g., 'BUTTON', 'LINK'). + * @param {string} webElementText - The text content of the web element. + * @param {string} webElementName - The name of the web element. + */ +const trackCohesionEvent = (eventData) => { + window.chsn_pageType = eventData.pageType; + const webElement = { + elementType: eventData.elementType, + text: eventData.webElementText, + name: eventData.webElementName, + }; + window.tagular('beam', { + '@type': EVENT_TYPES.ElementClicked, + webElement, + }); +}; + +export default trackCohesionEvent; diff --git a/src/cohesion/utils.js b/src/cohesion/utils.js new file mode 100644 index 00000000..248ba5d9 --- /dev/null +++ b/src/cohesion/utils.js @@ -0,0 +1,6 @@ +const mockTagular = () => { + const getTagular = jest.fn(); + window.tagular = getTagular; +}; + +export default mockTagular; diff --git a/src/common-components/SocialAuthProviders.jsx b/src/common-components/SocialAuthProviders.jsx index f76e4968..7b78d2c8 100644 --- a/src/common-components/SocialAuthProviders.jsx +++ b/src/common-components/SocialAuthProviders.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { getConfig } from '@edx/frontend-platform'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -9,16 +9,31 @@ import { Login } from '@openedx/paragon/icons'; import PropTypes from 'prop-types'; import messages from './messages'; -import { LOGIN_PAGE, REGISTER_PAGE, SUPPORTED_ICON_CLASSES } from '../data/constants'; +import { PAGE_TYPES } from '../cohesion/constants'; +import { setCohesionEventStates } from '../cohesion/data/actions'; +import { + LOGIN_PAGE, REGISTER_PAGE, SUPPORTED_ICON_CLASSES, +} from '../data/constants'; import { setCookie } from '../data/utils'; const SocialAuthProviders = (props) => { const { formatMessage } = useIntl(); + const dispatch = useDispatch(); const { referrer, socialAuthProviders } = props; const registrationFields = useSelector(state => state.register.registrationFormData); function handleSubmit(e) { e.preventDefault(); + const elementType = e.target.nodeName; + const elementText = e.target.name; + const eventData = { + pageType: referrer === LOGIN_PAGE ? PAGE_TYPES.SIGN_IN : PAGE_TYPES.ACCOUNT_CREATION, + elementType, + webElementText: elementText, + webElementName: elementText.toLowerCase(), + }; + + dispatch(setCohesionEventStates(eventData)); if (referrer === REGISTER_PAGE) { setCookie('marketingEmailsOptIn', registrationFields?.configurableFormFields?.marketingEmailsOptIn); diff --git a/src/data/reducers.js b/src/data/reducers.js index 11c12619..b8d8587c 100755 --- a/src/data/reducers.js +++ b/src/data/reducers.js @@ -1,5 +1,6 @@ import { combineReducers } from 'redux'; +import { reducer as cohesionReducer, storeName as cohesionStoreName } from '../cohesion/data/reducers'; import { reducer as commonComponentsReducer, storeName as commonComponentsStoreName, @@ -31,6 +32,7 @@ const createRootReducer = () => combineReducers({ [commonComponentsStoreName]: commonComponentsReducer, [forgotPasswordStoreName]: forgotPasswordReducer, [resetPasswordStoreName]: resetPasswordReducer, + [cohesionStoreName]: cohesionReducer, [authnProgressiveProfilingStoreName]: authnProgressiveProfilingReducers, }); export default createRootReducer; diff --git a/src/index.jsx b/src/index.jsx index b1131794..2674ea76 100755 --- a/src/index.jsx +++ b/src/index.jsx @@ -9,11 +9,14 @@ import { } from '@edx/frontend-platform'; import { ErrorPage } from '@edx/frontend-platform/react'; +import cohesion from './cohesion'; import configuration from './config'; import messages from './i18n'; import MainApp from './MainApp'; +import './cohesion/cohesion.scss'; subscribe(APP_READY, () => { + cohesion(); ReactDOM.render( , document.getElementById('root'), diff --git a/src/login/LoginPage.jsx b/src/login/LoginPage.jsx index 6a935935..107541b8 100644 --- a/src/login/LoginPage.jsx +++ b/src/login/LoginPage.jsx @@ -1,5 +1,5 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { connect } from 'react-redux'; +import { connect, useDispatch, useSelector } from 'react-redux'; import { getConfig } from '@edx/frontend-platform'; import { injectIntl, useIntl } from '@edx/frontend-platform/i18n'; @@ -20,6 +20,11 @@ import { import { INVALID_FORM, TPA_AUTHENTICATION_FAILURE } from './data/constants'; import LoginFailureMessage from './LoginFailure'; import messages from './messages'; +import { + ELEMENT_NAME, ELEMENT_TEXT, ELEMENT_TYPES, PAGE_TYPES, +} from '../cohesion/constants'; +import { setCohesionEventStates } from '../cohesion/data/actions'; +import trackCohesionEvent from '../cohesion/trackers'; import { FormGroup, InstitutionLogistration, @@ -31,9 +36,7 @@ import { getThirdPartyAuthContext } from '../common-components/data/actions'; import { thirdPartyAuthContextSelector } from '../common-components/data/selectors'; import EnterpriseSSO from '../common-components/EnterpriseSSO'; import ThirdPartyAuth from '../common-components/ThirdPartyAuth'; -import { - DEFAULT_STATE, PENDING_STATE, RESET_PAGE, -} from '../data/constants'; +import { DEFAULT_STATE, PENDING_STATE, RESET_PAGE } from '../data/constants'; import { getActivationStatus, getAllPossibleQueryParams, @@ -72,8 +75,10 @@ const LoginPage = (props) => { getTPADataFromBackend, } = props; const { formatMessage } = useIntl(); + const dispatch = useDispatch(); const activationMsgType = getActivationStatus(); const queryParams = useMemo(() => getAllPossibleQueryParams(), []); + const cohesionEventData = useSelector(state => state.cohesion.eventData); const [formFields, setFormFields] = useState({ ...backedUpFormData.formFields }); const [errorCode, setErrorCode] = useState({ type: '', count: 0, context: {} }); @@ -87,11 +92,13 @@ const LoginPage = (props) => { useEffect(() => { if (loginResult.success) { trackLoginSuccess(); + // This event is used by cohestion upon successful login + trackCohesionEvent(cohesionEventData); // Remove this cookie that was set to capture marketingEmailsOptIn for the onboarding component removeCookie('ssoPipelineRedirectionDone'); } - }, [loginResult]); + }, [loginResult, cohesionEventData]); useEffect(() => { const payload = { ...queryParams }; @@ -152,6 +159,13 @@ const LoginPage = (props) => { const handleSubmit = (event) => { event.preventDefault(); + const eventData = { + pageType: PAGE_TYPES.SIGN_IN, + elementType: ELEMENT_TYPES.BUTTON, + webElementText: ELEMENT_TEXT.SIGN_IN, + webElementName: ELEMENT_NAME.SIGN_IN, + }; + dispatch(setCohesionEventStates(eventData)); if (showResetPasswordSuccessBanner) { props.dismissPasswordResetBanner(); } diff --git a/src/login/tests/LoginPage.test.jsx b/src/login/tests/LoginPage.test.jsx index 38778b8c..6b3e10be 100644 --- a/src/login/tests/LoginPage.test.jsx +++ b/src/login/tests/LoginPage.test.jsx @@ -11,6 +11,7 @@ import { act } from 'react-dom/test-utils'; import { MemoryRouter } from 'react-router-dom'; import configureStore from 'redux-mock-store'; +import mockTagular from '../../cohesion/utils'; import { APP_NAME, COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE, } from '../../data/constants'; @@ -25,6 +26,7 @@ jest.mock('@edx/frontend-platform/analytics', () => ({ jest.mock('@edx/frontend-platform/auth', () => ({ getAuthService: jest.fn(), })); +mockTagular(); const IntlLoginPage = injectIntl(LoginPage); const mockStore = configureStore(); @@ -58,6 +60,7 @@ describe('LoginPage', () => { register: { validationApiRateLimited: false, }, + cohesion: { eventData: {} }, }; const secondaryProviders = { diff --git a/src/logistration/Logistration.test.jsx b/src/logistration/Logistration.test.jsx index b4b0d1e9..84c0b3d1 100644 --- a/src/logistration/Logistration.test.jsx +++ b/src/logistration/Logistration.test.jsx @@ -69,6 +69,7 @@ describe('Logistration', () => { usernameSuggestions: [], validationApiRateLimited: false, }, + cohesion: { eventData: {} }, commonComponents: { thirdPartyAuthContext: { providers: [], diff --git a/src/register/RegistrationPage.jsx b/src/register/RegistrationPage.jsx index 8b6dc9fd..b77d758d 100644 --- a/src/register/RegistrationPage.jsx +++ b/src/register/RegistrationPage.jsx @@ -11,6 +11,12 @@ import PropTypes from 'prop-types'; import { Helmet } from 'react-helmet'; import Skeleton from 'react-loading-skeleton'; +import { + InstitutionLogistration, + PasswordField, + RedirectLogistration, + ThirdPartyAuthAlert, +} from '../common-components'; import ConfigurableRegistrationForm from './components/ConfigurableRegistrationForm'; import RegistrationFailure from './components/RegistrationFailure'; import { @@ -34,22 +40,21 @@ import { import messages from './messages'; import { EmailField, NameField, UsernameField } from './RegistrationFields'; import { - InstitutionLogistration, - PasswordField, - RedirectLogistration, - ThirdPartyAuthAlert, -} from '../common-components'; + ELEMENT_NAME, ELEMENT_TEXT, ELEMENT_TYPES, PAGE_TYPES, +} from '../cohesion/constants'; +import { setCohesionEventStates } from '../cohesion/data/actions'; +import trackCohesionEvent from '../cohesion/trackers'; import { getThirdPartyAuthContext as getRegistrationDataFromBackend } from '../common-components/data/actions'; import EnterpriseSSO from '../common-components/EnterpriseSSO'; import ThirdPartyAuth from '../common-components/ThirdPartyAuth'; import { - APP_NAME, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE, + APP_NAME, COMPLETE_STATE, PENDING_STATE, + REGISTER_PAGE, } from '../data/constants'; import { getAllPossibleQueryParams, getTpaHint, getTpaProvider, isHostAvailableInQueryParams, removeCookie, setCookie, } from '../data/utils'; import { trackRegistrationPageViewed, trackRegistrationSuccess } from '../tracking/trackers/register'; - /** * Main Registration Page component */ @@ -89,6 +94,7 @@ const RegistrationPage = (props) => { const providers = useSelector(state => state.commonComponents.thirdPartyAuthContext.providers); const secondaryProviders = useSelector(state => state.commonComponents.thirdPartyAuthContext.secondaryProviders); const pipelineUserDetails = useSelector(state => state.commonComponents.thirdPartyAuthContext.pipelineUserDetails); + const cohesionEventData = useSelector(state => state.cohesion.eventData); const backendValidations = useSelector(getBackendValidations); const queryParams = useMemo(() => getAllPossibleQueryParams(), []); @@ -185,6 +191,9 @@ const RegistrationPage = (props) => { // This event is used by GTM trackRegistrationSuccess(); + // This event is used by cohestion upon successful registration + trackCohesionEvent(cohesionEventData); + // This is used by the "User Retention Rate Event" on GTM setCookie(getConfig().USER_RETENTION_COOKIE_NAME, true); @@ -193,7 +202,7 @@ const RegistrationPage = (props) => { // Remove this cookie that was set to capture marketingEmailsOptIn for the onboarding component removeCookie('ssoPipelineRedirectionDone'); } - }, [registrationResult]); + }, [registrationResult, cohesionEventData]); const handleOnChange = (event) => { const { name } = event.target; @@ -268,6 +277,13 @@ const RegistrationPage = (props) => { const handleSubmit = (e) => { e.preventDefault(); + const eventData = { + pageType: PAGE_TYPES.ACCOUNT_CREATION, + elementType: ELEMENT_TYPES.BUTTON, + webElementText: ELEMENT_TEXT.CREATE_ACCOUNT, + webElementName: ELEMENT_NAME.CREATE_ACCOUNT, + }; + dispatch(setCohesionEventStates(eventData)); registerUser(); }; diff --git a/src/register/RegistrationPage.test.jsx b/src/register/RegistrationPage.test.jsx index 5f23e2c2..8248ae6c 100644 --- a/src/register/RegistrationPage.test.jsx +++ b/src/register/RegistrationPage.test.jsx @@ -17,6 +17,7 @@ import { setUserPipelineDataLoaded, } from './data/actions'; import { INTERNAL_SERVER_ERROR } from './data/constants'; +import mockTagular from '../cohesion/utils'; import { NOT_INITIALIZED } from './data/optimizelyExperiment/helper'; import useAutoGeneratedUsernameExperimentVariation from './data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation'; @@ -37,6 +38,7 @@ jest.mock('./data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariati const IntlRegistrationPage = injectIntl(RegistrationPage); const mockStore = configureStore(); +mockTagular(); jest.mock('react-router-dom', () => { const mockNavigation = jest.fn(); @@ -106,6 +108,7 @@ describe('RegistrationPage', () => { usernameSuggestions: [], }, + cohesion: { eventData: {} }, commonComponents: { thirdPartyAuthApiStatus: null, thirdPartyAuthContext, diff --git a/src/register/components/ConfigurableRegistrationForm.jsx b/src/register/components/ConfigurableRegistrationForm.jsx index 3013be5f..47962084 100644 --- a/src/register/components/ConfigurableRegistrationForm.jsx +++ b/src/register/components/ConfigurableRegistrationForm.jsx @@ -5,6 +5,10 @@ import { getConfig } from '@edx/frontend-platform'; import { getCountryList, getLocale, useIntl } from '@edx/frontend-platform/i18n'; import PropTypes from 'prop-types'; +import { + ELEMENT_NAME, ELEMENT_TEXT, ELEMENT_TYPES, PAGE_TYPES, +} from '../../cohesion/constants'; +import trackCohesionEvent from '../../cohesion/trackers'; import { FormFieldRenderer } from '../../field-renderer'; import { backupRegistrationFormBegin } from '../data/actions'; import { FIELDS } from '../data/constants'; @@ -100,6 +104,15 @@ const ConfigurableRegistrationForm = (props) => { } // setting marketingEmailsOptIn state for SSO authentication flow for register API call if (name === 'marketingEmailsOptIn') { + if (!value) { + const cohesionEventData = { + pageType: PAGE_TYPES.ACCOUNT_CREATION, + elementType: ELEMENT_TYPES.BUTTON, + webElementText: ELEMENT_TEXT.CREATE_ACCOUNT, + webElementName: ELEMENT_NAME.CREATE_ACCOUNT, + }; + trackCohesionEvent(cohesionEventData); + } dispatch(backupRegistrationFormBegin({ ...backedUpFormData, configurableFormFields: { diff --git a/src/register/components/tests/ConfigurableRegistrationForm.test.jsx b/src/register/components/tests/ConfigurableRegistrationForm.test.jsx index 61a25848..fd423b92 100644 --- a/src/register/components/tests/ConfigurableRegistrationForm.test.jsx +++ b/src/register/components/tests/ConfigurableRegistrationForm.test.jsx @@ -99,6 +99,7 @@ describe('ConfigurableRegistrationForm', () => { registrationFormData, usernameSuggestions: [], }, + cohesion: { eventData: {} }, commonComponents: { thirdPartyAuthApiStatus: null, thirdPartyAuthContext, diff --git a/src/register/components/tests/RegistrationFailure.test.jsx b/src/register/components/tests/RegistrationFailure.test.jsx index da8867cd..352530b9 100644 --- a/src/register/components/tests/RegistrationFailure.test.jsx +++ b/src/register/components/tests/RegistrationFailure.test.jsx @@ -99,6 +99,7 @@ describe('RegistrationFailure', () => { registrationFormData, usernameSuggestions: [], }, + cohesion: { eventData: {} }, commonComponents: { thirdPartyAuthApiStatus: null, thirdPartyAuthContext, diff --git a/src/register/components/tests/ThirdPartyAuth.test.jsx b/src/register/components/tests/ThirdPartyAuth.test.jsx index 7706d185..74f5da34 100644 --- a/src/register/components/tests/ThirdPartyAuth.test.jsx +++ b/src/register/components/tests/ThirdPartyAuth.test.jsx @@ -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 mockTagular from '../../../cohesion/utils'; import { COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE, REGISTER_PAGE, } from '../../../data/constants'; @@ -26,6 +27,7 @@ jest.mock('@edx/frontend-platform/i18n', () => ({ getLocale: jest.fn(), })); jest.mock('../../data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation', () => jest.fn()); +mockTagular(); const IntlRegistrationPage = injectIntl(RegistrationPage); const mockStore = configureStore(); @@ -98,6 +100,7 @@ describe('ThirdPartyAuth', () => { registrationFormData, usernameSuggestions: [], }, + cohesion: { eventData: {} }, commonComponents: { thirdPartyAuthApiStatus: null, thirdPartyAuthContext,