diff --git a/addons/storyshots/storyshots-core/.storybook/config.js b/addons/storyshots/storyshots-core/.storybook/config.js index b783ddbd5679..04b51c0e405f 100644 --- a/addons/storyshots/storyshots-core/.storybook/config.js +++ b/addons/storyshots/storyshots-core/.storybook/config.js @@ -1,10 +1,9 @@ import { configure } from '@storybook/react'; -const req = require.context('../stories/required_with_context', true, /\.stories\.js$/); - -function loadStories() { - req.keys().forEach(filename => req(filename)); - require('../stories/directly_required'); -} - -configure(loadStories, module); +configure( + [ + require.context('../stories/required_with_context', false, /\.stories\.js$/), + require.context('../stories/directly_required', false, /index\.js$/), + ], + module +); diff --git a/addons/storyshots/storyshots-core/.storybook/configTest.js b/addons/storyshots/storyshots-core/.storybook/configTest.js index aa36b49e68ab..8ae32982a9b9 100644 --- a/addons/storyshots/storyshots-core/.storybook/configTest.js +++ b/addons/storyshots/storyshots-core/.storybook/configTest.js @@ -1,11 +1,12 @@ import { configure } from '@storybook/react'; -const req = require.context('../stories/required_with_context', true, /\.stories\.js$/); +const req = require.context('../stories/required_with_context', false, /\.stories\.js$/); -function loadStories() { - req.keys().forEach(filename => req(filename)); +const loadStories = () => { + const result = req.keys().map(filename => req(filename)); // eslint-disable-next-line global-require require('../stories/directly_required'); -} + return result; +}; configure(loadStories, module); diff --git a/addons/storyshots/storyshots-core/README.md b/addons/storyshots/storyshots-core/README.md index fcfefed34de5..65212ba913bc 100644 --- a/addons/storyshots/storyshots-core/README.md +++ b/addons/storyshots/storyshots-core/README.md @@ -588,6 +588,16 @@ Like the default, but allows you to specify a set of options for the renderer, j ### `multiSnapshotWithOptions(options)` Like `snapshotWithOptions`, but generate a separate snapshot file for each stories file rather than a single monolithic file (as is the convention in Jest). This makes it dramatically easier to review changes. If you'd like the benefit of separate snapshot files, but don't have custom options to pass, simply pass an empty object. +If you use [Component Story Format](https://storybook.js.org/docs/formats/component-story-format/), you may also need to add an additional Jest transform to automate detecting story file names: +```js +// jest.config.js +module.exports = { + transform: { + '^.+\\.stories\\.jsx?$': '@storybook/addon-storyshots/injectFileName', + '^.+\\.jsx?$': 'babel-jest', + }, +}; +``` #### integrityOptions diff --git a/addons/storyshots/storyshots-core/injectFileName.js b/addons/storyshots/storyshots-core/injectFileName.js new file mode 100644 index 000000000000..2b2cd5ca7799 --- /dev/null +++ b/addons/storyshots/storyshots-core/injectFileName.js @@ -0,0 +1,23 @@ +const { ScriptTransformer } = require('@jest/transform'); + +const getNextTransformer = (fileName, config) => { + const self = config.transform.find(([pattern]) => new RegExp(pattern).test(fileName)); + return new ScriptTransformer({ + ...config, + transform: config.transform.filter(entry => entry !== self), + }); +}; + +module.exports = { + process(src, fileName, config, { instrument }) { + const transformer = getNextTransformer(fileName, config); + const { code } = transformer.transformSource(fileName, src, instrument); + + return `${code}; +if(exports.default != null) { + exports.default.parameters = exports.default.parameters || {}; + exports.default.parameters.fileName = '${fileName}'; +} +`; + }, +}; diff --git a/addons/storyshots/storyshots-core/package.json b/addons/storyshots/storyshots-core/package.json index b98d47a532b7..be68367b2269 100644 --- a/addons/storyshots/storyshots-core/package.json +++ b/addons/storyshots/storyshots-core/package.json @@ -29,13 +29,15 @@ "storybook": "start-storybook -p 6006" }, "dependencies": { + "@jest/transform": "^24.9.0", "@storybook/addons": "5.2.1", "core-js": "^3.0.1", "glob": "^7.1.3", "global": "^4.3.2", "jest-specific-snapshot": "^2.0.0", "read-pkg-up": "^6.0.0", - "regenerator-runtime": "^0.12.1" + "regenerator-runtime": "^0.12.1", + "ts-dedent": "^1.1.0" }, "devDependencies": { "enzyme-to-json": "^3.3.5", diff --git a/addons/storyshots/storyshots-core/src/Stories2SnapsConverter.js b/addons/storyshots/storyshots-core/src/Stories2SnapsConverter.js index 626a467cdec0..afe797491d8f 100644 --- a/addons/storyshots/storyshots-core/src/Stories2SnapsConverter.js +++ b/addons/storyshots/storyshots-core/src/Stories2SnapsConverter.js @@ -1,4 +1,5 @@ import path from 'path'; +import dedent from 'ts-dedent'; const defaultOptions = { snapshotsDirName: '__snapshots__', @@ -24,9 +25,20 @@ class DefaultStories2SnapsConverter { } getSnapshotFileName(context) { - const { fileName } = context; + const { fileName, kind } = context; if (!fileName) { + // eslint-disable-next-line no-console + console.warn( + dedent` + Storybook was unable to detect filename for stories of kind "${kind}". + To fix it, add following to your jest.config.js: + transform: { + // should be above any other js transform like babel-jest + '^.+\\\\.stories\\\\.js$': '@storybook/addon-storyshots/injectFileName', + } + ` + ); return null; } diff --git a/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.enzyme.test.js.snap b/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.enzyme.test.js.snap index cae5deca1852..7cce1557a845 100644 --- a/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.enzyme.test.js.snap +++ b/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.enzyme.test.js.snap @@ -53,13 +53,13 @@ exports[`Storyshots Another Button with text 1`] = ` `; -exports[`Storyshots Async with 5ms timeout simulating async operation 1`] = ` +exports[`Storyshots Async With Timeout 1`] = `

`; -exports[`Storyshots Button with some emoji 1`] = ` +exports[`Storyshots Button With Some Emoji 1`] = ` `; -exports[`Storyshots Button with text 1`] = ` +exports[`Storyshots Button With Text 1`] = ` `; -exports[`Storyshots Welcome to Storybook 1`] = ` +exports[`Storyshots Welcome To Storybook 1`] = ` diff --git a/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.shallow.test.js.snap b/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.shallow.test.js.snap index e192aeccad5b..9410e1ba2f89 100644 --- a/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.shallow.test.js.snap +++ b/addons/storyshots/storyshots-core/stories/__snapshots__/storyshot.shallow.test.js.snap @@ -45,13 +45,13 @@ exports[`Storyshots Another Button with text 1`] = ` `; -exports[`Storyshots Async with 5ms timeout simulating async operation 1`] = ` +exports[`Storyshots Async With Timeout 1`] = `

`; -exports[`Storyshots Button with some emoji 1`] = ` +exports[`Storyshots Button With Some Emoji 1`] = `