From 9854cbeb56088d97ef22aa0eb92ac6bdaadd6b05 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 19 Aug 2022 00:40:52 +0900 Subject: [PATCH] Storybook: Set up local visual regression testing --- .gitignore | 2 + package.json | 1 + .../src/date-time/stories/date-time.tsx | 7 ++- .../components/src/date-time/stories/time.tsx | 3 ++ storybook/main.js | 1 + test/storybook-playwright/README.md | 33 ++++++++++++++ test/storybook-playwright/index.spec.ts | 45 +++++++++++++++++++ .../storybook-playwright/playwright.config.ts | 13 ++++++ 8 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 test/storybook-playwright/README.md create mode 100644 test/storybook-playwright/index.spec.ts create mode 100644 test/storybook-playwright/playwright.config.ts diff --git a/.gitignore b/.gitignore index 1f5680e2c6c2da..edc83a04d638e8 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ phpcs.xml phpunit.xml phpunit-watcher.yml .tool-versions +test/storybook-playwright/test-results +test/storybook-playwright/index.spec.ts-snapshots diff --git a/package.json b/package.json index e075a83646ef69..a188b627d9577e 100755 --- a/package.json +++ b/package.json @@ -295,6 +295,7 @@ "test:e2e": "wp-scripts test-e2e --config packages/e2e-tests/jest.config.js", "test:e2e:debug": "wp-scripts --inspect-brk test-e2e --config packages/e2e-tests/jest.config.js --puppeteer-devtools", "test:e2e:playwright": "playwright test --config test/e2e/playwright.config.ts", + "test:e2e:storybook": "playwright test --config test/storybook-playwright/playwright.config.ts", "test:e2e:watch": "npm run test:e2e -- --watch", "test:performance": "wp-scripts test-e2e --config packages/e2e-tests/jest.performance.config.js", "test:php": "npm-run-all lint:php test:unit:php", diff --git a/packages/components/src/date-time/stories/date-time.tsx b/packages/components/src/date-time/stories/date-time.tsx index 447b9cf265ab86..e428c94e2b08ee 100644 --- a/packages/components/src/date-time/stories/date-time.tsx +++ b/packages/components/src/date-time/stories/date-time.tsx @@ -52,11 +52,14 @@ const Template: ComponentStory< typeof DateTimePicker > = ( { export const Default: ComponentStory< typeof DateTimePicker > = Template.bind( {} ); +Default.args = { + currentDate: new Date( 'December 17, 2022 03:24:00' ), +}; export const WithEvents: ComponentStory< typeof DateTimePicker > = Template.bind( {} ); WithEvents.args = { - currentDate: new Date(), + ...Default.args, events: [ { date: daysFromNow( 2 ) }, { date: daysFromNow( 4 ) }, @@ -68,6 +71,6 @@ WithEvents.args = { export const WithInvalidDates: ComponentStory< typeof DateTimePicker > = Template.bind( {} ); WithInvalidDates.args = { - currentDate: new Date(), + ...Default.args, isInvalidDate: isWeekend, }; diff --git a/packages/components/src/date-time/stories/time.tsx b/packages/components/src/date-time/stories/time.tsx index 9fc72086075f7c..eb467c16e20094 100644 --- a/packages/components/src/date-time/stories/time.tsx +++ b/packages/components/src/date-time/stories/time.tsx @@ -49,3 +49,6 @@ const Template: ComponentStory< typeof TimePicker > = ( { }; export const Default: ComponentStory< typeof TimePicker > = Template.bind( {} ); +Default.args = { + currentTime: new Date( 'December 17, 2022 03:24:00' ), +}; diff --git a/storybook/main.js b/storybook/main.js index 99c8c2ea84bec1..6e85e27fbb1eb9 100644 --- a/storybook/main.js +++ b/storybook/main.js @@ -28,6 +28,7 @@ module.exports = { features: { babelModeV7: true, emotionAlias: false, + buildStoriesJson: true, }, // Workaround: // https://github.com/storybookjs/storybook/issues/12270 diff --git a/test/storybook-playwright/README.md b/test/storybook-playwright/README.md new file mode 100644 index 00000000000000..91d41f87b6ea17 --- /dev/null +++ b/test/storybook-playwright/README.md @@ -0,0 +1,33 @@ +# Storybook Playwright Tests + +This is currently set up for testing visual regressions in the `components` package. The tests do not run on CI, and is meant as a testing tool for local development. + +## How to run + +First, prepare a static build of the Storybook. This is required to generate the `stories.json` file, which contains metadata for every story. + +```sh +npm run storybook:build +``` + +Then serve the Storybook locally, using either the static build prepared in the previous step, or the dev server if you want to iterate in watch mode. + +```sh +# Using the static build +npx http-server storybook/build -p 50240 + +# Using the dev server +npm run storybook:dev +``` + +You are now ready to run the tests. The first run will generate the reference images, and subsequent runs will compare against them. + +```sh +npm run test:e2e:storybook +``` + +To update the reference images, pass the `--update-snapshots` flag. + +```sh +npm run test:e2e:storybook -- --update-snapshots +``` \ No newline at end of file diff --git a/test/storybook-playwright/index.spec.ts b/test/storybook-playwright/index.spec.ts new file mode 100644 index 00000000000000..499ac828e938d7 --- /dev/null +++ b/test/storybook-playwright/index.spec.ts @@ -0,0 +1,45 @@ +/** + * External dependencies + */ +import { test, expect } from '@playwright/test'; +import { readFileSync } from 'fs'; +import { resolve } from 'path'; +import type { StoryIndex, StoryIndexEntry } from '@storybook/store'; + +const STORYBOOK_PORT = '50240'; +const STORYBOOK_DIR = resolve( __dirname, '../../storybook/build' ); + +const { stories }: StoryIndex = JSON.parse( + readFileSync( resolve( STORYBOOK_DIR, 'stories.json' ) ).toString() +); + +const includeIds = [ /^components-/ ]; +const excludeIds = [ /animate/, /zstack/ ]; + +const filterMatches = ( story: StoryIndexEntry ) => { + const isIncluded = includeIds.some( ( includeRegex ) => + includeRegex.test( story.id ) + ); + const isExcluded = excludeIds.some( ( excludeRegex ) => + excludeRegex.test( story.id ) + ); + return isIncluded && ! isExcluded; +}; + +test.describe.parallel( 'Storybook visual regressions', () => { + Object.values( stories ) + .filter( filterMatches ) + .forEach( ( story ) => { + test( `${ story.title }: ${ story.name }`, async ( { page } ) => { + await page.goto( + `http://localhost:${ STORYBOOK_PORT }/iframe.html?id=${ story.id }`, + { waitUntil: 'load' } + ); + expect( + await page + .locator( '#root' ) + .screenshot( { animations: 'disabled' } ) + ).toMatchSnapshot( [ story.title, `${ story.id }.png` ] ); + } ); + } ); +} ); diff --git a/test/storybook-playwright/playwright.config.ts b/test/storybook-playwright/playwright.config.ts new file mode 100644 index 00000000000000..c89f3780c7229e --- /dev/null +++ b/test/storybook-playwright/playwright.config.ts @@ -0,0 +1,13 @@ +/** + * External dependencies + */ +import { PlaywrightTestConfig } from '@playwright/test'; + +const config: PlaywrightTestConfig = { + outputDir: 'test-results/output', + reporter: [ + [ 'html', { open: 'on-failure', outputFolder: 'test-results/report' } ], + ], +}; + +export default config;