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 ability to use image snapshots to addon-storyshots #2413

Merged
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b96345b
add jest-image-snapshot to storyshots
Dec 1, 2017
d5ce79e
use custom jest config for storyshots with image snapshots & re-add a…
Dec 28, 2017
edd03a9
clean circleci config for image snapshots
Dec 28, 2017
c7c1ef1
Update image snapshots test config for angular-cli
Dec 28, 2017
6d0abf1
reorder cicleci goals
Dec 28, 2017
5759db9
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Dec 28, 2017
6bea608
Add missing snapshot
Dec 29, 2017
7a74298
Merge branch 'master' into storyshots-add-image-snapshots
ndelangen Dec 29, 2017
724ab4c
improve image snapshots stories, remove deprecated use to please linter
Dec 29, 2017
2076574
Merge branch 'master' into storyshots-add-image-snapshots
ndelangen Dec 30, 2017
03e47af
Merge branch 'master' into storyshots-add-image-snapshots
ndelangen Jan 1, 2018
e9c2090
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 2, 2018
c124dd5
update snapshots with the correct ones
Jan 2, 2018
c798cdf
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 3, 2018
d94fa13
remove transformIgnorePatterns since lodash-es has been reverted
Jan 3, 2018
a63e1d8
put image-storyshots to official-storybook & update scripts
Jan 3, 2018
fcce2cd
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 3, 2018
ddde721
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 4, 2018
5a24d9d
remove unused code & fix image-snapshots script
Jan 4, 2018
1df4c87
Add official-storybook static build to CI
Jan 4, 2018
8a69e8b
re-move addon-jest config & script to official-storybook
Jan 4, 2018
ce9f389
Merge branch 'master' into storyshots-add-image-snapshots
ndelangen Jan 4, 2018
2b2b03c
store image snapshots on CI for official-storybook
Jan 5, 2018
ca8b1cc
re-add coverage config to addon-jest.config.js
Jan 5, 2018
e5b3233
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 5, 2018
6dca7b9
re-add cra-kitchen-sink to CI build for integration tests
Jan 5, 2018
9cae936
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 5, 2018
6a5911f
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 8, 2018
49e0338
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 8, 2018
28cb109
Merge branch 'master' into storyshots-add-image-snapshots
igor-dv Jan 8, 2018
c5a1fa1
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 10, 2018
96a5df5
Add more details in READMEfor image snapshots
Jan 10, 2018
1a4d34c
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 10, 2018
b104897
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 10, 2018
425937a
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 11, 2018
57b06f8
remove extra CI step to build static storybook on unit-test
Jan 11, 2018
797f2b7
Merge branch 'master' into storyshots-add-image-snapshots
thomasbertet Jan 11, 2018
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
33 changes: 21 additions & 12 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,19 @@ jobs:
name: "Link packages"
command: |
yarn install
- run:
name: Workaround for https://github.com/GoogleChrome/puppeteer/issues/290
command: sh ./scripts/workaround-puppeteer-issue-290.sh
- run:
name: "Build react kitchen-sink"
command: |
cd examples/cra-kitchen-sink
yarn build-storybook
- run:
name: "Build official-storybook"
command: |
cd examples/official-storybook
yarn build-storybook
- run:
name: "Build vue kitchen-sink"
command: |
Expand All @@ -73,28 +81,24 @@ jobs:
command: |
cd examples/angular-cli
yarn build-storybook

- run:
name: "Run react kitchen-sink"
name: "Run react kitchen-sink (smoke test)"
command: |
cd examples/cra-kitchen-sink
yarn storybook
Copy link
Member

Choose a reason for hiding this comment

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

Let's run yarn storybook --smoke-test (without background: true) just to check that devserver starts successfully)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Allright, will re-add this.

background: true
yarn storybook --smoke-test
- run:
name: "Run vue kitchen-sink"
name: "Run vue kitchen-sink (smoke test)"
command: |
cd examples/vue-kitchen-sink
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: "Run angular-cli"
name: "Run angular-cli (smoke test)"
command: |
cd examples/angular-cli
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: Workaround for https://github.com/GoogleChrome/puppeteer/issues/290
command: sh ./scripts/workaround-puppeteer-issue-290.sh
name: "Run image snapshots"
command: yarn test --image
Copy link
Member

Choose a reason for hiding this comment

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

Please store image diffs as artifacts (see below, plus docs)

That way it would be much easier to find out why is the CI test failing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice, will do !

- run:
name: Integration Test - Kichen sinks
command: yarn test --integration
Expand Down Expand Up @@ -195,6 +199,11 @@ jobs:
name: "Link packages"
command: |
yarn install
- run:
name: "Build static React kitchen-sink"
Copy link
Member

@Hypnosphi Hypnosphi Dec 11, 2017

Choose a reason for hiding this comment

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

Let's not add image snapshots to unit-test job but rather to example-kitchen-sinks, in the same place where screenshots of the whole interface are already tested

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Can this step be removed now?

