UNPKG

28 kBMarkdownView Raw
1# StoryShots
2
3StoryShots adds automatic Jest Snapshot Testing for [Storybook](https://storybook.js.org/).
4
5[Framework Support](https://github.com/storybookjs/storybook/blob/main/ADDONS_SUPPORT.md)
6
7![StoryShots In Action](https://raw.githubusercontent.com/storybookjs/storybook/HEAD/addons/storyshots/storyshots-core/docs/storyshots-fail.png)
8
9To use StoryShots, you must use your existing Storybook stories as the input for Jest Snapshot Testing.
10
11## Getting Started
12
13Add the following module into your app.
14
15```sh
16yarn add @storybook/addon-storyshots --dev
17```
18
19## Configure Storyshots for HTML snapshots
20
21Create a new test file with the name `Storyshots.test.js`. (Or whatever the name you prefer, as long as it matches Jest's config [`testMatch`](http://facebook.github.io/jest/docs/en/configuration.html#testmatch-array-string)).
22Then add following content to it:
23
24```js
25import initStoryshots from '@storybook/addon-storyshots';
26
27initStoryshots();
28```
29
30That's all.
31
32Now run your Jest test command. (Usually, `npm test`.) Then you can see all of your stories are converted as Jest snapshot tests.
33
34![Screenshot](https://raw.githubusercontent.com/storybookjs/storybook/HEAD/addons/storyshots/storyshots-core/docs/storyshots.png)
35
36### Testing stories that rely on addon-added decorators
37
38If you have stories in your Storybook that can only render inside a decorator (for instance the [`apollo-storybook-decorator`](https://github.com/abhiaiyer91/apollo-storybook-decorator)), you'll need to ensure those decorators are applied in Storyshots.
39
40If you export those decorators from your `.storybook/preview.js` then Storyshots will apply those decorators for you in the same way that Storybook does. However if the addon _automatically_ adds the decorator for you (which is a new feature in Storybook 6.0), you will find the decorator does not get added in Storyshots. This is a limitation in Storyshots currently.
41
42To ensure such decorators get added, export them from `.storybook/preview.js`:
43
44```js
45import addonDecorator from 'some-addon';
46
47export const decorators = [addonDecorator];
48```
49
50## Configure your app for Jest
51
52In many cases, for example Create React App, it's already configured for Jest. You need to create a filename with the extension `.test.js`.
53
54If you still need to configure jest you can use the resources mentioned below:
55
56- [Getting Started - Jest Official Documentation](https://facebook.github.io/jest/docs/en/getting-started.html)
57- [Javascript Testing with Jest - Egghead](https://egghead.io/lessons/javascript-test-javascript-with-jest). **_paid content_**
58
59> Note: If you use React 16, you'll need to follow [these additional instructions](https://github.com/facebook/react/issues/9102#issuecomment-283873039).
60>
61> Note: Make sure you have added the `json` extension to `moduleFileExtensions` in `jest.config.json`. If this is missing it leads to the [following error](https://github.com/storybookjs/storybook/issues/3728): `Cannot find module 'spdx-license-ids' from 'scan.js'`.
62>
63> Note: Please make sure you are using `jsdom` as the testEnvironment on your jest config file.
64
65### Configure Jest to work with Webpack's [require.context()](https://webpack.js.org/guides/dependency-management/#require-context)
66
67**NOTE**: if you are using Storybook 5.3's `main.js` to list story files, this is no longer needed.
68
69Sometimes it's useful to configure Storybook with Webpack's require.context feature. You could be loading stories [one of two ways](https://storybook.js.org/docs/react/writing-stories/loading-stories).
70
711. If you're using the `storiesOf` API, you can integrate it this way:
72
73```js
74import { configure } from '@storybook/react';
75
76const req = require.context('../stories', true, /\.stories\.js$/); // <- import all the stories at once
77
78function loadStories() {
79 req.keys().forEach((filename) => req(filename));
80}
81
82configure(loadStories, module);
83```
84
852. If you're using Component Story Format (CSF), you'll integrate it like so:
86
87```js
88import { configure } from '@storybook/react';
89
90const req = require.context('../stories', true, /\.stories\.js$/); // <- import all the stories at once
91
92configure(req, module);
93```
94
95The problem here is that it will work only during the build with webpack,
96other tools may lack this feature. Since Storyshot is running under Jest,
97we need to polyfill this functionality to work with Jest. The easiest
98way is to integrate it to babel.
99
100You can do this with a Babel [plugin](https://github.com/smrq/babel-plugin-require-context-hook) or [macro](https://github.com/storybookjs/require-context.macro). If you're using `create-react-app` (v2 or above), use the macro.
101
102#### Option 1: Plugin
103
104First, install it:
105
106```sh
107yarn add babel-plugin-require-context-hook --dev
108```
109
110Next, it needs to be registered and loaded before each test. To register it, create a file with the following register function `.jest/register-context.js`:
111
112```js
113import registerRequireContextHook from 'babel-plugin-require-context-hook/register';
114registerRequireContextHook();
115```
116
117That file needs to be added as a setup file for Jest. To do that, add (or create) a property in Jest's config called [`setupFiles`](https://jestjs.io/docs/en/configuration.html#setupfiles-array). Add the file name and path to this array.
118
119```json
120setupFiles: ['<rootDir>/.jest/register-context.js']
121```
122
123Finally, add the plugin to `.babelrc`:
124
125```json
126{
127 "presets": ["..."],
128 "plugins": ["..."],
129 "env": {
130 "test": {
131 "plugins": ["require-context-hook"]
132 }
133 }
134}
135```
136
137The plugin is only added to the test environment otherwise it could replace webpack's version of it.
138
139#### Option 2: Macro
140
141First, install it:
142
143```sh
144yarn add require-context.macro --dev
145```
146
147Now, inside of your Storybook config file, import the macro and run it in place of `require.context`, like so:
148
149```javascript
150import requireContext from 'require-context.macro';
151
152// const req = require.context('../stories', true, /\.stories\.js$/); <-- replaced
153const req = requireContext('../stories', true, /\.stories\.js$/);
154```
155
156### Configure Jest for React
157
158StoryShots addon for React is dependent on [react-test-renderer](https://github.com/facebook/react/tree/master/packages/react-test-renderer), but
159[doesn't](#deps-issue) install it, so you need to install it separately.
160
161```sh
162yarn add react-test-renderer --dev
163```
164
165### Configure Jest for Angular
166
167StoryShots addon for Angular is dependent on [jest-preset-angular](https://github.com/thymikee/jest-preset-angular), but
168[doesn't](#deps-issue) install it, so you need to install it separately.
169
170```sh
171yarn add jest-preset-angular
172```
173
174If you already use Jest for testing your angular app - probably you already have the needed jest configuration.
175Anyway you can add these lines to your jest config:
176
177```js
178module.exports = {
179 globals: {
180 __TRANSFORM_HTML__: true,
181 },
182 transform: {
183 '^.+\\.jsx?$': 'babel-jest',
184 '^.+\\.(ts|html)$': '<rootDir>/node_modules/jest-preset-angular/preprocessor.js',
185 },
186 moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node', '.html'],
187};
188```
189
190### Configure Jest for Vue
191
192StoryShots addon for Vue is dependent on [jest-vue-preprocessor](https://github.com/vire/jest-vue-preprocessor), but
193[doesn't](#deps-issue) install it, so you need to install it separately.
194
195```sh
196yarn add jest-vue-preprocessor
197```
198
199If you already use Jest for testing your vue app - probably you already have the needed jest configuration.
200Anyway you can add these lines to your jest config:
201
202```js
203module.exports = {
204 transform: {
205 '^.+\\.jsx?$': 'babel-jest',
206 '.*\\.(vue)$': '<rootDir>/node_modules/jest-vue-preprocessor',
207 },
208 transformIgnorePatterns: ['/node_modules/(?!(@storybook/.*\\.vue$))'],
209 moduleFileExtensions: ['vue', 'js', 'jsx', 'json', 'node'],
210};
211```
212
213### Configure Jest for Vue 3
214
215StoryShots addon for Vue is dependent on [vue-jest v5](https://www.npmjs.com/package/vue-jest/v/5.0.0-alpha.8), but
216[doesn't](#deps-issue) install it, so you need to install it separately.
217
218```sh
219yarn add vue-jest@5.0.0-alpha.8
220```
221
222If you already use Jest for testing your vue app - probably you already have the needed jest configuration.
223Anyway you can add these lines to your jest config:
224
225```js
226module.exports = {
227 transform: {
228 '^.+\\.jsx?$': 'babel-jest',
229 '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',
230 },
231 transformIgnorePatterns: ['/node_modules/(?!(@storybook/.*\\.vue$))'],
232 moduleFileExtensions: ['vue', 'js', 'jsx', 'json', 'node'],
233};
234```
235
236### Configure Jest for Preact
237
238StoryShots addon for Preact is dependent on [preact-render-to-string](https://github.com/preactjs/preact-render-to-string), but
239[doesn't](#deps-issue) install it, so you need to install it separately.
240
241```sh
242yarn add preact-render-to-string --dev
243```
244
245### Configure Jest for Web Components
246
247StoryShots addon for Web Components requires [jsdom](https://github.com/jsdom/jsdom) 16 or later to fully support the
248web component shadow dom. To use jsdom 16 or later you can set the Jest `testEnvironment` configuration key to
249`jest-environment-jsdom-sixteen`. This should work back to Jest 24 and is the default in Jest 26 and later.
250
251### Configure Jest for MDX Docs Add-On Stories
252
253If using the [Docs add-on](../../docs/README.md) with
254[MDX stories](../../docs/docs/mdx.md) you will need
255to configure Jest to transform MDX stories into something Storyshots can understand:
256
257Add the following to your Jest configuration:
258
259```json
260{
261 "transform": {
262 "^.+\\.[tj]sx?$": "babel-jest",
263 "^.+\\.mdx?$": "@storybook/addon-docs/jest-transform-mdx"
264 }
265}
266```
267
268### <a name="deps-issue"></a>Why don't we install dependencies of each framework ?
269
270Storyshots addon is currently supporting React, Angular and Vue. Each framework needs its own packages to be integrated with Jest. We don't want people that use only React will need to bring other dependencies that do not make sense for them.
271
272`dependencies` - will installed an exact version of the particular dep - Storyshots can work with different versions of the same framework (let's say React v16 and React v15), that have to be compatible with a version of its plugin (react-test-renderer).
273
274`optionalDependencies` - behaves like a regular dependency, but do not fail the installation in case there is a problem to bring the dep.
275
276`peerDependencies` - listing all the deps in peer will trigger warnings during the installation - we don't want users to install unneeded deps by hand.
277
278`optionalPeerDependencies` - unfortunately there is nothing like this =(
279
280For more information read npm [docs](https://docs.npmjs.com/files/package.json#dependencies)
281
282### Using `createNodeMock` to mock refs
283
284`react-test-renderer` doesn't provide refs for rendered components. By
285default, it returns null when the refs are referenced. In order to mock
286out elements that rely on refs, you will have to use the
287`createNodeMock` option [added to React](https://reactjs.org/blog/2016/11/16/react-v15.4.0.html#mocking-refs-for-snapshot-testing) starting with version 15.4.0.
288
289Here is an example of how to specify the `createNodeMock` option in Storyshots:
290
291```js
292import initStoryshots, { snapshotWithOptions } from '@storybook/addon-storyshots';
293import TextareaThatUsesRefs from '../component/TextareaThatUsesRefs';
294
295initStoryshots({
296 test: snapshotWithOptions({
297 createNodeMock: (element) => {
298 if (element.type === TextareaThatUsesRefs) {
299 return document.createElement('textarea');
300 }
301 },
302 }),
303});
304```
305
306Provide a function to have story-specific options:
307
308```js
309initStoryshots({
310 test: snapshotWithOptions((story) => ({
311 createNodeMock: (element) => {
312 if (story.name == 'foobar') {
313 return null;
314 }
315 return element;
316 },
317 })),
318});
319```
320
321### Using a custom renderer
322
323By design, [`react-test-renderer` doesn't use a browser environment or JSDOM](https://github.com/facebook/react/issues/20589). Because of this difference, some stories might render in your browser, but not in Storyshots. If you encounter this problem, you may want to switch for an higher level renderer such as `mount` from Enzyme or `render` from React Testing Library.
324
325#### Example with React Testing Library
326
327```js
328import initStoryshots from '@storybook/addon-storyshots';
329import { render } from '@testing-library/react';
330
331const reactTestingLibrarySerializer = {
332 print: (val, serialize, indent) => serialize(val.container.firstChild),
333 test: (val) => val && val.hasOwnProperty('container'),
334};
335
336initStoryshots({
337 renderer: render,
338 snapshotSerializers: [reactTestingLibrarySerializer],
339});
340```
341
342#### Example with Enzyme
343
344```js
345import initStoryshots from '@storybook/addon-storyshots';
346import { mount } from 'enzyme';
347
348initStoryshots({
349 renderer: mount,
350});
351```
352
353If you are using enzyme, you need to make sure jest knows how to serialize rendered components.
354For that, you can pass an enzyme-compatible snapshotSerializer (like [enzyme-to-json](https://github.com/adriantoine/enzyme-to-json), [jest-serializer-enzyme](https://github.com/rogeliog/jest-serializer-enzyme) etc.) with the `snapshotSerializer` option (see below).
355
356### StoryShots for async rendered components
357
358You can make use of [Jest done callback](https://jestjs.io/docs/en/asynchronous) to test components that render asynchronously. This callback is passed as param to test method passed to `initStoryshots(...)` when the `asyncJest` option is given as true.
359
360#### Example
361
362The following example shows how we can use the **done callback** to take StoryShots of a [Relay](http://facebook.github.io/relay/) component. Each kind of story is written into its own snapshot file with the use of `getSnapshotFileName`.
363
364Add _stories of UserForm_ in the file: UserForm.story.jsx
365
366```jsx
367/* global module */
368import React from 'react';
369import { QueryRenderer } from 'react-relay';
370import { storiesOf } from '@storybook/react';
371
372// Use the same queries used in YOUR app routes
373import { newUserFormQuery, editUserFormQuery } from 'app/routes';
374import UserFormContainer from 'app/users/UserForm';
375
376// YOUR function to generate a Relay Environment mock.
377// See https://github.com/1stdibs/relay-mock-network-layer for more info
378import getEnvironment from 'test/support/relay-environment-mock';
379
380// User test data YOU generated for your tests
381import { user } from 'test/support/data/index';
382
383// Use this function to return a new Environment for each story
384const Environment = () =>
385 getEnvironment({
386 mocks: {
387 Node: () => ({ __typename: 'User' }),
388 User: () => user,
389 },
390 });
391
392/**
393
394 NOTICE that the QueryRenderer render its children via its render props.
395
396 If we don't take the StoryShot async then we will only see the QueryRenderer in the StoryShot.
397
398 The following QueryRenderer returns null in the first render (it can be a loading indicator instead in real file) and then when it gets the data to respond to query, it renders again with props containing the data for the Component
399 */
400const renderStory = (query, environment, variables = {}) => (
401 <QueryRenderer
402 environment={environment}
403 query={query}
404 variables={variables}
405 render={({ props, error }) => {
406 if (error) {
407 console.error(error);
408 } else if (props) {
409 return <UserFormContainer {...props} />;
410 }
411 return null;
412 }}
413 />
414);
415
416storiesOf('users/UserForm', module)
417 .add('New User', () => {
418 const environment = new Environment();
419 return renderStory(newUserFormQuery, environment);
420 })
421 .add('Editing User', () => {
422 const environment = new Environment();
423 return renderStory(editUserFormQuery, environment, { id: user.id });
424 });
425```
426
427Then, init Storyshots for async component in the file: StoryShots.test.js
428
429```jsx
430import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
431import { mount } from 'enzyme';
432import toJson from 'enzyme-to-json';
433
434// Runner
435initStoryshots({
436 asyncJest: true, // this is the option that activates the async behaviour
437 test: ({
438 story,
439 context,
440 done, // --> callback passed to test method when asyncJest option is true
441 }) => {
442 const converter = new Stories2SnapsConverter();
443 const snapshotFilename = converter.getSnapshotFileName(context);
444 const storyElement = story.render();
445
446 // mount the story
447 const tree = mount(storyElement);
448
449 // wait until the mount is updated, in our app mostly by Relay
450 // but maybe something else updating the state of the component
451 // somewhere
452 const waitTime = 1;
453 setTimeout(() => {
454 if (snapshotFilename) {
455 expect(toJson(tree.update())).toMatchSpecificSnapshot(snapshotFilename);
456 }
457
458 done();
459 }, waitTime);
460 },
461 // other options here
462});
463```
464
465NOTICE that When using the `asyncJest: true` option, you also must specify a `test` method that calls the `done()` callback.
466
467This is a really powerful technique to write stories of Relay components because it integrates data fetching with component rendering. So instead of passing data props manually, we can let Relay do the job for us as it does in our application.
468
469Whenever you change your data requirements by adding (and rendering) or (accidentally) deleting fields in your graphql query fragments, you'll get a different snapshot and thus an error in the StoryShot test.
470
471## Using a custom directory
472
473Depending on your project's needs, you can configure the `@storybook/addon-storyshots` to use a custom directory for the snapshots. You can read more about it in the [official docs](https://storybook.js.org/docs/react/workflows/snapshot-testing).
474
475## Options
476
477### `config`
478
479The `config` parameter must be a function that helps to configure storybook like the `preview.js` does.
480If it's not specified, storyshots will try to use [configPath](#configPath) parameter.
481
482```js
483import initStoryshots from '@storybook/addon-storyshots';
484
485initStoryshots({
486 config: ({ configure }) =>
487 configure(() => {
488 require('../stories/Button.story.js');
489 }, module),
490});
491```
492
493### `configPath`
494
495By default, Storyshots assumes the config directory path for your project as below:
496
497- Storybook for React: `.storybook`
498- Storybook for React Native: `storybook`
499
500If you are using a different config directory path, you could change it like this:
501
502```js
503import initStoryshots from '@storybook/addon-storyshots';
504
505initStoryshots({
506 configPath: '.my-storybook-config-dir',
507});
508```
509
510Or, as a more complex example, if we have a package in our `lerna` project called `app` with the path `./packages/app/src/__tests__/storyshots.js` and the storybook config directory `./packages/app/.storybook`:
511
512```js
513import path from 'path';
514import initStoryshots from '@storybook/addon-storyshots';
515
516initStoryshots({ configPath: path.resolve(__dirname, '../../.storybook') });
517```
518
519`configPath` can also specify path to the `preview.js` itself. In this case, config directory will be
520a base directory of the `configPath`. It may be useful when the `preview.js` for test should differ from the
521original one. It also may be useful for separating tests to different test configs:
522
523```js
524initStoryshots({
525 configPath: '.my-storybook-config-dir/testConfig1.js',
526});
527
528initStoryshots({
529 configPath: '.my-storybook-config-dir/testConfig2.js',
530});
531```
532
533### `suite`
534
535By default, Storyshots groups stories inside a Jest test suite called "Storyshots". You could change it like this:
536
537```js
538import initStoryshots from '@storybook/addon-storyshots';
539
540initStoryshots({
541 suite: 'MyStoryshots',
542});
543```
544
545### `storyKindRegex`
546
547If you'd like to only run a subset of the stories for your snapshot tests based on the story's kind:
548
549```js
550import initStoryshots from '@storybook/addon-storyshots';
551
552initStoryshots({
553 storyKindRegex: /^MyComponent$/,
554});
555```
556
557This can be useful if you want to separate the snapshots in directories next to each component. See an example [here](https://github.com/storybookjs/storybook/issues/892).
558
559If you want to run all stories except stories of a specific kind, you can write an inverse regex which is true for all kinds except those with a specific word such as `DontTest`
560
561```js
562import initStoryshots from '@storybook/addon-storyshots';
563
564initStoryshots({
565 storyKindRegex: /^((?!.*?DontTest).)*$/,
566});
567```
568
569This can be useful while testing react components which make use of the findDomNode API since they always fail with snapshot testing
570while using react-test-renderer see [here](https://github.com/facebook/react/issues/8324)
571
572### `storyNameRegex`
573
574If you'd like to only run a subset of the stories for your snapshot tests based on the story's name:
575
576```js
577import initStoryshots from '@storybook/addon-storyshots';
578
579initStoryshots({
580 storyNameRegex: /buttons/,
581});
582```
583
584### `framework`
585
586If you are running tests from outside of your app's directory, storyshots' detection of which framework you are using may fail. Pass `"react"` or `"react-native"` to short-circuit this.
587
588For example:
589
590```js
591// storybook.test.js
592
593import path from 'path';
594import initStoryshots from '@storybook/addon-storyshots';
595
596initStoryshots({
597 framework: 'react', // Manually specify the project's framework
598 configPath: path.join(__dirname, '.storybook'),
599 integrityOptions: { cwd: path.join(__dirname, 'src', 'stories') },
600 // Other configurations
601});
602```
603
604Use this table as a reference for manually specifying the framework.
605
606| angular | html | preact |
607| -------------- | ---- | ------------ |
608| react | riot | react-native |
609| svelte | vue | vue3 |
610| web-components | rax | |
611
612### `test`
613
614Run a custom test function for each story, rather than the default (a vanilla snapshot test).
615Setting `test` will take precedence over the `renderer` option.
616You can still overwrite what renderer is used for the test function:
617
618```js
619import initStoryshots, { renderWithOptions } from '@storybook/addon-storyshots';
620import { mount } from 'enzyme';
621
622initStoryshots({
623 test: renderWithOptions({
624 renderer: mount,
625 }),
626});
627```
628
629### `renderer`
630
631Pass a custom renderer (such as enzymes `mount`) to record snapshots.
632This may be necessary if you want to use React features that are not supported by the default test renderer,
633such as **ref** or **Portals**.
634Note that setting `test` overrides `renderer`.
635
636### `snapshotSerializers`
637
638Pass an array of snapshotSerializers to the jest runtime that serializes your story (such as enzyme-to-json).
639
640```js
641import initStoryshots from '@storybook/addon-storyshots';
642import { createSerializer } from 'enzyme-to-json';
643
644initStoryshots({
645 renderer: mount,
646 snapshotSerializers: [createSerializer()],
647});
648```
649
650This option needs to be set if either:
651
652- the multiSnapshot function is used to create multiple snapshot files (i.e. one per story), since it ignores any serializers specified in your jest config.
653- serializers not specified in your jest config should be used when snapshotting stories.
654
655### `serializer` (deprecated)
656
657Pass a custom serializer (such as enzyme-to-json) to serialize components to snapshot-comparable data. The functionality of this option is completely covered by [snapshotSerializers](`snapshotSerializers`) which should be used instead.
658
659```js
660import initStoryshots from '@storybook/addon-storyshots';
661import toJSON from 'enzyme-to-json';
662
663initStoryshots({
664 renderer: mount,
665 serializer: toJSON,
666});
667```
668
669This option only needs to be set if the default `snapshotSerializers` is not set in your jest config.
670
671### `stories2snapsConverter`
672
673This parameter should be an instance of the [`Stories2SnapsConverter`](src/Stories2SnapsConverter.js) (or a derived from it) Class that is used to convert story-file name to snapshot-file name and vice versa.
674
675By default, the instance of this class is created with these default options:
676
677```js
678{
679 snapshotsDirName: '__snapshots__',
680 snapshotExtension: '.storyshot',
681 storiesExtensions: ['.js', '.jsx', '.ts', '.tsx'],
682}
683```
684
685This class might be overridden to extend the existing conversion functionality or instantiated to provide different options:
686
687```js
688import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
689
690initStoryshots({
691 stories2snapsConverter: new Stories2SnapsConverter({
692 snapshotExtension: '.storypuke',
693 storiesExtensions: ['.foo'],
694 }),
695});
696```
697
698## Exports
699
700Apart from the default export (`initStoryshots`), Storyshots also exports some named test functions (see the `test` option above):
701
702### `snapshot`
703
704The default, render the story as normal and take a Jest snapshot.
705
706### `renderOnly`
707
708Just render the story, don't check the output at all. This is useful as a low-effort way of smoke testing your
709components to ensure they do not error.
710
711### `snapshotWithOptions(options)`
712
713Like the default, but allows you to specify a set of options for the test renderer. [See for example here](https://github.com/storybookjs/storybook/blob/b915b5439786e0edb17d7f5ab404bba9f7919381/examples/test-cra/src/storyshots.test.js#L14-L16).
714
715### `renderWithOptions(options)`
716
717Like the default, but allows you to specify a set of options for the renderer, just like `snapshotWithOptions`.
718
719### `multiSnapshotWithOptions(options)`
720
721Like `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, you can pass an empty object.
722If you use [Component Story Format](https://storybook.js.org/docs/react/api/csf), you may also need to add an additional Jest transform to automate detecting story file names:
723
724```js
725// jest.config.js
726module.exports = {
727 transform: {
728 '^.+\\.stories\\.jsx?$': '@storybook/addon-storyshots/injectFileName',
729 '^.+\\.jsx?$': 'babel-jest',
730 },
731};
732```
733
734#### integrityOptions
735
736This option is useful when running test with `multiSnapshotWithOptions(options)` in order to track snapshots are matching the stories. (disabled by default).
737The value is a [settings](https://github.com/isaacs/node-glob#options) to a `glob` object, that searches for the snapshot files.
738
739```js
740initStoryshots({
741 integrityOptions: { cwd: __dirname }, // it will start searching from the current directory
742 test: multiSnapshotWithOptions(),
743});
744```
745
746### `shallowSnapshot`
747
748Take a snapshot of a shallow-rendered version of the component. Note that this option will be overridden if you pass a `renderer` option.
749
750### `Stories2SnapsConverter`
751
752This is a class that generates snapshot's name based on the story (kind, story & filename) and vice versa.
753
754###### Example:
755
756Let's say we wanted to create a test function for shallow && multi-file snapshots:
757
758```js
759import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
760import { shallow } from 'enzyme';
761import toJson from 'enzyme-to-json';
762
763const converter = new Stories2SnapsConverter();
764
765initStoryshots({
766 test: ({ story, context }) => {
767 const snapshotFileName = converter.getSnapshotFileName(context);
768 const storyElement = story.render();
769 const shallowTree = shallow(storyElement);
770
771 if (snapshotFileName) {
772 expect(toJson(shallowTree)).toMatchSpecificSnapshot(snapshotFileName);
773 }
774 },
775});
776```
777
778### `asyncJest`
779
780Enables Jest `done()` callback in the StoryShots tests for async testing. See [StoryShots for async rendered components](#storyshots-for-async-rendered-components) for more info.
781
782## Story Parameters
783
784### `disable`
785
786Some stories are difficult or impossible to snapshot, such as those covering components that use external DOM-modifying libraries, and those that deliberately throw errors. It is possible to skip stories like these by giving them a parameter of `storyshots: {disable: true}`. There is also a shorthand for this, `storyshots: false`.
787
788```js
789export const Exception = () => {
790 throw new Error('storyFn threw an error! WHOOPS');
791};
792Exception.storyName = 'story throws exception';
793Exception.parameters = {
794 storyshots: { disable: true },
795};
796```