Storybook: Storyshots fails with MDX stories via docs addon

Created on 28 Jun 2019  ยท  25Comments  ยท  Source: storybookjs/storybook

Describe the bug
If you try and use storyshots while using the docs addon, jest will try and import the MDX file, which will result in syntax errors (it not understanding markdown code and all)

To Reproduce
Steps to reproduce the behavior:

  1. Enable docs technical preview
  2. Setup storyshots
  3. Create an based MDX story
  4. Run jest

Expected behavior
Jest should create snapshots based on stories in MDX file like it does for jsx/tsx files or ignore them.

System:

  • OS: ubuntu
  • Device: N/A
  • Browser: N/A
  • Framework: react
  • Addons: docs, storyshots
  • Version: 5.2.0-alpha.29

Additional context

Not really that important as it's in alpha and i'm just poking at what the future might look like, but will probably cause lots of confusion after a stable release, the docs addon is awesome btw, looking forward to the final version.

I am thinking a webpack loader will be needed to transform the MDX a regular JSX file defining the stories?

docs storyshots bug has workaround in progress

Most helpful comment

storyshots found 0 stories

I faced a similar problem in CRA.
I tried fix problem. Try the following steps.

  • check jest transform ordering
$ yarn test --showConfig
... snip ...
"transform": [
  [
    "^.+\\.mdx$",   <------ check ordering before `fileTransform`
    "/path/to/project/node_modules/@storybook/addon-docs/jest-transform-mdx.js"
  ],
  [
    "^.+\\.(js|jsx|ts|tsx)$",
    "/path/to/project/node_modules/react-app-rewired/scripts/utils/babelTransform.js"
  ],
  [
    "^.+\\.css$",
    "/path/to/project/node_modules/react-scripts/config/jest/cssTransform.js"
  ],
  [
    "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)",
    /path/to/project/node_modules/react-scripts/config/jest/fileTransform.js"
  ]
],
  • modify node_modules/@storybook/addon-docs/jest-transform-mdx.js
