diff --git a/src/router/index.js b/src/router/index.js index 0c33cae4..25400a08 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -150,11 +150,29 @@ const router = createRouter({ }); router.beforeEach(async (to, from) => { + const store = useMainStore(); const fromQueryPage = from.query?.issPage; + if (fromQueryPage === undefined) { showIssLoadingModal(true); } + const callSaveSession = !store.order?.referralNumber && (to.name === issPageValues.VEHICLE_SELECTION || to.name === issPageValues.POLICY_VEHICLES); + if (callSaveSession) { + // Forcing a synchronous savesession call here to create the referral for the first time. + // AfterEach does not support synchronous calls that block navigation. Which is why this is in the beforeEach method. + // This only needs to be called once in a certain location, all other saveSession calls are async in afterEach (except the last one on order submission) + // NOTE: This call should be creating the referral number. After this point in the site flow, referral number is critical for several pieces of logic and logging. + // Therefore, we want to force a bailout here if it errors out. + showIssLoadingModal(true); + try { + await saveSession({ shouldAwaitSaveSessionQueue: true, bailoutOnError: true }); + } + finally { + showIssLoadingModal(false); + } + } + const toQueryPage = to.query?.issPage; const notToPayInAdvanceReturn = toQueryPage !== issPageValues.PAYMENT_RETURN; const isInIframe = window !== window.top || fromQueryPage === issPageValues.PAYMENT_PAGE; @@ -172,7 +190,6 @@ router.beforeEach(async (to, from) => { return false; } - const store = useMainStore(); // Prevent navigating backwards if we enter a bailout that we are not allowed to go back on if (store.isBailout && from.name === issPageValues.BAILOUT_PAGE && to.name !== 'root' && to.name !== issPageValues.CONTACT_CONFIRMATION && !canBailoutNavigateBack()) { @@ -204,10 +221,11 @@ router.afterEach(async (to, from) => { to.state?.[routerParams.SKIP_SAVE_SESSION] ?? router.options.history.state?.[routerParams.SKIP_SAVE_SESSION] ); - if (from.name !== undefined && !skipSaveSession && !store.hasSubmittedOrder()) { - await saveSession({ bailoutOnError: from.name === issPageValues.ENTRY_PAGE}); - } + if (from.name !== undefined && !skipSaveSession && !store.hasSubmittedOrder()) { + await saveSession({ bailoutOnError: false }); + } + document.title = routerTitles[to.query.issPage] || 'Safelite Solutions®'; if (shouldRunExperiments) { diff --git a/src/router/router.afterEach.spec.js b/src/router/router.afterEach.spec.js index 2a2185dc..6f2aee8f 100644 --- a/src/router/router.afterEach.spec.js +++ b/src/router/router.afterEach.spec.js @@ -110,6 +110,6 @@ describe('Router afterEach skipSaveSession', () => { ); expect(saveSession).toHaveBeenCalledTimes(1); - expect(saveSession).toHaveBeenCalledWith({ bailoutOnError: true }); + expect(saveSession).toHaveBeenCalledWith({ bailoutOnError: false }); }); }); \ No newline at end of file diff --git a/src/router/router.beforeEach.spec.js b/src/router/router.beforeEach.spec.js new file mode 100644 index 00000000..85c9160e --- /dev/null +++ b/src/router/router.beforeEach.spec.js @@ -0,0 +1,72 @@ +import issPageValues from '@/router/router-constants/issPage-values'; + +let router; +let saveSession; +let showIssLoadingModal; +let mockBeforeEachHandler; +let mockStore; + +jest.mock('vue-router', () => ({ + createWebHistory: jest.fn(() => ({ state: {} })), + createRouter: jest.fn((options) => ({ + options, + beforeEach: jest.fn((handler) => { + mockBeforeEachHandler = handler; + }), + afterEach: jest.fn(), + addRoute: jest.fn(), + getRoutes: jest.fn(() => []), + hasRoute: jest.fn(() => true), + push: jest.fn(), + go: jest.fn(), + currentRoute: { value: { query: { issPage: 'welcome-page' } } } + })) +})); + +jest.mock('@/helpers/order-helper.js', () => ({ + saveSession: jest.fn(() => Promise.resolve()) +})); + +jest.mock('@/helpers/loading-modal-helper', () => jest.fn()); + +jest.mock('@/store', () => ({ + useMainStore: jest.fn(() => mockStore) +})); + +describe('Router beforeEach callSaveSession', () => { + beforeAll(() => { + router = require('@/router/').default; + ({ saveSession } = require('@/helpers/order-helper.js')); + const loadingModalModule = require('@/helpers/loading-modal-helper'); + showIssLoadingModal = loadingModalModule.default || loadingModalModule; + }); + + beforeEach(() => { + mockStore = { + order: {}, + isBailout: false + }; + + jest.clearAllMocks(); + }); + + it('calls saveSession synchronously when entering vehicle-selection without a referral number', async () => { + const result = await mockBeforeEachHandler( + { + name: issPageValues.VEHICLE_SELECTION, + query: { issPage: issPageValues.VEHICLE_SELECTION }, + href: '/?issPage=vehicle-selection' + }, + { + name: issPageValues.WELCOME_PAGE, + query: { issPage: issPageValues.WELCOME_PAGE } + } + ); + + expect(saveSession).toHaveBeenCalledTimes(1); + expect(saveSession).toHaveBeenCalledWith({ shouldAwaitSaveSessionQueue: true, bailoutOnError: true }); + expect(showIssLoadingModal).toHaveBeenNthCalledWith(1, true); + expect(showIssLoadingModal).toHaveBeenNthCalledWith(2, false); + expect(result).toBe(true); + }); +}); \ No newline at end of file