diff --git a/packages/cypress/src/index.ts b/packages/cypress/src/index.ts index 1cb62dde..5d94e299 100644 --- a/packages/cypress/src/index.ts +++ b/packages/cypress/src/index.ts @@ -65,7 +65,11 @@ let watcher: Watcher = null; let host = ''; let port = 0; -const setupNetworkListener = async (): Promise => { +const setupNetworkListener = async ({ + allowedDomains, +}: { + allowedDomains?: string[]; +}): Promise => { try { const { webSocketDebuggerUrl } = await Version({ host, @@ -77,7 +81,7 @@ const setupNetworkListener = async (): Promise => { }); if (!watcher) { - watcher = new Watcher(cdp); + watcher = new Watcher(cdp, allowedDomains); await watcher.watch(); } } catch (err) { @@ -110,7 +114,7 @@ interface TaskParams { export const prepareArchives = async ({ action, payload }: TaskParams) => { switch (action) { case 'setup-network-listener': - return setupNetworkListener(); + return setupNetworkListener(payload); case 'save-archives': return saveArchives(payload); default: @@ -133,13 +137,17 @@ export const onBeforeBrowserLaunch = ( if (portArg) { [, portString] = portArg.split('='); - } else { + } else if (process.env.ELECTRON_EXTRA_LAUNCH_ARGS) { // Electron doesn't pass along the address and port in the launch options, so we need to read the port from the // environment variable that we'll require the user to use (this assumes the host will be 127.0.0.1). const entry = process.env.ELECTRON_EXTRA_LAUNCH_ARGS.split(' ').find((item) => item.startsWith('--remote-debugging-port') ); [, portString] = entry.split('='); + } else { + throw new Error( + 'Please provide a port number \nExample: ELECTRON_EXTRA_LAUNCH_ARGS=--remote-debugging-port= yarn cypress run' + ); } port = parseInt(portString, 10); diff --git a/packages/cypress/src/support.ts b/packages/cypress/src/support.ts index c0ab3c59..8c4da6f2 100644 --- a/packages/cypress/src/support.ts +++ b/packages/cypress/src/support.ts @@ -7,10 +7,16 @@ beforeEach(() => { // then cleaned up before the next test is run // (see https://docs.cypress.io/guides/core-concepts/variables-and-aliases#Aliases) cy.wrap([]).as('manualSnapshots'); - cy.task('prepareArchives', { action: 'setup-network-listener' }); + cy.task('prepareArchives', { + action: 'setup-network-listener', + payload: { allowedDomains: Cypress.env('assetDomains') }, + }); }); afterEach(() => { + if (Cypress.env('disableAutoSnapshot')) { + return; + } // can we be sure this always fires after all the requests are back? cy.document().then((doc) => { const snap = snapshot(doc); @@ -24,7 +30,19 @@ afterEach(() => { testTitle: Cypress.currentTest.title, domSnapshots: [...manualSnapshots, snap], chromaticStorybookParams: { - diffThreshold: Cypress.env('diffThreshold'), + ...(Cypress.env('diffThreshold') && { diffThreshold: Cypress.env('diffThreshold') }), + ...(Cypress.env('delay') && { delay: Cypress.env('delay') }), + ...(Cypress.env('diffIncludeAntiAliasing') && { + diffIncludeAntiAliasing: Cypress.env('diffIncludeAntiAliasing'), + }), + ...(Cypress.env('diffThreshold') && { diffThreshold: Cypress.env('diffThreshold') }), + ...(Cypress.env('forcedColors') && { forcedColors: Cypress.env('forcedColors') }), + ...(Cypress.env('pauseAnimationAtEnd') && { + pauseAnimationAtEnd: Cypress.env('pauseAnimationAtEnd'), + }), + ...(Cypress.env('prefersReducedMotion') && { + prefersReducedMotion: Cypress.env('prefersReducedMotion'), + }), }, pageUrl: url, }, diff --git a/packages/cypress/tests/cypress/e2e/archiving-assets.cy.ts b/packages/cypress/tests/cypress/e2e/archiving-assets.cy.ts index 3bd568d6..78322bfe 100644 --- a/packages/cypress/tests/cypress/e2e/archiving-assets.cy.ts +++ b/packages/cypress/tests/cypress/e2e/archiving-assets.cy.ts @@ -2,8 +2,7 @@ it('Assets / query params determine which asset is served', () => { cy.visit('/asset-paths/query-params'); }); -// TODO: Unskip when Cypress support achieves parity with Playwright -it.skip('Assets / asset doesnt prevent directory from being created', () => { +it('Assets / asset doesnt prevent directory from being created', () => { cy.visit('/asset-paths/asset-at-directory-name'); }); @@ -27,8 +26,7 @@ it.skip('Assets / external asset is archived', () => { cy.visit('/asset-paths/external-asset-archived'); }); -// TODO: Unskip when Cypress support achieves parity with Playwright -it.skip('Assets / assets from css urls are archived', () => { +it('Assets / assets from css urls are archived', () => { cy.visit('/asset-paths/css-urls'); }); diff --git a/packages/cypress/tests/cypress/e2e/options.cy.ts b/packages/cypress/tests/cypress/e2e/options.cy.ts new file mode 100644 index 00000000..97ec424d --- /dev/null +++ b/packages/cypress/tests/cypress/e2e/options.cy.ts @@ -0,0 +1,19 @@ +it('Options / delay', { env: { delay: 1200 } }, () => { + cy.visit('/options/delay'); +}); + +it('Options / diff threshold', { env: { diffThreshold: 1 } }, () => { + cy.visit('/options/diff-threshold'); +}); + +it('Options / pause animation at end', { env: { pauseAnimationAtEnd: true } }, () => { + cy.visit('/options/pause-animation-at-end'); +}); + +it('Options / force high-contrast', { env: { forcedColors: 'active' } }, () => { + cy.visit('/options/forced-colors'); +}); + +it('Options / prefers reduced motion', { env: { prefersReducedMotion: 'reduce' } }, () => { + cy.visit('/options/prefers-reduced-motion'); +}); diff --git a/packages/playwright/tests/options.spec.ts b/packages/playwright/tests/options.spec.ts new file mode 100644 index 00000000..00b21983 --- /dev/null +++ b/packages/playwright/tests/options.spec.ts @@ -0,0 +1,41 @@ +import { test } from '../src'; + +test.describe(() => { + test.use({ delay: 1200 }); + + test('Options / delay', async ({ page }) => { + await page.goto('/options/delay'); + }); +}); + +test.describe(() => { + test.use({ diffThreshold: 1 }); + + test('Options / diff threshold', async ({ page }) => { + await page.goto('/options/diff-threshold'); + }); +}); + +test.describe(() => { + test.use({ pauseAnimationAtEnd: true }); + + test('Options / pause animation at end', async ({ page }) => { + await page.goto('/options/pause-animation-at-end'); + }); +}); + +test.describe(() => { + test.use({ forcedColors: 'active' }); + + test('Options / force high-contrast', async ({ page }) => { + await page.goto('/options/forced-colors'); + }); +}); + +test.describe(() => { + test.use({ prefersReducedMotion: 'reduce' }); + + test('Options / prefers reduced motion', async ({ page }) => { + await page.goto('/options/prefers-reduced-motion'); + }); +}); diff --git a/test-server/fixtures/options/delay.html b/test-server/fixtures/options/delay.html new file mode 100644 index 00000000..80f9c726 --- /dev/null +++ b/test-server/fixtures/options/delay.html @@ -0,0 +1,28 @@ + + + + + + + +

The image should be snapshotted since we're waiting until the delayed-revealed image is visible.

+ + \ No newline at end of file diff --git a/test-server/fixtures/options/diff-threshold.html b/test-server/fixtures/options/diff-threshold.html new file mode 100644 index 00000000..437cfa19 --- /dev/null +++ b/test-server/fixtures/options/diff-threshold.html @@ -0,0 +1,22 @@ + + + + + + +

+

Number above should have no diff, even though it switches between 6 and 8, since the diff threshold is so high

+ + + + \ No newline at end of file diff --git a/test-server/fixtures/options/forced-colors.html b/test-server/fixtures/options/forced-colors.html new file mode 100644 index 00000000..6467df0f --- /dev/null +++ b/test-server/fixtures/options/forced-colors.html @@ -0,0 +1,13 @@ + + + + + + +

This title is hard to read without high-contrast mode.

+ + \ No newline at end of file diff --git a/test-server/fixtures/options/pause-animation-at-end.html b/test-server/fixtures/options/pause-animation-at-end.html new file mode 100644 index 00000000..be4346c2 --- /dev/null +++ b/test-server/fixtures/options/pause-animation-at-end.html @@ -0,0 +1,27 @@ + + + + + + + +

The image should be snapshotted since we're forcing animations to the end (when the image is fully opaque).

+ + \ No newline at end of file diff --git a/test-server/fixtures/options/prefers-reduced-motion.html b/test-server/fixtures/options/prefers-reduced-motion.html new file mode 100644 index 00000000..cc84e127 --- /dev/null +++ b/test-server/fixtures/options/prefers-reduced-motion.html @@ -0,0 +1,19 @@ + + + + + + +

This message should appear when prefers-reduced-motion is enabled.

+ + \ No newline at end of file diff --git a/test-server/server.js b/test-server/server.js index f8907ab7..d981ed6b 100644 --- a/test-server/server.js +++ b/test-server/server.js @@ -8,35 +8,6 @@ const port = 3000; const htmlIntro = ``; const htmlOutro = ``; -// Pages -app.get('/', (req, res) => { - res.send(`${htmlIntro}Testing${htmlOutro}`); -}); - -app.get('/asset-paths', (req, res) => { - res.sendFile(path.join(__dirname, 'fixtures/asset-paths.html')); -}); - -app.get('/ignore', (req, res) => { - res.sendFile(path.join(__dirname, 'fixtures/dynamic-content.html')); -}); - -app.get('/forms', (req, res) => { - res.sendFile(path.join(__dirname, 'fixtures/forms.html')); -}); - -// Send a redirect to the GET handler with the same path to ensure we're not caching POST responses and serving -// it instead of the real GET response. -app.post('/form-success', (req, res) => { - res.send( - `${htmlIntro}${htmlOutro}` - ); -}); - -app.get('/form-success', (req, res) => { - res.send(`${htmlIntro}

OK!

${htmlOutro}`); -}); - // Assets app.get('/css.urls.css', (req, res) => { @@ -74,11 +45,41 @@ app.get('/background-img.png', (req, res) => { res.sendFile(path.join(__dirname, 'fixtures/purple.png')); }); +// Pages +app.get('/', (req, res) => { + res.send(`${htmlIntro}Testing${htmlOutro}`); +}); + // Asset path pages app.get('/asset-paths/:page', (req, res) => { res.sendFile(path.join(__dirname, `fixtures/asset-paths/${req.params.page}.html`)); }); +// Options pages +app.get('/options/:page', (req, res) => { + res.sendFile(path.join(__dirname, `fixtures/options/${req.params.page}.html`)); +}); + +app.get('/ignore', (req, res) => { + res.sendFile(path.join(__dirname, 'fixtures/dynamic-content.html')); +}); + +app.get('/forms', (req, res) => { + res.sendFile(path.join(__dirname, 'fixtures/forms.html')); +}); + +// Send a redirect to the GET handler with the same path to ensure we're not caching POST responses and serving +// it instead of the real GET response. +app.post('/form-success', (req, res) => { + res.send( + `${htmlIntro}${htmlOutro}` + ); +}); + +app.get('/form-success', (req, res) => { + res.send(`${htmlIntro}

OK!

${htmlOutro}`); +}); + app.listen(port, () => { console.log(`Example app listening on port ${port}`); });