diff --git a/addons/jest/example/.storybook/addons.js b/addons/jest/example/.storybook/addons.js deleted file mode 100644 index d24151dd3ad0..000000000000 --- a/addons/jest/example/.storybook/addons.js +++ /dev/null @@ -1,6 +0,0 @@ -import '@storybook/addon-options/register'; -// --> import 'storybook-addon-jest/register' -import '../../register'; -// --> import 'storybook-addon-jest/styles' -import '../../dist/styles'; - diff --git a/addons/jest/example/.storybook/config.js b/addons/jest/example/.storybook/config.js deleted file mode 100644 index d3ef1681fc2e..000000000000 --- a/addons/jest/example/.storybook/config.js +++ /dev/null @@ -1,17 +0,0 @@ -import { configure, addDecorator } from '@storybook/react'; -import { setOptions } from '@storybook/addon-options'; -// --> import { setupJestAddon } from 'storybook-addon-jest'; - - -setOptions({ - name: 'JEST ADDON', - url: 'https://github.com/storybooks/storybook', - downPanelInRight: true, - showLeftPanel: true, -}); - -function loadStories() { - require('../List.story'); -} - -configure(loadStories, module); diff --git a/addons/jest/example/List.js b/addons/jest/example/List.js deleted file mode 100644 index c652384c14f5..000000000000 --- a/addons/jest/example/List.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; - -const List = ({ items }) => ; - -List.defaultProps = { - items: [], -}; - -export default List; diff --git a/addons/jest/example/List.story.js b/addons/jest/example/List.story.js deleted file mode 100644 index 43e76b5c1eb1..000000000000 --- a/addons/jest/example/List.story.js +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import React from 'react'; -import { storiesOf } from '@storybook/react'; - -import withTests from './withTests'; -import List from './List'; - -storiesOf('List', module) - .addDecorator(withTests('List')) - .add('3 items', () => ( - - )); diff --git a/addons/jest/example/List.test.js b/addons/jest/example/List.test.js deleted file mode 100644 index efc42eb7b1d6..000000000000 --- a/addons/jest/example/List.test.js +++ /dev/null @@ -1,13 +0,0 @@ -describe('Description: ', () => { - it('should contain 3 items', () => { - expect(3).toBe(3); - }); - - it('should work fine', () => { - expect(true).toBe(true); - }); -}); - -test('Failing test',() => { - expect(['foo', 'bar', 'baz']).toEqual(['foo', 'bar']); -}) diff --git a/addons/jest/example/withTests.js b/addons/jest/example/withTests.js deleted file mode 100644 index 1ce4a9281daa..000000000000 --- a/addons/jest/example/withTests.js +++ /dev/null @@ -1,9 +0,0 @@ -// ---> import { withTests } from 'storybook-addon-jest'; -import withTests from '../dist'; - -import jestTestResuls from './.jest-test-results.json'; - - -export default withTests(jestTestResuls, { - filesExt: '.test.js', -}); diff --git a/addons/jest/package.json b/addons/jest/package.json index 9f4b8982153b..4f6a34b3a8f3 100644 --- a/addons/jest/package.json +++ b/addons/jest/package.json @@ -26,7 +26,8 @@ "dependencies": { "@storybook/addons": "^3.2.15", "global": "^4.3.2", - "prop-types": "^15.6.0" + "prop-types": "^15.6.0", + "styled-components": "^2.2.3" }, "devDependencies": { "babel-cli": "^6.26.0", diff --git a/addons/jest/src/components/Indicator.js b/addons/jest/src/components/Indicator.js index d1932f47cfe4..ab54457a4855 100644 --- a/addons/jest/src/components/Indicator.js +++ b/addons/jest/src/components/Indicator.js @@ -21,11 +21,17 @@ const Indicator = ({ color, size, children = '', right }) => ( {children} ); + +Indicator.defaultProps = { + right: false, + children: null, +}; + Indicator.propTypes = { color: PropTypes.string.isRequired, size: PropTypes.number.isRequired, - children: PropTypes.node.isRequired, - right: PropTypes.bool.isRequired, + children: PropTypes.node, + right: PropTypes.bool, }; export default Indicator; diff --git a/addons/jest/src/components/TestsPanel.js b/addons/jest/src/components/Panel.js similarity index 63% rename from addons/jest/src/components/TestsPanel.js rename to addons/jest/src/components/Panel.js index 2f7e34ba8dc1..de7f2cc35a37 100644 --- a/addons/jest/src/components/TestsPanel.js +++ b/addons/jest/src/components/Panel.js @@ -2,10 +2,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import Indicator from './Indicator'; -import provideTests from '../hoc/provideTests'; +import Result from './Result'; +import provideJestResult from '../hoc/provideJestResult'; import colors from '../colors'; -const TestsPanel = ({ tests }) => { +const Panel = ({ tests }) => { const style = { padding: '10px 20px', flex: 1, @@ -104,45 +105,11 @@ const TestsPanel = ({ tests }) => { ); @@ -150,12 +117,17 @@ const TestsPanel = ({ tests }) => { ); }; -TestsPanel.propTypes = { + +Panel.defaultProps = { + tests: null, +}; + +Panel.propTypes = { tests: PropTypes.arrayOf( PropTypes.shape({ result: PropTypes.object, }) - ).isRequired, + ), }; -export default provideTests(TestsPanel); +export default provideJestResult(Panel); diff --git a/addons/jest/src/components/TestsPanelTitle.js b/addons/jest/src/components/PanelTitle.js similarity index 79% rename from addons/jest/src/components/TestsPanelTitle.js rename to addons/jest/src/components/PanelTitle.js index 4d56aa072a6b..6d93d698a74c 100644 --- a/addons/jest/src/components/TestsPanelTitle.js +++ b/addons/jest/src/components/PanelTitle.js @@ -1,11 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; -import provideTests from '../hoc/provideTests'; +import provideJestResult from '../hoc/provideJestResult'; import Indicator from './Indicator'; import colors from '../colors'; -const TestPanelTitle = ({ tests }) => { +const PanelTitle = ({ tests }) => { if (!tests) { return (
@@ -26,12 +26,17 @@ const TestPanelTitle = ({ tests }) => {
); }; -TestPanelTitle.propTypes = { + +PanelTitle.defaultProps = { + tests: null, +}; + +PanelTitle.propTypes = { tests: PropTypes.arrayOf( PropTypes.shape({ result: PropTypes.object, }) - ).isRequired, + ), }; -export default provideTests(TestPanelTitle); +export default provideJestResult(PanelTitle); diff --git a/addons/jest/src/components/Result.js b/addons/jest/src/components/Result.js new file mode 100644 index 000000000000..948bb38f51b6 --- /dev/null +++ b/addons/jest/src/components/Result.js @@ -0,0 +1,65 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; + +import Indicator from './Indicator'; +import colors from '../colors'; + +const FlexContainer = styled.div` + display: flex; + align-items: center; +`; + +const Result = ({ fullName, title, status, failureMessages }) => { + const color = status === 'passed' ? colors.success : colors.error; + return ( +
+
+ + +
{fullName || title}
+
+ + + {status} + + +
+ {/* eslint-disable react/no-array-index-key, react/no-danger */} + {failureMessages && + failureMessages.map((msg, i) => ( +
`)
+                .replace(/\[32m/g, ``)
+                .replace(/\[39m/g, ''),
+            }}
+          />
+        ))}
+    
+ ); +}; + +Result.defaultProps = { + fullName: '', + title: '', +}; + +Result.propTypes = { + fullName: PropTypes.string, + title: PropTypes.string, + status: PropTypes.string.isRequired, + failureMessages: PropTypes.arrayOf(PropTypes.string).isRequired, +}; + +export default Result; diff --git a/addons/jest/src/hoc/provideTests.js b/addons/jest/src/hoc/provideJestResult.js similarity index 100% rename from addons/jest/src/hoc/provideTests.js rename to addons/jest/src/hoc/provideJestResult.js diff --git a/addons/jest/src/index.js b/addons/jest/src/index.js index f88a66832640..e302a7a0f077 100644 --- a/addons/jest/src/index.js +++ b/addons/jest/src/index.js @@ -1 +1,35 @@ -export { default } from './withTests'; +import addons from '@storybook/addons'; + +const findTestResults = (testFiles, jestTestResults, jestTestFilesExt) => + testFiles.map(name => { + if (jestTestResults && jestTestResults.testResults) { + return { + name, + result: jestTestResults.testResults.find(t => + new RegExp(`${name}${jestTestFilesExt}`).test(t.name) + ), + }; + } + return { name }; + }); + +const emitAddTests = ({ kind, story, testFiles, options }) => { + addons.getChannel().emit('storybook/tests/add_tests', { + kind, + storyName: story, + tests: findTestResults(testFiles, options.results, options.filesExt), + }); +}; + +export const withTests = userOptions => { + const defaultOptions = { + filesExt: '((\\.specs?)|(\\.tests?))?(\\.js)?$', + }; + const options = Object.assign({}, defaultOptions, userOptions); + + return (...testFiles) => (storyFn, { kind, story }) => { + emitAddTests({ kind, story, testFiles, options }); + + return storyFn(); + }; +}; diff --git a/addons/jest/src/register.js b/addons/jest/src/register.js index 2df31875d0ba..8abcc1b9dfe8 100644 --- a/addons/jest/src/register.js +++ b/addons/jest/src/register.js @@ -2,14 +2,14 @@ import React from 'react'; import addons from '@storybook/addons'; -import TestPanelTitle from './components/TestsPanelTitle'; -import TestsPanel from './components/TestsPanel'; +import PanelTitle from './components/PanelTitle'; +import Panel from './components/Panel'; // Register the addon with a unique name. addons.register('storybook/tests', api => { // Also need to set a unique name to the panel. addons.addPanel('storybook/tests/panel', { - title: , - render: () => , + title: , + render: () => , }); }); diff --git a/addons/jest/src/withTests.js b/addons/jest/src/withTests.js deleted file mode 100644 index 48fc10645860..000000000000 --- a/addons/jest/src/withTests.js +++ /dev/null @@ -1,31 +0,0 @@ -import addons from '@storybook/addons'; - -const basename = path => path.split('/').slice(-1)[0]; - -const findTestResults = (testFiles, jestTestResults, jestTestFilesExt) => - testFiles.map(name => { - const fileName = name + jestTestFilesExt; - if (jestTestResults && jestTestResults.testResults) { - return { - fileName, - name, - result: jestTestResults.testResults.find(t => basename(t.name) === fileName), - }; - } - return { fileName, name }; - }); - -const emitAddTests = ({ kind, story, testFiles, results, options }) => { - addons.getChannel().emit('storybook/tests/add_tests', { - kind, - storyName: story, - tests: findTestResults(testFiles, results, options.filesExt), - }); -}; - -const withTests = (results, options) => (...testFiles) => (storyFn, { kind, story }) => { - emitAddTests({ kind, story, testFiles, results, options }); - return storyFn(); -}; - -export default withTests; diff --git a/examples/cra-kitchen-sink/.jest-setup.js b/examples/cra-kitchen-sink/.jest-setup.js new file mode 100644 index 000000000000..fc7b0dce1f5b --- /dev/null +++ b/examples/cra-kitchen-sink/.jest-setup.js @@ -0,0 +1,4 @@ +import Enzyme from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +Enzyme.configure({ adapter: new Adapter() }); diff --git a/examples/cra-kitchen-sink/.storybook/addons.js b/examples/cra-kitchen-sink/.storybook/addons.js index 123129bf9428..535310497346 100644 --- a/examples/cra-kitchen-sink/.storybook/addons.js +++ b/examples/cra-kitchen-sink/.storybook/addons.js @@ -6,3 +6,5 @@ import '@storybook/addon-options/register'; import '@storybook/addon-knobs/register'; import '@storybook/addon-backgrounds/register'; import '@storybook/addon-a11y/register'; +import '@storybook/addon-jest/register'; +import '@storybook/addon-jest/styles'; diff --git a/examples/cra-kitchen-sink/__mocks__/fileMock.js b/examples/cra-kitchen-sink/__mocks__/fileMock.js new file mode 100644 index 000000000000..105ff49748fa --- /dev/null +++ b/examples/cra-kitchen-sink/__mocks__/fileMock.js @@ -0,0 +1 @@ +module.exports = 'file-stub'; diff --git a/examples/cra-kitchen-sink/__mocks__/styleMock.js b/examples/cra-kitchen-sink/__mocks__/styleMock.js new file mode 100644 index 000000000000..f053ebf7976e --- /dev/null +++ b/examples/cra-kitchen-sink/__mocks__/styleMock.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/examples/cra-kitchen-sink/package.json b/examples/cra-kitchen-sink/package.json index 61e12a943652..55623550dce5 100644 --- a/examples/cra-kitchen-sink/package.json +++ b/examples/cra-kitchen-sink/package.json @@ -7,7 +7,7 @@ "eject": "react-scripts eject", "start": "react-scripts start", "storybook": "start-storybook -p 9010 -s public", - "test": "react-scripts test --env=jsdom" + "test": "jest --env=jsdom --json --outputFile=./node_modules/.cache/jest-results.json" }, "dependencies": { "eventemitter3": "^2.0.3", @@ -27,6 +27,7 @@ "@storybook/addon-centered": "^3.2.10", "@storybook/addon-events": "^3.2.10", "@storybook/addon-info": "^3.2.11", + "@storybook/addon-jest": "^3.2.11", "@storybook/addon-knobs": "^3.2.10", "@storybook/addon-links": "^3.2.10", "@storybook/addon-notes": "^3.2.10", @@ -35,7 +36,34 @@ "@storybook/addons": "^3.2.10", "@storybook/components": "^3.2.10", "@storybook/react": "^3.2.11", + "babel-jest": "^21.2.0", + "enzyme": "^3.1.1", + "enzyme-adapter-react-16": "^1.0.4", + "jest": "^21.2.1", "react-scripts": "1.0.17" }, - "private": true + "private": true, + "jest": { + "verbose": true, + "coverageDirectory": "coverage/", + "notify": true, + "setupTestFrameworkScriptFile": "/.jest-setup.js", + "transform": { + ".*": "/node_modules/babel-jest" + }, + "moduleNameMapper": { + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js", + "\\.s?css$": "/__mocks__/styleMock.js" + }, + "collectCoverage": true, + "collectCoverageFrom": [ + "src/**/*.js", + "src/*.js", + "!src/.*", + "!src/__test__/*", + "!src/**/__test__/*", + "!src/**/index.js", + "!src/**/story.js" + ] + } } diff --git a/examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap b/examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap index 3ad0629b9cbc..e05848d55243 100644 --- a/examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap +++ b/examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap @@ -5135,6 +5135,27 @@ exports[`Storyshots Addon a11y Label 1`] = ` `; +exports[`Storyshots Addon jest withTests 1`] = ` +
    +
  • + apple +
  • +
  • + orange +
  • +
  • + banana +
  • +
+`; + exports[`Storyshots App full app 1`] = `
{ + expect(true).toBe(true); +}); + +describe('List items: ', () => { + it('should render the good number of items', () => { + const wrapper = shallow(); + expect(wrapper.find('li')).toHaveLength(3); + }); + + it('should render items content', () => { + const items = ['apple', 'orange', 'banana']; + const wrapper = shallow(); + const renderedItems = wrapper + .children() + .map(item => item.text()) + // create an error voluntarily + .slice(0, -1); + + expect(renderedItems).toBe(items); + }); +}); diff --git a/examples/cra-kitchen-sink/src/components/SimpleList.js b/examples/cra-kitchen-sink/src/components/SimpleList.js new file mode 100644 index 000000000000..95b3ae8b2fa9 --- /dev/null +++ b/examples/cra-kitchen-sink/src/components/SimpleList.js @@ -0,0 +1,14 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const List = ({ items }) => ( +
    + {items.map(item =>
  • {item}
  • )} +
+); + +List.propTypes = { + items: PropTypes.arrayOf(PropTypes.string).isRequired, +}; + +export default List; diff --git a/examples/cra-kitchen-sink/src/stories/addon-jest.stories.js b/examples/cra-kitchen-sink/src/stories/addon-jest.stories.js new file mode 100644 index 000000000000..de760c40cde1 --- /dev/null +++ b/examples/cra-kitchen-sink/src/stories/addon-jest.stories.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import { withTests } from '@storybook/addon-jest'; +import SimpleList from '../components/SimpleList'; + +import results from '.cache/jest-results.json'; + +const withTestsFiles = withTests({ + results, +}); + +storiesOf('Addon jest', module) + .addDecorator(withTestsFiles('SimpleList')) + .add('withTests', () => );