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

Support Storybook 7.0.0 #289

Merged
merged 58 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
a5d3c4c
Updated package.json
bryanjtc Oct 20, 2022
ba980e8
Updated yarn.lock
bryanjtc Oct 20, 2022
4f587f3
Document new prerelease structure
shilman Oct 21, 2022
ee5a64b
Upgrade SB dependencies to `next`
shilman Oct 21, 2022
99d2bba
Update README.md
shilman Oct 21, 2022
cc6f26c
Merge branch 'next' into shilman/add-main-prerelease
shilman Oct 21, 2022
ac5ad43
Clarify README and change main-prerelease to prerelease
shilman Oct 22, 2022
6671cb3
Fix typo
shilman Oct 22, 2022
eefeed8
Upgrade to SB7
shilman Oct 22, 2022
6bc74b4
Merge pull request #209 from bryanjtc/dependency-fix
shilman Oct 22, 2022
476a834
Merge branch 'next' into shilman/add-main-prerelease
shilman Oct 22, 2022
8666bd0
Try to fix TS error
shilman Oct 22, 2022
d43ea0e
Run storybook in V7 mode
shilman Oct 22, 2022
c97c9c0
Merge pull request #210 from storybookjs/shilman/add-main-prerelease
shilman Oct 22, 2022
769fef8
Upgrade CSF to next
shilman Oct 22, 2022
0403710
Merge pull request #212 from storybookjs/shilman/upgrade-csf
shilman Oct 22, 2022
4cf13f8
make setup-page globally available for index-json mode
yannbf Nov 9, 2022
0fabe1c
add recipe for browser name [skip ci]
yannbf Nov 16, 2022
6d41927
Merge pull request #221 from storybookjs/docs/update-snapshot-recipe …
yannbf Nov 16, 2022
87eb771
Merge pull request #217 from storybookjs/fix/setup-page-not-defined
yannbf Nov 18, 2022
f0f7eae
remove unused development packages
yannbf Nov 24, 2022
e04b3a1
Merge pull request #227 from storybookjs/fix/remove-unused-deps
yannbf Nov 24, 2022
586f746
fix target url in error feedback
yannbf Dec 20, 2022
16bcf70
Merge pull request #233 from storybookjs/fix/target-url
yannbf Dec 20, 2022
fd3a480
Updating deps to handle TS 4.9
kasperpeulen Dec 28, 2022
8963d15
Update node
kasperpeulen Dec 28, 2022
b590957
Update snapshot tests
kasperpeulen Dec 28, 2022
9eb3c32
Address review
kasperpeulen Dec 28, 2022
725761b
Merge pull request #237 from storybookjs/kasper/sb-1133-test-runner23…
kasperpeulen Dec 28, 2022
eaaebc4
Fix safe json stringify code
hansottowirtz Dec 31, 2022
69c53fa
feat: add shard option
Niznikr Jan 9, 2023
89d8b97
introduce a prepare function and browser context
yannbf Jan 20, 2023
19e157b
fix CLI options formating
yannbf Jan 20, 2023
da0ff53
Merge pull request #243 from Niznikr/feat/shard-cli
yannbf Jan 20, 2023
b45b5f4
fix stress-test scenario
yannbf Jan 20, 2023
fe81f1b
Use ipv4 loopback address
IanVS Jan 27, 2023
e9cdfa7
add safe check
yannbf Jan 31, 2023
0945c4c
Merge pull request #239 from hansottowirtz/fix-safe-json-stringify
yannbf Feb 1, 2023
2bff48a
Merge pull request #252 from storybookjs/node-18
yannbf Feb 1, 2023
2b62dd1
Support other test-runner config extensions
yannbf Feb 1, 2023
942a3cc
Merge pull request #259 from storybookjs/fix/support-other-config-ext…
yannbf Feb 1, 2023
c5bfdab
Document index.json mode for Svelte CSF
JReinhold Feb 10, 2023
5db7777
README: link to addon-svelte-csf
JReinhold Feb 11, 2023
917a94d
Merge pull request #263 from storybookjs/indexjson-docs
JReinhold Feb 11, 2023
9729793
Use preview api instead of store and fix related deprecation messages
kasperpeulen Mar 1, 2023
08bdc9c
Update yarn.lock
kasperpeulen Mar 1, 2023
67cc43c
Merge pull request #273 from storybookjs/use-preview-api
yannbf Mar 6, 2023
714d3ca
Merge branch 'next' into feat/provide-prepare-api-and-browser-context
yannbf Mar 6, 2023
f2191b7
Merge pull request #245 from storybookjs/feat/provide-prepare-api-and…
yannbf Mar 6, 2023
4ef4cb1
Update getStorybookMain to throw an error if stories are not found in…
valentinpalkovic Mar 13, 2023
6427b31
Merge pull request #278 from storybookjs/valentin/throw-error-on-unde…
yannbf Mar 15, 2023
2ff4518
support Storybook 7.0.0
yannbf Mar 31, 2023
519c438
Merge pull request #283 from storybookjs/feat/prepare-for-sb7
yannbf Mar 31, 2023
1b073f4
Bump @storybook/csf to 0.1.0
kasperpeulen Apr 3, 2023
141978d
Merge pull request #288 from storybookjs/kasper/update-csf
shilman Apr 3, 2023
666d70c
Merge branch 'main' into next [skip ci]
yannbf Apr 3, 2023
15afffc
add version support table
yannbf Apr 3, 2023
e4fe17b
fix version in support table [skip ci]
yannbf Apr 3, 2023
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
8 changes: 4 additions & 4 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Use Node.js 14.x
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 16.x

