diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index fa06bb32..518c023a 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -123,21 +123,21 @@ jobs: - name: Fix local @storybook/csf version run: | yarn add @storybook/csf@0.0.2--canary.4566f4d.1 - + - name: Run test runner and expect failure uses: mathiasvr/command-output@v1 with: run: | yarn build yarn test-storybook:ci-failures - + - name: Process test results if: ${{ always() }} id: tests uses: sergeysova/jq-action@v2 with: cmd: 'jq .numPassedTests test-results.json -r' - + - name: Set failure check to env if: ${{ always() }} run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3d84250a..1eccc71d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,4 +25,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - yarn release \ No newline at end of file + yarn release diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml index 63424647..1fa805e9 100644 --- a/.github/workflows/stress-test.yml +++ b/.github/workflows/stress-test.yml @@ -2,7 +2,7 @@ name: Stress Tests on: pull_request: - types: [ labeled ] + types: [labeled] jobs: test: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3f7ed98f..2b3e15ca 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,7 +24,7 @@ jobs: run: | yarn build yarn test-storybook:ci-coverage - + - name: Generate code coverage uses: codecov/codecov-action@v2 with: diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..d24fdfc6 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged diff --git a/.prettierignore b/.prettierignore index 1521c8b7..8db646af 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,8 @@ dist +node_modules +storybook-static +.cache +.env +*.snap +__snapshots__ +CHANGELOG.md \ No newline at end of file diff --git a/.storybook/main.js b/.storybook/main.js index c8c2874d..73588dd5 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -18,18 +18,18 @@ if (process.env.STRESS_TEST) { stories.push('../stories/stress-test/*.stories.@(js|jsx|ts|tsx)'); } -if(process.env.TEST_FAILURES) { +if (process.env.TEST_FAILURES) { stories = ['../stories/expected-failures/*.stories.@(js|jsx|ts|tsx)']; } const addons = [ process.env.WITHOUT_DOCS ? { - name: '@storybook/addon-essentials', - options: { - docs: false, - }, - } + name: '@storybook/addon-essentials', + options: { + docs: false, + }, + } : '@storybook/addon-essentials', '@storybook/addon-interactions', '@storybook/addon-coverage', @@ -43,6 +43,6 @@ module.exports = { buildStoriesJson: true, }, core: { - disableTelemetry: true - } + disableTelemetry: true, + }, }; diff --git a/.vscode/settings.json b/.vscode/settings.json index 20ecf671..623432bf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,4 +5,4 @@ "titleBar.activeBackground": "#004752", "titleBar.activeForeground": "#ECFCFF" } -} \ No newline at end of file +} diff --git a/README.md b/README.md index e26a927d..cb2726df 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ See the announcement of Interaction Testing with Storybook in detail in [this bl The Storybook test runner uses Jest as a runner, and Playwright as a testing framework. Each one of your `.stories` files is transformed into a spec file, and each story becomes a test, which is run in a headless browser. The test runner is simple in design – it just visits each story from a running Storybook instance and makes sure the component is not failing: + - For stories without a `play` function, it verifies whether the story rendered without any errors. This is essentially a smoke test. - For those with a `play` function, it also checks for errors in the `play` function and that all assertions passed. This is essentially an [interaction test](https://storybook.js.org/docs/react/writing-tests/interaction-testing#write-an-interaction-test). @@ -299,7 +300,7 @@ The test runner supports code coverage with the `--coverage` flag or `STORYBOOK_ ### 1 - Instrument the code -Given that your components' code runs in the context of a real browser, they have to be instrumented so that the test runner is able to collect coverage. This is done by configuring [istanbul](https://istanbul.js.org/) in your Storybook. You can achieve that in two different ways: +Given that your components' code runs in the context of a real browser, they have to be instrumented so that the test runner is able to collect coverage. This is done by configuring [istanbul](https://istanbul.js.org/) in your Storybook. You can achieve that in two different ways: #### Using @storybook/addon-coverage @@ -317,9 +318,7 @@ And register it in your `.storybook/main.js` file: // .storybook/main.js module.exports = { // ...rest of your code here - addons: [ - "@storybook/addon-coverage", - ] + addons: ['@storybook/addon-coverage'], }; ``` @@ -359,7 +358,7 @@ If you want certain parts of your code to be deliberately ignored, you can use i ### 3 - Merging code coverage with coverage from other tools -The test runner reports coverage related to the `coverage/storybook/coverage-storybook.json` file. This is by design, showing you the coverage which is tested while running Storybook. +The test runner reports coverage related to the `coverage/storybook/coverage-storybook.json` file. This is by design, showing you the coverage which is tested while running Storybook. Now, you might have other tests (e.g. unit tests) which are _not_ covered in Storybook but are covered when running tests with Jest, which you might also generate coverage files from, for instance. In such cases, if you are using tools like [Codecov](https://codecov.io/) to automate reporting, the coverage files will be detected automatically and if there are multiple files in the coverage folder, they will be merged automatically. @@ -487,40 +486,43 @@ You can use it for multiple use cases, and here's an example that combines the s // .storybook/test-runner.js const { getStoryContext } = require('@storybook/test-runner'); const { injectAxe, checkA11y } = require('axe-playwright'); - + module.exports = { - async preRender(page, context) { - await injectAxe(page); - }, - async postRender(page, context) { - // Get entire context of a story, including parameters, args, argTypes, etc. - const storyContext = await getStoryContext(page, context); - - // Do not test a11y for stories that disable a11y - if (storyContext.parameters?.a11y?.disable) { - return; - } - - await checkA11y(page, '#root', { - detailedReport: true, - detailedReportOptions: { - html: true, - }, - // pass axe options defined in @storybook/addon-a11y - axeOptions: storyContext.parameters?.a11y?.options - }) - }, + async preRender(page, context) { + await injectAxe(page); + }, + async postRender(page, context) { + // Get entire context of a story, including parameters, args, argTypes, etc. + const storyContext = await getStoryContext(page, context); + + // Do not test a11y for stories that disable a11y + if (storyContext.parameters?.a11y?.disable) { + return; + } + + await checkA11y(page, '#root', { + detailedReport: true, + detailedReportOptions: { + html: true, + }, + // pass axe options defined in @storybook/addon-a11y + axeOptions: storyContext.parameters?.a11y?.options, + }); + }, }; ``` ## Troubleshooting #### Errors with Jest 28 + 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: + ```sh TypeError: Jest: Got error running globalSetup reason: Class extends value # is not a constructor or null ``` + 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. #### The error output in the CLI is too short diff --git a/package.json b/package.json index 43f72d7d..52d5581e 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ "test-storybook:ci-failures": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"TEST_FAILURES=1 yarn build-storybook --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && yarn test-storybook:failures\"", "test-storybook:ci-coverage": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn build-storybook --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && yarn test-storybook --coverage\"", "test-storybook:ci-json": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn build-storybook --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && yarn test-storybook:json\"", - "generate-dynamic-stories": "node scripts/generate-dynamic-stories.js" + "generate-dynamic-stories": "node scripts/generate-dynamic-stories.js", + "prepare": "husky install" }, "bin": { "test-storybook": "./bin/test-storybook.js" @@ -81,8 +82,10 @@ "babel-loader": "^8.1.0", "babel-plugin-istanbul": "^6.1.1", "concurrently": "^7.0.0", + "husky": "^8.0.0", "jest": "^27.0.6", "jest-image-snapshot": "^4.5.1", + "lint-staged": "^13.0.3", "prettier": "^2.3.1", "prop-types": "^15.7.2", "react": "^17.0.1", @@ -92,6 +95,9 @@ "typescript": "^4.2.4", "wait-on": "^6.0.0" }, + "lint-staged": { + "*.{ts,js,tsx,jsx,css,md}": "prettier --write" + }, "publishConfig": { "access": "public" }, diff --git a/playwright/custom-environment.js b/playwright/custom-environment.js index 5111e0a5..eb2457d9 100644 --- a/playwright/custom-environment.js +++ b/playwright/custom-environment.js @@ -6,7 +6,7 @@ const PlaywrightEnvironment = require('jest-playwright-preset/lib/PlaywrightEnvi class CustomEnvironment extends PlaywrightEnvironment { async setup() { await super.setup(); - await setupPage(this.global.page) + await setupPage(this.global.page); } async teardown() { diff --git a/playwright/jest-setup.js b/playwright/jest-setup.js index 9530720a..bf0d2bb4 100644 --- a/playwright/jest-setup.js +++ b/playwright/jest-setup.js @@ -13,4 +13,4 @@ if (testRunnerConfig) { } } -global.__sbCollectCoverage = process.env.STORYBOOK_COLLECT_COVERAGE === 'true' \ No newline at end of file +global.__sbCollectCoverage = process.env.STORYBOOK_COLLECT_COVERAGE === 'true'; diff --git a/playwright/test-runner-jest.config.js b/playwright/test-runner-jest.config.js index 80d3e57e..e4d7a201 100644 --- a/playwright/test-runner-jest.config.js +++ b/playwright/test-runner-jest.config.js @@ -6,4 +6,4 @@ module.exports = { /** Add your own overrides below * @see https://jestjs.io/docs/configuration */ -} \ No newline at end of file +}; diff --git a/playwright/transform.js b/playwright/transform.js index a5b6f3d4..a53fcced 100644 --- a/playwright/transform.js +++ b/playwright/transform.js @@ -15,7 +15,7 @@ module.exports = { '@babel/preset-react', ], }); - + return result ? result.code : src; }, }; diff --git a/stories/atoms/Button.jsx b/stories/atoms/Button.jsx index 19c96568..15dde392 100644 --- a/stories/atoms/Button.jsx +++ b/stories/atoms/Button.jsx @@ -1,20 +1,16 @@ -import React from "react"; -import PropTypes from "prop-types"; -import "./button.css"; +import React from 'react'; +import PropTypes from 'prop-types'; +import './button.css'; /** * Primary UI component for user interaction */ export const Button = ({ primary, backgroundColor, size, label, ...props }) => { - const mode = primary - ? "storybook-button--primary" - : "storybook-button--secondary"; + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; return (