diff --git a/addons/jest/README.md b/addons/jest/README.md index a2180eaa5713..ba151c2f7624 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-results file exists before you start storybook. -During development you will likely start jest in watch-mode +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 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,57 @@ 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
+ ); +``` + +### 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 @@ -124,7 +144,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,29 +153,31 @@ 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) diff --git a/addons/jest/package.json b/addons/jest/package.json index 6ba31c87f470..b1cea1fa17f0 100644 --- a/addons/jest/package.json +++ b/addons/jest/package.json @@ -30,7 +30,8 @@ "babel-runtime": "^6.26.0", "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..49c7cca457be 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 => { + Array.from(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.disable) { + 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 e5de001fb18a..f06e841cd8d1 100644 --- a/examples/angular-cli/addon-jest.testresults.json +++ b/examples/angular-cli/addon-jest.testresults.json @@ -1 +1,101 @@ -{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":1,"numPassedTests":3,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTotalTestSuites":1,"numTotalTests":3,"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":1530186110081,"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":1530186112997,"message":"","name":"/Users/jetbrains/IdeaProjects/storybook/examples/angular-cli/src/app/app.component.spec.ts","startTime":1530186110782,"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": 1527637782576, + "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": 1527637787074, + "message": "", + "name": + "/Users/jetbrains/IdeaProjects/storybook/examples/angular-cli/dist/app/app.component.spec.ts", + "startTime": 1527637783974, + "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": 1527637787196, + "message": "", + "name": + "/Users/jetbrains/IdeaProjects/storybook/examples/angular-cli/src/app/app.component.spec.ts", + "startTime": 1527637783968, + "status": "passed", + "summary": "" + } + ], + "wasInterrupted": false +} 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' } + );