- name: Install dependencies
uses: bahmutov/npm-install@v1
Expand Down Expand Up @@ -102,10 +102,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Use Node.js 14.x
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 16.x

- name: Install dependencies
uses: bahmutov/npm-install@v1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
- name: Prepare repository
run: git fetch --unshallow --tags

- name: Use Node.js 14.x
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 16.x

- name: Install dependencies
uses: bahmutov/npm-install@v1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/stress-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Use Node.js 14.x
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 16.x

- name: Install dependencies
uses: bahmutov/npm-install@v1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests-extended.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Use Node.js 14.x
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 16.x

- name: Install dependencies
uses: bahmutov/npm-install@v1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Use Node.js 14.x
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 16.x

- name: Install dependencies
uses: bahmutov/npm-install@v1
Expand Down
File renamed without changes.
10 changes: 5 additions & 5 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ let stories = [
'../stories/pages/**/*.stories.@(js|jsx|ts|tsx)',
];

if (process.env.STRESS_TEST) {
stories.push('../stories/stress-test/*.stories.@(js|jsx|ts|tsx)');
}

if (process.env.TEST_FAILURES) {
stories = ['../stories/expected-failures/*.stories.@(js|jsx|ts|tsx)'];
}
Expand All @@ -39,10 +35,14 @@ module.exports = {
stories,
addons,
features: {
storyStoreV7: process.env.STORY_STORE_V7 ? true : false,
storyStoreV7: process.env.STORY_STORE_V7 === 'false' ? false : true,
buildStoriesJson: true,
},
core: {
disableTelemetry: true,
},
framework: {
name: '@storybook/react-webpack5',
options: {},
},
};
76 changes: 74 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Storybook test runner turns all of your stories into executable tests.