Copy link
Contributor Author

@thomasbertet thomasbertet Jan 10, 2018

Choose a reason for hiding this comment

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

Ah no, it can't since the "integration" test is relying on it.
I forgot to answer when I looked at it sorry for the delay :)

Copy link
Member

Choose a reason for hiding this comment

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

This is unit-test job, integration test is in another place

command: |
cd examples/cra-kitchen-sink
yarn build-storybook
- run:
name: "Run unit tests"
command: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ package-lock.json
storybook-static
integration/__image_snapshots__/__diff_output__
.jest-test-results.json
/examples/cra-kitchen-sink/src/__image_snapshots__/__diff_output__/
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ In order for the snapshot-integration tests to be executed properly, examples be

Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images.

##### CRA-kitchen-sink - Image snapshots using Storyshots

`yarn test --image`

This option executes tests from `<rootdir>/examples/cra-kitchen-sink`
In order for the image snapshots to be correctly generated, you must have static build of the storybook up-to-date.

Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images. (just like integration tests)

#### 2b. Run e2e tests for CLI

Expand Down
63 changes: 62 additions & 1 deletion addons/storyshots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Usually, you might already have completed this step. If not, here are some resou

> Note: If you use React 16, you'll need to follow [these additional instructions](https://github.com/facebook/react/issues/9102#issuecomment-283873039).

## Configure Storyshots
## Configure Storyshots for HTML snapshots

Create 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)).
Then add following content to it:
Expand All @@ -53,6 +53,67 @@ Now run your Jest test command. (Usually, `npm test`.) Then you can see all of y

![Screenshot](docs/storyshots.png)


## Configure Storyshots for image snapshots

/*\ **React-native** is **not supported** by this test function.

Internally, it uses [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot).

When willing to generate and compare image snapshots for your stories, you have to two options:
- Have a storybook running (ie. accessible via http(s):// , for instance using `yarn run storybook`)
- Have a static build of the storybook (for instance, using `yarn run build-storybook`)

Then you will need to reference the storybook URL (`file://...` if local, `http(s)://...` if served)

### Using default values for _imageSnapshots_

Then you can either create a new Storyshots instance or edit the one you previously used:
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';

initStoryshots({suite: 'Image storyshots', test: imageSnapshot});
```
This will assume you have a storybook running on at _http://localhost:6006_.
Internally here are the steps:
- Launches a Chrome headless using [puppeteer](https://github.com/GoogleChrome/puppeteer)
- Browses each stories (calling _http://localhost:6006/iframe.html?..._ URL),
- Take screenshots & save all images under _\_image_snapshots\__ folder.

### Specifying the storybook URL

If you want to set specific storybook URL, you can specify via the `storybookUrl` parameter, see below:
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';

initStoryshots({suite: 'Image storyshots', test: imageSnapshot({storybookUrl: 'http://my-specific-domain.com:9010'})});
```
The above config will use _https://my-specific-domain.com:9010_ for screenshots.


You may also use a local static build of storybook if you do not want to run the webpack dev-server:
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';

initStoryshots({suite: 'Image storyshots', test: imageSnapshot({storybookUrl: 'file:///path/to/my/storybook-static'})});
```

### Specifying options to _jest-image-snapshots_

If you wish to customize [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot), then you can provide a `getMatchOptions` parameter that should return the options config object.
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';
const getMatchOptions = ({context : {kind, story}, url}) => {
return {
failureThreshold: 0.2,
failureThresholdType: 'percent',
}
}
initStoryshots({suite: 'Image storyshots', test: imageSnapshot({storybookUrl: 'http://localhost:6006', getMatchOptions})});
```
`getMatchOptions` receives an object: `{ context: {kind, story}, url}`. _kind_ is the kind of the story and the _story_ its name. _url_ is the URL the browser will use to screenshot.


## Options

### `configPath`
Expand Down
2 changes: 2 additions & 0 deletions addons/storyshots/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
"glob": "^7.1.2",
"global": "^4.3.2",
"jest-specific-snapshot": "^0.3.0",
"jest-image-snapshot": "^2.2.0",
"prop-types": "^15.6.0",
"puppeteer": "^0.13.0",
"read-pkg-up": "^3.0.0"
},
"devDependencies": {
Expand Down
23 changes: 19 additions & 4 deletions addons/storyshots/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import fs from 'fs';
import glob from 'glob';
import global, { describe, it } from 'global';
import global, { describe, it, beforeEach, afterEach } from 'global';
import readPkgUp from 'read-pkg-up';
import addons from '@storybook/addons';

Expand All @@ -18,6 +18,8 @@ export {
renderOnly,
} from './test-bodies';

export { imageSnapshot } from './test-body-image-snapshot';

export { getSnapshotFileName };

let storybook;
Expand Down Expand Up @@ -100,6 +102,20 @@ export default function testStorySnapshots(options = {}) {
}

describe(suite, () => {
beforeEach(() => {
if (typeof options.test.beforeEach === 'function') {
return options.test.beforeEach();
}
return Promise.resolve();
});

afterEach(() => {
if (typeof options.test.afterEach === 'function') {
return options.test.afterEach();
}
return Promise.resolve();
});

describe(kind, () => {
// eslint-disable-next-line
for (const story of group.stories) {
Expand All @@ -109,7 +125,7 @@ export default function testStorySnapshots(options = {}) {
}

it(story.name, () => {
const context = { fileName, kind, story: story.name };
const context = { fileName, kind, story: story.name, isRNStorybook };
return options.test({
story,
context,
Expand All @@ -122,14 +138,13 @@ export default function testStorySnapshots(options = {}) {
}

describe('Storyshots Integrity', () => {
describe('Abandoned Storyshots', () => {
test('Abandoned Storyshots', () => {
const storyshots = glob.sync('**/*.storyshot');

