Skip to content

Commit

Permalink
merge tags from preview annotations with meta and story tags
Browse files Browse the repository at this point in the history
  • Loading branch information
yannbf committed Jun 21, 2024
1 parent 1939323 commit 2559864
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 7 deletions.
8 changes: 7 additions & 1 deletion .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Preview } from '@storybook/react';
import { isTestRunner } from './is-test-runner';

const withSkippableTests = (StoryFn, { parameters }) => {
Expand All @@ -8,4 +9,9 @@ const withSkippableTests = (StoryFn, { parameters }) => {
return StoryFn();
};

export const decorators = [withSkippableTests];
const preview: Preview = {
tags: ['global-tag'],
decorators: [withSkippableTests],
};

export default preview;
6 changes: 4 additions & 2 deletions src/csf/transformCsf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ export const transformCsf = (
beforeEachPrefixer,
insertTestIfEmpty,
makeTitle,
}: TransformOptions
previewAnnotations = { tags: [] },
}: TransformOptions & { previewAnnotations?: Record<string, any> }
) => {
const { includeTags, excludeTags, skipTags } = getTagOptions();

Expand All @@ -130,7 +131,8 @@ export const transformCsf = (
'test',
'dev',
...(csf.meta?.tags || []),
...(csf._stories[key].tags || [])
...(csf._stories[key].tags || []),
...previewAnnotations.tags
);

return acc;
Expand Down
101 changes: 98 additions & 3 deletions src/playwright/transformPlaywright.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('Playwright', () => {
delete process.env.STORYBOOK_INCLUDE_TAGS;
delete process.env.STORYBOOK_EXCLUDE_TAGS;
delete process.env.STORYBOOK_SKIP_TAGS;
delete process.env.STORYBOOK_PREVIEW_TAGS;
});

describe('tag filtering mechanism', () => {
Expand Down Expand Up @@ -324,22 +325,26 @@ describe('Playwright', () => {
`);
});
it('should work in conjunction with includeTags, excludeTags and skipTags', () => {
process.env.STORYBOOK_INCLUDE_TAGS = 'play,design';
process.env.STORYBOOK_INCLUDE_TAGS = 'play,design,global-tag';
process.env.STORYBOOK_SKIP_TAGS = 'skip';
process.env.STORYBOOK_EXCLUDE_TAGS = 'exclude';
process.env.STORYBOOK_PREVIEW_TAGS = 'global-tag';

// Should result in:
// - A being excluded
// - B being included, but skipped
// - C being included
// - D being excluded
// - D being included
// - E being excluded
expect(
transformPlaywright(
dedent`
export default { title: 'foo/bar', component: Button };
export const A = { tags: ['play', 'exclude'] };
export const B = { tags: ['play', 'skip'] };
export const C = { tags: ['design'] };
export const D = { };
export const D = { tags: ['global-tag'] };
export const E = { };
`,
filename
)
Expand Down Expand Up @@ -436,6 +441,96 @@ describe('Playwright', () => {
}
});
});
describe("D", () => {
it("smoke-test", async () => {
const testFn = async () => {
const context = {
id: "example-foo-bar--d",
title: "Example/foo/bar",
name: "D"
};
if (globalThis.__sbPreVisit) {
await globalThis.__sbPreVisit(page, context);
}
const result = await page.evaluate(({
id,
hasPlayFn
}) => __test(id, hasPlayFn), {
id: "example-foo-bar--d"
});
if (globalThis.__sbPostVisit) {
await globalThis.__sbPostVisit(page, context);
}
if (globalThis.__sbCollectCoverage) {
const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window);
if (!isCoverageSetupCorrectly) {
throw new Error(\`[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.
More info: https://github.com/storybookjs/test-runner#setting-up-code-coverage\`);
}
await jestPlaywright.saveCoverage(page);
}
return result;
};
try {
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"}/\${"D"}". Retrying...\`);
await jestPlaywright.resetPage();
await globalThis.__sbSetupPage(globalThis.page, globalThis.context);
await testFn();
} else {
throw err;
}
}
});
});
describe("E", () => {
it("smoke-test", async () => {
const testFn = async () => {
const context = {
id: "example-foo-bar--e",
title: "Example/foo/bar",
name: "E"
};
if (globalThis.__sbPreVisit) {
await globalThis.__sbPreVisit(page, context);
}
const result = await page.evaluate(({
id,
hasPlayFn
}) => __test(id, hasPlayFn), {
id: "example-foo-bar--e"
});
if (globalThis.__sbPostVisit) {
await globalThis.__sbPostVisit(page, context);
}
if (globalThis.__sbCollectCoverage) {
const isCoverageSetupCorrectly = await page.evaluate(() => '__coverage__' in window);
if (!isCoverageSetupCorrectly) {
throw new Error(\`[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.
More info: https://github.com/storybookjs/test-runner#setting-up-code-coverage\`);
}
await jestPlaywright.saveCoverage(page);
}
return result;
};
try {
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"}/\${"E"}". Retrying...\`);
await jestPlaywright.resetPage();
await globalThis.__sbSetupPage(globalThis.page, globalThis.context);
await testFn();
} else {
throw err;
}
}
});
});
});
}
`);
Expand Down
2 changes: 2 additions & 0 deletions src/playwright/transformPlaywright.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ const makeTitleFactory = (filename: string) => {
};

export const transformPlaywright = (src: string, filename: string) => {
const tags = process.env.STORYBOOK_PREVIEW_TAGS?.split(',') ?? [];
const transformOptions = {
testPrefixer,
insertTestIfEmpty: true,
clearBody: true,
makeTitle: makeTitleFactory(filename),
previewAnnotations: { tags },
};

const result = transformCsf(src, transformOptions);
Expand Down
18 changes: 17 additions & 1 deletion src/test-storybook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { execSync } from 'child_process';
import fetch from 'node-fetch';
import canBindToHost from 'can-bind-to-host';
import dedent from 'ts-dedent';
import path from 'path';
import path, { join, resolve } from 'path';
import tempy from 'tempy';

import { JestOptions, getCliOptions } from './util/getCliOptions';
Expand All @@ -15,6 +15,8 @@ import { transformPlaywrightJson } from './playwright/transformPlaywrightJson';

import { glob } from 'glob';
import { TestRunnerConfig } from './playwright/hooks';
import { getInterpretedFile } from '@storybook/core-common';
import { readConfig } from '@storybook/csf-tools';

// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
Expand Down Expand Up @@ -260,6 +262,16 @@ function warnOnce(message: string) {
};
}

const extractTagsFromPreview = async (configDir = '.storybook') => {
const previewConfigPath = getInterpretedFile(join(resolve(configDir), 'preview'));

if (!previewConfigPath) return [];
const previewConfig = await readConfig(previewConfigPath);
const tags = previewConfig.getFieldValue(['tags']) ?? [];

return tags.join(',');
};

const main = async () => {
const { jestOptions, runnerOptions } = getCliOptions();

Expand Down Expand Up @@ -368,6 +380,10 @@ const main = async () => {
const { storiesPaths, lazyCompilation } = getStorybookMetadata();
process.env.STORYBOOK_STORIES_PATTERN = storiesPaths;

// 1 - We extract tags from preview file statically like it's done by the Storybook indexer. We only do this in non-index-json mode because it's not needed in that mode
// 2 - We pass it via env variable to avoid having to use async code in the babel plugin
process.env.STORYBOOK_PREVIEW_TAGS = await extractTagsFromPreview(runnerOptions.configDir);

if (lazyCompilation && isLocalStorybookIp) {
log(
`You're running Storybook with lazy compilation enabled, and will likely cause issues with the test runner locally. Consider disabling 'lazyCompilation' in ${runnerOptions.configDir}/main.js when running 'test-storybook' locally.`
Expand Down

0 comments on commit 2559864

Please sign in to comment.