From 0eb725b41cd8c87fa294577f0de5e55efba325d0 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 29 May 2018 15:53:03 +1000 Subject: [PATCH 1/4] Refactor addon-jest to use a parameter-based pattern --- addons/jest/README.md | 96 +++++++++++-------- addons/jest/package.json | 3 +- addons/jest/src/index.js | 27 +++++- examples/angular-cli/.storybook/withTests.ts | 7 -- .../angular-cli/addon-jest.testresults.json | 2 +- .../src/stories/addon-jest.stories.ts | 25 +++-- .../stories/addon-jest.stories.js | 8 +- .../stories/addon-jest.stories.js | 20 ++-- 8 files changed, 111 insertions(+), 77 deletions(-) delete mode 100644 examples/angular-cli/.storybook/withTests.ts diff --git a/addons/jest/README.md b/addons/jest/README.md index b6ea4d08c5f6..19224171d544 100644 --- a/addons/jest/README.md +++ b/addons/jest/README.md @@ -31,17 +31,19 @@ When running **Jest**, be sure to save the results in a json file: ``` You may want to add it the result file to `.gitignore`, since it's a generated file: + ``` jest-test-results.json ``` + But much like lockfiles and snapshots checking-in generated files can have certain advantages as well. It's up to you. -We recommend to **do** check in the test results file so starting storybook from an clean git clone doesn't require running all tests first, -but this can mean you'll experience merge conflicts on this file in the future. (*re-generating this file is super easy though, just like lockfiles and snapshots*) +We recommend to **do** check in the test results file so starting storybook from an clean git clone doesn't require running all tests first, +but this can mean you'll experience merge conflicts on this file in the future. (_re-generating this file is super easy though, just like lockfiles and snapshots_) ## Generating the test results You need to make sure the generated test-restuls file exists before you start storybook. -During development you will likely start jest in watch-mode +During development you will likely start jest in watch-mode and so the json file will be re-generated every time code or tests change. ```sh @@ -50,9 +52,10 @@ npm run test:generate-output -- --watch This change will then be HMR (hot module reloaded) using webpack and displayed by this addon. -If you want to pre-run jest automaticly during development or a static build, +If you want to pre-run jest automaticly during development or a static build, you may need to consider that if your tests fail, the script receives a non-0 exit code and will exit. You could create a `prebuild:storybook` npm script, which will never fail by appending `|| true`: + ```json "scripts": { "test:generate-output": "jest --json --outputFile=.jest-test-results.json || true", @@ -83,40 +86,47 @@ import results from '../.jest-test-results.json'; import { withTests } from '@storybook/addon-jest'; storiesOf('MyComponent', module) - .addDecorator(withTests({ results })('MyComponent', 'MyOtherComponent')) - .add('This story shows test results from MyComponent.test.js and MyOtherComponent.test.js', () => ( -
Jest results in storybook
- )); + .addDecorator(withTests({ results })) + .add( + 'This story shows test results from MyComponent.test.js and MyOtherComponent.test.js', + () =>
Jest results in storybook
, + { + jest: ['MyComponent.test.js', 'MyOtherComponent.test.js'], + } + ); ``` -Or in order to avoid importing `.jest-test-results.json` in each story, you can create a simple file `withTests.js`: +Or in order to avoid importing `.jest-test-results.json` in each story, simply add the decorator in your `.storybook/config.js` and results will display for stories that you have set the `jest` parameter on: ```js -import results from '../.jest-test-results.json'; +import { addDecorator } from '@storybook/react'; // <- or your view layer import { withTests } from '@storybook/addon-jest'; -export default withTests({ - results, -}); +import results from '../.jest-test-results.json'; + +addDecorator( + withTests({ + results, + }) +); ``` Then in your story: ```js -// import your file -import withTests from '.withTests'; - storiesOf('MyComponent', module) - .addDecorator(withTests('MyComponent', 'MyOtherComponent')) - .add('This story shows test results from MyComponent.test.js and MyOtherComponent.test.js', () => ( -
Jest results in storybook
- )); + // Use .addParameters if you want the same tests displayed for all stories of the component + .addParameters({ jest: ['MyComponent', 'MyOtherComponent'] }) + .add( + 'This story shows test results from MyComponent.test.js and MyOtherComponent.test.js', + () =>
Jest results in storybook
+ ); ``` ### withTests(options) -- **options.results**: OBJECT jest output results. *mandatory* -- **filesExt**: STRING test file extention. *optionnal*. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js... +* **options.results**: OBJECT jest output results. _mandatory_ +* **filesExt**: STRING test file extention. _optionnal_. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js... ## Usage with Angular @@ -124,7 +134,7 @@ Assuming that you have created a test files `my.component.spec.ts` and `my-other Configure Jest with [jest-preset-angular](https://www.npmjs.com/package/jest-preset-angular) -In project`s `typings.d.ts` add +In project`s`typings.d.ts` add ```ts declare module '*.json' { @@ -133,41 +143,43 @@ declare module '*.json' { } ``` -Create a simple file `withTests.ts`: +In your `.storybook/config.ts`: ```ts -import * as results from '../.jest-test-results.json'; +import { addDecorator } from '@storybook/angular'; import { withTests } from '@storybook/addon-jest'; -export const wTests = withTests({ - results, - filesExt: '((\\.specs?)|(\\.tests?))?(\\.ts)?$' -}); +import * as results from '../.jest-test-results.json'; + +addDecorator( + withTests({ + results, + filesExt: '((\\.specs?)|(\\.tests?))?(\\.ts)?$', + }) +); ``` Then in your story: ```js -// import your file -import wTests from '.withTests'; - storiesOf('MyComponent', module) - .addDecorator(wTests('my.component', 'my-other.component')) - .add('This story shows test results from my.component.spec.ts and my-other.component.spec.ts', () => ( -
Jest results in storybook
- )); + .addParameters({ jest: ['my.component', 'my-other.component'] }) + .add( + 'This story shows test results from my.component.spec.ts and my-other.component.spec.ts', + () =>
Jest results in storybook
+ ); ``` ##### Example [here](https://github.com/storybooks/storybook/tree/master/examples/angular-cli) ## TODO -- [ ] Add coverage -- [ ] Display nested test better (describe) -- [ ] Display the date of the test -- [ ] Add unit tests -- [ ] Add linting -- [ ] Split +* [ ] Add coverage +* [ ] Display nested test better (describe) +* [ ] Display the date of the test +* [ ] Add unit tests +* [ ] Add linting +* [ ] Split ## Contributing diff --git a/addons/jest/package.json b/addons/jest/package.json index d813411fa211..cf92e0ac3b15 100644 --- a/addons/jest/package.json +++ b/addons/jest/package.json @@ -31,7 +31,8 @@ "emotion": "^9.1.3", "global": "^4.3.2", "prop-types": "^15.6.1", - "react-emotion": "^9.1.3" + "react-emotion": "^9.1.3", + "util-deprecate": "^1.0.2" }, "peerDependencies": { "react": "*" diff --git a/addons/jest/src/index.js b/addons/jest/src/index.js index e302a7a0f077..a176c15d4b74 100644 --- a/addons/jest/src/index.js +++ b/addons/jest/src/index.js @@ -1,7 +1,8 @@ import addons from '@storybook/addons'; +import deprecate from 'util-deprecate'; const findTestResults = (testFiles, jestTestResults, jestTestFilesExt) => - testFiles.map(name => { + [].concat(testFiles).map(name => { if (jestTestResults && jestTestResults.testResults) { return { name, @@ -27,9 +28,27 @@ export const withTests = userOptions => { }; const options = Object.assign({}, defaultOptions, userOptions); - return (...testFiles) => (storyFn, { kind, story }) => { - emitAddTests({ kind, story, testFiles, options }); + return (...args) => { + if (typeof args[0] === 'string') { + return deprecate((story, { kind }) => { + emitAddTests({ kind, story, testFiles: args, options }); - return storyFn(); + return story(); + }, 'Passing component filenames to the `@storybook/addon-jest` via `withTests` is deprecated. Instead, use the `jest` story parameter'); + } + + const [ + story, + { + kind, + parameters: { jest: testFiles }, + }, + ] = args; + + if (testFiles && !testFiles.skip) { + emitAddTests({ kind, story, testFiles, options }); + } + + return story(); }; }; diff --git a/examples/angular-cli/.storybook/withTests.ts b/examples/angular-cli/.storybook/withTests.ts deleted file mode 100644 index 20182378f10f..000000000000 --- a/examples/angular-cli/.storybook/withTests.ts +++ /dev/null @@ -1,7 +0,0 @@ -import * as results from '../addon-jest.testresults.json'; -import { withTests } from '@storybook/addon-jest'; - -export const wTests = withTests({ - results, - filesExt: '((\\.specs?)|(\\.tests?))?(\\.ts)?$', -}); diff --git a/examples/angular-cli/addon-jest.testresults.json b/examples/angular-cli/addon-jest.testresults.json index d513e97c5a11..8f7da31bacf7 100644 --- a/examples/angular-cli/addon-jest.testresults.json +++ b/examples/angular-cli/addon-jest.testresults.json @@ -1 +1 @@ -{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":2,"numPassedTests":6,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTotalTestSuites":2,"numTotalTests":6,"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeys":[],"unmatched":0,"updated":0},"startTime":1527433445200,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should create the app","location":null,"status":"passed","title":"should create the app"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should have as title 'app'","location":null,"status":"passed","title":"should have as title 'app'"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should render title in a h1 tag","location":null,"status":"passed","title":"should render title in a h1 tag"}],"endTime":1527433449835,"message":"","name":"/Users/jetbrains/IdeaProjects/storybook/examples/angular-cli/src/app/app.component.spec.ts","startTime":1527433446968,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should create the app","location":null,"status":"passed","title":"should create the app"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should have as title 'app'","location":null,"status":"passed","title":"should have as title 'app'"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should render title in a h1 tag","location":null,"status":"passed","title":"should render title in a h1 tag"}],"endTime":1527433449838,"message":"","name":"/Users/jetbrains/IdeaProjects/storybook/examples/angular-cli/dist/app/app.component.spec.ts","startTime":1527433446974,"status":"passed","summary":""}],"wasInterrupted":false} \ No newline at end of file +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":2,"numPassedTests":6,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTotalTestSuites":2,"numTotalTests":6,"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeys":[],"unmatched":0,"updated":0},"startTime":1527573039637,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should create the app","location":null,"status":"passed","title":"should create the app"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should have as title 'app'","location":null,"status":"passed","title":"should have as title 'app'"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should render title in a h1 tag","location":null,"status":"passed","title":"should render title in a h1 tag"}],"endTime":1527573042008,"message":"","name":"/Users/tom/OSS/storybook/examples/angular-cli/dist/app/app.component.spec.ts","startTime":1527573040569,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should create the app","location":null,"status":"passed","title":"should create the app"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should have as title 'app'","location":null,"status":"passed","title":"should have as title 'app'"},{"ancestorTitles":["AppComponent"],"failureMessages":[],"fullName":"AppComponent should render title in a h1 tag","location":null,"status":"passed","title":"should render title in a h1 tag"}],"endTime":1527573042010,"message":"","name":"/Users/tom/OSS/storybook/examples/angular-cli/src/app/app.component.spec.ts","startTime":1527573040569,"status":"passed","summary":""}],"wasInterrupted":false} \ No newline at end of file diff --git a/examples/angular-cli/src/stories/addon-jest.stories.ts b/examples/angular-cli/src/stories/addon-jest.stories.ts index 0e71c9641fb7..918fe5550c77 100644 --- a/examples/angular-cli/src/stories/addon-jest.stories.ts +++ b/examples/angular-cli/src/stories/addon-jest.stories.ts @@ -1,10 +1,23 @@ import { storiesOf } from '@storybook/angular'; +import { withTests } from '@storybook/addon-jest'; + import { AppComponent } from '../app/app.component'; -import { wTests } from '../../.storybook/withTests'; +import * as results from '../../addon-jest.testresults.json'; storiesOf('Addon|Jest', module) - .addDecorator(wTests('app.component')) - .add('app.component with jest tests', () => ({ - component: AppComponent, - props: {}, - })); + .addDecorator( + withTests({ + results, + filesExt: '((\\.specs?)|(\\.tests?))?(\\.ts)?$', + }) + ) + .add( + 'app.component with jest tests', + () => ({ + component: AppComponent, + props: {}, + }), + { + jest: 'app.component', + } + ); diff --git a/examples/html-kitchen-sink/stories/addon-jest.stories.js b/examples/html-kitchen-sink/stories/addon-jest.stories.js index 543cc5642312..96df36d89e82 100644 --- a/examples/html-kitchen-sink/stories/addon-jest.stories.js +++ b/examples/html-kitchen-sink/stories/addon-jest.stories.js @@ -3,10 +3,6 @@ import { storiesOf } from '@storybook/html'; import { withTests } from '@storybook/addon-jest'; import results from './addon-jest.testresults.json'; -const withTestsFiles = withTests({ - results, -}); - storiesOf('Addons|jest', module) - .addDecorator(withTestsFiles('addon-jest')) - .add('withTests', () => 'This story shows test results'); + .addDecorator(withTests({ results })) + .add('withTests', () => 'This story shows test results', { jest: 'addon-jest' }); diff --git a/examples/official-storybook/stories/addon-jest.stories.js b/examples/official-storybook/stories/addon-jest.stories.js index 3cb6f9135907..2e612898bb1b 100644 --- a/examples/official-storybook/stories/addon-jest.stories.js +++ b/examples/official-storybook/stories/addon-jest.stories.js @@ -4,14 +4,14 @@ import { storiesOf } from '@storybook/react'; import { withTests } from '@storybook/addon-jest'; import results from './addon-jest.testresults.json'; -const withTestsFiles = withTests({ - results, -}); - storiesOf('Addons|jest', module) - .addDecorator(withTestsFiles('addon-jest')) - .add('withTests', () => ( -
-

Hello

-
- )); + .addDecorator(withTests({ results })) + .add( + 'withTests', + () => ( +
+

Hello

+
+ ), + { jest: 'addon-jest' } + ); From d075bfd3461deb151914591acab4f4dcbff5d15a Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 29 May 2018 20:03:16 +1000 Subject: [PATCH 2/4] Fix typo --- addons/jest/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/jest/README.md b/addons/jest/README.md index 19224171d544..7cf0d343227b 100644 --- a/addons/jest/README.md +++ b/addons/jest/README.md @@ -126,7 +126,7 @@ storiesOf('MyComponent', module) ### withTests(options) * **options.results**: OBJECT jest output results. _mandatory_ -* **filesExt**: STRING test file extention. _optionnal_. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js... +* **filesExt**: STRING test file extention. _optional_. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js... ## Usage with Angular From 2343a9a58839e11c9e5802a5ce5e6831c846b558 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Thu, 31 May 2018 16:59:08 +1000 Subject: [PATCH 3/4] Update `[].concat` to `Array.from` --- addons/jest/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/jest/src/index.js b/addons/jest/src/index.js index a176c15d4b74..357a778b509f 100644 --- a/addons/jest/src/index.js +++ b/addons/jest/src/index.js @@ -2,7 +2,7 @@ import addons from '@storybook/addons'; import deprecate from 'util-deprecate'; const findTestResults = (testFiles, jestTestResults, jestTestFilesExt) => - [].concat(testFiles).map(name => { + Array.from(testFiles).map(name => { if (jestTestResults && jestTestResults.testResults) { return { name, From 1e3d925a86ef7f339a7d5c426de741f2fbf96051 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 4 Jul 2018 15:46:28 +1000 Subject: [PATCH 4/4] Change skip => disabled in jest addond --- addons/jest/README.md | 26 ++++++++++++++++++-------- addons/jest/src/index.js | 2 +- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/addons/jest/README.md b/addons/jest/README.md index 7cf0d343227b..ba151c2f7624 100644 --- a/addons/jest/README.md +++ b/addons/jest/README.md @@ -123,10 +123,20 @@ storiesOf('MyComponent', module) ); ``` +### Disabling + +You can disable the addon for a single story by setting the `jest` parameter to `{disabled: true}`: + +```js +storiesOf('MyComponent', module).add('Story', () =>
Jest results disabled herek
, { + jest: disabled, +}); +``` + ### withTests(options) -* **options.results**: OBJECT jest output results. _mandatory_ -* **filesExt**: STRING test file extention. _optional_. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js... +- **options.results**: OBJECT jest output results. _mandatory_ +- **filesExt**: STRING test file extention. _optional_. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js... ## Usage with Angular @@ -174,12 +184,12 @@ storiesOf('MyComponent', module) ## TODO -* [ ] Add coverage -* [ ] Display nested test better (describe) -* [ ] Display the date of the test -* [ ] Add unit tests -* [ ] Add linting -* [ ] Split +- [ ] Add coverage +- [ ] Display nested test better (describe) +- [ ] Display the date of the test +- [ ] Add unit tests +- [ ] Add linting +- [ ] Split ## Contributing diff --git a/addons/jest/src/index.js b/addons/jest/src/index.js index 357a778b509f..49c7cca457be 100644 --- a/addons/jest/src/index.js +++ b/addons/jest/src/index.js @@ -45,7 +45,7 @@ export const withTests = userOptions => { }, ] = args; - if (testFiles && !testFiles.skip) { + if (testFiles && !testFiles.disable) { emitAddTests({ kind, story, testFiles, options }); }