From b7dec8f82fb33352deaae089dbac67197e7feb76 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 10 Feb 2022 13:34:59 +0100 Subject: [PATCH 1/6] fix: reset page between tests --- src/csf/transformCsf.ts | 26 +++++++++++++++++++--- src/playwright/transformPlaywright.test.ts | 9 ++++++++ src/playwright/transformPlaywright.ts | 7 ++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/csf/transformCsf.ts b/src/csf/transformCsf.ts index 8a65d1a2..6f3bd7db 100644 --- a/src/csf/transformCsf.ts +++ b/src/csf/transformCsf.ts @@ -20,6 +20,7 @@ type TestPrefixer = (context: TestContext) => TemplateResult; interface TransformOptions { clearBody?: boolean; filePrefixer?: FilePrefixer; + beforeEachPrefixer?: FilePrefixer; testPrefixer?: TestPrefixer; insertTestIfEmpty?: boolean; defaultTitle?: string; @@ -60,15 +61,26 @@ const makePlayTest = ( ]; }; -const makeDescribe = (key: string, tests: t.Statement[]): t.Statement | null => { +const makeDescribe = ( + key: string, + tests: t.Statement[], + beforeEachBlock?: t.ExpressionStatement +): t.Statement | null => { + const blockStatements = beforeEachBlock ? [beforeEachBlock, ...tests] : tests; return t.expressionStatement( t.callExpression(t.identifier('describe'), [ t.stringLiteral(key), - t.arrowFunctionExpression([], t.blockStatement(tests)), + t.arrowFunctionExpression([], t.blockStatement(blockStatements)), ]) ); }; +const makeBeforeEach = (beforeEachPrefixer?: FilePrefixer) => { + const stmt = beforeEachPrefixer() as t.ExpressionStatement; + + return t.expressionStatement(t.callExpression(t.identifier('beforeEach'), [stmt.expression])); +}; + const makeArray = (templateResult: TemplateResult) => Array.isArray(templateResult) ? templateResult : [templateResult]; @@ -78,6 +90,7 @@ export const transformCsf = ( filePrefixer, clearBody = false, testPrefixer, + beforeEachPrefixer, insertTestIfEmpty, defaultTitle, }: TransformOptions = {} @@ -118,7 +131,14 @@ export const transformCsf = ( } if (!clearBody) result = `${result}${code}\n`; if (allTests.length) { - const describe = makeDescribe(csf.meta.title, allTests); + if (beforeEachPrefixer) { + makeBeforeEach(beforeEachPrefixer); + } + const describe = makeDescribe( + csf.meta.title, + allTests, + beforeEachPrefixer ? makeBeforeEach(beforeEachPrefixer) : undefined + ); const { code: describeCode } = generate(describe, {}); result = dedent` ${result} diff --git a/src/playwright/transformPlaywright.test.ts b/src/playwright/transformPlaywright.test.ts index 30a754d4..d441d484 100644 --- a/src/playwright/transformPlaywright.test.ts +++ b/src/playwright/transformPlaywright.test.ts @@ -51,6 +51,9 @@ describe('Playwright', () => { if (!require.main) { describe("foo/bar", () => { + beforeEach(async () => { + await jestPlaywright.resetPage(); + }); describe("A", () => { it("play-test", async () => { const context = { @@ -104,6 +107,9 @@ describe('Playwright', () => { if (!require.main) { describe("foo/bar", () => { + beforeEach(async () => { + await jestPlaywright.resetPage(); + }); describe("A", () => { it("smoke-test", async () => { const context = { @@ -158,6 +164,9 @@ describe('Playwright', () => { if (!require.main) { describe("Example/Header", () => { + beforeEach(async () => { + await jestPlaywright.resetPage(); + }); describe("A", () => { it("smoke-test", async () => { const context = { diff --git a/src/playwright/transformPlaywright.ts b/src/playwright/transformPlaywright.ts index aa672d66..8484305a 100644 --- a/src/playwright/transformPlaywright.ts +++ b/src/playwright/transformPlaywright.ts @@ -9,6 +9,12 @@ const filePrefixer = template(` import global from 'global'; `); +const beforeEachPrefixer = template(` + async () => { + await jestPlaywright.resetPage() + } +`); + export const testPrefixer = template( ` console.log({ id: %%id%%, title: %%title%%, name: %%name%%, storyExport: %%storyExport%% }); @@ -52,6 +58,7 @@ export const transformPlaywright = (src: string, filename: string) => { filePrefixer, // @ts-ignore testPrefixer, + beforeEachPrefixer, insertTestIfEmpty: true, clearBody: true, defaultTitle, From 281ad3ae5422d8efb8876efa39f46cd9703838b7 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 15 Feb 2022 11:21:19 +0100 Subject: [PATCH 2/6] WIP move setup page to a helper function --- playwright/custom-environment.js | 120 ------------------------ src/config/jest-playwright.ts | 2 +- src/index.ts | 1 + src/playwright/transformPlaywright.ts | 5 +- src/setup-page.ts | 127 ++++++++++++++++++++++++++ test-runner-jest.config.js | 2 +- 6 files changed, 132 insertions(+), 125 deletions(-) create mode 100644 src/setup-page.ts diff --git a/playwright/custom-environment.js b/playwright/custom-environment.js index b51408d3..dc4763be 100644 --- a/playwright/custom-environment.js +++ b/playwright/custom-environment.js @@ -1,129 +1,9 @@ require('regenerator-runtime/runtime'); const PlaywrightEnvironment = require('jest-playwright-preset/lib/PlaywrightEnvironment').default; -const sanitizeURL = (url) => { - let finalURL = url - // prepend URL protocol if not there - if (finalURL.indexOf("http://") === -1 && finalURL.indexOf("https://") === -1) { - finalURL = 'http://' + finalURL; - } - - // remove iframe.html if present - finalURL = finalURL.replace(/iframe.html\s*$/, ""); - - // add forward slash at the end if not there - if (finalURL.slice(-1) !== '/') { - finalURL = finalURL + '/'; - } - - return finalURL; -} - class CustomEnvironment extends PlaywrightEnvironment { async setup() { await super.setup(); - const page = this.global.page; - const start = new Date(); - const targetURL = sanitizeURL(process.env.TARGET_URL || `http://localhost:6006`); - - const referenceURL = process.env.REFERENCE_URL && sanitizeURL(process.env.REFERENCE_URL); - - if ('TARGET_URL' in process.env && !process.env.TARGET_URL) { - console.log(`Received TARGET_URL but with a falsy value: ${process.env.TARGET_URL - }, will fallback to ${targetURL} instead.`) - } - - await page.goto(`${targetURL}iframe.html`, { waitUntil: 'load' }).catch((err) => { - if (err.message?.includes('ERR_CONNECTION_REFUSED')) { - const errorMessage = `Could not access the Storybook instance at ${targetURL}. Are you sure it's running?\n\n${err.message}`; - throw new Error(errorMessage) - } - - throw err; - }); // FIXME: configure - console.log(`page loaded in ${new Date() - start}ms.`); - - // if we ever want to log something from the browser to node - await page.exposeBinding('logToPage', (_, message) => console.log(message)); - - await page.addScriptTag({ - content: ` - class StorybookTestRunnerError extends Error { - constructor(storyId, errorMessage) { - super(errorMessage); - this.name = 'StorybookTestRunnerError'; - const storyUrl = \`${referenceURL || targetURL}?path=/story/\${storyId}\`; - const finalStoryUrl = \`\${storyUrl}&addonPanel=storybook/interactions/panel\`; - - this.message = \`\nAn error occurred in the following story:\n\${finalStoryUrl}\n\nMessage:\n \${errorMessage}\`; - } - } - - async function __throwError(storyId, errorMessage) { - throw new StorybookTestRunnerError(storyId, errorMessage); - } - - async function __waitForElement(selector) { - return new Promise((resolve, reject) => { - - const timeout = setTimeout(() => { - reject(); - }, 10000); - - if (document.querySelector(selector)) { - clearTimeout(timeout); - return resolve(document.querySelector(selector)); - } - - const observer = new MutationObserver(mutations => { - if (document.querySelector(selector)) { - clearTimeout(timeout); - resolve(document.querySelector(selector)); - observer.disconnect(); - } - }); - - observer.observe(document.body, { - childList: true, - subtree: true - }); - }); - } - - async function __test(storyId) { - try { - await __waitForElement('#root'); - } catch(err) { - const message = \`Timed out waiting for Storybook to load after 10 seconds. Are you sure the Storybook is running correctly in that URL? Is the Storybook private (e.g. under authentication layers)?\n\n\nHTML: \${document.body.innerHTML}\`; - throw new StorybookTestRunnerError(storyId, message); - } - - const channel = window.__STORYBOOK_ADDONS_CHANNEL__; - if(!channel) { - throw new StorybookTestRunnerError( - storyId, - 'The test runner could not access the Storybook channel. Are you sure the Storybook is running correctly in that URL?' - ); - } - - return new Promise((resolve, reject) => { - channel.on('storyRendered', () => resolve(document.getElementById('root'))); - channel.on('storyUnchanged', () => resolve(document.getElementById('root'))); - channel.on('storyErrored', ({ description }) => reject( - new StorybookTestRunnerError(storyId, description)) - ); - channel.on('storyThrewException', (error) => reject( - new StorybookTestRunnerError(storyId, error.message)) - ); - channel.on('storyMissing', (id) => id === storyId && reject( - new StorybookTestRunnerError(storyId, 'The story was missing when trying to access it.')) - ); - - channel.emit('setCurrentStory', { storyId }); - }); - }; - `, - }); } async teardown() { diff --git a/src/config/jest-playwright.ts b/src/config/jest-playwright.ts index f6c65302..ea30bbe2 100644 --- a/src/config/jest-playwright.ts +++ b/src/config/jest-playwright.ts @@ -12,7 +12,7 @@ export const getJestConfig = () => { preset: 'jest-playwright-preset', globalSetup: '@storybook/test-runner/playwright/global-setup.js', globalTeardown: '@storybook/test-runner/playwright/global-teardown.js', - testEnvironment: '@storybook/test-runner/playwright/custom-environment.js', + // testEnvironment: '@storybook/test-runner/playwright/custom-environment.js', // @TODO: setupFilesAfterEnv: ['@storybook/test-runner/setup'] }; diff --git a/src/index.ts b/src/index.ts index 0ce45489..e08f2aa1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ export * from './playwright/hooks'; export * from './config/jest-playwright'; +export * from './setup-page'; diff --git a/src/playwright/transformPlaywright.ts b/src/playwright/transformPlaywright.ts index 8484305a..3500c0e7 100644 --- a/src/playwright/transformPlaywright.ts +++ b/src/playwright/transformPlaywright.ts @@ -7,12 +7,11 @@ import { transformCsf } from '../csf/transformCsf'; const filePrefixer = template(` import global from 'global'; + const { setupPage } = require('../../dist/cjs'); `); const beforeEachPrefixer = template(` - async () => { - await jestPlaywright.resetPage() - } + async () => setupPage(global.page) `); export const testPrefixer = template( diff --git a/src/setup-page.ts b/src/setup-page.ts new file mode 100644 index 00000000..1417b430 --- /dev/null +++ b/src/setup-page.ts @@ -0,0 +1,127 @@ +//@ts-nocheck +const sanitizeURL = (url) => { + let finalURL = url; + // prepend URL protocol if not there + if (finalURL.indexOf('http://') === -1 && finalURL.indexOf('https://') === -1) { + finalURL = 'http://' + finalURL; + } + + // remove iframe.html if present + finalURL = finalURL.replace(/iframe.html\s*$/, ''); + + // add forward slash at the end if not there + if (finalURL.slice(-1) !== '/') { + finalURL = finalURL + '/'; + } + + return finalURL; +}; + +export const setupPage = async () => { + // await jestPlaywright.resetPage(); + + const page = global.browser.newPage(); + + const start = new Date(); + const targetURL = sanitizeURL(process.env.TARGET_URL || `http://localhost:6006`); + + const referenceURL = process.env.REFERENCE_URL && sanitizeURL(process.env.REFERENCE_URL); + + if ('TARGET_URL' in process.env && !process.env.TARGET_URL) { + console.log( + `Received TARGET_URL but with a falsy value: ${process.env.TARGET_URL}, will fallback to ${targetURL} instead.` + ); + } + + await page.goto(`${targetURL}iframe.html`, { waitUntil: 'load' }).catch((err) => { + if (err.message?.includes('ERR_CONNECTION_REFUSED')) { + const errorMessage = `Could not access the Storybook instance at ${targetURL}. Are you sure it's running?\n\n${err.message}`; + throw new Error(errorMessage); + } + + throw err; + }); // FIXME: configure + console.log(`page loaded in ${new Date() - start}ms.`); + + // if we ever want to log something from the browser to node + await page.exposeBinding('logToPage', (_, message) => console.log(message)); + + await page.addScriptTag({ + content: ` + class StorybookTestRunnerError extends Error { + constructor(storyId, errorMessage) { + super(errorMessage); + this.name = 'StorybookTestRunnerError'; + const storyUrl = \`${referenceURL || targetURL}?path=/story/\${storyId}\`; + const finalStoryUrl = \`\${storyUrl}&addonPanel=storybook/interactions/panel\`; + + this.message = \`\nAn error occurred in the following story:\n\${finalStoryUrl}\n\nMessage:\n \${errorMessage}\`; + } + } + + async function __throwError(storyId, errorMessage) { + throw new StorybookTestRunnerError(storyId, errorMessage); + } + + async function __waitForElement(selector) { + return new Promise((resolve, reject) => { + + const timeout = setTimeout(() => { + reject(); + }, 10000); + + if (document.querySelector(selector)) { + clearTimeout(timeout); + return resolve(document.querySelector(selector)); + } + + const observer = new MutationObserver(mutations => { + if (document.querySelector(selector)) { + clearTimeout(timeout); + resolve(document.querySelector(selector)); + observer.disconnect(); + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + }); + } + + async function __test(storyId) { + try { + await __waitForElement('#root'); + } catch(err) { + const message = \`Timed out waiting for Storybook to load after 10 seconds. Are you sure the Storybook is running correctly in that URL? Is the Storybook private (e.g. under authentication layers)?\n\n\nHTML: \${document.body.innerHTML}\`; + throw new StorybookTestRunnerError(storyId, message); + } + + const channel = window.__STORYBOOK_ADDONS_CHANNEL__; + if(!channel) { + throw new StorybookTestRunnerError( + storyId, + 'The test runner could not access the Storybook channel. Are you sure the Storybook is running correctly in that URL?' + ); + } + + return new Promise((resolve, reject) => { + channel.on('storyRendered', () => resolve(document.getElementById('root'))); + channel.on('storyUnchanged', () => resolve(document.getElementById('root'))); + channel.on('storyErrored', ({ description }) => reject( + new StorybookTestRunnerError(storyId, description)) + ); + channel.on('storyThrewException', (error) => reject( + new StorybookTestRunnerError(storyId, error.message)) + ); + channel.on('storyMissing', (id) => id === storyId && reject( + new StorybookTestRunnerError(storyId, 'The story was missing when trying to access it.')) + ); + + channel.emit('setCurrentStory', { storyId }); + }); + }; + `, + }); +}; diff --git a/test-runner-jest.config.js b/test-runner-jest.config.js index 3a05521e..39cc8e7e 100644 --- a/test-runner-jest.config.js +++ b/test-runner-jest.config.js @@ -12,6 +12,6 @@ module.exports = { }, globalSetup: './playwright/global-setup.js', globalTeardown: './playwright/global-teardown.js', - testEnvironment: './playwright/custom-environment.js', + // testEnvironment: './playwright/custom-environment.js', setupFilesAfterEnv: ['/jest-setup.js'], }; From c8d8e3d12b93f92abd86665a9390c2076ae167c5 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 23 Feb 2022 12:36:12 +0100 Subject: [PATCH 3/6] fix: reset page when the context is destroyed and retry test --- playwright/custom-environment.js | 98 +-------------------------- src/playwright/transformPlaywright.ts | 47 +++++++------ src/setup-page.ts | 6 +- 3 files changed, 32 insertions(+), 119 deletions(-) diff --git a/playwright/custom-environment.js b/playwright/custom-environment.js index ee76363b..5111e0a5 100644 --- a/playwright/custom-environment.js +++ b/playwright/custom-environment.js @@ -1,104 +1,12 @@ +const { setupPage } = require('../dist/cjs/setup-page'); + require('regenerator-runtime/runtime'); const PlaywrightEnvironment = require('jest-playwright-preset/lib/PlaywrightEnvironment').default; class CustomEnvironment extends PlaywrightEnvironment { async setup() { await super.setup(); - const page = this.global.page; - const start = new Date(); - const { TARGET_URL: targetUrl, REFERENCE_URL: referenceUrl } = process.env - - await page.goto(`${targetUrl}iframe.html`, { waitUntil: 'load' }).catch((err) => { - if (err.message?.includes('ERR_CONNECTION_REFUSED')) { - const errorMessage = `Could not access the Storybook instance at ${targetUrl}. Are you sure it's running?\n\n${err.message}`; - throw new Error(errorMessage) - } - - throw err; - }); // FIXME: configure - console.log(`page loaded in ${new Date() - start}ms.`); - - // if we ever want to log something from the browser to node - await page.exposeBinding('logToPage', (_, message) => console.log(message)); - - await page.addScriptTag({ - content: ` - class StorybookTestRunnerError extends Error { - constructor(storyId, errorMessage) { - super(errorMessage); - this.name = 'StorybookTestRunnerError'; - const storyUrl = \`${referenceUrl || targetUrl}?path=/story/\${storyId}\`; - const finalStoryUrl = \`\${storyUrl}&addonPanel=storybook/interactions/panel\`; - - this.message = \`\nAn error occurred in the following story:\n\${finalStoryUrl}\n\nMessage:\n \${errorMessage}\`; - } - } - - async function __throwError(storyId, errorMessage) { - throw new StorybookTestRunnerError(storyId, errorMessage); - } - - async function __waitForElement(selector) { - return new Promise((resolve, reject) => { - - const timeout = setTimeout(() => { - reject(); - }, 10000); - - if (document.querySelector(selector)) { - clearTimeout(timeout); - return resolve(document.querySelector(selector)); - } - - const observer = new MutationObserver(mutations => { - if (document.querySelector(selector)) { - clearTimeout(timeout); - resolve(document.querySelector(selector)); - observer.disconnect(); - } - }); - - observer.observe(document.body, { - childList: true, - subtree: true - }); - }); - } - - async function __test(storyId) { - try { - await __waitForElement('#root'); - } catch(err) { - const message = \`Timed out waiting for Storybook to load after 10 seconds. Are you sure the Storybook is running correctly in that URL? Is the Storybook private (e.g. under authentication layers)?\n\n\nHTML: \${document.body.innerHTML}\`; - throw new StorybookTestRunnerError(storyId, message); - } - - const channel = window.__STORYBOOK_ADDONS_CHANNEL__; - if(!channel) { - throw new StorybookTestRunnerError( - storyId, - 'The test runner could not access the Storybook channel. Are you sure the Storybook is running correctly in that URL?' - ); - } - - return new Promise((resolve, reject) => { - channel.on('storyRendered', () => resolve(document.getElementById('root'))); - channel.on('storyUnchanged', () => resolve(document.getElementById('root'))); - channel.on('storyErrored', ({ description }) => reject( - new StorybookTestRunnerError(storyId, description)) - ); - channel.on('storyThrewException', (error) => reject( - new StorybookTestRunnerError(storyId, error.message)) - ); - channel.on('storyMissing', (id) => id === storyId && reject( - new StorybookTestRunnerError(storyId, 'The story was missing when trying to access it.')) - ); - - channel.emit('setCurrentStory', { storyId }); - }); - }; - `, - }); + await setupPage(this.global.page) } async teardown() { diff --git a/src/playwright/transformPlaywright.ts b/src/playwright/transformPlaywright.ts index 3500c0e7..ac2b0b52 100644 --- a/src/playwright/transformPlaywright.ts +++ b/src/playwright/transformPlaywright.ts @@ -10,33 +10,43 @@ const filePrefixer = template(` const { setupPage } = require('../../dist/cjs'); `); -const beforeEachPrefixer = template(` - async () => setupPage(global.page) -`); - export const testPrefixer = template( ` console.log({ id: %%id%%, title: %%title%%, name: %%name%%, storyExport: %%storyExport%% }); async () => { - const context = { id: %%id%%, title: %%title%%, name: %%name%% }; + const testFn = async() => { + const context = { id: %%id%%, title: %%title%%, name: %%name%% }; - page.on('pageerror', (err) => { - page.evaluate(({ id, err }) => __throwError(id, err), { id: %%id%%, err: err.message }); - }); + page.on('pageerror', (err) => { + page.evaluate(({ id, err }) => __throwError(id, err), { id: %%id%%, err: err.message }); + }); - if(global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if(global.__sbPreRender) { + await global.__sbPreRender(page, context); + } - const result = await page.evaluate(({ id, hasPlayFn }) => __test(id, hasPlayFn), { - id: %%id%%, - }); + const result = await page.evaluate(({ id, hasPlayFn }) => __test(id, hasPlayFn), { + id: %%id%%, + }); + + if(global.__sbPostRender) { + await global.__sbPostRender(page, context); + } - if(global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + return result; + }; - return result; + try { + await testFn(); + } catch(err) { + if(err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } } `, { @@ -57,7 +67,6 @@ export const transformPlaywright = (src: string, filename: string) => { filePrefixer, // @ts-ignore testPrefixer, - beforeEachPrefixer, insertTestIfEmpty: true, clearBody: true, defaultTitle, diff --git a/src/setup-page.ts b/src/setup-page.ts index 1417b430..87d6ac7e 100644 --- a/src/setup-page.ts +++ b/src/setup-page.ts @@ -17,11 +17,7 @@ const sanitizeURL = (url) => { return finalURL; }; -export const setupPage = async () => { - // await jestPlaywright.resetPage(); - - const page = global.browser.newPage(); - +export const setupPage = async (page) => { const start = new Date(); const targetURL = sanitizeURL(process.env.TARGET_URL || `http://localhost:6006`); From 62c427aa902f2a9a0fa2147fbd8ad66ddb84654b Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 23 Feb 2022 13:03:59 +0100 Subject: [PATCH 4/6] test: update snapshots --- src/playwright/transformPlaywright.test.ts | 213 +++++++++------ .../transformPlaywrightJson.test.ts | 256 +++++++++++------- 2 files changed, 285 insertions(+), 184 deletions(-) diff --git a/src/playwright/transformPlaywright.test.ts b/src/playwright/transformPlaywright.test.ts index d441d484..c04897c9 100644 --- a/src/playwright/transformPlaywright.test.ts +++ b/src/playwright/transformPlaywright.test.ts @@ -49,44 +49,59 @@ describe('Playwright', () => { ).toMatchInlineSnapshot(` import global from 'global'; + const { + setupPage + } = require('../../dist/cjs'); + if (!require.main) { describe("foo/bar", () => { - beforeEach(async () => { - await jestPlaywright.resetPage(); - }); describe("A", () => { it("play-test", async () => { - const context = { - id: "foo-bar--a", - title: "foo/bar", - name: "A" - }; - page.on('pageerror', err => { - page.evaluate(({ - id, - err - }) => __throwError(id, err), { + const testFn = async () => { + const context = { id: "foo-bar--a", - err: err.message + title: "foo/bar", + name: "A" + }; + page.on('pageerror', err => { + page.evaluate(({ + id, + err + }) => __throwError(id, err), { + id: "foo-bar--a", + err: err.message + }); }); - }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if (global.__sbPreRender) { + await global.__sbPreRender(page, context); + } - const result = await page.evaluate(({ - id, - hasPlayFn - }) => __test(id, hasPlayFn), { - id: "foo-bar--a" - }); + const result = await page.evaluate(({ + id, + hasPlayFn + }) => __test(id, hasPlayFn), { + id: "foo-bar--a" + }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + if (global.__sbPostRender) { + await global.__sbPostRender(page, context); + } - return result; + return result; + }; + + try { + await testFn(); + } catch (err) { + if (err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } }); }); }); @@ -105,44 +120,59 @@ describe('Playwright', () => { ).toMatchInlineSnapshot(` import global from 'global'; + const { + setupPage + } = require('../../dist/cjs'); + if (!require.main) { describe("foo/bar", () => { - beforeEach(async () => { - await jestPlaywright.resetPage(); - }); describe("A", () => { it("smoke-test", async () => { - const context = { - id: "foo-bar--a", - title: "foo/bar", - name: "A" - }; - page.on('pageerror', err => { - page.evaluate(({ - id, - err - }) => __throwError(id, err), { + const testFn = async () => { + const context = { id: "foo-bar--a", - err: err.message + title: "foo/bar", + name: "A" + }; + page.on('pageerror', err => { + page.evaluate(({ + id, + err + }) => __throwError(id, err), { + id: "foo-bar--a", + err: err.message + }); }); - }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if (global.__sbPreRender) { + await global.__sbPreRender(page, context); + } - const result = await page.evaluate(({ - id, - hasPlayFn - }) => __test(id, hasPlayFn), { - id: "foo-bar--a" - }); + const result = await page.evaluate(({ + id, + hasPlayFn + }) => __test(id, hasPlayFn), { + id: "foo-bar--a" + }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + if (global.__sbPostRender) { + await global.__sbPostRender(page, context); + } + + return result; + }; - return result; + try { + await testFn(); + } catch (err) { + if (err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } }); }); }); @@ -162,44 +192,59 @@ describe('Playwright', () => { ).toMatchInlineSnapshot(` import global from 'global'; + const { + setupPage + } = require('../../dist/cjs'); + if (!require.main) { describe("Example/Header", () => { - beforeEach(async () => { - await jestPlaywright.resetPage(); - }); describe("A", () => { it("smoke-test", async () => { - const context = { - id: "example-header--a", - title: "Example/Header", - name: "A" - }; - page.on('pageerror', err => { - page.evaluate(({ - id, - err - }) => __throwError(id, err), { + const testFn = async () => { + const context = { id: "example-header--a", - err: err.message + title: "Example/Header", + name: "A" + }; + page.on('pageerror', err => { + page.evaluate(({ + id, + err + }) => __throwError(id, err), { + id: "example-header--a", + err: err.message + }); }); - }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if (global.__sbPreRender) { + await global.__sbPreRender(page, context); + } + + const result = await page.evaluate(({ + id, + hasPlayFn + }) => __test(id, hasPlayFn), { + id: "example-header--a" + }); - const result = await page.evaluate(({ - id, - hasPlayFn - }) => __test(id, hasPlayFn), { - id: "example-header--a" - }); + if (global.__sbPostRender) { + await global.__sbPostRender(page, context); + } - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + return result; + }; - return result; + try { + await testFn(); + } catch (err) { + if (err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } }); }); }); diff --git a/src/playwright/transformPlaywrightJson.test.ts b/src/playwright/transformPlaywrightJson.test.ts index 6916f19f..d991e0a3 100644 --- a/src/playwright/transformPlaywrightJson.test.ts +++ b/src/playwright/transformPlaywrightJson.test.ts @@ -52,109 +52,151 @@ Object { "example-header": "describe(\\"Example/Header\\", () => { describe(\\"Logged In\\", () => { it(\\"test\\", async () => { - const context = { - id: \\"example-header--logged-in\\", - title: \\"Example/Header\\", - name: \\"Logged In\\" - }; - page.on('pageerror', err => { - page.evaluate(({ - id, - err - }) => __throwError(id, err), { + const testFn = async () => { + const context = { id: \\"example-header--logged-in\\", - err: err.message + title: \\"Example/Header\\", + name: \\"Logged In\\" + }; + page.on('pageerror', err => { + page.evaluate(({ + id, + err + }) => __throwError(id, err), { + id: \\"example-header--logged-in\\", + err: err.message + }); }); - }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if (global.__sbPreRender) { + await global.__sbPreRender(page, context); + } + + const result = await page.evaluate(({ + id, + hasPlayFn + }) => __test(id, hasPlayFn), { + id: \\"example-header--logged-in\\" + }); - const result = await page.evaluate(({ - id, - hasPlayFn - }) => __test(id, hasPlayFn), { - id: \\"example-header--logged-in\\" - }); + if (global.__sbPostRender) { + await global.__sbPostRender(page, context); + } - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + return result; + }; - return result; + try { + await testFn(); + } catch (err) { + if (err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } }); }); describe(\\"Logged Out\\", () => { it(\\"test\\", async () => { - const context = { - id: \\"example-header--logged-out\\", - title: \\"Example/Header\\", - name: \\"Logged Out\\" - }; - page.on('pageerror', err => { - page.evaluate(({ - id, - err - }) => __throwError(id, err), { + const testFn = async () => { + const context = { id: \\"example-header--logged-out\\", - err: err.message + title: \\"Example/Header\\", + name: \\"Logged Out\\" + }; + page.on('pageerror', err => { + page.evaluate(({ + id, + err + }) => __throwError(id, err), { + id: \\"example-header--logged-out\\", + err: err.message + }); }); - }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if (global.__sbPreRender) { + await global.__sbPreRender(page, context); + } + + const result = await page.evaluate(({ + id, + hasPlayFn + }) => __test(id, hasPlayFn), { + id: \\"example-header--logged-out\\" + }); - const result = await page.evaluate(({ - id, - hasPlayFn - }) => __test(id, hasPlayFn), { - id: \\"example-header--logged-out\\" - }); + if (global.__sbPostRender) { + await global.__sbPostRender(page, context); + } - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + return result; + }; - return result; + try { + await testFn(); + } catch (err) { + if (err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } }); }); });", "example-page": "describe(\\"Example/Page\\", () => { describe(\\"Logged In\\", () => { it(\\"test\\", async () => { - const context = { - id: \\"example-page--logged-in\\", - title: \\"Example/Page\\", - name: \\"Logged In\\" - }; - page.on('pageerror', err => { - page.evaluate(({ - id, - err - }) => __throwError(id, err), { + const testFn = async () => { + const context = { id: \\"example-page--logged-in\\", - err: err.message + title: \\"Example/Page\\", + name: \\"Logged In\\" + }; + page.on('pageerror', err => { + page.evaluate(({ + id, + err + }) => __throwError(id, err), { + id: \\"example-page--logged-in\\", + err: err.message + }); }); - }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if (global.__sbPreRender) { + await global.__sbPreRender(page, context); + } + + const result = await page.evaluate(({ + id, + hasPlayFn + }) => __test(id, hasPlayFn), { + id: \\"example-page--logged-in\\" + }); - const result = await page.evaluate(({ - id, - hasPlayFn - }) => __test(id, hasPlayFn), { - id: \\"example-page--logged-in\\" - }); + if (global.__sbPostRender) { + await global.__sbPostRender(page, context); + } - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + return result; + }; - return result; + try { + await testFn(); + } catch (err) { + if (err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } }); }); });", @@ -199,37 +241,51 @@ Object { "example-page": "describe(\\"Example/Page\\", () => { describe(\\"Logged In\\", () => { it(\\"test\\", async () => { - const context = { - id: \\"example-page--logged-in\\", - title: \\"Example/Page\\", - name: \\"Logged In\\" - }; - page.on('pageerror', err => { - page.evaluate(({ - id, - err - }) => __throwError(id, err), { + const testFn = async () => { + const context = { id: \\"example-page--logged-in\\", - err: err.message + title: \\"Example/Page\\", + name: \\"Logged In\\" + }; + page.on('pageerror', err => { + page.evaluate(({ + id, + err + }) => __throwError(id, err), { + id: \\"example-page--logged-in\\", + err: err.message + }); }); - }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); - } + if (global.__sbPreRender) { + await global.__sbPreRender(page, context); + } + + const result = await page.evaluate(({ + id, + hasPlayFn + }) => __test(id, hasPlayFn), { + id: \\"example-page--logged-in\\" + }); - const result = await page.evaluate(({ - id, - hasPlayFn - }) => __test(id, hasPlayFn), { - id: \\"example-page--logged-in\\" - }); + if (global.__sbPostRender) { + await global.__sbPostRender(page, context); + } - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); - } + return result; + }; - return result; + try { + await testFn(); + } catch (err) { + if (err.toString().includes('Execution context was destroyed')) { + await jestPlaywright.resetPage(); + await setupPage(global.page); + await testFn(); + } else { + throw err; + } + } }); }); });", From 668e34b8c28caa980185c0883941378aad5e895f Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 23 Feb 2022 15:13:02 +0100 Subject: [PATCH 5/6] small fixes --- src/csf/transformCsf.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/csf/transformCsf.ts b/src/csf/transformCsf.ts index 6f3bd7db..d1bc5078 100644 --- a/src/csf/transformCsf.ts +++ b/src/csf/transformCsf.ts @@ -75,7 +75,7 @@ const makeDescribe = ( ); }; -const makeBeforeEach = (beforeEachPrefixer?: FilePrefixer) => { +const makeBeforeEach = (beforeEachPrefixer: FilePrefixer) => { const stmt = beforeEachPrefixer() as t.ExpressionStatement; return t.expressionStatement(t.callExpression(t.identifier('beforeEach'), [stmt.expression])); @@ -131,9 +131,6 @@ export const transformCsf = ( } if (!clearBody) result = `${result}${code}\n`; if (allTests.length) { - if (beforeEachPrefixer) { - makeBeforeEach(beforeEachPrefixer); - } const describe = makeDescribe( csf.meta.title, allTests, From e38bd00e4a45b629c313a04fa401baca542425a0 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 23 Feb 2022 16:20:28 +0100 Subject: [PATCH 6/6] fix stress tests --- .gitignore | 2 +- scripts/generate-dynamic-stories.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 11dff938..d92e0ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ build-storybook.log .DS_Store .env .cache -stories/stress-test +stories/atoms/StressTest.stories.js yarn-error.log \ No newline at end of file diff --git a/scripts/generate-dynamic-stories.js b/scripts/generate-dynamic-stories.js index 1f6547ac..1f526c9e 100644 --- a/scripts/generate-dynamic-stories.js +++ b/scripts/generate-dynamic-stories.js @@ -1,6 +1,6 @@ const fs = require('fs'); -const storiesFolderPath = 'stories/stress-test'; +const storiesFolderPath = 'stories/atoms'; if (!fs.existsSync(storiesFolderPath)) { fs.mkdirSync(storiesFolderPath); @@ -11,7 +11,7 @@ const storyCount = Number(process.env.DYNAMIC_STORIES_COUNT) || 500; let content = ` import React from 'react'; -import { Button } from '../basic/Button'; +import { Button } from './Button'; export default { title: 'StressTest',