An addon to visually test the stories in the multiple browsers within storybook environment.
Addon will not work in storybook static build, but the screenshots can be tested against the static build files.
This package has been tested with react framework only, therefore it may not work with other frameworks.
Works with Component Story Format (CSF) only.
Package | Version |
---|---|
storybook | ~6.4 |
playwright | ~1.17 |
Being able to make components that feel and look same in all browser were always a challenge, it's required that developer keep switching between browsers and visually checking the components. It's also important to keep track of the changes and be able to detect changes as quickly as possible. That's why this add-on has been created. With the help of playwright and storybook now it's possible to visually check components and be notified of changes all in one place.
storybook-addon-playwright-example
Required packages:
yarn add storybook-addon-playwright @storybook/addon-knobs --dev
within .storybook/main.js
module.exports = {
stories: ['../**/*.stories.[tj]sx'],
addons: [
'@storybook/addon-knobs/register',
'storybook-addon-playwright/preset',
'storybook-addon-playwright/register',
],
};
If story book complain that it can not find
register
in@storybook/addon-knobs/register
path you may need to point it to destination folder:@storybook/addon-knobs/dist/register
within .storybook/main.js
OR .storybook/middleware.js
:
const { setConfig } = require('storybook-addon-playwright/configs');
const playwright = require('playwright');
(async () => {
let browser = {
chromium: await playwright['chromium'].launch(),
firefox: await playwright['firefox'].launch(),
webkit: await playwright['webkit'].launch(),
};
setConfig({
storybookEndpoint: `http://localhost:6006/`,
getPage: async (browserType, options) => {
const page = await browser[browserType].newPage(options);
return page;
},
afterScreenshot: async (page) => {
await page.close();
},
});
})();
within .storybook/middleware.js
:
const middleware = require('storybook-addon-playwright/middleware');
module.exports = middleware;
storybookEndpoint
must match the ip/port of storybook.
For docker and none locale browsers, the public ip address of storybook required.
If set true will apply changes to the json file generate by add-on, read more in Migration
section.
Will be called before taking a screenshot, useful to manipulate the page.
Will be called after a screenshot taken.
Will be called before/after running image diff test on whole application screenshot.
Will be called before/after running image diff on particular story.
Will be called before/after running image diff on particular file.
Will be called after imageDiff process of all stories screenshots complete.
please refer top Playwright API page.goto option
Will be called before page.goto, can be used to manipulate url.
Will be called when page navigated to story.
When set to true, will execute keyboard.up for modifier key, Shift, Meta, Control, or Alt, after screenshot taken.
Default Options to apply when taking screenshot.
It overrides the default theme of the addon. It is a json
of type material-ui Theme
object.
.
.
.
setConfig({
theme: {
palette: {
primary: {
main: '#0052cc',
},
secondary: {
main: '#edf2ff',
},
},
}
});
.
.
.
This add-on is basically an interface between playwright and storybook stories. Add-on executes user instruction on the page provided in configuration.
Instructions created by user will save in a json file next to the story file. therefore its available for the next load.
This add-on consist of there parts:
Action panel act like a playground, it consists of the list of action sets that created by user for specific story and will be executed in the browser page when selected.
An action set can have single or multiple actions.
Actions are referred to the playwright page methods such as click, mouse move etc...
This panel holds the screenshots taken previously by user, here you can manage screenshots such as delete edit or sort screenshots.
The preview panel displays the latest screenshots taken by the playwright, it can selectively display all or some of the supported browser by playwright.
Here you can save and change the screenshots settings such as with, height etc.
The screenshots are saved in the folder named __screenshots__
under the story folder.
To add or extend the playwright method, the following properties are available in the setConfig
method:
This property enables developer to add a new method to the playwright page. every entries in the customActionSchema
property will appear in the 'Add Actions' menu under the Actions
panel.
This property follows the json-schema rules with one additional property named
parameters
, therefore clear understanding ofjson-schema
required.
Here is an example to add a box to the page:
//async function addBox(this: Page, position: { x: number; y: number })
async function addBox(position) {
await this.evaluate((pos) => {
if (!pos) return;
const div = document.createElement('div');
div.style.backgroundColor = '#009EEA';
div.style.width = '200px';
div.style.height = '200px';
div.style.position = 'absolute';
div.style.top = pos.y + 'px';
div.style.left = pos.x + 'px';
document.body.append(div);
}, position);
}
(async () => {
let browser = {
chromium: await playwright['chromium'].launch(),
firefox: await playwright['firefox'].launch(),
webkit: await playwright['webkit'].launch(),
};
setConfig({
storybookEndpoint: `http://localhost:6006/`,
getPage: async (browserType, options) => {
const page = await browser[browserType].newPage(options);
page.addBox = addBox;
return page;
},
afterScreenshot: async (page) => {
await page.close();
},
customActionSchema: {
addBox: {
type: 'promise',
parameters: {
position: {
type: 'object',
properties: {
x: {
type: 'number',
},
y: {
type: 'number',
},
},
required: ['x', 'y'],
},
},
},
},
});
})();
The following custom methods has been added to the playwright page:
This method fetches an element with selector
, waits for actionability checks, focuses the element, clear it and triggers an input event.
This method fetches an element with selector
, and perform mousedown on the center of selector.
This method fetches an element with selector
, and move the mouse to center of selector.
This method fetches an element with selector
, and set the selector with or height.
This method fetches an element with selector
, and set the selector scrollLeft and scrollTop.
This method fetches an element with selector
, and move it to the position given by user.
This method will take a screenshot between actions, its useful for taking a screenshot in sequence for events/actions. In the end the screenshots will be merged with the final screenshot.
The purpose of this action is to have centralized options for all screenshots. This action can be used in conjunction with takeScreenshot action only. Only one instance can be used.
This method fetches an element with selector
, and dispatch WheelEvent.
This method will perform mouse down, move,and up from to selected location.
Screenshots saved with the addon can also be tested with the test framework like jest. to do so configure the jest as follow:
add setup file to jest.config.js
module.exports = {
setupFilesAfterEnv: ['./jest.setup.js'],
};
within jest.setup.js
const playwright = require('playwright');
const { setConfig } = require('storybook-addon-playwright/configs');
const { toMatchScreenshots } = require('storybook-addon-playwright');
expect.extend({ toMatchScreenshots });
let browser = {};
beforeAll(async () => {
browser = {
chromium: await playwright['chromium'].launch(),
firefox: await playwright['firefox'].launch(),
webkit: await playwright['webkit'].launch(),
};
setConfig({
storybookEndpoint: `http://localhost:6006/`, // or `./storybook-static`
getPage: async (browserType, options) => {
const page = await browser[browserType].newPage(options);
return page;
},
afterScreenshot: async (page) => {
await page.close();
},
});
});
afterAll(async () => {
const promises = Object.keys(browser).map((browserType) =>
browser[browserType].close(),
);
await Promise.resolve(promises);
});
and within the test file:
describe('test screenshots', () => {
it('should pass image diff', async () => {
await expect('*').toMatchScreenshots();
}, 10000);
});
Or with toMatchImageSnapshot
:
const { getScreenshots } = require('storybook-addon-playwright');
describe('test screenshots manually', () => {
it('should pass image diff', async () => {
await getScreenshots({
onScreenshotReady: (screenshotBuffer, baselineScreenshotPath) => {
expect(screenshotBuffer).toMatchImageSnapshot({
customSnapshotIdentifier: baselineScreenshotPath.screenshotIdentifier,
customSnapshotsDir: baselineScreenshotPath.screenshotsDir,
});
},
});
}, 10000);
});
Make sure to set appropriate timeout for your tests.
If your editor does not recognise the toMatchScreenshots
matcher, add a global.d.ts file to your project with:
import 'storybook-addon-playwright';
It is possible that the structure of the json file generated by addon change because of the new features, to fix and apply the changes set the enableMigration
to true
in setConfig
and run the storybook.
Make sure after migration set the
enableMigration
tofalse