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

feat: support DOM snapshot testing #117

Merged
merged 1 commit into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from all 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 .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const stories = [
directory: '../stories/molecules',
},
// general glob
'../stories/pages/**/*.stories.*',
'../stories/pages/**/*.stories.@(js|jsx|ts|tsx)',
];

if (process.env.STRESS_TEST) {
Expand Down
6 changes: 6 additions & 0 deletions .storybook/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ const config: TestRunnerConfig = {
expect.extend({ toMatchImageSnapshot });
},
async postRender(page, context) {
// Visual snapshot tests
const image = await page.screenshot({ fullPage: true });
expect(image).toMatchImageSnapshot({
customSnapshotsDir,
customSnapshotIdentifier: context.id,
failureThreshold: 0.03,
failureThresholdType: 'percent',
});

const elementHandler = await page.$('#root');
const innerHTML = await elementHandler.innerHTML();
// HTML snapshot tests
expect(innerHTML).toMatchSnapshot();
},
};

Expand Down
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ Read the announcement: [Interaction Testing with Storybook](https://storybook.js
- [Image snapshot recipe](#image-snapshot-recipe)
- [Render lifecycle](#render-lifecycle)
- [Troubleshooting](#troubleshooting)
- [The test runner seems flaky and keeps timing out](#the-test-runner-seems-flaky-and-keeps-timing-out)
- [Adding the test runner to other CI environments](#adding-the-test-runner-to-other-ci-environments)
- [The test runner seems flaky and keeps timing out](#the-test-runner-seems-flaky-and-keeps-timing-out)
- [Adding the test runner to other CI environments](#adding-the-test-runner-to-other-ci-environments)
- [Future work](#future-work)

## Features
Expand Down Expand Up @@ -170,7 +170,7 @@ module.exports = {
};
```

Once you have a valid `stories.json` file, your Storybook will be compatible with the "stories.json mode".
Once you have a valid `stories.json` file, your Storybook will be compatible with the "stories.json mode".

By default, the test runner will detect whether your Storybook URL is local or remote, and if it is remote, it will run in "stories.json mode" automatically. To disable it, you can pass the `--no-stories-json` flag:

Expand Down Expand Up @@ -265,9 +265,25 @@ All three functions can be set up in the configuration file `.storybook/test-run

> **NOTE:** These test hooks are experimental and may be subject to breaking changes. We encourage you to test as much as possible within the story's play function.

### DOM snapshot recipe

The `postRender` function provides a [Playwright page](https://playwright.dev/docs/api/class-page) instance, of which you can use for DOM snapshot testing:

```js
// .storybook/test-runner.js
module.exports = {
async postRender(page, context) {
// the #root element wraps the story
const elementHandler = await page.$('#root');
const innerHTML = await elementHandler.innerHTML();
expect(innerHTML).toMatchSnapshot();
},
};
```

### Image snapshot recipe

Consider, for example, the following recipe to take image snapshots:
Here's a slightly different recipe for image snapshot testing:

```js
// .storybook/test-runner.js
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"global": "^4.4.0",
"is-localhost-ip": "^1.4.0",
"jest-playwright-preset": "^1.7.0",
"jest-serializer-html": "^7.1.0",
"jest-watch-typeahead": "^1.0.0",
"node-fetch": "^2",
"playwright": "^1.14.0",
Expand Down
1 change: 1 addition & 0 deletions src/config/jest-playwright.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const getJestConfig = () => {
globalTeardown: '@storybook/test-runner/playwright/global-teardown.js',
testEnvironment: '@storybook/test-runner/playwright/custom-environment.js',
setupFilesAfterEnv: ['@storybook/test-runner/playwright/jest-setup.js'],
snapshotSerializers: ['jest-serializer-html'],
testEnvironmentOptions: {
'jest-playwright': {
browsers: TEST_BROWSERS.split(',')
Expand Down
39 changes: 39 additions & 0 deletions stories/atoms/__snapshots__/Button.stories.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Atoms/Button Demo play-test 2`] = `
<button type="button">
Click
</button>
`;

exports[`Atoms/Button FindBy play-test 2`] = `
<button type="button">
Loaded!
</button>
`;

exports[`Atoms/Button Primary smoke-test 2`] = `
<button type="button"
class="storybook-button storybook-button--medium storybook-button--primary"
>
Button
</button>
`;

exports[`Atoms/Button WaitFor play-test 2`] = `
<button type="button">
Click
</button>
`;

exports[`Atoms/Button WaitForElementToBeRemoved play-test 2`] = `
<button type="button">
Loaded!
</button>
`;

exports[`Atoms/Button WithLoaders play-test 2`] = `
<button type="button">
Todo: delectus aut autem
</button>
`;
88 changes: 88 additions & 0 deletions stories/molecules/__snapshots__/Header.stories.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Molecules/Header LoggedIn smoke-test 2`] = `
<header>
<div class="wrapper">
<div>
<svg width="32"
height="32"
viewbox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="none"
fill-rule="evenodd"
>
<path d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z"
fill="#FFF"
>
</path>
<path d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z"
fill="#555AB9"
>
</path>
<path d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z"
fill="#91BAF8"
>
</path>
</g>
</svg>
<h1>
Acme
</h1>
</div>
<div>
<button type="button"
class="storybook-button storybook-button--small storybook-button--secondary"
>
Log out
</button>
</div>
</div>
</header>
`;

exports[`Molecules/Header LoggedOut smoke-test 2`] = `
<header>
<div class="wrapper">
<div>
<svg width="32"
height="32"
viewbox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="none"
fill-rule="evenodd"
>
<path d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z"
fill="#FFF"
>
</path>
<path d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z"
fill="#555AB9"
>
</path>
<path d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z"
fill="#91BAF8"
>
</path>
</g>
</svg>
<h1>
Acme
</h1>
</div>
<div>
<button type="button"
class="storybook-button storybook-button--small storybook-button--secondary"
>
Log in
</button>
<button type="button"
class="storybook-button storybook-button--small storybook-button--primary"
>
Sign up
</button>
</div>
</div>
</header>
`;
Loading