Skip to content

Commit

Permalink
✨ add storybook v7 support (#829)
Browse files Browse the repository at this point in the history
* feat: uncache stories before extracting them (#828)

* ✨ add fetching env support for storybook v7+ (#827)

* feat: add fetching env support for storybook v7+

* chore: lint using --fix

* fix: evalStorybookEnvironmentInfo

* feat: update package.json and lockfile for storybook v7

* fix: convert start-storybook to storybook dev

* fix: add framework option to storybook config

* feat: update babel and package config to node 16

* feat: update github actions to use node 16

* chore: lint fix

* feat: add storybook-v6 to support start-storybook and build-storybook binaries

* wip: use storybook 6 as default

* fix: make storybook6 default, and keep storybook7 separate

* fix: inherit stdio to run tests

* fix: support storybook6 tests

* wip: add flag support for switching between storybook v6 <> v7 tests

* fix: build storybook command in pretest

* wip: add utils and support for storybook v7 tests only

* test: fix case where storybook had not loaded yet for live url testing

* wip: run storybook6 tests by default

* fix: change babel build target version to 14

* feat: add storybook v6 and v7 test workflows, also remove default test workflow

* feat: downgrade node 16 to node 14 in github workflows and package json engine

* feat: upgrade node 14 to 16 for lint and release workflows, since they run yarn in their workflows

* chore: update yarn.lock as per storybook v7, node 16

* fix: pin action sha, use inputs.branch and use yarn test in v6

* fix: check if error exists before checking for message attribute

* docs: add and update `Development` section in readme

* chore: add EOF
  • Loading branch information
nilshah98 authored Oct 27, 2023
1 parent b73fab9 commit af8fa6c
Show file tree
Hide file tree
Showing 15 changed files with 2,882 additions and 5,470 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ jobs:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 16
- uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}/node-14/${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}/node-14/
key: ${{ runner.os }}/node-16/${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}/node-16/
- run: yarn
env:
PERCY_POSTINSTALL_BROWSER: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 16
registry-url: 'https://registry.npmjs.org'
- run: yarn
- run: yarn build
Expand Down
58 changes: 58 additions & 0 deletions .github/workflows/test-storybook-v6.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Test
on:
push:
workflow_dispatch:
inputs:
branch:
required: false
type: string
default: master
jobs:
test:
name: Test Storybook v6
strategy:
matrix:
os: [ubuntu-latest]
node: [14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions-ecosystem/action-regex-match@9e6c4fb3d5e898f505be7a1fb6e7b0a278f6665b
id: regex-match
if: ${{ github.event_name == 'workflow_dispatch' }}
with:
text: ${{ inputs.branch }}
regex: '^[a-zA-Z0-9_/\-]+$'
- name: Break on invalid branch name
run: exit 1
if: ${{ github.event_name == 'workflow_dispatch' && steps.regex-match.outputs && steps.regex-match.outputs.match == '' }}
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: ./prepare-storybook-v6-tests.sh
- uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}/node-${{ matrix.node }}/${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}/node-${{ matrix.node }}/
- run: yarn
env:
PERCY_POSTINSTALL_BROWSER: true
- run: yarn build
- name: Set up @percy/cli from git
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
cd /tmp
git clone --branch ${{ inputs.branch }} --depth 1 https://github.com/percy/cli
cd cli
PERCY_PACKAGES=`find packages -type d -mindepth 1 -maxdepth 1 | sed -e 's/packages/@percy/g' | tr '\n' ' '`
echo "Packages: $PERCY_PACKAGES"
git log -1
yarn
yarn build
yarn global:link
cd ${{ github.workspace }}
yarn link `echo $PERCY_PACKAGES`
npx percy --version
- run: yarn test
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ on:
default: master
jobs:
test:
name: Test
name: Test Storybook v7
strategy:
matrix:
os: [ubuntu-latest]
node: [14]
node: [16]
runs-on: ${{ matrix.os }}
steps:
- uses: actions-ecosystem/action-regex-match@v2
- uses: actions-ecosystem/action-regex-match@9e6c4fb3d5e898f505be7a1fb6e7b0a278f6665b
id: regex-match
if: ${{ github.event_name == 'workflow_dispatch' }}
with:
text: ${{ github.event.inputs.branch }}
text: ${{ inputs.branch }}
regex: '^[a-zA-Z0-9_/\-]+$'
- name: Break on invalid branch name
run: exit 1
Expand All @@ -42,7 +42,7 @@ jobs:
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
cd /tmp
git clone --branch ${{ github.event.inputs.branch }} --depth 1 https://github.com/percy/cli
git clone --branch ${{ inputs.branch }} --depth 1 https://github.com/percy/cli
cd cli
PERCY_PACKAGES=`find packages -type d -mindepth 1 -maxdepth 1 | sed -e 's/packages/@percy/g' | tr '\n' ' '`
echo "Packages: $PERCY_PACKAGES"
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,7 @@ JavaScript is disabled by default to prevent flakey diffs caused by animations o
running on the page. With the new SDK and real DOM snapshots, JS is disabled by default. If you
upgrade and experience diffs due to the lack of JavaScript, it can be re-enabled using the matching
Percy config file or per-snapshot option, [`enableJavaScript`](https://docs.percy.io/docs/cli-configuration#snapshot).

## Development
- Current package.json and yarn.lock install storybook v7 as devDependency and hence require node 16 for development.
- There are separate package.json and config files for storybook v6, for testing purposes. Please check `prepare-storybook-v6-tests.sh` file for more details around changes for storybook v6 testing.
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"clean": "git clean -Xdf -e !node_modules -e !node_modules/**",
"lint": "eslint --ignore-path .gitignore .",
"readme": "percy-cli-readme",
"pretest": "build-storybook --config-dir=./test/.storybook --output-dir=./test/.storybook-build --loglevel error",
"pretest": "storybook build --config-dir=./test/.storybook --output-dir=./test/.storybook-build --loglevel error",
"test": "yarn test:env jasmine --config=./test/jasmine.json",
"test:env": "cross-env NODE_ENV=test NODE_OPTIONS='--loader=./test/loader.js'",
"test:coverage": "nyc yarn test"
Expand All @@ -45,7 +45,8 @@
"@babel/eslint-parser": "^7.19.1",
"@babel/eslint-plugin": "^7.19.1",
"@babel/preset-env": "^7.22.9",
"@storybook/react": "^6.5.13",
"@storybook/react": "^7.5.0",
"@storybook/react-webpack5": "^7.5.0",
"babel-eslint": "^10.0.3",
"babel-plugin-istanbul": "^6.1.1",
"cross-env": "^7.0.3",
Expand All @@ -61,6 +62,7 @@
"nock": "^13.2.9",
"nyc": "^15.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"storybook": "^7.5.0"
}
}
66 changes: 66 additions & 0 deletions packageV6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@percy/storybook",
"version": "4.3.7",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/percy/percy-storybook.git"
},
"engine": {
"node": ">=14"
},
"files": [
"bin",
"dist"
],
"bin": {
"percy-storybook": "./bin/percy-storybook.cjs"
},
"main": "./dist/index.js",
"exports": "./dist/index.js",
"type": "module",
"scripts": {
"build": "babel src --out-dir dist",
"clean": "git clean -Xdf -e !node_modules -e !node_modules/**",
"lint": "eslint --ignore-path .gitignore .",
"readme": "percy-cli-readme",
"pretest": "build-storybook --config-dir=./test/.storybook --output-dir=./test/.storybook-build --loglevel error",
"test": "yarn test:env jasmine --config=./test/jasmine.json",
"test:env": "cross-env NODE_ENV=test NODE_OPTIONS='--loader=./test/loader.js'",
"test:coverage": "nyc yarn test"
},
"@percy/cli": {
"commands": [
"./dist/storybook.js"
]
},
"dependencies": {
"@percy/cli-command": "^1.24.0",
"cross-spawn": "^7.0.3",
"qs": "^6.11.0"
},
"devDependencies": {
"@babel/cli": "^7.23.0",
"@babel/core": "^7.23.2",
"@babel/eslint-parser": "^7.19.1",
"@babel/eslint-plugin": "^7.19.1",
"@babel/preset-env": "^7.22.9",
"@storybook/react": "^6.5.13",
"babel-eslint": "^10.0.3",
"babel-plugin-istanbul": "^6.1.1",
"cross-env": "^7.0.3",
"eslint": "^8.51.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"jasmine": "^4.5.0",
"jasmine-spec-reporter": "^7.0.0",
"mock-require": "^3.0.3",
"nock": "^13.2.9",
"nyc": "^15.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
5 changes: 5 additions & 0 deletions prepare-storybook-v6-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

# move package and storybook configs
mv ./packageV6.json ./package.json
mv ./test/.storybook/mainV6.js ./test/.storybook/main.js
12 changes: 9 additions & 3 deletions src/start.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import command from '@percy/cli-command';
import * as common from './common.js';
import { checkStorybookVersion } from './utils.js';

export const start = command('start', {
description: 'Run start-storybook to snapshot stories',
Expand Down Expand Up @@ -31,12 +32,17 @@ export const start = command('start', {
let { takeStorybookSnapshots } = yield import('./snapshots.js');
let { default: { spawn } } = yield import('cross-spawn');
let { host, port } = flags;
let storybookVersion = await checkStorybookVersion();

let args = ['--ci', `--host=${host}`, `--port=${port}`, ...argv];
log.info(`Running "start-storybook ${args.join(' ')}"`);
let args = storybookVersion === 7 ? ['dev'] : [];
args = args.concat(['--ci', `--host=${host}`, `--port=${port}`, ...argv]);

let storybookBinary = storybookVersion === 7 ? 'storybook' : 'start-storybook';

log.info(`Running "${storybookBinary} ${args.join(' ')}"`);

let proc = yield new Promise((resolve, reject) => resolve(
spawn('start-storybook', args, { stdio: 'inherit' }).on('error', reject)
spawn(storybookBinary, args, { stdio: 'inherit' }).on('error', reject)
));

/* istanbul ignore next: this is a storybook flag we don't need to test */
Expand Down
25 changes: 23 additions & 2 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
import { request, createRootResource, yieldTo } from '@percy/cli-command/utils';
import spawn from 'cross-spawn';

// check storybook version
export function checkStorybookVersion() {
return new Promise((resolve, reject) => {
spawn('storybook', ['--version'])
.on('exit', (code) => { if (code === 0) resolve(7); })
.on('error', (err) => {
if (err.code === 'ENOENT') {
resolve(6);
}
reject(err);
});
});
}

// Transforms authorization credentials into a basic auth header and returns all config request
// headers with the additional authorization header if not already set.
Expand Down Expand Up @@ -127,7 +142,7 @@ export async function* withPage(percy, url, callback, retry) {
return yield* yieldTo(callback(page));
} catch (error) {
// if the page crashed and retry returns truthy, try again
if (error.message?.includes('crashed') && retry?.()) {
if (error?.message?.includes('crashed') && retry?.()) {
return yield* withPage(...arguments);
}

Expand All @@ -147,7 +162,10 @@ export async function* withPage(percy, url, callback, retry) {
// Evaluate and return Storybook environment information from the about page
/* istanbul ignore next: no instrumenting injected code */
export function evalStorybookEnvironmentInfo({ waitForXPath }) {
return waitForXPath("//header[starts-with(text(), 'Storybook ')]", 5000)
let possibleEnvs = [];
possibleEnvs.push(waitForXPath("//header[starts-with(text(), 'Storybook ')]", 5000));
possibleEnvs.push(waitForXPath("//strong[starts-with(text(), 'You are on Storybook ')]", 5000));
return Promise.any(possibleEnvs)
.then(el => `storybook/${el.innerText.match(/-?\d*\.?\d+/g).join('')}`)
.catch(() => 'storybook/unknown');
}
Expand Down Expand Up @@ -180,6 +198,9 @@ export function evalStorybookStorySnapshots({ waitFor }) {
};

return waitFor(async () => {
// uncache stories, if cached via storyStorev7: true
await (window.__STORYBOOK_PREVIEW__?.cacheAllCSFFiles?.() ||
window.__STORYBOOK_STORY_STORE__?.cacheAllCSFFiles?.());
// use newer storybook APIs before old APIs
await (window.__STORYBOOK_PREVIEW__?.extract?.() ||
window.__STORYBOOK_STORY_STORE__?.extract?.());
Expand Down
4 changes: 4 additions & 0 deletions test/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@ module.exports = {
stories: ['*.stories.js'],
features: {
postcss: false
},
framework: {
name: '@storybook/react-webpack5',
options: {}
}
};
6 changes: 6 additions & 0 deletions test/.storybook/mainV6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
stories: ['*.stories.js'],
features: {
postcss: false
}
};
4 changes: 2 additions & 2 deletions test/storybook-start.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('percy storybook:start', () => {
] : []);

expect(logger.stdout).toEqual(jasmine.arrayContaining([
`[percy] Running "start-storybook --ci --host=localhost --port=9000 ${args.join(' ')}"`,
jasmine.stringMatching(`\\[percy\\] Running "(start-storybook|storybook dev) --ci --host=localhost --port=9000 ${args.join(' ').replace('.', '\\.')}"`),
'[percy] Percy has started!',
'[percy] Snapshot taken: Snapshot: First',
'[percy] Snapshot taken: Snapshot: Second',
Expand All @@ -51,7 +51,7 @@ describe('percy storybook:start', () => {
await expectAsync(start([...args])).toBeRejectedWithError('FAKE ENOENT');

expect(logger.stdout).toEqual([
`[percy] Running "start-storybook --ci --host=localhost --port=9000 ${args.join(' ')}"`
jasmine.stringMatching(`\\[percy\\] Running "(start-storybook|storybook dev) --ci --host=localhost --port=9000 ${args.join(' ').replace('.', '\\.')}"`)
]);
expect(logger.stderr).toEqual([
'[percy] Error: FAKE ENOENT'
Expand Down
14 changes: 12 additions & 2 deletions test/storybook.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import spawn from 'cross-spawn';
import { request } from '@percy/cli-command/utils';
import { api, logger, setupTest, createTestServer } from '@percy/cli-command/test/helpers';
import { storybook } from '../src/index.js';
import { checkStorybookVersion } from '../src/utils.js';

describe('percy storybook', () => {
let server, proc;
Expand All @@ -16,11 +17,16 @@ describe('percy storybook', () => {
default: () => [200, 'text/html', '<p>Not Storybook</p>']
});

proc = spawn('start-storybook', [
let storybookVersion = await checkStorybookVersion();
let args = storybookVersion === 7 ? ['dev'] : [];
args = args.concat([
'--config-dir=./test/.storybook',
'--port=9000',
'--ci'
]);
let storybookBinary = storybookVersion === 7 ? 'storybook' : 'start-storybook';

proc = spawn(storybookBinary, args, { stdio: 'inherit' });

// wait for storybook to become available
await request('http://localhost:9000', {
Expand Down Expand Up @@ -49,7 +55,11 @@ describe('percy storybook', () => {
it('snapshots live urls', async () => {
await storybook(['http://localhost:9000']);

expect(logger.stderr).toEqual([]);
// if there are stderr logs ensure it is only an acceptable warning
expect(logger.stderr).toEqual(logger.stderr.length ? [
'[percy] Waiting on a response from Storybook...'
] : []);

expect(logger.stdout).toEqual(jasmine.arrayContaining([
'[percy] Percy has started!',
'[percy] Snapshot taken: Snapshot: First',
Expand Down
Loading

0 comments on commit af8fa6c

Please sign in to comment.