Describe the bug
I'm having issues getting TypeScript, StoryShots and multiSnapshotWithOptions to work nicely together.
To Reproduce
yarn create react-app storyshots-test/ --template typescript, npx -p @storybook/cli sb init and adding src/Storyshots.test.ts, src/App.stories.tsx, src/Component.tsx and src/Component.stories.tsxyarn installyarn test --watchAll PASS src/App.test.tsx
PASS src/Storyshots.test.ts
● Console
console.warn node_modules/@storybook/addon-storyshots/dist/Stories2SnapsConverter.js:44
Storybook was unable to detect filename for stories of kind "App".
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',
}
console.warn node_modules/@storybook/addon-storyshots/dist/Stories2SnapsConverter.js:44
Storybook was unable to detect filename for stories of kind "Component".
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',
}
Test Suites: 2 passed, 2 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 5.142s
Ran all test suites.
Expected behavior
I expected my two stories to get run through a snapshot test.
Code snippets
The most interesting file here is src/Storyshots.test.ts:
import initStoryshots, {
multiSnapshotWithOptions,
Stories2SnapsConverter,
} from "@storybook/addon-storyshots";
import { mount } from "enzyme";
import toJson from "enzyme-to-json";
initStoryshots({
asyncJest: true,
test: ({ story, context, done }) => {
const converter = new Stories2SnapsConverter();
const snapshotFilename = converter.getSnapshotFileName(context);
const storyElement = story.render(context);
// mount the story
const tree = mount(storyElement);
// wait until the mount is updated,
const waitTime = 1;
setTimeout(() => {
if (snapshotFilename) {
expect(toJson(tree.update())).toMatchSpecificSnapshot(snapshotFilename);
}
done();
}, waitTime);
},
// if I remove the other `test` key and replace it with this, Jest times out
// if I also remove the `ayncJest` key, I end up with a different error message:
// Jest: `it` and `test` must return either a Promise or undefined.
// test: multiSnapshotWithOptions,
});
System:
Environment Info:
System:
OS: macOS 10.15.3
CPU: (8) x64 Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz
Binaries:
Node: 14.2.0 - /usr/local/bin/node
Yarn: 1.22.4 - /usr/local/bin/yarn
npm: 6.14.4 - /usr/local/bin/npm
Browsers:
Chrome: 81.0.4044.138
Firefox: 76.0
Safari: 13.0.5
npmPackages:
@storybook/addon-actions: ^5.3.18 => 5.3.18
@storybook/addon-links: ^5.3.18 => 5.3.18
@storybook/addon-storyshots: ^5.3.18 => 5.3.18
@storybook/addons: ^5.3.18 => 5.3.18
@storybook/preset-create-react-app: ^2.1.2 => 2.1.2
@storybook/react: ^5.3.18 => 5.3.18
I've tried to look into this as best I can, and I _think_ I know what's going on:
The following snippet _almost_ works with the code I linked above:
initStoryshots({
test: multiSnapshotWithOptions(),
})
The only missing piece is the custom Jest transformer that inserts the file name into the story. I can tell Jest to use that transformer through two different ways:
package.json jest fieldyarn test --transform <transform-string>~The issue then is that this completely overrides the configuration given by Create React App (which I'm using in both this minimized example, and the more complex real-world-application I'm working on (which is closed-source, unfortunately)).~
Correction: it does not override the transform configuration, but it adds the transformer at the end. Since there's already a transformer that matches my story files the file name injector does not get applied
I verified this by doing the following:
yarn ejectyarn test --showConfigjest.config.js file, alongside the @storybook/addon-storyshots/injectFileName Jest transformer. I know have working multi-snapshots 🎉
But I've also ejected from CRA, which I don't want to do...
I guess this might be more of a CRA issue then a Storybook issue. But are there any workarounds for this, that could solve my problem?
I found the solution!
I added a file jest.json:
{
"transform": {
"^.+\\.stories\\.tsx$": "@storybook/addon-storyshots/injectFileName",
"^.+\\.(js|jsx|ts|tsx)$": "react-scripts/config/jest/babelTransform.js",
"^.+\\.css$": "react-scripts/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "react-scripts/config/jest/fileTransform.js"
}
}
And replaced my test script in package.json with:
{
"test": "react-scripts test --transform $(jq -c .transform jest.json)",
}
This uses jq to read in the complete Jest transformation configuration and pass it to the test runner. I found the regexes and transformers above by looking at the Jest config generated by react-scripts
Most helpful comment
I found the solution!
I added a file
jest.json:And replaced my
testscript inpackage.jsonwith:This uses
jqto read in the complete Jest transformation configuration and pass it to the test runner. I found the regexes and transformers above by looking at the Jest config generated byreact-scripts