Skip to content

Commit b1db5ef

Browse files
authored
Merge pull request #35 from storybookjs/feat/CH-1358-support-auto-title
Support auto title stories
2 parents dd3dc55 + 8a26a58 commit b1db5ef

File tree

7 files changed

+125
-13
lines changed

7 files changed

+125
-13
lines changed

.storybook/main.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
const { STRESS_TEST, STORY_STORE_V7, WITHOUT_DOCS } = process.env;
22

3-
const stories = ['../stories/basic/*.stories.mdx', '../stories/basic/*.stories.@(js|jsx|ts|tsx)'];
3+
const stories = [
4+
{
5+
directory: '../stories',
6+
},
7+
];
48

59
if (STRESS_TEST) {
610
stories.push('../stories/stress-test/*.stories.@(js|jsx|ts|tsx)');

playwright/transform.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const { transformPlaywright } = require('../dist/cjs/playwright/transformPlaywri
33

44
module.exports = {
55
process(src, filename, config) {
6-
const csfTest = transformPlaywright(src);
6+
const csfTest = transformPlaywright(src, filename);
77

88
const result = babelTransform(csfTest, {
99
filename,

src/csf/transformCsf.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ export interface TestContext {
1616
}
1717
type FilePrefixer = () => t.Statement[];
1818
type TestPrefixer = (context: TestContext) => t.Statement[];
19-
const JEST_GLOBAL_REGEX = /(before|after)(All|Each)$/;
2019

2120
interface TransformOptions {
2221
clearBody?: boolean;
2322
filePrefixer?: FilePrefixer;
2423
testPrefixer?: TestPrefixer;
2524
insertTestIfEmpty?: boolean;
25+
defaultTitle?: string;
2626
}
2727

2828
const prefixFunction = (
@@ -73,9 +73,15 @@ const makeDescribe = (key: string, tests: t.Statement[]): t.Statement | null =>
7373

7474
export const transformCsf = (
7575
code: string,
76-
{ filePrefixer, clearBody = false, testPrefixer, insertTestIfEmpty }: TransformOptions = {}
76+
{
77+
filePrefixer,
78+
clearBody = false,
79+
testPrefixer,
80+
insertTestIfEmpty,
81+
defaultTitle,
82+
}: TransformOptions = {}
7783
) => {
78-
const csf = loadCsf(code, { defaultTitle: 'FIXME' });
84+
const csf = loadCsf(code, { defaultTitle });
7985
csf.parse();
8086

8187
const storyExports = Object.keys(csf._stories);

src/playwright/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { transform as babelTransform } from '@babel/core';
22
import { transformPlaywright } from './transformPlaywright';
33

44
export const process = (src: string, filename: string, config: any) => {
5-
const csfTest = transformPlaywright(src);
5+
const csfTest = transformPlaywright(src, filename);
66

77
const result = babelTransform(csfTest, {
88
filename,

src/playwright/transformPlaywright.test.ts

+76-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
11
import dedent from 'ts-dedent';
2+
import path from 'path';
3+
import * as coreCommon from '@storybook/core-common';
4+
25
import { transformPlaywright } from './transformPlaywright';
36

7+
jest.mock('@storybook/core-common');
8+
49
expect.addSnapshotSerializer({
510
print: (val: any) => val.trim(),
611
test: (val: any) => true,
712
});
813

914
describe('Playwright', () => {
15+
beforeEach(() => {
16+
const relativeSpy = jest.spyOn(path, 'relative');
17+
relativeSpy.mockReturnValueOnce('stories/basic/Header.stories.js');
18+
jest.spyOn(coreCommon, 'serverRequire').mockImplementation(() => ({
19+
stories: [
20+
{
21+
directory: '../stories/basic',
22+
titlePrefix: 'Example',
23+
},
24+
],
25+
}));
26+
jest.spyOn(coreCommon, 'normalizeStories').mockImplementation(() => [
27+
{
28+
titlePrefix: 'Example',
29+
files: '**/*.stories.@(mdx|tsx|ts|jsx|js)',
30+
directory: './stories/basic',
31+
importPathMatcher:
32+
/^\.[\\/](?:stories\/basic(?:\/(?!\.)(?:(?:(?!(?:^|\/)\.).)*?)\/|\/|$)(?!\.)(?=.)[^/]*?\.stories\.(mdx|tsx|ts|jsx|js))$/,
33+
},
34+
]);
35+
});
36+
37+
const filename = './stories/basic/Header.stories.js';
1038
it('should generate a play test when the story has a play function', () => {
1139
expect(
12-
transformPlaywright(dedent`
13-
export default { title: 'foo/bar' };
40+
transformPlaywright(
41+
dedent`
42+
export default { title: 'foo/bar', component: Button };
1443
export const A = () => {};
1544
A.play = () => {};
16-
`)
45+
`,
46+
filename
47+
)
1748
).toMatchInlineSnapshot(`
1849
if (!require.main) {
1950
describe("foo/bar", () => {
@@ -43,10 +74,13 @@ describe('Playwright', () => {
4374
});
4475
it('should generate a smoke test when story does not have a play function', () => {
4576
expect(
46-
transformPlaywright(dedent`
77+
transformPlaywright(
78+
dedent`
4779
export default { title: 'foo/bar' };
4880
export const A = () => {};
49-
`)
81+
`,
82+
filename
83+
)
5084
).toMatchInlineSnapshot(`
5185
if (!require.main) {
5286
describe("foo/bar", () => {
@@ -74,4 +108,41 @@ describe('Playwright', () => {
74108
}
75109
`);
76110
});
111+
112+
it('should generate a smoke test with auto title', () => {
113+
expect(
114+
transformPlaywright(
115+
dedent`
116+
export default { component: Button };
117+
export const A = () => {};
118+
`,
119+
filename
120+
)
121+
).toMatchInlineSnapshot(`
122+
if (!require.main) {
123+
describe("Example/Header", () => {
124+
describe("A", () => {
125+
it("smoke-test", async () => {
126+
page.on('pageerror', err => {
127+
page.evaluate(({
128+
id,
129+
err
130+
}) => __throwError(id, err), {
131+
id: "example-header--a",
132+
err: err.message
133+
});
134+
});
135+
return page.evaluate(({
136+
id,
137+
hasPlayFn
138+
}) => __test(id, hasPlayFn), {
139+
id: "example-header--a",
140+
hasPlayFn: false
141+
});
142+
});
143+
});
144+
});
145+
}
146+
`);
147+
});
77148
});

src/playwright/transformPlaywright.ts

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
import { resolve, join, relative } from 'path';
12
import template from '@babel/template';
3+
import { serverRequire, normalizeStories } from '@storybook/core-common';
4+
import { autoTitle } from '@storybook/store';
5+
26
import { transformCsf } from '../csf/transformCsf';
37

48
export const testPrefixer = template(
@@ -19,12 +23,40 @@ export const testPrefixer = template(
1923
plugins: ['jsx'],
2024
}
2125
);
22-
export const transformPlaywright = (src: string) => {
26+
27+
const getDefaultTitle = (filename: string) => {
28+
// we'll need to figure this out for different cases
29+
// e.g. --config-dir
30+
const configDir = resolve('.storybook');
31+
const workingDir = resolve();
32+
33+
const main = serverRequire(join(configDir, 'main'));
34+
35+
if (!main) {
36+
throw new Error(`Could not load main.js in ${configDir}`);
37+
}
38+
39+
const normalizedStoriesEntries = normalizeStories(main.stories, {
40+
configDir,
41+
workingDir,
42+
}).map((specifier) => ({
43+
...specifier,
44+
importPathMatcher: new RegExp(specifier.importPathMatcher),
45+
}));
46+
47+
const filePath = './' + relative(workingDir, filename);
48+
49+
return autoTitle(filePath, normalizedStoriesEntries);
50+
};
51+
52+
export const transformPlaywright = (src: string, filename: string) => {
53+
const defaultTitle = getDefaultTitle(filename);
2354
const result = transformCsf(src, {
2455
// @ts-ignore
2556
testPrefixer,
2657
insertTestIfEmpty: true,
2758
clearBody: true,
59+
defaultTitle,
2860
});
2961
return result;
3062
};

stories/basic/Button.stories.js

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
import { Button } from './Button';
1111

1212
export default {
13-
title: 'Example/Button',
1413
component: Button,
1514
argTypes: {
1615
onSubmit: { action: true },

0 commit comments

Comments
 (0)