Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add renderer option to storyshots #2414

Merged
merged 15 commits into from
Dec 2, 2017
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion addons/storyshots/.babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"presets": ["env", "react"],
"presets": ["env", "stage-0", "react"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it needed? Can we include the particular transform instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the destructuring assignment here: https://github.com/storybooks/storybook/pull/2414/files#diff-75fdf0f2c6757366489b97c6898ea585R6

i would have used stage-2, but storybook itself pulls in stage-0, so i went with that to stay consistent

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see. I wonder if we can remove this nested .babelrc to avoid confusion

@ndelangen what do you think?

"plugins": [
"transform-runtime"
]
Expand Down
48 changes: 46 additions & 2 deletions addons/storyshots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,51 @@ If you are running tests from outside of your app's directory, storyshots' detec

### `test`

Run a custom test function for each story, rather than the default (a vanilla snapshot test). See the exports section below for more details.
Run a custom test function for each story, rather than the default (a vanilla snapshot test). Setting `test` will take precedence over the `renderer` option. See the exports section below for more details.

### `renderer`

Pass a custom renderer (such as enzymes `mount`) to record snapshots.

```js
import initStoryshots from '@storybook/addon-storyshots';
import { mount } from 'enzyme';

initStoryshots({
renderer: mount,
});
```

If you are using enzyme, you need to make sure jest knows how to serialize rendered components.
You can either pass in a serializer (see below) or specify an enzyme-compatible serializer (like [enzyme-to-json](https://github.com/adriantoine/enzyme-to-json), [jest-serializer-enzyme](https://github.com/rogeliog/jest-serializer-enzyme) etc.) as the default `snapshotSerializer` in your config.

Example for jest config in `package.json`:
```json
"devDependencies": {
"enzyme-to-json": "^3.2.2"
},
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
}
```

### `serializer`

Pass a custom serializer (such as enzyme-to-json) to serialize components to snapshot-comparable data.

```js
import initStoryshots from '@storybook/addon-storyshots';
import toJSON from 'enzyme-to-json';

initStoryshots({
renderer: mount,
serializer: toJSON,
});
```

This option only needs to be set if the default `snapshotSerializers` is not set in your jest config.

## Exports

Expand All @@ -153,7 +197,7 @@ Like `snapshotWithOptions`, but generate a separate snapshot file for each stori

### `shallowSnapshot`

Take a snapshot of a shallow-rendered version of the component.
Take a snapshot of a shallow-rendered version of the component. Note that this option will be overriden if you pass a `renderer` option.

### `getSnapshotFileName`

Expand Down
2 changes: 2 additions & 0 deletions addons/storyshots/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"enzyme-to-json": "^3.2.2",
"jest": "^20.0.4",
"jest-cli": "^20.0.4",
"react": "^16.1.0",
Expand Down
17 changes: 13 additions & 4 deletions addons/storyshots/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import addons from '@storybook/addons';

import runWithRequireContext from './require_context';
import createChannel from './storybook-channel-mock';
import { snapshot } from './test-bodies';
import { snapshotWithOptions } from './test-bodies';
import { getPossibleStoriesFiles, getSnapshotFileName } from './utils';

export {
Expand Down Expand Up @@ -37,7 +37,8 @@ export default function testStorySnapshots(options = {}) {
addons.setChannel(createChannel());

const isStorybook =
options.framework === 'react' || (!options.framework && hasDependency('@storybook/react'));
options.framework === 'react' ||
(!options.framework && hasDependency('@storybook/react'));
const isRNStorybook =
options.framework === 'react-native' ||
(!options.framework && hasDependency('@storybook/react-native'));
Expand Down Expand Up @@ -82,8 +83,13 @@ export default function testStorySnapshots(options = {}) {
// Added not to break existing storyshots configs (can be removed in a future major release)
// eslint-disable-next-line
options.storyNameRegex = options.storyNameRegex || options.storyRegex;
const snapshotOptions = {
renderer: options.renderer,
serializer: options.serializer,
};
// eslint-disable-next-line
options.test = options.test || snapshot;
options.test =
options.test || snapshotWithOptions({ options: snapshotOptions });

// eslint-disable-next-line
for (const group of stories) {
Expand All @@ -105,7 +111,10 @@ export default function testStorySnapshots(options = {}) {

it(story.name, () => {
const context = { fileName, kind, story: story.name };
return options.test({ story, context });
return options.test({
story,
context,
});
});
}
});
Expand Down
19 changes: 11 additions & 8 deletions addons/storyshots/src/test-bodies.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import renderer from 'react-test-renderer';
import reactTestRenderer from 'react-test-renderer';
import shallow from 'react-test-renderer/shallow';
import 'jest-specific-snapshot';
import { getSnapshotFileName } from './utils';

function getRenderedTree(story, context, options) {
function getRenderedTree(story, context, { renderer, serializer, ...rendererOptions }) {
const currentRenderer = renderer || reactTestRenderer.create;
const storyElement = story.render(context);
return renderer.create(storyElement, options).toJSON();
const tree = currentRenderer(storyElement, rendererOptions);
return serializer ? serializer(tree) : tree;
}

export const snapshotWithOptions = options => ({ story, context }) => {
Expand All @@ -27,13 +29,14 @@ export const multiSnapshotWithOptions = options => ({ story, context }) => {

export const snapshot = snapshotWithOptions({});

export function shallowSnapshot({ story, context }) {
const shallowRenderer = shallow.createRenderer();
const result = shallowRenderer.render(story.render(context));
expect(result).toMatchSnapshot();
export function shallowSnapshot({ story, context, options: { renderer, serializer } }) {
const shallowRenderer = renderer || shallow.createRenderer();
const tree = shallowRenderer.render(story.render(context));
const serializedTree = serializer ? serializer(tree) : tree;
expect(serializedTree).toMatchSnapshot();
}

export function renderOnly({ story, context }) {
const storyElement = story.render(context);
renderer.create(storyElement);
reactTestRenderer.create(storyElement);
}
140 changes: 140 additions & 0 deletions addons/storyshots/stories/__snapshots__/storyshot.enzyme.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Storyshots Another Button with some emoji 1`] = `
<button
className="css-1yjiefr"
onClick={[Function]}
>
😀 😎 👍 💯
</button>
`;

exports[`Storyshots Another Button with text 1`] = `
<button
className="css-1yjiefr"
onClick={[Function]}
>
Hello Button
</button>
`;

exports[`Storyshots Button with some emoji 1`] = `
<button
className="css-1yjiefr"
onClick={[Function]}
>
😀 😎 👍 💯
</button>
`;

exports[`Storyshots Button with text 1`] = `
<button
className="css-1yjiefr"
onClick={[Function]}
>
Hello Button
</button>
`;

exports[`Storyshots Welcome to Storybook 1`] = `
<article
className="css-1fqbdip"
>
<h1
className="css-nil"
>
Welcome to storybook
</h1>
<p>
This is a UI component dev environment for your app.
</p>
<p>
We've added some basic stories inside the

<code
className="css-mteq83"
>
src/stories
</code>

directory.
<br />
A story is a single state of one or more UI components. You can have as many stories as you want.
<br />
(Basically a story is like a visual test case.)
</p>
<p>
See these sample

<a
className="css-ca0824"
onClick={[Function]}
role="button"
tabIndex="0"
>
stories
</a>

for a component called

<code
className="css-mteq83"
>
Button
</code>
.
</p>
<p>
Just like that, you can add your own components as stories.
<br />
You can also edit those components and see changes right away.
<br />
(Try editing the
<code
className="css-mteq83"
>
Button
</code>
stories located at
<code
className="css-mteq83"
>
src/stories/index.js
</code>
.)
</p>
<p>
Usually we create stories with smaller UI components in the app.
<br />
Have a look at the

<a
className="css-ca0824"
href="https://storybook.js.org/basics/writing-stories"
rel="noopener noreferrer"
target="_blank"
>
Writing Stories
</a>

section in our documentation.
</p>
<p
className="css-bwdon3"
>
<b>
NOTE:
</b>
<br />
Have a look at the

<code
className="css-mteq83"
>
.storybook/webpack.config.js
</code>

to add webpack loaders and plugins you are using in this project.
</p>
</article>
`;
11 changes: 11 additions & 0 deletions addons/storyshots/stories/storyshot.enzyme.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import path from 'path';
import { mount } from 'enzyme';
import toJSON from 'enzyme-to-json';
import initStoryshots from '../src';

initStoryshots({
framework: 'react',
configPath: path.join(__dirname, '..', '.storybook'),
renderer: mount,
serializer: toJSON,
});
1 change: 1 addition & 0 deletions addons/storyshots/stories/storyshot.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path';
import initStoryshots, { multiSnapshotWithOptions } from '../src';

// with react-test-renderer
initStoryshots({
framework: 'react',
configPath: path.join(__dirname, '..', '.storybook'),
Expand Down
9 changes: 9 additions & 0 deletions examples/cra-kitchen-sink/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
"@storybook/components": "^3.3.0-alpha.4",
"@storybook/react": "^3.3.0-alpha.4",
"babel-jest": "^21.2.0",
"enzyme": "^3.2.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to have a single enzyme instance across the codebase, so it shouldn’t be added to package dependencies

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i know. but i figured an "example project" should include the necessary dependencies? its a lot more difficult to understand if i need to look outside of the project for its code to work. thats why i included enzyme setup there

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, makes sense

"enzyme-adapter-react-16": "^1.1.0",
"enzyme-to-json": "^3.2.2",
"jest": "^21.2.1",
"react-scripts": "1.0.17"
},
Expand All @@ -50,6 +53,12 @@
"transform": {
".*": "babel-jest"
},
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"setupFiles": [
"<rootDir>/src/enzyme.js"
],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.s?css$": "<rootDir>/__mocks__/styleMock.js"
Expand Down
Loading