@@ -29,6 +29,6 @@
       import { mdx } from '@mdx-js/react'
       ${mdx.sync(src, { compilers, filepath: filename })}
     `;
-    return getNextTransformer(filename, config).transformSource(filename, result, instrument);
+    return getNextTransformer(filename, config).transformSource(filename + '.jsx', result, instrument);
   },
 };

โ˜๏ธ I don't know if this is a bug. It might be better to create custom transformer.

  • modify node_modules/@storybook/components/dist/syntaxhighlighter/syntaxhighlighter.js
@@ -51,17 +51,17 @@
 var _memoizerific = _interopRequireDefault(require("memoizerific"));
-var _jsx = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/jsx"));
+var _jsx = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/jsx"));
-var _bash = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/bash"));
+var _bash = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/bash"));
-var _css = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/css"));
+var _css = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/css"));
-var _markup = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/markup"));
+var _markup = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/markup"));
-var _tsx = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/tsx"));
+var _tsx = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/tsx"));
-var _typescript = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/typescript"));
+var _typescript = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/typescript"));
 var _reactSyntaxHighlighter = require("react-syntax-highlighter");

fixed in v6.0.0-alpha.7 (https://github.com/storybookjs/storybook/pull/9780)

All 25 comments

This is also blocking this PR https://github.com/storybookjs/storybook/pull/7222 so we'll need to deal with it sooner rather than later.

@danielknell For now, I just added the mdx file to a list of fileMock files, so it effectively skips the test. Not a very good workaround, but it unbreaks storyshots.

There's already a webpack loader that transforms the stories into JSX. Do you have any interest in trying to get that working for jest? I probably don't have time to look at this much more for awhile, but I'd be happy to answer questions if you want to tackle it. The webpack setup is here: https://github.com/storybookjs/storybook/blob/next/addons/docs/common/preset.js

Out of curiosity: Will Storyshots still work with MDX files? E.g. for

import { action } from '@storybook/addon-actions';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';

<Meta title='MDX|Button' />

# Hello Docs

Welcome to the future of Storybook!

<Story name="hello">
  <Button onClick={action('clicked')}>Hello button!</Button>
</Story>

<Story name="with emoji">
  <Button onClick={action('clicked')}>๐Ÿค˜๐Ÿš€๐Ÿ’ฏ</Button>
</Story>

so that both stories get picked up?

@rwieruch See my comment
https://github.com/storybookjs/storybook/issues/7223#issuecomment-506912633

  • If we fileMock MDX files they will be ignored and the stories won't be picked up
  • If we write a jest transformation (equivalent to a webpack loader) or figure out how to adapt the webpack loader, these stories will be snapshotted. However, it requires investigation (help wanted!)
const createCompiler = require("@storybook/addon-docs/mdx-compiler-plugin");
const mdx = require("@mdx-js/mdx");
const babel = require("babel-jest");
const deasyncPromise = require("deasync-promise");

const compilers = [createCompiler({})];

module.exports = {
  process(src, filename, config, options) {
    let result = deasyncPromise(
      mdx(src, { compilers: compilers, filepath: filename }),
    );

    result = `/* @jsx mdx */
    import React from 'react'
    import { mdx } from '@mdx-js/react'
    ${result}
    `;

    return babel.process(result, filename, config, options);
  },
};

hacky as fuck but seems to work...?

using the following in jest config

{
  "transform": {
    "^.+\\.[tj]sx?$": "babel-jest",
    "^.+\\.mdx?$": "<rootDir>mdx.loader.js",
  }
}

Nice @danielknell. Would somebody mind putting that into a PR as @storybook/addon-docs/jest-transform.js or the like?! ๐Ÿ™€

@shilman it assumes you are using babel-jest, is that a safe assumption? thats also probably not the right way to chain jest transforms either but i couldn't see any other ways in the docs...

@danielknell I think we could require users to use babel-jest if that's what's needed to make it work? Obviously the fewer requirements the better tho.

i looked into it more and it seems that is how other people chain transforms, and there was some unneeded stuff in there, so i've updated the comment and wrapped it up in a pr

Just a note re: the above code snippet if you're using it while waiting for #7330 to drop, you don't need to use deasync-promise, just use mdx.sync instead of mdx.

See: https://github.com/storybookjs/storybook/pull/7330#issuecomment-532885357

Ta-da!! I just released https://github.com/storybookjs/storybook/releases/tag/v5.3.0-alpha.27 containing PR #8189 that references this issue. Upgrade today to try it out!

You can find this prerelease on the @next NPM tag.

Closing this issue. Please re-open if you think there's still more to do.

Finished except for instrumenting vue-kitchen-sink, which I'll follow up with in #8557

Hi, I have just installed Storybook 5.3.14, addon-docs and addon-storyshots and tried to run Storyshot.test.js, all of it as given in the instructions for this version, but it fails with

storyshots found 0 stories

I have only one story in src/Home

import { Meta, Story, Preview } from "@storybook/addon-docs/blocks";
import { Home } from "./Home";

<Meta title="Home" component={Home} />

# Home

The Home

<Preview>
  <Story name="Home">
    <Home />
  </Story>
</Preview>

Just for the record, .js format works

import React from "react";
import { Home } from "./Home";

export default {
  component: Home,
  title: "Home"
};

export const base = () => <Home />;

I debugged it a little bit and found that storybook.raw() length is 0 in https://github.com/storybookjs/storybook/blob/next/addons/storyshots/storyshots-core/src/api/index.ts line 51 at the time of this writing, so maybe the culprit is in the loadFramework function.

storyshots found 0 stories

I faced a similar problem in CRA.
I tried fix problem. Try the following steps.

  • check jest transform ordering
$ yarn test --showConfig
... snip ...
"transform": [
  [
    "^.+\\.mdx$",   <------ check ordering before `fileTransform`
    "/path/to/project/node_modules/@storybook/addon-docs/jest-transform-mdx.js"
  ],
  [
    "^.+\\.(js|jsx|ts|tsx)$",
    "/path/to/project/node_modules/react-app-rewired/scripts/utils/babelTransform.js"
  ],
  [
    "^.+\\.css$",
    "/path/to/project/node_modules/react-scripts/config/jest/cssTransform.js"
  ],
  [
    "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)",
    /path/to/project/node_modules/react-scripts/config/jest/fileTransform.js"
  ]
],
  • modify node_modules/@storybook/addon-docs/jest-transform-mdx.js
@@ -29,6 +29,6 @@
       import { mdx } from '@mdx-js/react'
       ${mdx.sync(src, { compilers, filepath: filename })}
     `;
