diff --git a/package.json b/package.json index 8c0dffe7..6c0f80ba 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,6 @@ "can-bind-to-host": "^1.1.1", "commander": "^9.0.0", "expect-playwright": "^0.8.0", - "global": "^4.4.0", "jest": "^28.0.0", "jest-environment-node":"^28.0.0", "jest-circus":"^28.0.0", diff --git a/playwright/jest-setup.js b/playwright/jest-setup.js index bf0d2bb4..222efea0 100644 --- a/playwright/jest-setup.js +++ b/playwright/jest-setup.js @@ -1,4 +1,4 @@ -const { getTestRunnerConfig, setPreRender, setPostRender } = require('../dist/cjs'); +const { getTestRunnerConfig, setPreRender, setPostRender, setupPage } = require('../dist/cjs'); const testRunnerConfig = getTestRunnerConfig(process.env.STORYBOOK_CONFIG_DIR); if (testRunnerConfig) { @@ -13,4 +13,7 @@ if (testRunnerConfig) { } } -global.__sbCollectCoverage = process.env.STORYBOOK_COLLECT_COVERAGE === 'true'; +// If the transformed tests need a dependency, it has to be globally available +// in order to work both in defaul (file transformation) and stories/index.json mode. +globalThis.__sbSetupPage = setupPage; +globalThis.__sbCollectCoverage = process.env.STORYBOOK_COLLECT_COVERAGE === 'true'; diff --git a/src/csf/transformCsf.ts b/src/csf/transformCsf.ts index cf7646ba..4356fe9d 100644 --- a/src/csf/transformCsf.ts +++ b/src/csf/transformCsf.ts @@ -5,8 +5,6 @@ import generate from '@babel/generator'; import { toId, storyNameFromExport } from '@storybook/csf'; import dedent from 'ts-dedent'; -const logger = console; - export interface TestContext { storyExport?: t.Identifier; name: t.Literal; @@ -19,7 +17,6 @@ export type TestPrefixer = (context: TestContext) => TemplateResult; interface TransformOptions { clearBody?: boolean; - filePrefixer?: FilePrefixer; beforeEachPrefixer?: FilePrefixer; testPrefixer?: TestPrefixer; insertTestIfEmpty?: boolean; @@ -87,7 +84,6 @@ const makeArray = (templateResult: TemplateResult) => export const transformCsf = ( code: string, { - filePrefixer, clearBody = false, testPrefixer, beforeEachPrefixer, @@ -124,11 +120,6 @@ export const transformCsf = ( let result = ''; - // FIXME: insert between imports - if (filePrefixer) { - const { code: prefixCode } = generate(t.program(makeArray(filePrefixer())), {}); - result = `${prefixCode}\n`; - } if (!clearBody) result = `${result}${code}\n`; if (allTests.length) { const describe = makeDescribe( diff --git a/src/playwright/hooks.ts b/src/playwright/hooks.ts index 52cc1930..67249eed 100644 --- a/src/playwright/hooks.ts +++ b/src/playwright/hooks.ts @@ -1,4 +1,3 @@ -import global from 'global'; import type { Page } from 'playwright'; import type { StoryContext } from '@storybook/csf'; @@ -17,11 +16,11 @@ export interface TestRunnerConfig { } export const setPreRender = (preRender: TestHook) => { - global.__sbPreRender = preRender; + globalThis.__sbPreRender = preRender; }; export const setPostRender = (postRender: TestHook) => { - global.__sbPostRender = postRender; + globalThis.__sbPostRender = postRender; }; export const getStoryContext = async (page: Page, context: TestContext): Promise => { diff --git a/src/playwright/transformPlaywright.test.ts b/src/playwright/transformPlaywright.test.ts index 63967496..ae63647c 100644 --- a/src/playwright/transformPlaywright.test.ts +++ b/src/playwright/transformPlaywright.test.ts @@ -47,12 +47,6 @@ describe('Playwright', () => { filename ) ).toMatchInlineSnapshot(` - import global from 'global'; - - const { - setupPage - } = require('@storybook/test-runner'); - if (!require.main) { describe("Example/foo/bar", () => { describe("A", () => { @@ -73,8 +67,8 @@ describe('Playwright', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -84,11 +78,11 @@ describe('Playwright', () => { id: "example-foo-bar--a" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -107,8 +101,9 @@ describe('Playwright', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: "\${"Example/foo/bar"}/\${"A"}". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -130,12 +125,6 @@ describe('Playwright', () => { filename ) ).toMatchInlineSnapshot(` - import global from 'global'; - - const { - setupPage - } = require('@storybook/test-runner'); - if (!require.main) { describe("Example/foo/bar", () => { describe("A", () => { @@ -156,8 +145,8 @@ describe('Playwright', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -167,11 +156,11 @@ describe('Playwright', () => { id: "example-foo-bar--a" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -190,8 +179,9 @@ describe('Playwright', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: "\${"Example/foo/bar"}/\${"A"}". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -214,12 +204,6 @@ describe('Playwright', () => { filename ) ).toMatchInlineSnapshot(` - import global from 'global'; - - const { - setupPage - } = require('@storybook/test-runner'); - if (!require.main) { describe("Example/Header", () => { describe("A", () => { @@ -240,8 +224,8 @@ describe('Playwright', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -251,11 +235,11 @@ describe('Playwright', () => { id: "example-header--a" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -274,8 +258,9 @@ describe('Playwright', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: "\${"Example/Header"}/\${"A"}". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; diff --git a/src/playwright/transformPlaywright.ts b/src/playwright/transformPlaywright.ts index 67ddb472..e6484334 100644 --- a/src/playwright/transformPlaywright.ts +++ b/src/playwright/transformPlaywright.ts @@ -7,11 +7,6 @@ import { transformCsf } from '../csf/transformCsf'; import type { TestPrefixer } from '../csf/transformCsf'; import dedent from 'ts-dedent'; -const filePrefixer = template(` - import global from 'global'; - const { setupPage } = require('@storybook/test-runner'); -`); - const coverageErrorMessage = dedent` [Test runner] An error occurred when evaluating code coverage: The code in this story is not instrumented, which means the coverage setup is likely not correct. @@ -29,19 +24,19 @@ export const testPrefixer = template( page.evaluate(({ id, err }) => __throwError(id, err), { id: %%id%%, err: err.message }); }); - if(global.__sbPreRender) { - await global.__sbPreRender(page, context); + if(globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ id, hasPlayFn }) => __test(id, hasPlayFn), { id: %%id%%, }); - if(global.__sbPostRender) { - await global.__sbPostRender(page, context); + if(globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if(global.__sbCollectCoverage) { + if(globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { throw new Error(\`${coverageErrorMessage}\`); @@ -57,8 +52,9 @@ export const testPrefixer = template( await testFn(); } catch(err) { if(err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: "\${%%title%%}/\${%%name%%}". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -80,7 +76,6 @@ const makeTitleFactory = (filename: string) => { export const transformPlaywright = (src: string, filename: string) => { const result = transformCsf(src, { - filePrefixer, testPrefixer, insertTestIfEmpty: true, clearBody: true, diff --git a/src/playwright/transformPlaywrightJson.test.ts b/src/playwright/transformPlaywrightJson.test.ts index bbabd6ae..6aa84b67 100644 --- a/src/playwright/transformPlaywrightJson.test.ts +++ b/src/playwright/transformPlaywrightJson.test.ts @@ -47,8 +47,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -58,11 +58,11 @@ describe('Playwright Json', () => { id: \\"example-header--logged-in\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -81,8 +81,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Header\\"}/\${\\"Logged In\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -108,8 +109,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -119,11 +120,11 @@ describe('Playwright Json', () => { id: \\"example-header--logged-out\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -142,8 +143,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Header\\"}/\${\\"Logged Out\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -171,8 +173,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -182,11 +184,11 @@ describe('Playwright Json', () => { id: \\"example-page--logged-in\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -205,8 +207,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Page\\"}/\${\\"Logged In\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -259,8 +262,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -270,11 +273,11 @@ describe('Playwright Json', () => { id: \\"example-page--logged-in\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -293,8 +296,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Page\\"}/\${\\"Logged In\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -375,8 +379,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -386,11 +390,11 @@ describe('Playwright Json', () => { id: \\"example-header--logged-in\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -409,8 +413,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Header\\"}/\${\\"Logged In\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -436,8 +441,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -447,11 +452,11 @@ describe('Playwright Json', () => { id: \\"example-header--logged-out\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -470,8 +475,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Header\\"}/\${\\"Logged Out\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -499,8 +505,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -510,11 +516,11 @@ describe('Playwright Json', () => { id: \\"example-page--logged-in\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -533,8 +539,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Page\\"}/\${\\"Logged In\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; @@ -600,8 +607,8 @@ describe('Playwright Json', () => { }); }); - if (global.__sbPreRender) { - await global.__sbPreRender(page, context); + if (globalThis.__sbPreRender) { + await globalThis.__sbPreRender(page, context); } const result = await page.evaluate(({ @@ -611,11 +618,11 @@ describe('Playwright Json', () => { id: \\"example-page--logged-in\\" }); - if (global.__sbPostRender) { - await global.__sbPostRender(page, context); + if (globalThis.__sbPostRender) { + await globalThis.__sbPostRender(page, context); } - if (global.__sbCollectCoverage) { + if (globalThis.__sbCollectCoverage) { const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window); if (!isCoverageSetupCorrectly) { @@ -634,8 +641,9 @@ describe('Playwright Json', () => { await testFn(); } catch (err) { if (err.toString().includes('Execution context was destroyed')) { + console.log(\`An error occurred in the following story, most likely because of a navigation: \\"\${\\"Example/Page\\"}/\${\\"Logged In\\"}\\". Retrying...\`); await jestPlaywright.resetPage(); - await setupPage(global.page); + await globalThis.__sbSetupPage(globalThis.page); await testFn(); } else { throw err; diff --git a/src/typings.d.ts b/src/typings.d.ts index 2f4eb9cf..4bf84d6a 100644 --- a/src/typings.d.ts +++ b/src/typings.d.ts @@ -1 +1,7 @@ -declare module 'global'; +import { TestHook } from './playwright/hooks'; + +declare global { + var __sbPreRender: TestHook; + var __sbPostRender: TestHook; + var __getContext: (storyId: string) => any; +}