Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MWPW-144108: Project PEP unit tests #2136

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libs/features/webapp-prompt/webapp-prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class AppPrompt {

const metadata = getMetadata(content.querySelector('.section-metadata'));
metadata['loader-duration'] = parseInt(metadata['loader-duration'] || CONFIG.delay, 10);
metadata['loader-color'] = metadata['loader-color'] || CONFIG.defaultColor;
metadata['loader-color'] = metadata['loader-color'] || CONFIG.loaderColor;
this.options = metadata;
};

Expand Down
5 changes: 4 additions & 1 deletion test/blocks/global-navigation/global-navigation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('global navigation', () => {
before(() => {
document.head.innerHTML = `<link rel="icon" href="/libs/img/favicons/favicon.ico" size="any">
<script src="https://auth.services.adobe.com/imslib/imslib.min.js" type="javascript/blocked" data-loaded="true"></script>
<script src="https://stage.adobeccstatic.com/unav/1.0/UniversalNav.js" type="javascript/blocked" data-loaded="true"></script>
<script src="https://stage.adobeccstatic.com/unav/1.1/UniversalNav.js" type="javascript/blocked" data-loaded="true"></script>
`;
});

Expand Down Expand Up @@ -71,12 +71,15 @@ describe('global navigation', () => {
});

it("should log when there's issues within onReady", async () => {
const ogIms = window.adobeIMS;
const gnav = await createFullGlobalNavigation({});
sinon.stub(gnav, 'decorateProfile').callsFake(() => {
throw new Error('error');
});
window.adobeIMS = { isSignedInUser: () => true };
await gnav.imsReady();
expect(window.lana.log.getCalls().find((c) => c.args[0].includes('issues within onReady'))).to.exist;
window.adobeIMS = ogIms;
});

it('should log when IMS signIn method is not available', async () => {
Expand Down
Binary file added test/features/webapp-prompt/mocks/media-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions test/features/webapp-prompt/mocks/pep-prompt-content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export default ({ color, loaderDuration, redirectUrl, productName }) => `<div>
<p>
<picture>
<source type="image/webp" srcset="http://localhost:2000/test/features/webapp-prompt/mocks/media-icon.png" media="(min-width: 600px)">
<source type="image/webp" srcset="http://localhost:2000/test/features/webapp-prompt/mocks/media-icon.png">
<source type="image/png" srcset="http://localhost:2000/test/features/webapp-prompt/mocks/media-icon.png" media="(min-width: 600px)">
<img loading="lazy" alt="" src="http://localhost:2000/test/features/webapp-prompt/mocks/media-icon.png">
</picture>
</p>
<h2 id="taking-you-to-creative-cloud">Taking you to Creative Cloud</h2>
<h3 id="cancel-to-stay-on-web-page">Cancel to stay on web page</h3>
<p><em><a href="https://www.adobe.com/">Stay on this page</a></em></p>
<div class="section-metadata">
${color && `<div>
<div>loader-color</div>
<div>${color}</div>
</div>`}
${loaderDuration && `<div>
<div>loader-duration</div>
<div>${loaderDuration}</div>
</div>`}
${redirectUrl && `<div>
<div>redirect-url</div>
<div><a href="${redirectUrl}">${redirectUrl}</a></div>
</div>`}
${productName && `<div>
<div>product-name</div>
<div>${productName}</div>
</div>`}
</div>
</div>`;
46 changes: 46 additions & 0 deletions test/features/webapp-prompt/test-utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { setViewport } from '@web/test-runner-commands';
import init from '../../../libs/features/webapp-prompt/webapp-prompt.js';
import { viewports, mockRes as importedMockRes } from '../../blocks/global-navigation/test-utilities.js';
import { getConfig, loadStyle, setConfig, updateConfig } from '../../../libs/utils/utils.js';

export const allSelectors = {
fedsUtilities: '.feds-utilities',
pepWrapper: '.appPrompt',
closeIcon: '.appPrompt-close',
promptIcon: '.appPrompt-icon',
avatarImage: '.appPrompt-avatar-image',
title: '.appPrompt-title',
footer: '.appPrompt-footer',
subtitle: '.appPrompt-text',
cta: '.appPrompt-cta--close',
progressWrapper: '.appPrompt-progressWrapper',
progress: '.appPrompt-progress',
appSwitcher: '#unav-app-switcher',
};

export const defaultConfig = {
color: '#b30b00',
loaderDuration: 7500,
redirectUrl: 'https://www.adobe.com/?pep=true',
productName: 'photoshop',
};

export const mockRes = importedMockRes;

export const initPep = async ({ entName = 'firefly-web-usage', isAnchorOpen = false }) => {
setConfig({
imsClientId: 'milo',
codeRoot: '/libs',
locales: { '': { ietf: 'en-US', tk: 'hah7vzn.css' } },
});
updateConfig({ ...getConfig(), entitlements: () => ['firefly-web-usage'] });
await setViewport(viewports.desktop);
await loadStyle('../../../libs/features/webapp-prompt/webapp-prompt.css');

return init({
promptPath: 'https://pep-mocks.test/pep-prompt-content.plain.html',
getAnchorState: async () => ({ id: 'unav-app-switcher', isOpen: isAnchorOpen }),
entName,
parent: document.querySelector('div.feds-utilities'),
});
};
154 changes: 154 additions & 0 deletions test/features/webapp-prompt/webapp-prompt.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { expect } from '@esm-bundle/chai';
import sinon, { stub } from 'sinon';
import pepPromptContent from './mocks/pep-prompt-content.js';

describe('PEP', () => {
let clock;
let allSelectors;
let defaultConfig;
let mockRes;
let initPep;

beforeEach(async () => {
clock = sinon.useFakeTimers({
toFake: ['setTimeout'],
shouldAdvanceTime: true,
});
// We need to import the utilities after mocking setTimeout to ensure
// their setTimeout calls use Sinon's mocked implementation.
// Importing before mocking would lead to a 5s PEP timeout, exceeding the 2s test limit.
const { allSelectors: importedAllSelectors, defaultConfig: importedDefaultConfig, mockRes: importedMockRes } = await import('./test-utilities.js');
allSelectors = importedAllSelectors;
defaultConfig = importedDefaultConfig;
mockRes = importedMockRes;
initPep = (await import('./test-utilities.js')).initPep;
document.body.innerHTML = `<div class="${allSelectors.fedsUtilities.replace('.', '')}" style="position:relative">
<div id="${allSelectors.appSwitcher.replace('#', '')}" tabindex="0">App Switcher</div>
</div>`;
stub(window, 'fetch').callsFake(async (url) => {
if (url.includes('pep-prompt-content.plain.html')) return mockRes({ payload: pepPromptContent({ ...defaultConfig }) });
return null;
});
});

afterEach(() => {
sinon.restore();
clock.restore();
document.body.innerHTML = '';
document.cookie = `${document.cookie};expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
});

describe('PEP rendering tests', () => {
it('should render PEP', async () => {
await initPep({});
await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.exist;
});

it('should not render PEP when previously dismissed', async () => {
document.cookie = 'dismissedAppPrompts=["pep-prompt-content.plain.html"]';
await initPep({});
await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should not render PEP when the entitlement does not match', async () => {
await initPep({ entName: 'not-matching-entitlement' });
await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should not render PEP when there is no prompt content', async () => {
sinon.restore();
stub(window, 'fetch').callsFake(async (url) => {
if (url.includes('pep-prompt-content.plain.html')) {
return mockRes({
payload: null,
ok: false,
status: 400,
});
}
return null;
});
await initPep({});
await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should not render PEP when the redirect url or product name are not provided', async () => {
sinon.restore();
stub(window, 'fetch').callsFake(async (url) => {
if (url.includes('pep-prompt-content.plain.html')) return mockRes({ payload: pepPromptContent({ ...defaultConfig, redirectUrl: false, productName: false }) });
return null;
});
await initPep({});
await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should not render PEP when the anchor element is open', async () => {
await initPep({ isAnchorOpen: true });
await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});
});

describe('PEP configuration tests', () => {
it('should use config values when metadata loader color or duration are not provided', async () => {
sinon.restore();
stub(window, 'fetch').callsFake(async (url) => {
if (url.includes('pep-prompt-content.plain.html')) return mockRes({ payload: pepPromptContent({ ...defaultConfig, color: false, loaderDuration: false }) });
return null;
});
const pep = await initPep({});
await clock.runAllAsync();
const { 'loader-color': pepColor, 'loader-duration': pepDuration } = pep.options;
expect(!!pepColor && !!pepDuration).to.equal(true);
});
});

describe('PEP interaction tests', () => {
it('should close PEP on Escape key', async () => {
await initPep({});
await clock.runAllAsync();
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should close PEP on clicking the close icon', async () => {
await initPep({});
await clock.runAllAsync();
document.querySelector(allSelectors.closeIcon).click();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should close PEP on clicking the CTA', async () => {
await initPep({});
await clock.runAllAsync();
document.querySelector(allSelectors.cta).click();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should close PEP on clicking the anchor element', async () => {
await initPep({});
await clock.runAllAsync();
document.querySelector(allSelectors.appSwitcher).click();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});
});

describe('PEP focus tests', () => {
it('should focus on the close icon on initial render', async () => {
await initPep({});
await clock.runAllAsync();
expect(document.activeElement).to.equal(document.querySelector(allSelectors.closeIcon));
});

it('should focus on the anchor element after closing', async () => {
await initPep({});
await clock.runAllAsync();
document.querySelector(allSelectors.closeIcon).click();
expect(document.activeElement).to.equal(document.querySelector(allSelectors.appSwitcher));
});
});
});
Loading