Skip to content

Commit

Permalink
Mhv 61207 contact list navigate away (#31756)
Browse files Browse the repository at this point in the history
* added guards for browser navigation with unsaved changes

* added unit tests

* MHV-61207 recycling beforeunload in sm nav guard

* add navigation away tests

---------

Co-authored-by: Alex Morgun <oleksii.morgun@va.gov>
Co-authored-by: fazilqa <fazil.mammadov@bylight.com>
  • Loading branch information
3 people authored Sep 9, 2024
1 parent d3b5c0c commit e3d9239
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useEffect, useState, useCallback } from 'react';
import React, { useEffect, useState, useCallback, useMemo } from 'react';
import { Prompt } from 'react-router-dom';
import PropTypes from 'prop-types';
import { VaModal } from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import { resetUserSession } from '../../util/helpers';

const SmRouteNavigationGuard = ({
when,
Expand Down Expand Up @@ -43,12 +44,56 @@ const SmRouteNavigationGuard = ({
[isBlocking, setIsBlocking, updateModalVisible],
);

const localStorageValues = useMemo(() => {
return {
atExpires: localStorage.atExpires,
hasSession: localStorage.hasSession,
sessionExpiration: localStorage.sessionExpiration,
userFirstName: localStorage.userFirstName,
};
}, []);

const { signOutMessage, timeoutId } = resetUserSession(localStorageValues);

const noTimeout = useCallback(
() => {
clearTimeout(timeoutId);
},
[timeoutId],
);

const beforeUnloadHandler = useCallback(
e => {
if (when) {
e.preventDefault();
window.onbeforeunload = () => signOutMessage;
e.returnValue = signOutMessage;
}
},
[when, signOutMessage],
);

// Update blocking state based on the `when` prop
useEffect(
() => {
setIsBlocking(when);

// beforeunload prevents the user from navigating away from the page
// without saving their work. This is a browser feature and cannot be
// disabled. The message displayed to the user is also a browser feature
if (when) {
window.addEventListener('beforeunload', beforeUnloadHandler);
} else {
window.removeEventListener('beforeunload', beforeUnloadHandler);
noTimeout();
}
return () => {
window.removeEventListener('beforeunload', beforeUnloadHandler);
window.onbeforeunload = null;
noTimeout();
};
},
[when],
[when, beforeUnloadHandler, noTimeout],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { renderWithStoreAndRouter } from '@department-of-veterans-affairs/platform-testing/react-testing-library-helpers';
import { expect } from 'chai';
import { cleanup, fireEvent, waitFor } from '@testing-library/react';
import sinon from 'sinon';
import noBlockedRecipients from '../fixtures/json-triage-mocks/triage-teams-mock.json';
import oneBlockedRecipient from '../fixtures/json-triage-mocks/triage-teams-one-blocked-mock.json';
import oneBlockedFacility from '../fixtures/json-triage-mocks/triage-teams-facility-blocked-mock.json';
Expand Down Expand Up @@ -263,4 +264,45 @@ describe('Edit Contact List container', async () => {
ErrorMessages.ContactList.MINIMUM_SELECTION,
);
});

it('adds eventListener if path is /contact-list', async () => {
const screen = setup();

const addEventListenerSpy = sinon.spy(window, 'addEventListener');
expect(addEventListenerSpy.calledWith('beforeunload')).to.be.false;

const checkbox = await screen.findByTestId(
'contact-list-select-team-1013155',
);

checkVaCheckbox(checkbox, false);

await waitFor(() => {
expect(addEventListenerSpy.calledWith('beforeunload')).to.be.true;
});
});

it('removes eventListener if contact list changes are reverted', async () => {
const screen = setup();

const addEventListenerSpy = sinon.spy(window, 'addEventListener');
const removeEventListenerSpy = sinon.spy(window, 'removeEventListener');
expect(addEventListenerSpy.calledWith('beforeunload')).to.be.false;

const checkbox = await screen.findByTestId(
'contact-list-select-team-1013155',
);

checkVaCheckbox(checkbox, false);

await waitFor(() => {
expect(addEventListenerSpy.calledWith('beforeunload')).to.be.true;
});

checkVaCheckbox(checkbox, true);

await waitFor(() => {
expect(removeEventListenerSpy.calledWith('beforeunload')).to.be.true;
});
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import SecureMessagingSite from './sm_site/SecureMessagingSite';
import PatientInboxPage from './pages/PatientInboxPage';
import ContactListPage from './pages/ContactListPage';
import { AXE_CONTEXT } from './utils/constants';
import mockMixedCernerFacilitiesUser from './fixtures/userResponse/user-cerner-mixed.json';
import mockFacilities from './fixtures/facilityResponse/cerner-facility-mock-data.json';
import mockEhrData from './fixtures/userResponse/vamc-ehr-cerner-mixed.json';
import mockMixRecipients from './fixtures/multi-facilities-recipients-response.json';
import SecureMessagingSite from '../sm_site/SecureMessagingSite';
import PatientInboxPage from '../pages/PatientInboxPage';
import ContactListPage from '../pages/ContactListPage';
import { AXE_CONTEXT } from '../utils/constants';
import mockMixedCernerFacilitiesUser from '../fixtures/userResponse/user-cerner-mixed.json';
import mockFacilities from '../fixtures/facilityResponse/cerner-facility-mock-data.json';
import mockEhrData from '../fixtures/userResponse/vamc-ehr-cerner-mixed.json';
import mockMixRecipients from '../fixtures/multi-facilities-recipients-response.json';

describe('SM Contact list', () => {
it('verify base web-elements - single facility', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import SecureMessagingSite from './sm_site/SecureMessagingSite';
import PatientInboxPage from './pages/PatientInboxPage';
import ContactListPage from './pages/ContactListPage';
import { AXE_CONTEXT } from './utils/constants';
import mockEhrData from './fixtures/userResponse/vamc-ehr-cerner-mixed.json';
import mockMixedCernerFacilitiesUser from './fixtures/userResponse/user-cerner-mixed.json';
import mockFacilities from './fixtures/facilityResponse/cerner-facility-mock-data.json';
import mockMixRecipients from './fixtures/multi-facilities-recipients-response.json';
import SecureMessagingSite from '../sm_site/SecureMessagingSite';
import PatientInboxPage from '../pages/PatientInboxPage';
import ContactListPage from '../pages/ContactListPage';
import { AXE_CONTEXT } from '../utils/constants';
import mockEhrData from '../fixtures/userResponse/vamc-ehr-cerner-mixed.json';
import mockMixedCernerFacilitiesUser from '../fixtures/userResponse/user-cerner-mixed.json';
import mockFacilities from '../fixtures/facilityResponse/cerner-facility-mock-data.json';
import mockMixRecipients from '../fixtures/multi-facilities-recipients-response.json';

describe('SM Single Facility Contact list', () => {
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import SecureMessagingSite from '../sm_site/SecureMessagingSite';
import PatientInboxPage from '../pages/PatientInboxPage';
import ContactListPage from '../pages/ContactListPage';
import { AXE_CONTEXT, Paths } from '../utils/constants';
import mockEhrData from '../fixtures/userResponse/vamc-ehr-cerner-mixed.json';
import mockMixedCernerFacilitiesUser from '../fixtures/userResponse/user-cerner-mixed.json';
import mockFacilities from '../fixtures/facilityResponse/cerner-facility-mock-data.json';
import mockMixRecipients from '../fixtures/multi-facilities-recipients-response.json';

describe('SM Single Facility Contact list', () => {
beforeEach(() => {
SecureMessagingSite.login(
mockEhrData,
true,
mockMixedCernerFacilitiesUser,
mockFacilities,
);
PatientInboxPage.loadInboxMessages();
ContactListPage.loadContactList(mockMixRecipients);
ContactListPage.selectAllCheckBox();
});

it('navigate away using secondary navigation', () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.visit(`${Paths.UI_MAIN}/medications/about`);

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/medications/about`,
);
});
});
});

it(`navigate away using navbar`, () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.visit(`${Paths.UI_MAIN}/find-locations`);

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/find-locations`,
);
});
});
});

it(`navigate away using browser back button`, () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.go(`back`);

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/inbox/`,
);
});
});
});

it(`navigate away using browser reload`, () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.reload();

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/contact-list`,
);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SecureMessagingSite from './sm_site/SecureMessagingSite';
import PatientInboxPage from './pages/PatientInboxPage';
import ContactListPage from './pages/ContactListPage';
import { AXE_CONTEXT } from './utils/constants';
import SecureMessagingSite from '../sm_site/SecureMessagingSite';
import PatientInboxPage from '../pages/PatientInboxPage';
import ContactListPage from '../pages/ContactListPage';
import { AXE_CONTEXT } from '../utils/constants';

describe('SM Single Facility Contact list', () => {
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import SecureMessagingSite from '../sm_site/SecureMessagingSite';
import PatientInboxPage from '../pages/PatientInboxPage';
import ContactListPage from '../pages/ContactListPage';
import { AXE_CONTEXT, Paths } from '../utils/constants';

describe('SM Single Facility Contact list', () => {
beforeEach(() => {
SecureMessagingSite.login();
PatientInboxPage.loadInboxMessages();
ContactListPage.loadContactList();
ContactListPage.selectAllCheckBox();
});

it('navigate away using secondary navigation', () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.visit(`${Paths.UI_MAIN}/medications/about`);

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/medications/about`,
);
});
});
});

it(`navigate away using navbar`, () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.visit(`${Paths.UI_MAIN}/find-locations`);

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/find-locations`,
);
});
});
});

it(`navigate away using browser back button`, () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.go(`back`);

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/inbox/`,
);
});
});
});

it(`navigate away using browser reload`, () => {
cy.injectAxe();
cy.axeCheck(AXE_CONTEXT);

cy.window().then(win => {
const beforeUnloadStub = cy.stub();

win.addEventListener('beforeunload', beforeUnloadStub);

cy.reload();

cy.then(() => {
expect(beforeUnloadStub).to.have.been.called;
expect(win.location.href).to.eq(
`http://localhost:3001${Paths.UI_MAIN}/contact-list`,
);
});
});
});
});

0 comments on commit e3d9239

Please sign in to comment.