Storybook: StoryShots, TypeScript and multiSnapshotWithOptions does not work

Created on 11 May 2020  ·  2Comments  ·  Source: storybookjs/storybook

Describe the bug
I'm having issues getting TypeScript, StoryShots and multiSnapshotWithOptions to work nicely together.

To Reproduce

  1. Clone this repo: https://github.com/torkelrogstad/storyshots-test. It was created by doing 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.tsx
  2. Run yarn install
  3. Run yarn test --watchAll
  4. Observe this output:
 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 
storyshots question / support

Most helpful comment

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

All 2 comments

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:

  1. Set it in the package.json jest field
  2. Pass it directly to the test command: yarn 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:

  1. yarn eject
  2. yarn test --showConfig
  3. Taking the relevant output of the previous command and inserting it into a jest.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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

43081j picture 43081j  ·  61Comments

hckhanh picture hckhanh  ·  69Comments

p3k picture p3k  ·  61Comments

hansthinhle picture hansthinhle  ·  57Comments

tycho01 picture tycho01  ·  76Comments