-    return getNextTransformer(filename, config).transformSource(filename, result, instrument);
+    return getNextTransformer(filename, config).transformSource(filename + '.jsx', result, instrument);
   },
 };

โ˜๏ธ I don't know if this is a bug. It might be better to create custom transformer.

  • modify node_modules/@storybook/components/dist/syntaxhighlighter/syntaxhighlighter.js
@@ -51,17 +51,17 @@
 var _memoizerific = _interopRequireDefault(require("memoizerific"));
-var _jsx = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/jsx"));
+var _jsx = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/jsx"));
-var _bash = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/bash"));
+var _bash = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/bash"));
-var _css = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/css"));
+var _css = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/css"));
-var _markup = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/markup"));
+var _markup = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/markup"));
-var _tsx = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/tsx"));
+var _tsx = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/tsx"));
-var _typescript = _interopRequireDefault(require("react-syntax-highlighter/dist/esm/languages/prism/typescript"));
+var _typescript = _interopRequireDefault(require("react-syntax-highlighter/dist/cjs/languages/prism/typescript"));
 var _reactSyntaxHighlighter = require("react-syntax-highlighter");

fixed in v6.0.0-alpha.7 (https://github.com/storybookjs/storybook/pull/9780)

@Yama-Tomo Do you mean the mdx ordering should be moved to top from transform?

@CjChoiNZ Yes. (no problem anywhere before fileTransform.js

Same error. "storyshots found 0 stories" :-(

@Yama-Tomo
hmm...I modified the node_modules/@storybook/addon-docs/jest-transform-mdx.js as your suggest.

...
return getNextTransformer(filename, config).transformSource(filename + '.jsx', result, instrument);

And confirmed use this path dist/cjs but it doesn't work for me.

I defined the jest from my package.json as below.

 "jest": {
    "transform": {
      "^.+\\.[tj]sx?$": "babel-jest",
      "^.+\\.mdx$": "@storybook/addon-docs/jest-transform-mdx"
    },
    "transformIgnorePatterns": [
      "/node_modules/"
    ]
  },

And the result of transform still displays mdx is bottom.

...
 "transform": [
        [
          "^.+\\.(js|jsx|ts|tsx)$",
          "C:\\Users\\CjChoi\\Workspace\\product-core\\node_modules\\react-scripts\\config\\jest\\babelTransform.js"
        ],
        [
          "^.+\\.css$",
          "C:\\Users\\CjChoi\\Workspace\\product-core\\node_modules\\react-scripts\\config\\jest\\cssTransform.js"
        ],
        [
          "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)",
          "C:\\Users\\CjChoi\\Workspace\\product-core\\node_modules\\react-scripts\\config\\jest\\fileTransform.js"
        ],
        [
          "^.+\\.[tj]sx?$",
          "C:\\Users\\CjChoi\\Workspace\\product-core\\node_modules\\babel-jest\\build\\index.js"
        ],
        [
          "^.+\\.mdx$",
          "C:\\Users\\CjChoi\\Workspace\\product-core\\node_modules\\@storybook\\addon-docs\\jest-transform-mdx.js"
        ]
      ],
...

Did I miss something?

@CjChoiNZ You need to customize the order of transform with the react-app-rewired

  • config-overrides.js
module.exports = {
  ...
  jest: function (config) {
    ...
    config.transform = {
      '^.+\\.mdx$': '/path/to/transformer(e.g. @storybook/addon-docs/jest-transform-mdx)',
       ...config.transform
    }

    return config
  }
}

@Yama-Tomo
Cool, I removed the jest configuration from package.json and created a config-overrides.js and then it does work for me. Cheers bro!!

I've tried the config-overrides.js and react-rewire solutions proposed above, and I've tried upgrading to v6.0.0-alpha.31. I'm still getting:

 FAIL  src/tests/storyshots.test.js
  โ— Test suite failed to run

    storyshots found 0 stories

      1 | import initStoryshots from "@storybook/addon-storyshots";
      2 | import { imageSnapshot } from "@storybook/addon-storyshots-puppeteer";
      3 | 
    > 4 | initStoryshots({ suite: "Image storyshots", test: imageSnapshot() });
        | ^
      5 | 

      at testStorySnapshots (node_modules/@storybook/addon-storyshots/dist/api/index.js:96:15)
      at Object.<anonymous> (src/components/tests/storyshots.test.js:4:1)

I've got a button.stories.mdx sitting in the same folder as button.js:

import { Meta, Story, Preview } from "@storybook/addon-docs/blocks";
import { action } from "@storybook/addon-actions";
import { Button } from "./button";

<Meta title="Components/Button" component={Button} />

# Button

This is a demo of a button documentation page.

- This is a text button:

  <Button onClick={action("clicked")}>Hello Button</Button>

- This is a button with emojis:
  <Button onClick={action("clicked")}>
    <span role="img" aria-label="so cool">
      ๐Ÿ˜€ ๐Ÿ˜Ž ๐Ÿ‘
    </span>
  </Button>

My package.json:

{
  "name": "storybook",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "react-scripts test",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "styled-components": "^5.1.0"
  },
  "devDependencies": {
    "@storybook/addon-actions": "^6.0.0-alpha.31",
    "@storybook/addon-docs": "^6.0.0-alpha.31",
    "@storybook/addon-links": "^6.0.0-alpha.31",
    "@storybook/addon-storyshots": "^6.0.0-alpha.31",
    "@storybook/addon-storyshots-puppeteer": "^6.0.0-alpha.31",
    "@storybook/addons": "^6.0.0-alpha.31",
    "@storybook/preset-create-react-app": "^2.1.1",
    "@storybook/react": "^6.0.0-alpha.31",
    "jest-image-snapshot": "^3.0.1",
    "puppeteer": "^2.1.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-scripts": "^3.4.1",
    "react-test-renderer": "^16.13.1"
  }
}

My .storybook/main.js:

module.exports = {
  stories: ["../src/**/*.stories.(js|mdx)"],
  addons: [
    "@storybook/preset-create-react-app",
    "@storybook/addon-actions",
    "@storybook/addon-links",
    {
      name: "@storybook/addon-docs",
      options: {
        configureJSX: true
      }
    }
  ]
};

My jest.config.js:

modules.exports = {
  transform: {
    "^.+\\.[tj]sx?$": "babel-jest",
    "^.+\\.mdx?$": "@storybook/addon-docs/jest-transform-mdx"
  }
};

Non-MDX stories are picked up and test just fine.

For me also no MDX stories are not picked up but I'm using ts-jest instead of babel-jest not sure if that can be the issue

Faced the same issue recently. Solved by the following trick it package.json:

"scripts": {
  "test": "cross-env NODE_PATH=src react-scripts test --transform='{\"^.+\\\\\\.[tj]sx?$\":\"ts-jest\",\"^.+\\\\\\.mdx?$\":\"@storybook/addon-docs/jest-transform-mdx\"}'",
},

Just faced this same issue with Storybook v6:

 FAIL  src/Storyshots.test.js
  โ— Test suite failed to run

    storyshots found 0 stories

      1 | import initStoryshots from '@storybook/addon-storyshots'
      2 | 
    > 3 | initStoryshots()
        | ^
      4 | 

      at testStorySnapshots (node_modules/@storybook/addon-storyshots/dist/api/index.js:104:15)
      at Object.<anonymous> (src/Storyshots.test.js:3:1)

We've encountered the same issue, but it had nothing to do with storybook. In our case the files weren't getting recognised by jest.

Adding this line to jest storyshots config fixed the problem:

moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node', 'mdx'],

https://jestjs.io/docs/en/configuration#modulefileextensions-arraystring

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ZigGreen picture ZigGreen  ยท  3Comments

tlrobinson picture tlrobinson  ยท  3Comments

wahengchang picture wahengchang  ยท  3Comments

purplecones picture purplecones  ยท  3Comments

xogeny picture xogeny  ยท  3Comments