UNPKG

25.5 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/master/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 Preact
214
215StoryShots addon for Preact is dependent on [preact-render-to-json](https://github.com/nathancahill/preact-render-to-json), but
216[doesn't](#deps-issue) install it, so you need to install it separately.
217
218```sh
219yarn add preact-render-to-json --dev
220```
221
222### Configure Jest for Web Components
223
224StoryShots addon for Web Components requires [jsdom](https://github.com/jsdom/jsdom) 16 or later to fully support the
225web component shadow dom. To use jsdom 16 or later you can set the Jest `testEnvironment` configuration key to
226`jest-environment-jsdom-sixteen`. This should work back to Jest 24 and is the default in Jest 26 and later.
227
228### Configure Jest for MDX Docs Add-On Stories
229
230If using the [Docs add-on](../../docs/README.md) with
231[MDX stories](../../docs/docs/mdx.md) you will need
232to configure Jest to transform MDX stories into something Storyshots can understand:
233
234Add the following to your Jest configuration:
235
236```json
237{
238 "transform": {
239 "^.+\\.[tj]sx?$": "babel-jest",
240 "^.+\\.mdx?$": "@storybook/addon-docs/jest-transform-mdx"
241 }
242}
243```
244
245### <a name="deps-issue"></a>Why don't we install dependencies of each framework ?
246
247Storyshots 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.
248
249`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).
250
251`optionalDependencies` - behaves like a regular dependency, but do not fail the installation in case there is a problem to bring the dep.
252
253`peerDependencies` - listing all the deps in peer will trigger warnings during the installation - we don't want users to install unneeded deps by hand.
254
255`optionalPeerDependencies` - unfortunately there is nothing like this =(
256
257For more information read npm [docs](https://docs.npmjs.com/files/package.json#dependencies)
258
259### Using `createNodeMock` to mock refs
260
261`react-test-renderer` doesn't provide refs for rendered components. By
262default, it returns null when the refs are referenced. In order to mock
263out elements that rely on refs, you will have to use the
264`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.
265
266Here is an example of how to specify the `createNodeMock` option in Storyshots:
267
268```js
269import initStoryshots, { snapshotWithOptions } from '@storybook/addon-storyshots';
270import TextareaThatUsesRefs from '../component/TextareaThatUsesRefs';
271
272initStoryshots({
273 test: snapshotWithOptions({
274 createNodeMock: (element) => {
275 if (element.type === TextareaThatUsesRefs) {
276 return document.createElement('textarea');
277 }
278 },
279 }),
280});
281```
282
283Provide a function to have story-specific options:
284
285```js
286initStoryshots({
287 test: snapshotWithOptions((story) => ({
288 createNodeMock: (element) => {
289 if (story.name == 'foobar') {
290 return null;
291 }
292 return element;
293 },
294 })),
295});
296```
297
298### StoryShots for async rendered components
299
300You 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.
301
302#### Example
303
304The 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`.
305
306Add _stories of UserForm_ in the file: UserForm.story.jsx
307
308```jsx
309/* global module */
310import React from 'react';
311import { QueryRenderer } from 'react-relay';
312import { storiesOf } from '@storybook/react';
313
314// Use the same queries used in YOUR app routes
315import { newUserFormQuery, editUserFormQuery } from 'app/routes';
316import UserFormContainer from 'app/users/UserForm';
317
318// YOUR function to generate a Relay Environment mock.
319// See https://github.com/1stdibs/relay-mock-network-layer for more info
320import getEnvironment from 'test/support/relay-environment-mock';
321
322// User test data YOU generated for your tests
323import { user } from 'test/support/data/index';
324
325// Use this function to return a new Environment for each story
326const Environment = () =>
327 getEnvironment({
328 mocks: {
329 Node: () => ({ __typename: 'User' }),
330 User: () => user,
331 },
332 });
333
334/**
335
336 NOTICE that the QueryRenderer render its children via its render props.
337
338 If we don't take the StoryShot async then we will only see the QueryRenderer in the StoryShot.
339
340 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
341 */
342const renderStory = (query, environment, variables = {}) => (
343 <QueryRenderer
344 environment={environment}
345 query={query}
346 variables={variables}
347 render={({ props, error }) => {
348 if (error) {
349 console.error(error);
350 } else if (props) {
351 return <UserFormContainer {...props} />;
352 }
353 return null;
354 }}
355 />
356);
357
358storiesOf('users/UserForm', module)
359 .add('New User', () => {
360 const environment = new Environment();
361 return renderStory(newUserFormQuery, environment);
362 })
363 .add('Editing User', () => {
364 const environment = new Environment();
365 return renderStory(editUserFormQuery, environment, { id: user.id });
366 });
367```
368
369Then, init Storyshots for async component in the file: StoryShots.test.js
370
371```jsx
372import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
373import { mount } from 'enzyme';
374import toJson from 'enzyme-to-json';
375
376// Runner
377initStoryshots({
378 asyncJest: true, // this is the option that activates the async behaviour
379 test: ({
380 story,
381 context,
382 done, // --> callback passed to test method when asyncJest option is true
383 }) => {
384 const converter = new Stories2SnapsConverter();
385 const snapshotFilename = converter.getSnapshotFileName(context);
386 const storyElement = story.render();
387
388 // mount the story
389 const tree = mount(storyElement);
390
391 // wait until the mount is updated, in our app mostly by Relay
392 // but maybe something else updating the state of the component
393 // somewhere
394 const waitTime = 1;
395 setTimeout(() => {
396 if (snapshotFilename) {
397 expect(toJson(tree.update())).toMatchSpecificSnapshot(snapshotFilename);
398 }
399
400 done();
401 }, waitTime);
402 },
403 // other options here
404});
405```
406
407NOTICE that When using the `asyncJest: true` option, you also must specify a `test` method that calls the `done()` callback.
408
409This 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.
410
411Whenever 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.
412
413## Options
414
415### `config`
416
417The `config` parameter must be a function that helps to configure storybook like the `preview.js` does.
418If it's not specified, storyshots will try to use [configPath](#configPath) parameter.
419
420```js
421import initStoryshots from '@storybook/addon-storyshots';
422
423initStoryshots({
424 config: ({ configure }) =>
425 configure(() => {
426 require('../stories/Button.story.js');
427 }, module),
428});
429```
430
431### `configPath`
432
433By default, Storyshots assumes the config directory path for your project as below:
434
435- Storybook for React: `.storybook`
436- Storybook for React Native: `storybook`
437
438If you are using a different config directory path, you could change it like this:
439
440```js
441import initStoryshots from '@storybook/addon-storyshots';
442
443initStoryshots({
444 configPath: '.my-storybook-config-dir',
445});
446```
447
448Or, as a more complex example, if we have a package in our `lerna` project called `app` with the path `./packages/app/src/__tests__/storsyhots.js` and the storybook config directory `./packages/app/.storybook`:
449
450```js
451import path from 'path';
452import initStoryshots from '@storybook/addon-storyshots';
453
454initStoryshots({ configPath: path.resolve(__dirname, '../../.storybook') });
455```
456
457`configPath` can also specify path to the `preview.js` itself. In this case, config directory will be
458a base directory of the `configPath`. It may be useful when the `preview.js` for test should differ from the
459original one. It also may be useful for separating tests to different test configs:
460
461```js
462initStoryshots({
463 configPath: '.my-storybook-config-dir/testConfig1.js',
464});
465
466initStoryshots({
467 configPath: '.my-storybook-config-dir/testConfig2.js',
468});
469```
470
471### `suite`
472
473By default, Storyshots groups stories inside a Jest test suite called "Storyshots". You could change it like this:
474
475```js
476import initStoryshots from '@storybook/addon-storyshots';
477
478initStoryshots({
479 suite: 'MyStoryshots',
480});
481```
482
483### `storyKindRegex`
484
485If you'd like to only run a subset of the stories for your snapshot tests based on the story's kind:
486
487```js
488import initStoryshots from '@storybook/addon-storyshots';
489
490initStoryshots({
491 storyKindRegex: /^MyComponent$/,
492});
493```
494
495This 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).
496
497If 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`
498
499```js
500import initStoryshots from '@storybook/addon-storyshots';
501
502initStoryshots({
503 storyKindRegex: /^((?!.*?DontTest).)*$/,
504});
505```
506
507This can be useful while testing react components which make use of the findDomNode API since they always fail with snapshot testing
508while using react-test-renderer see [here](https://github.com/facebook/react/issues/8324)
509
510### `storyNameRegex`
511
512If you'd like to only run a subset of the stories for your snapshot tests based on the story's name:
513
514```js
515import initStoryshots from '@storybook/addon-storyshots';
516
517initStoryshots({
518 storyNameRegex: /buttons/,
519});
520```
521
522### `framework`
523
524If 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.
525
526### `test`
527
528Run a custom test function for each story, rather than the default (a vanilla snapshot test).
529Setting `test` will take precedence over the `renderer` option.
530You can still overwrite what renderer is used for the test function:
531
532```js
533import initStoryshots, { renderWithOptions } from '@storybook/addon-storyshots';
534import { mount } from 'enzyme';
535
536initStoryshots({
537 test: renderWithOptions({
538 renderer: mount,
539 }),
540});
541```
542
543### `renderer`
544
545Pass a custom renderer (such as enzymes `mount`) to record snapshots.
546This may be necessary if you want to use React features that are not supported by the default test renderer,
547such as **ref** or **Portals**.
548Note that setting `test` overrides `renderer`.
549
550```js
551import initStoryshots from '@storybook/addon-storyshots';
552import { mount } from 'enzyme';
553
554initStoryshots({
555 renderer: mount,
556});
557```
558
559If you are using enzyme, you need to make sure jest knows how to serialize rendered components.
560For 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).
561
562### `snapshotSerializers`
563
564Pass an array of snapshotSerializers to the jest runtime that serializes your story (such as enzyme-to-json).
565
566```js
567import initStoryshots from '@storybook/addon-storyshots';
568import { createSerializer } from 'enzyme-to-json';
569
570initStoryshots({
571 renderer: mount,
572 snapshotSerializers: [createSerializer()],
573});
574```
575
576This option needs to be set if either:
577
578- 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.
579- serializers not specified in your jest config should be used when snapshotting stories.
580
581### `serializer` (deprecated)
582
583Pass 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.
584
585```js
586import initStoryshots from '@storybook/addon-storyshots';
587import toJSON from 'enzyme-to-json';
588
589initStoryshots({
590 renderer: mount,
591 serializer: toJSON,
592});
593```
594
595This option only needs to be set if the default `snapshotSerializers` is not set in your jest config.
596
597### `stories2snapsConverter`
598
599This 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.
600
601By default, the instance of this class is created with these default options:
602
603```js
604{
605 snapshotsDirName: '__snapshots__',
606 snapshotExtension: '.storyshot',
607 storiesExtensions: ['.js', '.jsx', '.ts', '.tsx'],
608}
609```
610
611This class might be overridden to extend the existing conversion functionality or instantiated to provide different options:
612
613```js
614import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
615
616initStoryshots({
617 stories2snapsConverter: new Stories2SnapsConverter({
618 snapshotExtension: '.storypuke',
619 storiesExtensions: ['.foo'],
620 }),
621});
622```
623
624## Exports
625
626Apart from the default export (`initStoryshots`), Storyshots also exports some named test functions (see the `test` option above):
627
628### `snapshot`
629
630The default, render the story as normal and take a Jest snapshot.
631
632### `renderOnly`
633
634Just render the story, don't check the output at all. This is useful as a low-effort way of smoke testing your
635components to ensure they do not error.
636
637### `snapshotWithOptions(options)`
638
639Like 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).
640
641### `renderWithOptions(options)`
642
643Like the default, but allows you to specify a set of options for the renderer, just like `snapshotWithOptions`.
644
645### `multiSnapshotWithOptions(options)`
646
647Like `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.
648If 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:
649
650```js
651// jest.config.js
652module.exports = {
653 transform: {
654 '^.+\\.stories\\.jsx?$': '@storybook/addon-storyshots/injectFileName',
655 '^.+\\.jsx?$': 'babel-jest',
656 },
657};
658```
659
660#### integrityOptions
661
662This option is useful when running test with `multiSnapshotWithOptions(options)` in order to track snapshots are matching the stories. (disabled by default).
663The value is a [settings](https://github.com/isaacs/node-glob#options) to a `glob` object, that searches for the snapshot files.
664
665```js
666initStoryshots({
667 integrityOptions: { cwd: __dirname }, // it will start searching from the current directory
668 test: multiSnapshotWithOptions(),
669});
670```
671
672### `shallowSnapshot`
673
674Take a snapshot of a shallow-rendered version of the component. Note that this option will be overridden if you pass a `renderer` option.
675
676### `Stories2SnapsConverter`
677
678This is a class that generates snapshot's name based on the story (kind, story & filename) and vice versa.
679
680###### Example:
681
682Let's say we wanted to create a test function for shallow && multi-file snapshots:
683
684```js
685import initStoryshots, { Stories2SnapsConverter } from '@storybook/addon-storyshots';
686import { shallow } from 'enzyme';
687import toJson from 'enzyme-to-json';
688
689const converter = new Stories2SnapsConverter();
690
691initStoryshots({
692 test: ({ story, context }) => {
693 const snapshotFileName = converter.getSnapshotFileName(context);
694 const storyElement = story.render();
695 const shallowTree = shallow(storyElement);
696
697 if (snapshotFileName) {
698 expect(toJson(shallowTree)).toMatchSpecificSnapshot(snapshotFileName);
699 }
700 },
701});
702```
703
704### `asyncJest`
705
706Enables Jest `done()` callback in the StoryShots tests for async testing. See [StoryShots for async rendered components](#storyshots-for-async-rendered-components) for more info.
707
708## Story Parameters
709
710### `disable`
711
712Some 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`.
713
714```js
715export const Exception = () => {
716 throw new Error('storyFn threw an error! WHOOPS');
717};
718Exception.storyName = 'story throws exception';
719Exception.parameters = {
720 storyshots: { disable: true },
721};
722```