const abandonedStoryshots = storyshots.filter(fileName => {
const possibleStoriesFiles = getPossibleStoriesFiles(fileName);
return !possibleStoriesFiles.some(fs.existsSync);
});

expect(abandonedStoryshots).toHaveLength(0);
});
});
67 changes: 67 additions & 0 deletions addons/storyshots/src/test-body-image-snapshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import puppeteer from 'puppeteer';
import { toMatchImageSnapshot } from 'jest-image-snapshot';

expect.extend({ toMatchImageSnapshot });

export const imageSnapshot = ({
storybookUrl = 'http://localhost:6006',
getMatchOptions = () => {},
}) => {
let browser; // holds ref to browser. (ie. Chrome)
let page; // Hold ref to the page to screenshot.

const testFn = ({ context }) => {
if (context.isRNStorybook) {
// Skip tests since we de not support RN image snapshots.
console.error(
"It seems you are running imageSnapshot on RN app and it's not supported. Skipping test."
);
return Promise.resolve();
}

const encodedKind = encodeURIComponent(context.kind);
const encodedStoryName = encodeURIComponent(context.story);
const storyUrl = `/iframe.html?selectedKind=${encodedKind}&selectedStory=${encodedStoryName}`;
const url = storybookUrl + storyUrl;
if (!browser || !page) {
console.error(
`Error when generating image snapshot for test ${context.kind} - ${
context.story
} : It seems the headless browser is not running.`
);
return Promise.reject(new Error('no-headless-browser-running'));
}

expect.assertions(1);
return page
.goto(url)
.catch(e => {
console.error(
`ERROR WHILE CONNECTING TO ${url}, did you start or build the storybook first ? A storybook instance should be running or a static version should be built when using image snapshot feature.`,
e
);
throw e;
})
.then(() =>
page.screenshot().then(image => {
expect(image).toMatchImageSnapshot(getMatchOptions({ context, url }));
})
);
};

testFn.beforeEach = () =>
puppeteer
// add some options "no-sandbox" to make it work properly on some Linux systems as proposed here: https://github.com/Googlechrome/puppeteer/issues/290#issuecomment-322851507
.launch({ args: ['--no-sandbox ', '--disable-setuid-sandbox'] })
.then(b => {
browser = b;
})
.then(() => browser.newPage())
.then(p => {
page = p;
});

testFn.afterEach = () => browser.close();

return testFn;
};
1 change: 0 additions & 1 deletion examples/cra-kitchen-sink/README.md

This file was deleted.

1 change: 0 additions & 1 deletion examples/cra-kitchen-sink/__mocks__/fileMock.js

This file was deleted.

1 change: 0 additions & 1 deletion examples/cra-kitchen-sink/__mocks__/styleMock.js

This file was deleted.

28 changes: 0 additions & 28 deletions examples/cra-kitchen-sink/config-addon-jest.json

This file was deleted.

1 change: 0 additions & 1 deletion examples/cra-kitchen-sink/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"build": "react-scripts build",
"build-storybook": "build-storybook -s public",
"eject": "react-scripts eject",
"generate-addon-jest-testresults": "jest src/stories/addon-jest.test.js --config=config-addon-jest.json --env=jsdom --json --outputFile=src/stories/addon-jest.testresults.json",
"start": "react-scripts start",
"storybook": "start-storybook -p 9010 -s public",
"test": "react-scripts test --env=jsdom"
Expand Down
4 changes: 0 additions & 4 deletions examples/cra-kitchen-sink/src/enzyme.js

This file was deleted.

28 changes: 0 additions & 28 deletions examples/official-storybook/config-addon-jest.json

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions examples/official-storybook/image-snapshots/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const path = require('path');
const globalJestConfig = require('../../../jest.config');

const finalJestConfig = globalJestConfig;

finalJestConfig.rootDir = path.join(__dirname, '../../..');
finalJestConfig.testMatch = [
'<rootDir>/examples/official-storybook/image-snapshots/storyshots-image.runner.js',
];

module.exports = finalJestConfig;
Loading