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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: jest 28 support #154

Merged
merged 9 commits into from Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 22 additions & 8 deletions README.md
Expand Up @@ -24,7 +24,7 @@ Storybook test runner turns all of your stories into executable tests.
- [Image snapshot recipe](#image-snapshot-recipe)
- [Render lifecycle](#render-lifecycle)
- [Troubleshooting](#troubleshooting)
- [Errors with Jest 28](#errors-with-jest-28)
- [Jest 27 support](#jest-27-support)
- [The error output in the CLI is too short](#the-error-output-in-the-cli-is-too-short)
- [The test runner seems flaky and keeps timing out](#the-test-runner-seems-flaky-and-keeps-timing-out)
- [The test runner reports "No tests found" running on a Windows CI](#the-test-runner-reports-"no-tests-found"-running-on-a-windows-ci)
Expand Down Expand Up @@ -68,7 +68,7 @@ yarn add @storybook/test-runner -D
Jest is a peer dependency. If you don't have it, also install it

```jsx
yarn add jest@27 -D
yarn add jest -D
```

<details>
Expand Down Expand Up @@ -513,16 +513,30 @@ module.exports = {

## Troubleshooting

#### Errors with Jest 28
#### Jest 27 support

Jest 28 has been released, but unfortunately `jest-playwright` is not yet compatible with it, therefore the test-runner is also not compatible. You likely are having an issue that looks like this:
[`jest-playwright` 2.0.0](https://github.com/playwright-community/jest-playwright/releases/tag/v2.0.0) has a breaking change of requiring Jest 28+. To support older versions of Jest you will need to use [Yarn resolutions](https://yarnpkg.com/configuration/manifest/#resolutions) or [NPM overrides](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides) to downgrade `jest-playwright-preset` to `^1.7.2`.

```sh
TypeError: Jest: Got error running globalSetup
reason: Class extends value #<Object> is not a constructor or null

```json
// Yarn resolutions in your projects package.json
{
"resolutions": {
"jest-playwright-preset": "^1.7.2"
}
}
```

As soon as `jest-playwright` is compatible, so the test-runner will be too. Please follow [this issue](https://github.com/storybookjs/test-runner/issues/99) for updates.
```json
// NPM overrides in your projects package.json
{
"overrides": {
"@storybook/test-runner": {
"jest-playwright-preset": "^1.7.2"
}
}
}
```

#### The error output in the CLI is too short

Expand Down
40 changes: 16 additions & 24 deletions bin/test-storybook.js
Expand Up @@ -40,15 +40,15 @@ const cleanup = () => {
let isWatchMode = false;
async function reportCoverage() {
if (isWatchMode || process.env.STORYBOOK_COLLECT_COVERAGE !== 'true') {
return
return;
}

const coverageFolderE2E = path.resolve(process.cwd(), '.nyc_output');
const coverageFolder = path.resolve(process.cwd(), 'coverage/storybook');

// in case something goes wrong and .nyc_output does not exist, bail
if (!fs.existsSync(coverageFolderE2E)) {
return
return;
}

// if there's no coverage folder, create one
Expand All @@ -57,22 +57,21 @@ async function reportCoverage() {
}

// move the coverage files from .nyc_output folder (coming from jest-playwright) to coverage, then delete .nyc_output
fs.renameSync(
`${coverageFolderE2E}/coverage.json`,
`${coverageFolder}/coverage-storybook.json`,
);
fs.renameSync(`${coverageFolderE2E}/coverage.json`, `${coverageFolder}/coverage-storybook.json`);
fs.rmSync(coverageFolderE2E, { recursive: true });

// --skip-full in case we only want to show not fully covered code
// --check-coverage if we want to break if coverage reaches certain threshold
// .nycrc will be respected for thresholds etc. https://www.npmjs.com/package/nyc#coverage-thresholds
execSync(`npx nyc report --reporter=text -t ${coverageFolder} --report-dir ${coverageFolder}`, { stdio: 'inherit' })
execSync(`npx nyc report --reporter=text -t ${coverageFolder} --report-dir ${coverageFolder}`, {
stdio: 'inherit',
});
}

const onProcessEnd = () => {
cleanup();
reportCoverage();
}
};

process.on('SIGINT', onProcessEnd);
process.on('exit', onProcessEnd);
Expand Down Expand Up @@ -101,16 +100,12 @@ function sanitizeURL(url) {
const checkForIncompatibilities = () => {
try {
const jestVersion = require('jest/package.json').version;
if (semver.gte(jestVersion, '28.0.0')) {
error(dedent`We detected that your project is using Jest 28.0.0 or higher, which is currently incompatible with the test runner.

You can find more info at: https://github.com/storybookjs/test-runner#errors-with-jest-28
`);
process.exit(1);
if (semver.valid(jestVersion) === null) {
throw new Error('Not valid Jest version or no Jest installed');
}
} catch (err) {
error(
'We detected that Jest is not installed in your project. Please install Jest@27 and run test-storybook again.'
'We detected that Jest is not installed in your project. Please install Jest and run test-storybook again.'
);
process.exit(1);
}
Expand Down Expand Up @@ -151,23 +146,20 @@ async function getIndexJson(url) {
const indexJsonUrl = new URL('index.json', url).toString();
const storiesJsonUrl = new URL('stories.json', url).toString();

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

if (indexRes.ok) {
try {
const json = await indexRes.text();
return JSON.parse(json);
} catch (err) { }
} catch (err) {}
}

if(storiesRes.ok) {
if (storiesRes.ok) {
try {
const json = await storiesRes.text();
return JSON.parse(json);
} catch (err) { }
} catch (err) {}
}

throw new Error(dedent`
Expand All @@ -187,7 +179,7 @@ async function getIndexJson(url) {
async function getIndexTempDir(url) {
let tmpDir;
try {
const indexJson = await getIndexJson(url)
const indexJson = await getIndexJson(url);
const titleIdToTest = transformPlaywrightJson(indexJson);

tmpDir = tempy.directory();
Expand Down Expand Up @@ -236,7 +228,7 @@ const main = async () => {
const rawTargetURL = process.env.TARGET_URL || runnerOptions.url || 'http://localhost:6006';
await checkStorybook(rawTargetURL);

const targetURL = sanitizeURL(rawTargetURL)
const targetURL = sanitizeURL(rawTargetURL);

process.env.TARGET_URL = targetURL;

Expand Down
18 changes: 9 additions & 9 deletions package.json
Expand Up @@ -61,7 +61,7 @@
"@babel/preset-typescript": "^7.13.0",
"@babel/template": "^7.14.5",
"@babel/types": "^7.14.8",
"@jest/types": "^27.0.6",
"@jest/types": "^28.1.3",
"@storybook/addon-coverage": "^0.0.1",
"@storybook/addon-essentials": "^6.5.0",
"@storybook/addon-interactions": "^6.5.0",
Expand All @@ -72,21 +72,21 @@
"@testing-library/dom": "^8.1.0",
"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^13.2.1",
"@types/jest": "^27.0.3",
"@types/jest": "^28.1.6",
"@types/node": "^16.4.1",
"auto": "^10.3.0",
"babel-jest": "^27.0.6",
"babel-jest": "^28.1.3",
"babel-loader": "^8.1.0",
"babel-plugin-istanbul": "^6.1.1",
"concurrently": "^7.0.0",
"jest": "^27.0.6",
"jest-image-snapshot": "^4.5.1",
"jest": "^28.1.3",
"jest-image-snapshot": "^5.1.0",
"prettier": "^2.3.1",
"prop-types": "^15.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"rimraf": "^3.0.2",
"ts-jest": "^27.0.4",
"ts-jest": "^28.0.7",
"typescript": "^4.2.4",
"wait-on": "^6.0.0"
},
Expand All @@ -105,9 +105,9 @@
"can-bind-to-host": "^1.1.1",
"commander": "^9.0.0",
"global": "^4.4.0",
"jest-playwright-preset": "^1.7.2",
"jest-playwright-preset": "^1.7.2 || ^2.0.0",
"jest-serializer-html": "^7.1.0",
"jest-watch-typeahead": "^1.0.0",
"jest-watch-typeahead": "^2.0.0",
"node-fetch": "^2",
"playwright": "^1.14.0",
"semver": "^7.3.7",
Expand All @@ -118,7 +118,7 @@
"@storybook/core-common": "^6.5.0",
"@storybook/csf-tools": "^6.5.0",
"@storybook/store": "^6.5.0",
"jest": "^26.6.3 || ^27.0.0"
"jest": "^26.6.3 || ^27.0.0 || ^28.0.0"
},
"auto": {
"plugins": [
Expand Down
21 changes: 20 additions & 1 deletion playwright/transform.js
@@ -1,4 +1,5 @@
const { transform: babelTransform } = require('@babel/core');
const semver = require('semver');
const { transformPlaywright } = require('../dist/cjs/playwright/transformPlaywright');

module.exports = {
Expand All @@ -15,6 +16,24 @@ module.exports = {
'@babel/preset-react',
],
});
return result ? result.code : src;

if (result) {
/**
* To support Jest 28 we need to check the version of Jest used in the project.
* As process() and processAsync() methods of a custom transformer module cannot return a string anymore.
* They must always return an object. See https://jestjs.io/docs/upgrading-to-jest28#transformer
*/
const jestVersion = require('jest/package.json').version;

if (semver.lte(jestVersion, '28.0.0')) {
return result.code;
}

return {
code: result.code,
};
}

return src;
},
};