- [Features](#features)
- [How it works](#how-it-works)
- [Storybook compatibility](#storybook-compatibility)
- [Getting started](#getting-started)
- [CLI Options](#cli-options)
- [Ejecting configuration](#ejecting-configuration)
Expand All @@ -24,6 +25,8 @@ Storybook test runner turns all of your stories into executable tests.
- [2 - Run tests with --coverage flag](#2---run-tests-with---coverage-flag)
- [3 - Merging code coverage with coverage from other tools](#3---merging-code-coverage-with-coverage-from-other-tools)
- [Experimental test hook API](#experimental-test-hook-api)
- [prepare](#prepare)
- [getHttpHeaders](#gethttpheaders)
- [DOM snapshot recipe](#dom-snapshot-recipe)
- [Image snapshot recipe](#image-snapshot-recipe)
- [Render lifecycle](#render-lifecycle)
Expand All @@ -37,6 +40,9 @@ Storybook test runner turns all of your stories into executable tests.
- [Adding the test runner to other CI environments](#adding-the-test-runner-to-other-ci-environments)
- [Merging test coverage results in wrong coverage](#merging-test-coverage-results-in-wrong-coverage)
- [Future work](#future-work)
- [Contributing](#contributing)
- [Branch structure](#branch-structure)
- [Release process](#release-process)

## Features

Expand Down Expand Up @@ -65,6 +71,15 @@ If there are any failures, the test runner will provide an output with the error

![](.github/assets/click-to-debug.gif)

## Storybook compatibility

Use the following table to use the correct version of this package, based on the version of Storybook you're using:

| Test runner version | Storybook version |
| ------------------- | ----------------- |
| ^0.10.0 | ^7.0.0 |
| ~0.9.4 | ^6.4.0 |

## Getting started

1. Install the test runner:
Expand Down Expand Up @@ -184,7 +199,9 @@ yarn test-storybook --url https://the-storybook-url-here.com

By default, the test runner transforms your story files into tests. It also supports a secondary "index.json mode" which runs directly against your Storybook's index data, which dependending on your Storybook version is located in a `stories.json` or `index.json`, a static index of all the stories.

This is particularly useful for running against a deployed storybook because `index.json` is guaranteed to be in sync with the Storybook you are testing. In the default, story file-based mode, your local story files may be out of sync – or you might not even have access to the source code. Furthermore, it is not possible to run the test-runner directly against `.mdx` stories, and `index.json` mode must be used.
This is particularly useful for running against a deployed storybook because `index.json` is guaranteed to be in sync with the Storybook you are testing. In the default, story file-based mode, your local story files may be out of sync – or you might not even have access to the source code.

Furthermore, it is not possible to run the test-runner directly against `.mdx` stories or custom CSF dialects like when writing Svelte native stories with [`addon-svelte-csf`](https://github.com/storybookjs/addon-svelte-csf). In these cases `index.json` mode must be used.

<!-- TODO: switch details to 6.4 once Storybook 7.0 becomes default -->

Expand Down Expand Up @@ -407,10 +424,43 @@ To enable use cases like visual or DOM snapshots, the test runner exports test h

There are three hooks: `setup`, `preRender`, and `postRender`. `setup` executes once before all the tests run. `preRender` and `postRender` execute within a test before and after a story is rendered.

The render functions are async functions that receive a [Playwright Page](https://playwright.dev/docs/pages) and a context object with the current story `id`, `title`, and `name`. They are globally settable by `@storybook/test-runner`'s `setPreRender` and `setPostRender` APIs.
The render functions are async functions that receive a [Playwright Page](https://playwright.dev/docs/pages) and a context object with the current story's `id`, `title`, and `name`. They are globally settable by `@storybook/test-runner`'s `setPreRender` and `setPostRender` APIs.

All three functions can be set up in the configuration file `.storybook/test-runner.js` which can optionally export any of these functions.

Apart from these hooks, there are additional properties you can set in `.storybook/test-runner.js`:

#### prepare

The test-runner has a default `prepare` function which gets the browser in the right environment before testing the stories. You can override this behavior, in case you might want to hack the behavior of the browser. For example, you might want to set a cookie, or add query parameters to the visiting URL, or do some authentication before reaching the Storybook URL. You can do that by overriding the `prepare` function.

The `prepare` function receives an object containing:

- `browserContext`: a [Playwright Browser Context](https://playwright.dev/docs/api/class-browsercontext) instance
- `page`: a [Playwright Page](https://playwright.dev/docs/api/class-page) instance.
- `testRunnerConfig`: the test runner configuration object, coming from the `.storybook/test-runner.js`.

For reference, please use the [default `prepare`](https://github.com/storybookjs/test-runner/blob/next/src/setup-page.ts#L12) function as a starting point.

> **Note**
> If you override the default prepare behavior, even though this is powerful, you will be responsible for properly preparing the browser. Future changes to the default prepare function will not get included in your project, so you will have to keep an eye out for changes in upcoming releases.

#### getHttpHeaders

The test-runner makes a few `fetch` calls to check the status of a Storybook instance, and to get the index of the Storybook's stories. Additionally, it visits a page using Playwright. In all of these scenarios, it's possible, depending on where your Storybook is hosted, that you might need to set some HTTP headers. For example, if your Storybook is hosted behind a basic authentication, you might need to set the `Authorization` header. You can do so by passing a `getHttpHeaders` function to your test-runner config. That function receives the `url` of the fetch calls and page visits, and should return an object with the headers to be set.

```js
// .storybook/test-runner.js
module.exports = {
getHttpHeaders: async (url) => {
const token = url.includes('prod') ? 'XYZ' : 'ABC';
return {
Authorization: `Bearer ${token}`,
};
},
};
```

> **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.

Expand Down Expand Up @@ -459,6 +509,8 @@ module.exports = {
expect.extend({ toMatchImageSnapshot });
},
async postRender(page, context) {
// If you want to take screenshot of multiple browsers, use
// page.context().browser().browserType().name() to get the browser name to prefix the file name
const image = await page.screenshot();
expect(image).toMatchImageSnapshot({
customSnapshotsDir,
Expand Down Expand Up @@ -616,3 +668,23 @@ Future plans involve adding support for the following features:

- 📄 Run addon reports
- ⚙️ Spawning Storybook via the test runner in a single command

---

## Contributing

We welcome contributions to the test runner!

### Branch structure

- **next** - the `next` version on npm, and the development branch where most work occurs
- **prerelease** - the `prerelease` version on npm, where eventual changes to `main` get tested
- **main** - the `latest` version on npm and the stable version that most users use

### Release process

1. All PRs should target the `next` branch, which depends on the `next` version of Storybook.
2. When merged, a new version of this package will be released on the `next` NPM tag.
3. If the change contains a bugfix that needs to be patched back to the stable version, please note that in PR description.
4. PRs labeled `pick` will get cherry-picked back to the `prerelease` branch and will generate a release on the `prerelease` npm tag.
5. Once validated, `prerelease` PRs will get merged back to the `main` branch, which will generate a release on the `latest` npm tag.
22 changes: 18 additions & 4 deletions bin/test-storybook.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const path = require('path');
const tempy = require('tempy');
const { getCliOptions } = require('../dist/cjs/util/getCliOptions');
const { getStorybookMetadata } = require('../dist/cjs/util/getStorybookMetadata');
const { getTestRunnerConfig } = require('../dist/cjs/util/getTestRunnerConfig');
const { transformPlaywrightJson } = require('../dist/cjs/playwright/transformPlaywrightJson');

const glob_og = require('glob');
Expand All @@ -27,6 +28,8 @@ process.env.NODE_ENV = 'test';
process.env.STORYBOOK_TEST_RUNNER = 'true';
process.env.PUBLIC_URL = '';

let getHttpHeaders = (_url) => Promise.resolve({});

// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
Expand Down Expand Up @@ -142,7 +145,8 @@ async function executeJestPlaywright(args) {

async function checkStorybook(url) {
try {
const res = await fetch(url, { method: 'HEAD' });
const headers = await getHttpHeaders(url);
const res = await fetch(url, { method: 'HEAD', headers });
if (res.status !== 200) throw new Error(`Unxpected status: ${res.status}`);
} catch (e) {
console.error(
Expand All @@ -161,8 +165,13 @@ async function checkStorybook(url) {
async function getIndexJson(url) {
const indexJsonUrl = new URL('index.json', url).toString();
const storiesJsonUrl = new URL('stories.json', url).toString();
const headers = await getHttpHeaders(url);
const fetchOptions = { headers };

const [indexRes, storiesRes] = await Promise.all([fetch(indexJsonUrl), fetch(storiesJsonUrl)]);
const [indexRes, storiesRes] = await Promise.all([
fetch(indexJsonUrl, fetchOptions),
fetch(storiesJsonUrl, fetchOptions),
]);

if (indexRes.ok) {
try {
Expand Down Expand Up @@ -236,6 +245,13 @@ const main = async () => {
process.exit(0);
}

process.env.STORYBOOK_CONFIG_DIR = runnerOptions.configDir;

const testRunnerConfig = getTestRunnerConfig(runnerOptions.configDir) || {};
if (testRunnerConfig.getHttpHeaders) {
getHttpHeaders = testRunnerConfig.getHttpHeaders;
}

// set this flag to skip reporting coverage in watch mode
isWatchMode = jestOptions.watch || jestOptions.watchAll;

Expand Down Expand Up @@ -278,8 +294,6 @@ const main = async () => {
process.env.TEST_MATCH = '**/*.test.js';
}

process.env.STORYBOOK_CONFIG_DIR = runnerOptions.configDir;

const { storiesPaths, lazyCompilation } = getStorybookMetadata();
process.env.STORYBOOK_STORIES_PATTERN = storiesPaths;

Expand Down
Loading