├── .babelrc ├── .coveralls.yml ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .gitmodules ├── .npmignore ├── .npmrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bootstrap-documentation-generation-testrenderer.js ├── bootstrap-documentation-generation.js ├── bootstrap-unexpected-markdown-test-renderer.js ├── bootstrap-unexpected-markdown.js ├── demo ├── 1.png └── 2.png ├── documentation ├── assertions │ ├── ReactElement │ │ ├── queried-for.md │ │ ├── to-contain.md │ │ ├── to-deeply-render-as.md │ │ ├── to-have-rendered.md │ │ ├── to-match-snapshot.md │ │ ├── to-render-as.md │ │ ├── to-satisfy-snapshot.md │ │ ├── when-deeply-rendered.md │ │ ├── when-rendered.md │ │ └── with-event.md │ ├── ReactTestRenderer │ │ ├── queried-for.md │ │ ├── to-contain.md │ │ ├── to-have-rendered.md │ │ ├── to-match-snapshot.md │ │ ├── to-satisfy-snapshot.md │ │ └── with-event.md │ └── RenderedReactElement │ │ ├── queried-for.md │ │ ├── to-contain.md │ │ ├── to-have-rendered.md │ │ ├── to-match-snapshot.md │ │ ├── to-satisfy-snapshot.md │ │ └── with-event.md └── index.md ├── gulpfile.js ├── jest-integration ├── baseTemplate │ ├── package.json │ ├── src │ │ ├── ClickCounter.js │ │ └── __tests__ │ │ │ └── ClickCounter.spec.js │ ├── unexpected-react-non-jest.js │ ├── unexpected-react-test-renderer.js │ └── unexpected-react.js ├── compare-json.js ├── jest-normalizer.js ├── normalize-jest-json.js ├── run-with-version.sh ├── run.sh ├── tests │ ├── basics │ │ ├── 1-create-initial-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ │ ├── 2-validate-existing-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ │ ├── 3-change-in-code │ │ │ ├── ClickCounter.spec.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ ├── 4-update-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ │ └── 5-revalidate-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ ├── cleanup │ │ ├── 1-create-initial-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ │ ├── 2-remove-test-and-update │ │ │ ├── ClickCounter.spec.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ ├── 3-add-test-back-with-different-snapshot │ │ │ ├── ClickCounter.spec.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ └── 4-revalidate-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ ├── functions │ │ ├── 1-create-initial-snapshots │ │ │ ├── ClickCounter.spec.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ ├── 2-remove-event-binding │ │ │ ├── ClickCounter.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ ├── 3-update-without-binding │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ │ ├── 4-add-binding-back │ │ │ ├── ClickCounter.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ ├── 5-update-with-binding │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ │ └── 6-revalidate-new-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ ├── multiple │ │ ├── 1-create-initial-snapshots │ │ │ ├── ClickCounter-other.spec.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ ├── 2-validate-existing-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ │ ├── 3-change-in-code │ │ │ ├── ClickCounter-other.spec.js │ │ │ ├── ClickCounter.spec.js │ │ │ ├── expectedOutput.json │ │ │ ├── prepare.sh │ │ │ └── run.sh │ │ ├── 4-update-snapshots │ │ │ ├── expectedOutput.json │ │ │ ├── no_expectation │ │ │ └── run.sh │ │ └── 5-revalidate-snapshots │ │ │ ├── expectedOutput.json │ │ │ └── run.sh │ └── wrong-require │ │ └── 1-failures │ │ ├── ClickCounter.spec.js │ │ ├── expectedOutput.json │ │ ├── prepare.sh │ │ └── run.sh ├── update-test.sh └── useReleasedUnexpectedReact │ ├── prepare.sh │ ├── unexpected-react-test-renderer.js │ └── unexpected-react.js ├── jest.js ├── package-lock.json ├── package.json ├── react-native.js ├── src ├── assertions │ ├── AssertionGenerator.js │ ├── deepAgainstRawAssertions.js │ ├── deepAssertions.js │ ├── jestSnapshotStandardRendererAssertions.js │ ├── jestSnapshotTestRendererAssertions.js │ ├── shallowAgainstRawAssertions.js │ ├── shallowAssertions.js │ ├── snapshotFunctionAssertions.js │ ├── snapshotFunctionType.js │ ├── testRendererAgainstRawAssertions.js │ └── testRendererAssertions.js ├── helpers │ ├── snapshotLoader.js │ └── snapshots.js ├── jest.js ├── react-native.js ├── reactEventNames.js ├── test-renderer-jest.js ├── test-renderer.js ├── tests │ ├── components │ │ ├── ClickCounter.js │ │ ├── Select.js │ │ ├── SelectOption.js │ │ └── TwoClickCounters.js │ ├── errors │ │ └── out-of-order.spec.js │ ├── fixtures │ │ ├── functions.js │ │ ├── multiple.snapshot │ │ ├── multipleclasses.snapshot │ │ ├── single.snapshot │ │ └── twoclicks.snapshot │ ├── general │ │ ├── Select.spec.js │ │ ├── incorrect-require │ │ │ └── standard-instead-of-jest.spec.js │ │ ├── snapshots-deep.spec.js │ │ ├── snapshots-shallow.spec.js │ │ ├── unexpected-react-deep.spec.js │ │ └── unexpected-react-shallow.spec.js │ ├── helpers │ │ ├── emulateDom.js │ │ └── mock-jasmine.js │ ├── regressions │ │ ├── dangerouslySetHtml.spec.js │ │ ├── issue28.spec.js │ │ ├── issue31.spec.js │ │ ├── issue34.spec.js │ │ └── issue9.spec.js │ └── testRenderer │ │ ├── dummy.js │ │ ├── incorrect-require │ │ └── test-renderer-instead-of-test-renderer-jest.spec.js │ │ ├── snapshot.spec.js │ │ └── unexpected-react-testrenderer.spec.js ├── types │ ├── dom-types.js │ ├── test-renderer-type-wrapper.js │ └── types.js └── unexpected-react.js ├── test-renderer-jest.js ├── test-renderer.js ├── test └── mocha.opts ├── wallaby-testrenderer.js ├── wallaby.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "sourceMaps": true, 3 | "presets": [ 4 | "@babel/preset-env", 5 | "@babel/preset-react" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # Unix-style newlines with a newline ending every file 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | [*.{js,jsx}] 9 | indent_style = space 10 | indent_size = 4 11 | 12 | # Tab indentation (no size specified) 13 | [Makefile] 14 | indent_style = tab 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "plugins": [ 8 | "react" 9 | ], 10 | "rules": { 11 | "curly": [2, "multi-line"], 12 | "no-shadow": 0, 13 | "no-trailing-spaces": 0, 14 | "no-underscore-dangle": 0, 15 | "no-unused-expressions": 0, 16 | "object-curly-spacing": [1, "always"], 17 | "quotes": [2, "single", "avoid-escape"], 18 | "react/jsx-no-undef": 1, 19 | "jsx-quotes": 1, 20 | "react/sort-prop-types": 1, 21 | "react/jsx-uses-react": 1, 22 | "react/jsx-uses-vars": 1, 23 | "react/no-did-mount-set-state": 1, 24 | "react/no-did-update-set-state": 1, 25 | "react/no-unknown-property": 1, 26 | "react/prop-types": 1, 27 | "react/react-in-jsx-scope": 1, 28 | "react/self-closing-comp": 1, 29 | "react/sort-comp": 1, 30 | "react/jsx-wrap-multilines": 1, 31 | "semi": 2, 32 | "strict": 0 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | lib/ 4 | .idea/ 5 | site-build/ 6 | site-reactelement/ 7 | site-renderedreactelement/ 8 | site-testrenderer/ 9 | 10 | # We don't want to commit the yarn.lock in this case. 11 | # We use yarn for the integration tests to make them quicker, but we actually want 12 | # to always update to the latest jest (version is "*" in package.json) 13 | jest-integration/baseTemplate/yarn.lock 14 | 15 | jest-integration/build/ 16 | jest-integration/output/ 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/react-devtools"] 2 | path = src/react-devtools 3 | url = https://github.com/facebook/react-devtools.git 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | wallaby.js 3 | wallaby-testrenderer.js 4 | site-build/ 5 | site-reactelement/ 6 | site-renderedreactelement/ 7 | site-testrenderer/ 8 | jest-integration/ 9 | demo/ 10 | src/tests/ 11 | lib/tests/ 12 | .travis.yml 13 | .coveralls.yml 14 | .eslintrc 15 | npm-debug.log 16 | yarn.lock 17 | bootstrap-documentation-generation.js 18 | bootstrap-documentation-generation-testrenderer.js 19 | bootstrap-unexpected-markdown.js 20 | bootstrap-unexpected-markdown-test-renderer.js 21 | gulpfile.js 22 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock = false 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "v4" 5 | - "v6" 6 | script: 7 | - npm test 8 | - npm run coveralls 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Dave Brotherstone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bootstrap-documentation-generation-testrenderer.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | 3 | require('./bootstrap-unexpected-markdown-test-renderer'); 4 | -------------------------------------------------------------------------------- /bootstrap-documentation-generation.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | 3 | require('./bootstrap-unexpected-markdown'); 4 | -------------------------------------------------------------------------------- /bootstrap-unexpected-markdown-test-renderer.js: -------------------------------------------------------------------------------- 1 | /*global unexpected:true, React:true, TestRenderer:true, sinon:true*/ 2 | 3 | global.unexpected = require('unexpected') 4 | .clone() 5 | .use(require('./src/test-renderer')); 6 | unexpected.output.preferredWidth = 80; 7 | 8 | global.React = require('react'); 9 | global.PropTypes = require('prop-types'); 10 | global.TestRenderer = require('react-test-renderer'); 11 | global.createRenderer = require('react-test-renderer/shallow').createRenderer; 12 | global.createClass = require('create-react-class'); 13 | 14 | 15 | const TodoItem = createClass({ 16 | displayName: 'TodoItem', 17 | propTypes: { 18 | id: PropTypes.number, 19 | label: PropTypes.string 20 | }, 21 | 22 | getInitialState() { 23 | return { 24 | completed: false 25 | }; 26 | }, 27 | 28 | onClick() { 29 | this.setState({ 30 | completed: true 31 | }); 32 | if (this.props.onClick) { 33 | this.props.onClick(); 34 | } 35 | }, 36 | 37 | render() { 38 | return ( 39 |
45 | {this.props.id} 46 | {this.props.label} 47 | {this.state.completed ? 'Completed!' : 'Todo'} 48 |
49 | ); 50 | } 51 | }); 52 | 53 | const TodoList = createClass({ 54 | displayName: 'TodoList', 55 | propTypes: { 56 | children: PropTypes.node 57 | }, 58 | 59 | getInitialState() { 60 | return { clicked: {} }; 61 | }, 62 | 63 | onClick(index) { 64 | // State mutation, this is not recommended, but saves us rebuilding each time 65 | this.state.clicked[index] = true; 66 | this.setState({ 67 | clicked: this.state.clicked 68 | }); 69 | }, 70 | 71 | noop() {}, 72 | 73 | render() { 74 | const children = this.props.children.map(child => { 75 | return React.cloneElement(child, { 76 | key: child.props.id, 77 | onClick: this.onClick.bind(this, child.props.id), 78 | clicked: !!this.state.clicked[child.props.id], 79 | onMouseDown: this.noop 80 | }); 81 | }); 82 | 83 | 84 | return ( 85 |
86 |
87 | { children } 88 |
89 |
90 | 91 |
92 |
93 | ); 94 | } 95 | }); 96 | 97 | const App = createClass({ 98 | displayName: 'App', 99 | getInitialState() { 100 | return { clickTestClicked: false }; 101 | }, 102 | 103 | onClickTest() { 104 | this.setState({ clickTestClicked: true }); 105 | }, 106 | 107 | render() { 108 | return ( 109 |
110 |
111 |
112 | 115 |
116 |
117 | ); 118 | } 119 | }); 120 | 121 | global.TodoItem = TodoItem; 122 | global.TodoList = TodoList; 123 | global.App = App; 124 | 125 | const MyButton = createClass({ 126 | displayName: 'MyButton', 127 | getInitialState () { 128 | return { 129 | count: 0 130 | }; 131 | }, 132 | 133 | onClick () { 134 | const { count } = this.state; 135 | this.setState({ count: count + 1 }); 136 | }, 137 | 138 | render() { 139 | const { count } = this.state; 140 | 141 | return ( 142 | 145 | ); 146 | } 147 | }); 148 | 149 | global.MyButton = MyButton; 150 | -------------------------------------------------------------------------------- /bootstrap-unexpected-markdown.js: -------------------------------------------------------------------------------- 1 | /*global unexpected:true, TestUtils:true, React:true, sinon:true*/ 2 | 3 | require( './src/tests/helpers/emulateDom'); 4 | 5 | global.unexpected = require('unexpected') 6 | .clone() 7 | .use(require('./src/unexpected-react')); 8 | unexpected.output.preferredWidth = 80; 9 | 10 | global.TestUtils = require('react-dom/test-utils'); 11 | global.React = require('react'); 12 | global.PropTypes = require('prop-types'); 13 | global.createRenderer = require('react-test-renderer/shallow').createRenderer; 14 | global.createClass = require('create-react-class'); 15 | 16 | 17 | const TodoItem = createClass({ 18 | displayName: 'TodoItem', 19 | propTypes: { 20 | id: PropTypes.number, 21 | label: PropTypes.string 22 | }, 23 | 24 | getInitialState() { 25 | return { 26 | completed: false 27 | }; 28 | }, 29 | 30 | onClick() { 31 | this.setState({ 32 | completed: true 33 | }); 34 | }, 35 | 36 | render() { 37 | return ( 38 |
43 | {this.props.id} 44 | {this.props.label} 45 | {this.state.completed ? 'Completed!' : 'Todo'} 46 |
47 | ); 48 | } 49 | }); 50 | 51 | const TodoList = createClass({ 52 | displayName: 'TodoList', 53 | propTypes: { 54 | children: PropTypes.node 55 | }, 56 | 57 | getInitialState() { 58 | return { clicked: {} }; 59 | }, 60 | 61 | onClick(index) { 62 | // State mutation, this is not recommended, but saves us rebuilding each time 63 | this.state.clicked[index] = true; 64 | this.setState({ 65 | clicked: this.state.clicked 66 | }); 67 | }, 68 | 69 | noop() {}, 70 | 71 | render() { 72 | const children = this.props.children.map(child => { 73 | return React.cloneElement(child, { 74 | key: child.props.id, 75 | onClick: this.onClick.bind(this, child.props.id), 76 | clicked: !!this.state.clicked[child.props.id], 77 | onMouseDown: this.noop 78 | }); 79 | }); 80 | 81 | 82 | return ( 83 |
84 |
85 | { children } 86 |
87 |
88 | 89 |
90 |
91 | ); 92 | } 93 | }); 94 | 95 | const App = createClass({ 96 | 97 | displayName: 'App', 98 | getInitialState() { 99 | return { clickTestClicked: false }; 100 | }, 101 | 102 | onClickTest() { 103 | this.setState({ clickTestClicked: true }); 104 | }, 105 | 106 | render() { 107 | return ( 108 |
109 |
110 |
111 | 114 |
115 |
116 | ); 117 | } 118 | }); 119 | 120 | global.TodoItem = TodoItem; 121 | global.TodoList = TodoList; 122 | global.App = App; 123 | 124 | const MyButton = createClass({ 125 | displayName: 'MyButton', 126 | getInitialState () { 127 | return { 128 | count: 0 129 | }; 130 | }, 131 | 132 | onClick () { 133 | const { count } = this.state; 134 | this.setState({ count: count + 1 }); 135 | }, 136 | 137 | render() { 138 | const { count } = this.state; 139 | 140 | return ( 141 | 144 | ); 145 | } 146 | }); 147 | 148 | global.MyButton = MyButton; 149 | -------------------------------------------------------------------------------- /demo/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bruderstein/unexpected-react/e7cbb1a00de5b413147af96761007b45ec08b88f/demo/1.png -------------------------------------------------------------------------------- /demo/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bruderstein/unexpected-react/e7cbb1a00de5b413147af96761007b45ec08b88f/demo/2.png -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/queried-for.md: -------------------------------------------------------------------------------- 1 | This enables finding a particular component or element, to then perform further assertions on. 2 | 3 | e.g. 4 | ```js 5 | var renderer = createRenderer() 6 | renderer.render( 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | 14 | expect( 15 | renderer, 'queried for', 16 | , 17 | 'to have rendered', 18 | 19 | ); 20 | ``` 21 | 22 | Here the `TodoList` component is rendering a list of todo items. Here we're 23 | querying for the todo item with the id 3 and then we check that it has the 24 | expected text. This example show how you only mention exactly what you are 25 | searching for. If the assertion finds a match it is forwarded to the next 26 | assertion; otherwise it fails with a helpful message. 27 | 28 | You can use `to have rendered` or `to contain` with all the options as usual following a `queried for`. 29 | 30 | 31 | It is possible to use `queried for` to extract a part of a component. 32 | 33 | ```js#async:true 34 | return expect(renderer, 'queried for', ) 35 | .then(todoItem => { 36 | expect(todoItem.props.label, 'to equal', 'Buy groceries'); 37 | }); 38 | ``` 39 | 40 | Note that it is not possible to call an event using `with event` after using `queried for` in 41 | an assertion. This is because the `queried for` extracts the rendered output from the shallow 42 | renderer, so future events will be lost. 43 | 44 | ## queryTarget 45 | 46 | If you want to find a target nested inside a parent element, use `queryTarget` in the query. 47 | e.g. This `queried for` clause returns the `input` element inside the `div` with 48 | the class `add-new-item`. 49 | 50 | ```js 51 | expect(renderer, 'queried for',
, 52 | 'to have rendered', ); 53 | ``` 54 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/to-contain.md: -------------------------------------------------------------------------------- 1 | It's possible to check for a part of the subtree, without 2 | testing the entire returned tree. This allows you to test specific elements, without 3 | writing brittle tests that break when the structure changes. 4 | 5 | Assuming the following component output 6 | ```js 7 | const MyComponent = () => ( 8 |
9 | one 10 | two 11 | three 12 |
13 | ) 14 | 15 | var renderer = createRenderer() 16 | renderer.render() 17 | ``` 18 | 19 | ```js 20 | // This will pass, as `two` can be found in the renderers output 21 | expect(renderer, 'to contain', two); 22 | ``` 23 | 24 | Notice that the extra `className="middle"` in the `two` is ignored, 25 | in a similar way to the `to have rendered` assertion. 26 | 27 | You can override this behaviour by using `'to contain exactly'`, and `'to contain with all children'` 28 | 29 | 30 | ```js 31 | // This will fail, as `two` cannot be found in the renderers output, due to 32 | // the missing `className="middle"` prop 33 | expect(renderer, 'to contain exactly', two); 34 | ``` 35 | 36 | ```output 37 | expected 38 |
39 | one 40 | two 41 | three 42 |
43 | to contain exactly two 44 | 45 | the best match was 46 | 48 | two 49 | 50 | ``` 51 | 52 | The same thing applies to children for `'to contain'` as for `'to have rendered'`. 53 | 54 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/to-deeply-render-as.md: -------------------------------------------------------------------------------- 1 | Given the following test component: 2 | 3 | ```js 4 | const MyComponent = () => ( 5 |
6 | one 7 | two 8 | three 9 |
10 | ) 11 | ``` 12 | 13 | You can validate the rendering of this component with the `to deeply render as` assertion, 14 | which renders the component using the full virtual DOM renderer, and validates the output. 15 | 16 | ```js 17 | expect(, 'to deeply render as',
); 18 | ``` 19 | 20 | This works using the same rules as `to have rendered`, but saves you using the TestUtils 21 | and `renderIntoDocument()` or using `ReactDOM.render(...)` directly when you just want to 22 | validate some translation of props to output. 23 | 24 | ```js 25 | // The span "two" is missing here, but it is ignored. 26 | expect(, 'to render as', 27 |
28 | one 29 | three 30 |
31 | ); 32 | ``` 33 | 34 | ```js 35 | // The following assertion will fail, as 'four' does not exist 36 | expect(, 'to render as', 37 |
38 | one 39 | four 40 |
41 | ); 42 | ``` 43 | 44 | ```output 45 | expected 46 | to render as
onefour
47 | 48 |
49 | one 50 | 51 | two // -two 52 | // +four 53 | 54 | three 55 |
56 | ``` 57 | 58 | If you want to check for an exact render, use `'to exactly deeply render as'`. 59 | 60 | Alternatively, if you don't care about extra props, but want to check that there are no extra child nodes, use `'to have rendered with all children'` 61 | Note that `exactly` implies `with all children`, so you using both options is not necessary. 62 | 63 | Normally wrappers (elements that simply wrap other components) are ignored. This can be useful if you have higher order 64 | components wrapping your components, you can simply ignore them in your tests (they will be shown greyed out 65 | if there is a "real" error). If you want to test that there are no extra wrappers, simply add 66 | `with all wrappers` to the assertion. 67 | 68 | 69 | ```js 70 | // The span "two" is missing here, as is `className="parent"` 71 | // The missing span will cause an assertion error, but the extra prop will be ignored 72 | // due to `to have rendered with all children` being used 73 | 74 | expect(, 'to deeply render with all children as', 75 |
76 | one 77 | three 78 |
79 | ); 80 | ``` 81 | 82 | ```output 83 | expected 84 | to deeply render with all children as
onethree
85 | 86 | 87 |
88 | one 89 | two // should be removed 90 | three 91 |
92 |
93 | ``` 94 | 95 | ```js 96 | // The span "two" is missing here, as is `className="parent"` 97 | // This will cause an assertion error, 98 | // due to `to have exactly rendered` being used 99 | 100 | expect(, 'to exactly deeply render as', 101 | 102 |
103 | one 104 | three 105 |
106 |
107 | ); 108 | ``` 109 | 110 | ```output 111 | expected 112 | to exactly deeply render as
onethree
113 | 114 | 115 |
117 | one 118 | two // should be removed 119 | three 120 |
121 |
122 | ``` 123 | 124 | If you want to trigger events, use the `when deeply rendered` assertion to render 125 | the component, then use the other `with event` and `to have rendered` or `to contain` 126 | assertions to validate the output. 127 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/to-have-rendered.md: -------------------------------------------------------------------------------- 1 | Given the following test component: 2 | 3 | ```js 4 | const MyComponent = () => ( 5 |
6 | one 7 | two 8 | three 9 |
10 | ) 11 | ``` 12 | 13 | Let's render the output with the shallow renderer: 14 | 15 | ```js 16 | const renderer = createRenderer(); 17 | renderer.render(); 18 | ``` 19 | 20 | ```js 21 | // Extra props and children from the render are ignored 22 | expect(renderer, 'to have rendered',
); 23 | ``` 24 | 25 | ```js 26 | // The span "two" is missing here, but it is ignored. 27 | expect(renderer, 'to have rendered', 28 |
29 | one 30 | three 31 |
32 | ); 33 | ``` 34 | 35 | ```js 36 | // The following assertion will fail, as 'four' does not exist 37 | expect(renderer, 'to have rendered', 38 |
39 | one 40 | four 41 |
42 | ); 43 | ``` 44 | 45 | ```output 46 | expected 47 |
48 | onetwothree 49 |
50 | to have rendered
onefour
51 | 52 |
53 | one 54 | 55 | two // -two 56 | // +four 57 | 58 | three 59 |
60 | ``` 61 | 62 | If you want to check for an exact render, use `'to have exactly rendered'`. 63 | 64 | Alternatively, if you don't care about extra props, but want to check that there are no extra child nodes, use `'to have rendered with all children'` 65 | Note that `exactly` implies `with all children`, so you using both options is not necessary. 66 | 67 | Normally wrappers (elements that simply wrap other components) are ignored. This can be useful if you have higher order 68 | components wrapping your components, you can simply ignore them in your tests (they will be shown greyed out 69 | if there is a "real" error). If you want to test that there are no extra wrappers, simply add 70 | `with all wrappers` to the assertion. 71 | 72 | 73 | ```js 74 | // The span "two" is missing here, as is `className="parent"` 75 | // The missing span will cause an assertion error, but the extra prop will be ignored 76 | // due to `to have rendered with all children` being used 77 | 78 | expect(renderer, 'to have rendered with all children', 79 |
80 | one 81 | three 82 |
83 | ); 84 | ``` 85 | 86 | ```output 87 | expected 88 |
89 | onetwothree 90 |
91 | to have rendered with all children
onethree
92 | 93 |
94 | one 95 | two // should be removed 96 | three 97 |
98 | ``` 99 | 100 | ```js 101 | // The span "two" is missing here, as is `className="parent"` 102 | // This will cause an assertion error, 103 | // due to `to have exactly rendered` being used 104 | 105 | expect(renderer, 'to have exactly rendered', 106 |
107 | one 108 | three 109 |
110 | ); 111 | ``` 112 | 113 | ```output 114 | expected 115 |
116 | onetwothree 117 |
118 | to have exactly rendered
onethree
119 | 120 |
122 | one 123 | two // should be removed 124 | three 125 |
126 | ``` 127 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/to-match-snapshot.md: -------------------------------------------------------------------------------- 1 | Under [jest](https://facebook.github.io/jest/), you can use snapshots. Snapshot tests save a snapshot of the component as it is currently rendered to a `.snapshot` file under a directory `__snapshots__`. Note that the snapshots for `unexpected-react` are saved to a different filename than those jest uses natively. This is because the format differs slightly. 2 | 3 | Remember that to include snapshot support for the shallow and DOM renderers, you need to require unexpected-react as `require('unexpected-react/jest')` 4 | 5 | Given the following test component: 6 | 7 | ```js 8 | const MyComponent = () => ( 9 |
10 | one 11 | two 12 | three 13 |
14 | ) 15 | ``` 16 | 17 | Let's render the output with the shallow renderer: 18 | 19 | ```js 20 | var renderer = createRenderer(); 21 | renderer.render(); 22 | ``` 23 | 24 | Then we can validate it matches the snapshot. If no snapshot exists, it will be automatically created the first time it is run. 25 | 26 | ```js#evaluate:false 27 | expect(renderer, 'to match snapshot'); 28 | ``` 29 | 30 | If in the future the component output changes, the error will be highlighted (using the same error highlighting used in the rest of unexpected-react). 31 | 32 | Once you have checked that the changes are correct, you can run `jest -u` to update the snapshot, or if running in watch mode, press `u`. 33 | 34 | ### Events 35 | Triggered events still works, and can be combined with matching snaphots. 36 | 37 | e.g. 38 | 39 | ```js#evaluate:false 40 | var renderer = createRenderer(); 41 | renderer.render(); 42 | 43 | expect(renderer, 44 | 'with event click', 45 | 'to match snapshot' 46 | ); 47 | ``` 48 | 49 | 50 | ### Matching 51 | 52 | The snapshot matches everything, so extra classes and attributes will causes a difference to be highlighted. If you want your snapshots to work more like `to have rendered`, so new attributes, classes and child elements can be added without triggering a change, see the assertion `to satisfy snapshot`. 53 | 54 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/to-render-as.md: -------------------------------------------------------------------------------- 1 | Given the following test component: 2 | 3 | ```js 4 | const MyComponent = () => ( 5 |
6 | one 7 | two 8 | three 9 |
10 | ) 11 | ``` 12 | 13 | You can validate the rendering of this component with the `to render as` assertion, 14 | which renders the component to a new shallow renderer, and validates the output. 15 | 16 | ```js 17 | expect(, 'to render as',
); 18 | ``` 19 | 20 | This works using the same rules as `to have rendered`, but saves you creating a 21 | new shallow renderer when you just want to validate some translation of props to 22 | output. 23 | 24 | ```js 25 | // The span "two" is missing here, but it is ignored. 26 | expect(, 'to render as', 27 |
28 | one 29 | three 30 |
31 | ); 32 | ``` 33 | 34 | ```js 35 | // The following assertion will fail, as 'four' does not exist 36 | expect(, 'to render as', 37 |
38 | one 39 | four 40 |
41 | ); 42 | ``` 43 | 44 | ```output 45 | expected 46 | to render as
onefour
47 | 48 |
49 | one 50 | 51 | two // -two 52 | // +four 53 | 54 | three 55 |
56 | ``` 57 | 58 | If you want to check for an exact render, use `'to exactly render as'`. 59 | 60 | Alternatively, if you don't care about extra props, but want to check that there are no extra child nodes, use `'to have rendered with all children'` 61 | Note that `exactly` implies `with all children`, so you using both options is not necessary. 62 | 63 | Normally wrappers (elements that simply wrap other components) are ignored. This can be useful if you have higher order 64 | components wrapping your components, you can simply ignore them in your tests (they will be shown greyed out 65 | if there is a "real" error). If you want to test that there are no extra wrappers, simply add 66 | `with all wrappers` to the assertion. 67 | 68 | 69 | ```js 70 | // The span "two" is missing here, as is `className="parent"` 71 | // The missing span will cause an assertion error, but the extra prop will be ignored 72 | // due to `to have rendered with all children` being used 73 | 74 | expect(, 'to render with all children as', 75 |
76 | one 77 | three 78 |
79 | ); 80 | ``` 81 | 82 | ```output 83 | expected 84 | to render with all children as
onethree
85 | 86 |
87 | one 88 | two // should be removed 89 | three 90 |
91 | ``` 92 | 93 | ```js 94 | // The span "two" is missing here, as is `className="parent"` 95 | // This will cause an assertion error, 96 | // due to `to have exactly rendered` being used 97 | 98 | expect(, 'to exactly render as', 99 |
100 | one 101 | three 102 |
103 | ); 104 | ``` 105 | 106 | ```output 107 | expected 108 | to exactly render as
onethree
109 | 110 |
112 | one 113 | two // should be removed 114 | three 115 |
116 | ``` 117 | 118 | If you want to trigger events, use the `when rendered` assertion to render 119 | the component, then use the other `with event` and `to have rendered` or `to contain` 120 | assertions to validate the output. 121 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/to-satisfy-snapshot.md: -------------------------------------------------------------------------------- 1 | Under [jest](https://facebook.github.io/jest/), you can use snapshots. Snapshot tests save a snapshot of the component as it is currently rendered to a `.snapshot` file under a directory `__snapshots__`. Note that the snapshots for `unexpected-react` are saved to a different filename than those jest uses natively. This is because the format differs slightly. 2 | 3 | Remember that to include snapshot support for the shallow and DOM renderers, you need to require unexpected-react as `require('unexpected-react/jest')` 4 | 5 | Given the following test component: 6 | 7 | ```js 8 | var MyComponent = () => ( 9 |
10 | one 11 | two 12 | three 13 |
14 | ) 15 | ``` 16 | 17 | Let's render the output with the shallow renderer: 18 | 19 | ```js 20 | var renderer = createRenderer(); 21 | renderer.render(); 22 | ``` 23 | 24 | Then we can validate it matches the snapshot. If no snapshot exists, it will be automatically created the first time it is run. 25 | 26 | ```js#evaluate:false 27 | expect(renderer, 'to satisfy snapshot'); 28 | ``` 29 | 30 | If in the future the component output changes, the error will be highlighted (using the same error highlighting used in the rest of unexpected-react). 31 | 32 | Once you have checked that the changes are correct, you can run `jest -u` to update the snapshot, or if running in watch mode, press `u`. 33 | 34 | ### Events 35 | Triggered events still works, and can be combined with matching snaphots. 36 | 37 | e.g. 38 | 39 | ```js#evaluate:false 40 | var renderer = createRenderer(); 41 | renderer.render(); 42 | 43 | expect(renderer, 44 | 'with event click', 45 | 'to satisfy snapshot' 46 | ); 47 | ``` 48 | 49 | ### Matching 50 | 51 | The snapshot matches in the same way as `to have rendered`, so new classes, attributes and child nodes are not treated as a difference. This can be advantageous when you want to add new features to a component, but expect the existing component to keep the same basic template. 52 | 53 | If you'd prefer to match the template exactly (order of classes is still ignored), see the assertion `to match snapshot`. 54 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/when-deeply-rendered.md: -------------------------------------------------------------------------------- 1 | 2 | You can render a component with the full DOM renderer directly with the `when deeply rendered` assertion. 3 | 4 | This works with both stateful and stateless (functional) components, which can be easier than creating a manual wrapper and manually rendering into the DOM with `TestUtils.renderIntoDocument(...)` or `ReactDOM.render(...)` 5 | 6 | Say you have these components: 7 | ```js 8 | 9 | const Page = (props) => Page {props.page}; 10 | 11 | const Pages = (props) => { 12 | const pageElements = []; 13 | for (let i = 1; i <= props.count; ++i) { 14 | pageElements.push(); 15 | } 16 | return ( 17 |
18 | {pageElements} 19 |
20 | ); 21 | }; 22 | 23 | ``` 24 | 25 | You can check the rendering directly using the `when deeply rendered` assertion, saving you from creating stateless wrappers and rendering into the DOM by hand: 26 | ```js 27 | expect(, 28 | 'when deeply rendered', 29 | 'to have rendered', 30 |
31 | Page 1 32 | Page 2 33 | Page 3 34 |
35 | ); 36 | ``` 37 | 38 | Everything works after the `when deeply rendered`, so you can use events and all the other assertions as normal 39 | ```js 40 | expect(, 41 | 'when deeply rendered', 42 | 'with event', 'click', 43 | 'to have rendered', 44 | 45 | ); 46 | ``` 47 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/when-rendered.md: -------------------------------------------------------------------------------- 1 | 2 | You can render a component with the shallow renderer directly with the `when rendered` assertion. 3 | 4 | Say you have this component: 5 | ```js 6 | const Pages = (props) => { 7 | const pageElements = []; 8 | for (let i = 1; i <= props.count; ++i) { 9 | pageElements.push(Page {i}); 10 | } 11 | return ( 12 |
13 | {pageElements} 14 |
15 | ); 16 | }; 17 | 18 | ``` 19 | 20 | You can check the rendering directly using the `when rendered` assertion, saving you from creating the shallow renderer by hand: 21 | ```js 22 | expect(, 23 | 'when rendered', 24 | 'to have rendered', 25 |
26 | Page 1 27 | Page 2 28 | Page 3 29 |
30 | ); 31 | ``` 32 | 33 | Everything works after the `when rendered` as normal, so you can trigger events and use the other assertions as you would otherwise. 34 | ```js 35 | expect(, 36 | 'when rendered', 37 | 'with event', 'click', 38 | 'to have rendered', 39 | 40 | ); 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/assertions/ReactElement/with-event.md: -------------------------------------------------------------------------------- 1 | ## `with event` .... [`on`] 2 | 3 | `with event` can trigger events in both the shallow and full renderer. For the normal full renderer, 4 | `TestUtils.Simulate` is used to simulate the event. For the shallow renderer, it is expected that 5 | there is a prop with the name `on[EventName]`, where the first letter of the event is capitalised. 6 | 7 | e.g. with a button that counts it's own clicks 8 | 9 | ```js 10 | var renderer = createRenderer() 11 | renderer.render(); 12 | 13 | expect(renderer, 'with event', 'click', 'to have rendered', ); 14 | ``` 15 | 16 | This works with the component directly, as a shallow renderer is automatically created. 17 | Also note that due to unexpected's clever string handling, you can concatenated the `with event` and the 18 | event name. 19 | 20 | 21 | ```js 22 | expect(, 'with event click', 'to have rendered', ); 23 | ``` 24 | 25 | Given the following todo list: 26 | 27 | ```js 28 | var renderer = createRenderer() 29 | renderer.render( 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | ``` 37 | 38 | If you want to trigger an event on a specific component, (i.e. not the top level component), use `on` 39 | after the event. 40 | 41 | ```js 42 | expect( 43 | renderer, 44 | 'with event click', 45 | 'on', , 46 | 'to contain', 47 | ); 48 | ``` 49 | 50 | To pass arguments to the event, simply include the event object after the event name 51 | 52 | ```js 53 | expect( 54 | renderer, 55 | 'with event mouseDown', { mouseX: 150, mouseY: 50 }, 56 | 'on', , 57 | 'to contain', 58 | ); 59 | ``` 60 | 61 | This will call the function passed in the `onMouseDown` prop of the ``. 62 | 63 | 64 | 65 | You can take the renderer after the event has been triggered by using the promise returned 66 | from `expect`. This is often used to test that spy or mock callbacks have been called (using for instance [sinon.js](http://sinonjs.org)). 67 | 68 | ```js#async:true 69 | return expect( 70 | renderer, 71 | 'with event click', 'on', 72 | ).then(renderer => { 73 | const todoListInstance = renderer.getMountedInstance(); 74 | expect(todoListInstance.state, 'to satisfy', { clicked: { 2: true } }); 75 | }); 76 | 77 | ``` 78 | 79 | ## eventTarget 80 | 81 | You can add an `eventTarget` prop to the expected to trigger the event on a child component. 82 | e.g. 83 | ```js 84 | var renderer = createRenderer() 85 | renderer.render(); 86 | 87 | expect(renderer, 88 | 'with event', 'click', 'on',
, 89 | 'to have rendered', 90 |
91 |
92 |
93 |
); 94 | ``` 95 | -------------------------------------------------------------------------------- /documentation/assertions/ReactTestRenderer/queried-for.md: -------------------------------------------------------------------------------- 1 | This enables finding a particular component or element, to then perform further assertions on. 2 | 3 | e.g. 4 | ```js 5 | var TestRenderer = require('react-test-renderer'); 6 | var renderer = TestRenderer.create( 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | 14 | expect( 15 | renderer, 'queried for', 16 |
, 17 | 'to have rendered', 18 |
19 | Buy groceries 20 |
21 | ); 22 | ``` 23 | 24 | Here the `TodoList` component is rendering a list of todo items. Here we're 25 | querying for the todo item with the id 3 and then we check that it has the 26 | expected text. This example show how you only mention exactly what you are 27 | searching for. If the assertion finds a match it is forwarded to the next 28 | assertion; otherwise it fails with a helpful message. 29 | 30 | You can use `to have rendered` or `to contain` with all the options as usual following a `queried for`. 31 | 32 | ## queryTarget 33 | 34 | If you want to find a target nested inside a parent element, use `queryTarget` in the query. 35 | e.g. This `queried for` clause returns the `input` element inside the `div` with 36 | the class `add-new-item`. 37 | 38 | ```js 39 | expect(renderer, 'queried for',
, 40 | 'to have rendered', ); 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/assertions/ReactTestRenderer/to-contain.md: -------------------------------------------------------------------------------- 1 | It's possible to check for a part of the subtree, without 2 | testing the entire returned tree. This allows you to test specific elements, without 3 | writing brittle tests that break when the structure changes. 4 | 5 | Assuming the following component output 6 | ```js 7 | const MyComponent = () => ( 8 |
9 | one 10 | two 11 | three 12 |
13 | ) 14 | 15 | var renderer = TestRenderer.create(); 16 | ``` 17 | 18 | ```js 19 | // This will pass, as `two` can be found in the renderers output 20 | expect(renderer, 'to contain', two); 21 | ``` 22 | 23 | Notice that the extra `className="middle"` in the `two` is ignored, 24 | in a similar way to the `to have rendered` assertion. 25 | 26 | You can override this behaviour by using `'to contain exactly'`, and `'to contain with all children'` 27 | 28 | 29 | ```js 30 | // This will fail, as `two` cannot be found in the renderers output, due to 31 | // the missing `className="middle"` prop 32 | expect(renderer, 'to contain exactly', two); 33 | ``` 34 | 35 | ```output 36 | expected 37 |
38 | one 39 | two 40 | three 41 |
42 | to contain exactly two 43 | 44 | the best match was 45 | 47 | two 48 | 49 | ``` 50 | 51 | The same thing applies to children for `'to contain'` as for `'to have rendered'`. 52 | 53 | -------------------------------------------------------------------------------- /documentation/assertions/ReactTestRenderer/to-have-rendered.md: -------------------------------------------------------------------------------- 1 | Given the following test component: 2 | 3 | ```js 4 | const MyComponent = () => ( 5 |
6 | one 7 | two 8 | three 9 |
10 | ) 11 | ``` 12 | 13 | Let's render the output with the test renderer: 14 | 15 | ```js 16 | const renderer = TestRenderer.create(); 17 | ``` 18 | 19 | ```js 20 | // Extra props and children from the render are ignored 21 | expect(renderer, 'to have rendered',
); 22 | ``` 23 | 24 | ```js 25 | // The span "two" is missing here, but it is ignored. 26 | expect(renderer, 'to have rendered', 27 |
28 | one 29 | three 30 |
31 | ); 32 | ``` 33 | 34 | ```js 35 | // The following assertion will fail, as 'four' does not exist 36 | expect(renderer, 'to have rendered', 37 |
38 | one 39 | four 40 |
41 | ); 42 | ``` 43 | 44 | ```output 45 | expected 46 |
47 | onetwothree 48 |
49 | to have rendered
onefour
50 | 51 |
52 | one 53 | 54 | two // -two 55 | // +four 56 | 57 | three 58 |
59 | ``` 60 | 61 | If you want to check for an exact render, use `'to have exactly rendered'`. 62 | 63 | Alternatively, if you don't care about extra props, but want to check that there are no extra child nodes, use `'to have rendered with all children'` 64 | Note that `exactly` implies `with all children`, so you using both options is not necessary. 65 | 66 | Normally wrappers (elements that simply wrap other components) are ignored. This can be useful if you have higher order 67 | components wrapping your components, you can simply ignore them in your tests (they will be shown greyed out 68 | if there is a "real" error). If you want to test that there are no extra wrappers, simply add 69 | `with all wrappers` to the assertion. 70 | 71 | 72 | ```js 73 | // The span "two" is missing here, as is `className="parent"` 74 | // The missing span will cause an assertion error, but the extra prop will be ignored 75 | // due to `to have rendered with all children` being used 76 | 77 | expect(renderer, 'to have rendered with all children', 78 |
79 | one 80 | three 81 |
82 | ); 83 | ``` 84 | 85 | ```output 86 | expected 87 |
88 | onetwothree 89 |
90 | to have rendered with all children
onethree
91 | 92 |
93 | one 94 | two // should be removed 95 | three 96 |
97 | ``` 98 | 99 | ```js 100 | // The span "two" is missing here, as is `className="parent"` 101 | // This will cause an assertion error, 102 | // due to `to have exactly rendered` being used 103 | 104 | expect(renderer, 'to have exactly rendered', 105 |
106 | one 107 | three 108 |
109 | ); 110 | ``` 111 | 112 | ```output 113 | expected 114 |
115 | onetwothree 116 |
117 | to have exactly rendered
onethree
118 | 119 |
121 | one 122 | two // should be removed 123 | three 124 |
125 | ``` 126 | -------------------------------------------------------------------------------- /documentation/assertions/ReactTestRenderer/to-match-snapshot.md: -------------------------------------------------------------------------------- 1 | Under [jest](https://facebook.github.io/jest/), you can use snapshots. Snapshot tests save a snapshot of the component as it is currently rendered to a `.snapshot` file under a directory `__snapshots__`. Note that the snapshots for `unexpected-react` are saved to a different filename than those jest uses natively. This is because the format differs slightly. 2 | 3 | Remember that to include snapshot support for the test renderer, you need to require unexpected-react as `require('unexpected-react/test-renderer-jest')` 4 | 5 | Given the following test component: 6 | 7 | ```js 8 | const MyComponent = () => ( 9 |
10 | one 11 | two 12 | three 13 |
14 | ) 15 | ``` 16 | 17 | Let's render the output with the test renderer: 18 | 19 | ```js 20 | const renderer = TestRenderer.create(); 21 | ``` 22 | 23 | Then we can validate it matches the snapshot. If no snapshot exists, it will be automatically created the first time it is run. 24 | 25 | ```js#evaluate:false 26 | expect(renderer, 'to match snapshot'); 27 | ``` 28 | 29 | If in the future the component output changes, the error will be highlighted (using the same error highlighting used in the rest of unexpected-react). 30 | 31 | Once you have checked that the changes are correct, you can run `jest -u` to update the snapshot, or if running in watch mode, press `u`. 32 | 33 | ### Events 34 | Triggered events still works, and can be combined with matching snaphots. 35 | 36 | e.g. 37 | 38 | ```js#evaluate:false 39 | const renderer = TestRenderer.create(); 40 | 41 | expect(renderer, 42 | 'with event click', 43 | 'to match snapshot' 44 | ); 45 | ``` 46 | 47 | ### Matching 48 | 49 | The snapshot matches everything, so extra classes and attributes will causes a difference to be highlighted. If you want your snapshots to work more like `to have rendered`, so new attributes, classes and child elements can be added without triggering a change, see the assertion `to satisfy snapshot`. 50 | 51 | -------------------------------------------------------------------------------- /documentation/assertions/ReactTestRenderer/to-satisfy-snapshot.md: -------------------------------------------------------------------------------- 1 | Under [jest](https://facebook.github.io/jest/), you can use snapshots. Snapshot tests save a snapshot of the component as it is currently rendered to a `.snapshot` file under a directory `__snapshots__`. Note that the snapshots for `unexpected-react` are saved to a different filename than those jest uses natively. This is because the format differs slightly. 2 | 3 | Remember that to include snapshot support for the test renderer, you need to require unexpected-react as `require('unexpected-react/test-renderer-jest')` 4 | 5 | Given the following test component: 6 | 7 | ```js 8 | const MyComponent = () => ( 9 |
10 | one 11 | two 12 | three 13 |
14 | ) 15 | ``` 16 | 17 | Let's render the output with the test renderer: 18 | 19 | ```js 20 | var renderer = TestRenderer.create(); 21 | ``` 22 | 23 | Then we can validate it matches the snapshot. If no snapshot exists, it will be automatically created the first time it is run. 24 | 25 | ```js#evaluate:false 26 | expect(renderer, 'to satisfy snapshot'); 27 | ``` 28 | 29 | If in the future the component output changes, the error will be highlighted (using the same error highlighting used in the rest of unexpected-react). 30 | 31 | Once you have checked that the changes are correct, you can run `jest -u` to update the snapshot, or if running in watch mode, press `u`. 32 | 33 | ### Events 34 | Triggered events still works, and can be combined with matching snaphots. 35 | 36 | e.g. 37 | 38 | ```js#evaluate:false 39 | var renderer = TestRenderer.create(); 40 | 41 | expect(renderer, 42 | 'with event click', 43 | 'to satisfy snapshot' 44 | ); 45 | ``` 46 | 47 | ### Matching 48 | 49 | The snapshot matches in the same way as `to have rendered`, so new classes, attributes and child nodes are not treated as a difference. This can be advantageous when you want to add new features to a component, but expect the existing component to keep the same basic template. 50 | 51 | If you'd prefer to match the template exactly (order of classes is still ignored), see the assertion `to match snapshot`. 52 | -------------------------------------------------------------------------------- /documentation/assertions/ReactTestRenderer/with-event.md: -------------------------------------------------------------------------------- 1 | ## `with event` .... [`on`] 2 | 3 | `with event` can trigger events in the shallow, full and test renderers. For the normal full renderer, 4 | `TestUtils.Simulate` is used to simulate the event. For the shallow and test renderers, it is expected that 5 | there is a prop with the name `on[EventName]`, where the first letter of the event is capitalised. 6 | 7 | e.g. with a button that counts its own clicks 8 | 9 | ```js 10 | var renderer = TestRenderer.create() 11 | 12 | expect(renderer, 'with event', 'click', 'to have rendered', ); 13 | ``` 14 | 15 | Also note that due to unexpected's clever string handling, you can often concatenate the `with event` and the 16 | event name. 17 | 18 | Given the following todo list: 19 | 20 | ```js 21 | var renderer = TestRenderer.create( 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | ``` 29 | 30 | If you want to trigger an event on a specific component, (i.e. not the top level component), use `on` 31 | after the event. 32 | 33 | ```js 34 | expect( 35 | renderer, 36 | 'with event click', 'on',
, 37 | 'to contain',
Completed!
38 | ); 39 | ``` 40 | 41 | To pass arguments to the event, simply include the event object after the event name 42 | 43 | ```js 44 | expect( 45 | renderer, 46 | 'with event mouseDown', { mouseX: 150, mouseY: 50 }, 47 | 'on',
, 48 | 'not to contain',
Completed!
49 | ); 50 | ``` 51 | 52 | This will call the function passed in the `onMouseDown` prop of the ``. 53 | 54 | 55 | You can take the renderer after the event has been triggered by using the promise returned 56 | from `expect`. This is often used to test that spy or mock callbacks have been called (using for instance [sinon.js](http://sinonjs.org)). 57 | 58 | ```js 59 | expect( 60 | renderer, 61 | 'with event click', 'on',
62 | ); 63 | ``` 64 | 65 | ```js#async:true 66 | return expect( 67 | renderer, 68 | 'with event click', 'on',
69 | ).then(function (renderer) { 70 | var todoListInstance = renderer.getInstance(); 71 | expect(todoListInstance.state, 'to satisfy', { clicked: { 2: true } }); 72 | }); 73 | 74 | ``` 75 | 76 | ## eventTarget 77 | 78 | You can add an `eventTarget` prop to the expected to trigger the event on a child component. 79 | e.g. 80 | ```js 81 | var renderer = TestRenderer.create(); 82 | 83 | expect(renderer, 84 | 'with event', 'click', 'on',
, 85 | 'to have rendered', 86 |
87 |
88 |
89 |
); 90 | ``` 91 | -------------------------------------------------------------------------------- /documentation/assertions/RenderedReactElement/queried-for.md: -------------------------------------------------------------------------------- 1 | This enables finding a particular component or element, to then perform further assertions on. 2 | 3 | e.g. 4 | ```js 5 | 6 | var component = TestUtils.renderIntoDocument( 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | 14 | expect( 15 | component, 16 | 'queried for', 17 |
18 | 3 19 |
, 20 | 'to have rendered', 21 |
22 | Buy groceries 23 |
24 | ); 25 | ``` 26 | 27 | Here we're searching for a `div` representing a todo item with the id 3. Because 28 | props are checked with `to satisfy`, extra data in this object is ignored. 29 | 30 | You can use `to have rendered` or `to contain` with all the options as usual following a `queried for`. 31 | 32 | It is also possible to extract the found component, by using the value of the returned promise from `expect`. 33 | 34 | 35 | ```js#async:true 36 | return expect(component, 'queried for', ) 37 | .then(todoItem => { 38 | expect(todoItem.props.label, 'to equal', 'Buy groceries'); 39 | }); 40 | ``` 41 | 42 | ## queryTarget 43 | 44 | If you want to find a target nested inside a parent element, use `queryTarget` in the query. 45 | e.g. This `queried for` clause returns the `span` inside the `TodoItem` 46 | 47 | ```js 48 | expect( 49 | component, 50 | 'queried for', 51 | 52 |
53 | 54 |
55 |
, 56 | 'to have rendered', 57 | Buy groceries 58 | ); 59 | ``` 60 | -------------------------------------------------------------------------------- /documentation/assertions/RenderedReactElement/to-contain.md: -------------------------------------------------------------------------------- 1 | It's possible to check for a part of the subtree, without 2 | testing the entire returned tree. This allows you to test specific elements, without 3 | writing brittle tests that break when the structure changes. 4 | 5 | Assuming the following component output 6 | ```js 7 | class MyComponent extends React.Component { 8 | render () { 9 | return ( 10 |
11 | one 12 | two 13 | three 14 |
15 | ); 16 | } 17 | }; 18 | 19 | var component = TestUtils.renderIntoDocument( 20 | 21 | ); 22 | ``` 23 | 24 | ```js 25 | // This will pass, as `two` can be found in the component's output 26 | expect(component, 'to contain', two); 27 | ``` 28 | 29 | Notice that the extra `className="middle"` in the `two` is ignored, 30 | in a similar way to the `to have rendered` assertion. 31 | 32 | You can override this behaviour by using `'to contain exactly'`, and `'to contain with all children'` 33 | 34 | 35 | ```js 36 | // This will fail, as `two` cannot be found in the renderers output, due to 37 | // the missing `className="middle"` prop 38 | expect(component, 'to contain exactly', two); 39 | ``` 40 | 41 | ```output 42 | expected 43 | 44 |
45 | one 46 | two 47 | three 48 |
49 |
50 | to contain exactly two 51 | 52 | the best match was 53 | 55 | two 56 | 57 | ``` 58 | 59 | The same thing applies to children for `'to contain'` as for `'to have rendered'`. 60 | 61 | -------------------------------------------------------------------------------- /documentation/assertions/RenderedReactElement/to-have-rendered.md: -------------------------------------------------------------------------------- 1 | Given the following test component: 2 | 3 | ```js 4 | class MyComponent extends React.Component { 5 | render () { 6 | return ( 7 |
8 | one 9 | two 10 | three 11 |
12 | ); 13 | } 14 | } 15 | ``` 16 | 17 | Let's render the component with the virtual DOM renderer: 18 | 19 | ```js 20 | const component = TestUtils.renderIntoDocument(); 21 | ``` 22 | 23 | ```js 24 | // Extra props and children from the render are ignored 25 | expect(component, 'to have rendered',
); 26 | ``` 27 | 28 | ```js 29 | // The span "two" is missing here, but it is ignored. 30 | expect(component, 'to have rendered', 31 |
32 | one 33 | three 34 |
35 | ); 36 | ``` 37 | 38 | ```js 39 | // The following assertion will fail, as 'four' does not exist 40 | expect(component, 'to have rendered', 41 |
42 | one 43 | four 44 |
45 | ); 46 | ``` 47 | 48 | ```output 49 | expected 50 | 51 |
52 | onetwothree 53 |
54 |
55 | to have rendered
onefour
56 | 57 | 58 |
59 | one 60 | 61 | two // -two 62 | // +four 63 | 64 | three 65 |
66 |
67 | ``` 68 | 69 | If you want to check for an exact render, use `'to have exactly rendered'`. 70 | 71 | Alternatively, if you don't care about extra props, but want to check that there are no extra child nodes, use `'to have rendered with all children'` 72 | Note that `exactly` implies `with all children`, so you using both options is not necessary. 73 | 74 | Normally wrappers (elements that simply wrap other components) are ignored. This can be useful if you have higher order 75 | components wrapping your components, you can simply ignore them in your tests (they will be shown greyed out 76 | if there is a "real" error). If you want to test that there are no extra wrappers, simply add 77 | `with all wrappers` to the assertion. 78 | 79 | 80 | ```js 81 | // The span "two" is missing here, as is `className="parent"` 82 | // The missing span will cause an assertion error, but the extra prop will be ignored 83 | // due to `to have rendered with all children` being used 84 | 85 | expect(component, 'to have rendered with all children', 86 |
87 | one 88 | three 89 |
90 | ); 91 | ``` 92 | 93 | ```output 94 | expected 95 | 96 |
97 | onetwothree 98 |
99 |
100 | to have rendered with all children
onethree
101 | 102 | 103 |
104 | one 105 | two // should be removed 106 | three 107 |
108 |
109 | ``` 110 | 111 | ```js 112 | // The span "two" is missing here, as is `className="parent"` 113 | // This will cause an assertion error, 114 | // due to `to have exactly rendered` being used 115 | 116 | expect(component, 'to have exactly rendered', 117 | 118 |
119 | one 120 | three 121 |
122 |
123 | ); 124 | ``` 125 | 126 | ```output 127 | expected 128 | 129 |
130 | onetwothree 131 |
132 |
133 | to have exactly rendered
onethree
134 | 135 | 136 |
138 | one 139 | two // should be removed 140 | three 141 |
142 |
143 | ``` 144 | 145 | -------------------------------------------------------------------------------- /documentation/assertions/RenderedReactElement/to-match-snapshot.md: -------------------------------------------------------------------------------- 1 | Under [jest](https://facebook.github.io/jest/), you can use snapshots. Snapshot tests save a snapshot of the component as it is currently rendered to a `.snapshot` file under a directory `__snapshots__`. Note that the snapshots for `unexpected-react` are saved to a different filename than those jest uses natively. This is because the format differs slightly. 2 | 3 | Remember that to include snapshot support for the shallow and DOM renderers, you need to require unexpected-react as `require('unexpected-react/jest')` 4 | 5 | With `unexpected-react`, you can snapshot DOM rendered tests in exactly the same way. 6 | 7 | ```js 8 | class MyComponent extends React.Component { 9 | render () { 10 | return ( 11 |
12 | one 13 | two 14 | three 15 |
16 | ); 17 | } 18 | } 19 | ``` 20 | 21 | Let's render the component with the virtual DOM renderer: 22 | 23 | ```js 24 | var component = TestUtils.renderIntoDocument(); 25 | ``` 26 | 27 | Then we can validate it matches the snapshot. If no snapshot exists, it will be automatically created the first time it is run. 28 | 29 | ```js#evaluate:false 30 | expect(component, 'to match snapshot'); 31 | ``` 32 | 33 | If in the future the component output changes, the error will be highlighted (using the same error highlighting used in the rest of unexpected-react). 34 | 35 | Once you have checked that the changes are correct, you can run `jest -u` to update the snapshot, or if running in watch mode, press `u`. 36 | 37 | ### Events 38 | Triggered events still works, and can be combined with matching snaphots. 39 | 40 | e.g. 41 | 42 | ```js#evaluate:false 43 | var component = TestUtils.renderIntoDocument(); 44 | 45 | expect(component, 46 | 'with event click', 47 | 'to match snapshot' 48 | ); 49 | ``` 50 | 51 | ### Matching 52 | 53 | The snapshot matches everything, so extra classes and attributes will causes a difference to be highlighted. If you want your snapshots to work more like `to have rendered`, so new attributes, classes and child elements can be added without triggering a change, see the assertion `to satisfy snapshot`. 54 | 55 | -------------------------------------------------------------------------------- /documentation/assertions/RenderedReactElement/to-satisfy-snapshot.md: -------------------------------------------------------------------------------- 1 | Under [jest](https://facebook.github.io/jest/), you can use snapshots. Snapshot tests save a snapshot of the component as it is currently rendered to a `.snapshot` file under a directory `__snapshots__`. Note that the snapshots for `unexpected-react` are saved to a different filename than those jest uses natively. This is because the format differs slightly. 2 | 3 | Remember that to include snapshot support for the shallow and DOM renderers, you need to require unexpected-react as `require('unexpected-react/jest')` 4 | 5 | With `unexpected-react`, you can snapshot DOM rendered tests in exactly the same way. 6 | 7 | ```js 8 | class MyComponent extends React.Component { 9 | render () { 10 | return ( 11 |
12 | one 13 | two 14 | three 15 |
16 | ); 17 | } 18 | } 19 | ``` 20 | 21 | Let's render the component with the virtual DOM renderer: 22 | 23 | ```js 24 | var component = TestUtils.renderIntoDocument(); 25 | ``` 26 | 27 | Then we can validate it matches the snapshot. If no snapshot exists, it will be automatically created the first time it is run. 28 | 29 | ```js#evaluate:false 30 | expect(component, 'to satisfy snapshot'); 31 | ``` 32 | 33 | If in the future the component output changes, the error will be highlighted (using the same error highlighting used in the rest of unexpected-react). 34 | 35 | Once you have checked that the changes are correct, you can run `jest -u` to update the snapshot, or if running in watch mode, press `u`. 36 | 37 | ### Events 38 | Triggered events still works, and can be combined with matching snaphots. 39 | 40 | e.g. 41 | 42 | ```js#evaluate:false 43 | var component = TestUtils.renderIntoDocument(); 44 | 45 | expect(component, 46 | 'with event click', 47 | 'to satisfy snapshot' 48 | ); 49 | ``` 50 | 51 | ### Matching 52 | 53 | The snapshot matches in the same way as `to have rendered`, so new classes, attributes and child nodes are not treated as a difference. This can be advantageous when you want to add new features to a component, but expect the existing component to keep the same basic template. 54 | 55 | If you'd prefer to match the template exactly (order of classes is still ignored), see the assertion `to match snapshot`. 56 | -------------------------------------------------------------------------------- /documentation/assertions/RenderedReactElement/with-event.md: -------------------------------------------------------------------------------- 1 | ## `with event` .... [`on`] 2 | 3 | `with event` can trigger events in both the shallow and full renderer. For the normal full renderer, 4 | `TestUtils.Simulate` is used to simulate the event. For the shallow renderer, it is expected that 5 | there is a prop with the name `on[EventName]`, where the first letter of the event is capitalised. 6 | 7 | e.g. with a button that counts it's own clicks 8 | 9 | ```js 10 | var component = TestUtils.renderIntoDocument(); 11 | 12 | expect(component, 'with event', 'click', 'to have rendered', ); 13 | ``` 14 | 15 | Given the following todo list: 16 | 17 | ```js 18 | var component = TestUtils.renderIntoDocument( 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | ``` 26 | 27 | If you want to trigger an event on a specific component, (i.e. not the top level component), use `on` 28 | after the event. 29 | 30 | ```js 31 | expect( 32 | component, 33 | 'with event click', 34 | 'on', , 35 | 'to contain', 36 |
37 | Buy groceries 38 |
39 | ); 40 | ``` 41 | 42 | To pass arguments to the event, simply include the event object after the event name 43 | 44 | ```js 45 | expect( 46 | component, 47 | 'with event mouseDown', { mouseX: 150, mouseY: 50 }, 48 | 'on', , 49 | 'to contain', 50 |
51 | Buy groceries 52 |
53 | ); 54 | ``` 55 | 56 | This will call the function passed in the `onMouseDown` prop of the ``. 57 | 58 | ## Multiple events 59 | 60 | To call multiple events, simple list them one after the other: 61 | 62 | 63 | ```js 64 | expect(component, 65 | 'with event click', { mouseX: 150, mouseY: 50 }, 66 | 'on',
, 67 | 'with event click', { mouseX: 50, mouseY: 50 }, 68 | 'on',
, 69 | 'to have rendered', 70 | 71 |
72 | 73 |
74 | 75 | 76 |
77 | 78 |
79 | 80 | ); 81 | ``` 82 | 83 | You can optionally add `and` before the second and further events, to make it easier to read: 84 | 85 | ```js 86 | expect(component, 87 | 'with event mouseDown', { mouseX: 150, mouseY: 50 }, 88 | 'on', , 89 | 'and with event mouseDown', { mouseX: 50, mouseY: 50 }, 90 | 'on', , 91 | 'to have rendered', 92 | 93 |
94 | 95 |
96 | 97 | 98 |
99 | 100 |
101 | 102 | ); 103 | ``` 104 | 105 | You can extract the renderer after an event by using the result of the promise returned from `expect` 106 | 107 | ```js#async:true 108 | return expect( 109 | component, 110 | 'with event mouseDown', { mouseX: 150, mouseY: 50 }, 111 | 'on', 112 | ).then(renderer => { 113 | expect( 114 | renderer, 115 | 'to contain', 116 | 117 |
118 | 119 | ); 120 | }); 121 | ``` 122 | 123 | ## eventTarget 124 | 125 | You can add an `eventTarget` prop to the expected to trigger the event on a child component. 126 | e.g. This will trigger the click in the ` 21 | ); 22 | } 23 | } 24 | 25 | ClickCounter.propTypes = { 26 | className: PropTypes.string 27 | }; 28 | -------------------------------------------------------------------------------- /jest-integration/baseTemplate/src/__tests__/ClickCounter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | 6 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 7 | 8 | const expect = Unexpected.clone().use(UnexpectedReact); 9 | 10 | describe('ClickCounter', function () { 11 | 12 | it('renders with default props', function () { 13 | 14 | const renderer = TestRenderer.create(); 15 | expect(renderer, 'to match snapshot'); 16 | }); 17 | 18 | it('counts a single click', function () { 19 | const renderer = TestRenderer.create(); 20 | expect(renderer, 'with event click', 'to match snapshot'); 21 | }); 22 | 23 | it('counts multiple clicks', function () { 24 | const renderer = TestRenderer.create(); 25 | expect(renderer, 26 | 'with event click', 27 | 'with event click', 28 | 'with event click', 29 | 'to match snapshot'); 30 | }); 31 | 32 | it('passes multiple snapshots in a single test', function () { 33 | let renderer = TestRenderer.create(); 34 | expect(renderer, 'to match snapshot'); 35 | renderer = TestRenderer.create(); 36 | expect(renderer, 37 | 'with event click', 38 | 'with event click', 39 | 'with event click', 40 | 'to match snapshot'); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /jest-integration/baseTemplate/unexpected-react-non-jest.js: -------------------------------------------------------------------------------- 1 | module.exports = require('unexpected-react'); 2 | -------------------------------------------------------------------------------- /jest-integration/baseTemplate/unexpected-react-test-renderer.js: -------------------------------------------------------------------------------- 1 | module.exports = require('unexpected-react/test-renderer-jest'); 2 | -------------------------------------------------------------------------------- /jest-integration/baseTemplate/unexpected-react.js: -------------------------------------------------------------------------------- 1 | module.exports = require('unexpected-react/jest'); 2 | -------------------------------------------------------------------------------- /jest-integration/compare-json.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var normalizer = require('./jest-normalizer'); 3 | var jestJson = require(path.resolve(process.argv[2])); 4 | var expectedJson = require(path.resolve(process.argv[3])); 5 | var expect = require('unexpected'); 6 | 7 | try { 8 | expect(normalizer(jestJson, path.resolve(process.argv[4])), 'to satisfy', expectedJson); 9 | process.exit(0); 10 | } catch (error) { 11 | console.log(error.getDiff('text').toString()); 12 | process.exit(1); 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /jest-integration/jest-normalizer.js: -------------------------------------------------------------------------------- 1 | var stackTraceRegex = /^\s+at [^\s]+\s\([^:]+:[0-9]+:[0-9]+\)/m; 2 | module.exports = function (jestJson, commonPath) { 3 | 4 | delete jestJson.startTime; 5 | jestJson.testResults.forEach(function (result) { 6 | 7 | delete result.startTime; 8 | delete result.endTime; 9 | result.assertionResults.forEach(function (test) { 10 | if (test.failureMessages) { 11 | test.failureMessages = test.failureMessages.map(function (msg) { 12 | var match = stackTraceRegex.exec(msg); 13 | if (match) { 14 | msg = msg.substr(0, match.index); 15 | } 16 | 17 | return msg; 18 | }); 19 | } 20 | }); 21 | 22 | result.assertionResults = result.assertionResults.sort(function (a, b) { 23 | if (a.title < b.title) { 24 | return -1; 25 | } else if (a.title > b.title) { 26 | return 1; 27 | } 28 | return 0; 29 | }); 30 | 31 | if (result.name.substr(0, commonPath.length) === commonPath) { 32 | result.name = result.name.substr(commonPath.length) 33 | } 34 | // Remove the stacktrace - often includes node internals which vary per version 35 | var match = stackTraceRegex.exec(result.message); 36 | if (match) { 37 | result.message = result.message.substr(0, match.index); 38 | } 39 | 40 | }); 41 | 42 | jestJson.testResults = jestJson.testResults.sort(function (a, b) { 43 | if (a.name < b.name) { 44 | return -1; 45 | } else if (a.name > b.name) { 46 | return 1; 47 | } 48 | return 0; 49 | }); 50 | 51 | return jestJson; 52 | } 53 | -------------------------------------------------------------------------------- /jest-integration/normalize-jest-json.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var jestJson = require(path.resolve(process.argv[2])); 3 | var normalizer = require('./jest-normalizer'); 4 | 5 | console.log(JSON.stringify(normalizer(jestJson, process.cwd()), null, 2)); 6 | -------------------------------------------------------------------------------- /jest-integration/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")" 6 | 7 | ./run-with-version.sh 16.0.0 "$@" 8 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/1-create-initial-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 4, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "snapshot": { 12 | "added": 5, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 1, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 0, 20 | "total": 5, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts a single click", 35 | "status": "passed", 36 | "title": "counts a single click" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter counts multiple clicks", 44 | "status": "passed", 45 | "title": "counts multiple clicks" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter passes multiple snapshots in a single test", 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "ancestorTitles": [ 58 | "ClickCounter" 59 | ], 60 | "failureMessages": [], 61 | "fullName": "ClickCounter renders with default props", 62 | "status": "passed", 63 | "title": "renders with default props" 64 | } 65 | ], 66 | "message": "", 67 | "name": "/src/__tests__/ClickCounter.spec.js", 68 | "status": "passed", 69 | "summary": "" 70 | } 71 | ], 72 | "wasInterrupted": false 73 | } 74 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/1-create-initial-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/2-validate-existing-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 4, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 5, 20 | "total": 5, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts a single click", 35 | "status": "passed", 36 | "title": "counts a single click" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter counts multiple clicks", 44 | "status": "passed", 45 | "title": "counts multiple clicks" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter passes multiple snapshots in a single test", 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "ancestorTitles": [ 58 | "ClickCounter" 59 | ], 60 | "failureMessages": [], 61 | "fullName": "ClickCounter renders with default props", 62 | "status": "passed", 63 | "title": "renders with default props" 64 | } 65 | ], 66 | "message": "", 67 | "name": "/src/__tests__/ClickCounter.spec.js", 68 | "status": "passed", 69 | "summary": "" 70 | } 71 | ], 72 | "wasInterrupted": false 73 | } 74 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/2-validate-existing-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/3-change-in-code/ClickCounter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | import jestSnapshot from 'jest-snapshot'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | it('renders with default props', function () { 14 | 15 | const renderer = TestRenderer.create(); 16 | expect(renderer, 'to match snapshot'); 17 | }); 18 | 19 | it('counts a single click', function () { 20 | const renderer = TestRenderer.create(); 21 | expect(renderer, 'with event click', 'to match snapshot'); 22 | }); 23 | 24 | it('counts multiple clicks', function () { 25 | const renderer = TestRenderer.create(); 26 | expect(renderer, 27 | 'with event click', 28 | 'with event click', 29 | 'with event click', 30 | 'with event click', 31 | 'to match snapshot'); 32 | }); 33 | 34 | it('passes multiple snapshots in a single test', function () { 35 | let renderer = TestRenderer.create(); 36 | expect(renderer, 'to match snapshot'); 37 | renderer = TestRenderer.create(); 38 | expect(renderer, 39 | 'with event click', 40 | 'with event click', 41 | 'with event click', 42 | 'to match snapshot'); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/3-change-in-code/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 1, 3 | "numFailedTests": 1, 4 | "numPassedTestSuites": 0, 5 | "numPassedTests": 3, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "openHandles": [], 12 | "snapshot": { 13 | "added": 0, 14 | "didUpdate": false, 15 | "failure": true, 16 | "filesAdded": 0, 17 | "filesRemoved": 0, 18 | "filesUnmatched": 1, 19 | "filesUpdated": 0, 20 | "matched": 4, 21 | "total": 5, 22 | "unchecked": 0, 23 | "uncheckedKeysByFile": [], 24 | "unmatched": 1, 25 | "updated": 0 26 | }, 27 | "success": false, 28 | "testResults": [ 29 | { 30 | "assertionResults": [ 31 | { 32 | "ancestorTitles": [ 33 | "ClickCounter" 34 | ], 35 | "failureMessages": [], 36 | "fullName": "ClickCounter counts a single click", 37 | "location": null, 38 | "status": "passed", 39 | "title": "counts a single click" 40 | }, 41 | { 42 | "ancestorTitles": [ 43 | "ClickCounter" 44 | ], 45 | "failureMessages": [ 46 | "UnexpectedError: \nexpected\n\nwith event click with event click 'with event click' with event click 'to match snapshot'\n\n\n" 47 | ], 48 | "fullName": "ClickCounter counts multiple clicks", 49 | "location": null, 50 | "status": "failed", 51 | "title": "counts multiple clicks" 52 | }, 53 | { 54 | "ancestorTitles": [ 55 | "ClickCounter" 56 | ], 57 | "failureMessages": [], 58 | "fullName": "ClickCounter passes multiple snapshots in a single test", 59 | "location": null, 60 | "status": "passed", 61 | "title": "passes multiple snapshots in a single test" 62 | }, 63 | { 64 | "ancestorTitles": [ 65 | "ClickCounter" 66 | ], 67 | "failureMessages": [], 68 | "fullName": "ClickCounter renders with default props", 69 | "location": null, 70 | "status": "passed", 71 | "title": "renders with default props" 72 | } 73 | ], 74 | "message": " ● ClickCounter › counts multiple clicks\n\n UnexpectedError: \n expected\n \n with event click with event click 'with event click' with event click 'to match snapshot'\n\n \n\n 24 | it('counts multiple clicks', function () {\n 25 | const renderer = TestRenderer.create();\n > 26 | expect(renderer,\n | ^\n 27 | 'with event click',\n 28 | 'with event click',\n 29 | 'with event click',\n", 75 | "name": "/src/__tests__/ClickCounter.spec.js", 76 | "status": "failed", 77 | "summary": "" 78 | } 79 | ], 80 | "wasInterrupted": false 81 | } 82 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/3-change-in-code/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.spec.js src/__tests__/ 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/3-change-in-code/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/4-update-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 4, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": true, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 1, 19 | "matched": 4, 20 | "total": 5, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 1 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts a single click", 35 | "status": "passed", 36 | "title": "counts a single click" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter counts multiple clicks", 44 | "status": "passed", 45 | "title": "counts multiple clicks" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter passes multiple snapshots in a single test", 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "ancestorTitles": [ 58 | "ClickCounter" 59 | ], 60 | "failureMessages": [], 61 | "fullName": "ClickCounter renders with default props", 62 | "status": "passed", 63 | "title": "renders with default props" 64 | } 65 | ], 66 | "message": "", 67 | "name": "/src/__tests__/ClickCounter.spec.js", 68 | "status": "passed", 69 | "summary": "" 70 | } 71 | ], 72 | "wasInterrupted": false 73 | } 74 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/4-update-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn run test-update 4 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/5-revalidate-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 4, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 5, 20 | "total": 5, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts a single click", 35 | "status": "passed", 36 | "title": "counts a single click" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter counts multiple clicks", 44 | "status": "passed", 45 | "title": "counts multiple clicks" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter passes multiple snapshots in a single test", 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "ancestorTitles": [ 58 | "ClickCounter" 59 | ], 60 | "failureMessages": [], 61 | "fullName": "ClickCounter renders with default props", 62 | "status": "passed", 63 | "title": "renders with default props" 64 | } 65 | ], 66 | "message": "", 67 | "name": "/src/__tests__/ClickCounter.spec.js", 68 | "status": "passed", 69 | "summary": "" 70 | } 71 | ], 72 | "wasInterrupted": false 73 | } 74 | -------------------------------------------------------------------------------- /jest-integration/tests/basics/5-revalidate-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/1-create-initial-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 4, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "snapshot": { 12 | "added": 5, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 1, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 0, 20 | "total": 5, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts a single click", 35 | "status": "passed", 36 | "title": "counts a single click" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter counts multiple clicks", 44 | "status": "passed", 45 | "title": "counts multiple clicks" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter passes multiple snapshots in a single test", 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "ancestorTitles": [ 58 | "ClickCounter" 59 | ], 60 | "failureMessages": [], 61 | "fullName": "ClickCounter renders with default props", 62 | "status": "passed", 63 | "title": "renders with default props" 64 | } 65 | ], 66 | "message": "", 67 | "name": "/src/__tests__/ClickCounter.spec.js", 68 | "status": "passed", 69 | "summary": "" 70 | } 71 | ], 72 | "wasInterrupted": false 73 | } 74 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/1-create-initial-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/2-remove-test-and-update/ClickCounter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | import jestSnapshot from 'jest-snapshot'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | it('renders with default props', function () { 14 | 15 | const renderer = TestRenderer.create(); 16 | expect(renderer, 'to match snapshot'); 17 | }); 18 | 19 | it('counts multiple clicks', function () { 20 | const renderer = TestRenderer.create(); 21 | expect(renderer, 22 | 'with event click', 23 | 'with event click', 24 | 'with event click', 25 | 'to match snapshot'); 26 | }); 27 | 28 | it('passes multiple snapshots in a single test', function () { 29 | let renderer = TestRenderer.create(); 30 | expect(renderer, 'to match snapshot'); 31 | renderer = TestRenderer.create(); 32 | expect(renderer, 33 | 'with event click', 34 | 'with event click', 35 | 'with event click', 36 | 'to match snapshot'); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/2-remove-test-and-update/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 3, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 3, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": true, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 4, 20 | "total": 4, 21 | "unchecked": 1, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts multiple clicks", 35 | "status": "passed", 36 | "title": "counts multiple clicks" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter passes multiple snapshots in a single test", 44 | "status": "passed", 45 | "title": "passes multiple snapshots in a single test" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter renders with default props", 53 | "status": "passed", 54 | "title": "renders with default props" 55 | } 56 | ], 57 | "message": "", 58 | "name": "/src/__tests__/ClickCounter.spec.js", 59 | "status": "passed", 60 | "summary": "" 61 | } 62 | ], 63 | "wasInterrupted": false 64 | } 65 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/2-remove-test-and-update/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.spec.js src/__tests__/ 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/2-remove-test-and-update/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn run test-update 4 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/3-add-test-back-with-different-snapshot/ClickCounter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | import jestSnapshot from 'jest-snapshot'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | it('renders with default props', function () { 14 | 15 | const renderer = TestRenderer.create(); 16 | expect(renderer, 'to match snapshot'); 17 | }); 18 | 19 | it('counts a single click', function () { 20 | // This test is the one that has been added back, only this time we change the output 21 | // by adding an extra click - the test should still pass because it didn't exist on the last run, 22 | // so the snapshot should have been cleaned up 23 | const renderer = TestRenderer.create(); 24 | expect(renderer, 25 | 'with event click', 26 | 'with event click', 27 | 'to match snapshot'); 28 | }); 29 | 30 | it('counts multiple clicks', function () { 31 | const renderer = TestRenderer.create(); 32 | expect(renderer, 33 | 'with event click', 34 | 'with event click', 35 | 'with event click', 36 | 'to match snapshot'); 37 | }); 38 | 39 | it('passes multiple snapshots in a single test', function () { 40 | let renderer = TestRenderer.create(); 41 | expect(renderer, 'to match snapshot'); 42 | renderer = TestRenderer.create(); 43 | expect(renderer, 44 | 'with event click', 45 | 'with event click', 46 | 'with event click', 47 | 'to match snapshot'); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/3-add-test-back-with-different-snapshot/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 4, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "snapshot": { 12 | "added": 1, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 1, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 4, 20 | "total": 5, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts a single click", 35 | "status": "passed", 36 | "title": "counts a single click" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter counts multiple clicks", 44 | "status": "passed", 45 | "title": "counts multiple clicks" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter passes multiple snapshots in a single test", 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "ancestorTitles": [ 58 | "ClickCounter" 59 | ], 60 | "failureMessages": [], 61 | "fullName": "ClickCounter renders with default props", 62 | "status": "passed", 63 | "title": "renders with default props" 64 | } 65 | ], 66 | "message": "", 67 | "name": "/src/__tests__/ClickCounter.spec.js", 68 | "status": "passed", 69 | "summary": "" 70 | } 71 | ], 72 | "wasInterrupted": false 73 | } 74 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/3-add-test-back-with-different-snapshot/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.spec.js src/__tests__/ 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/3-add-test-back-with-different-snapshot/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn run test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/4-revalidate-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 4, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 5, 20 | "total": 5, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter counts a single click", 35 | "status": "passed", 36 | "title": "counts a single click" 37 | }, 38 | { 39 | "ancestorTitles": [ 40 | "ClickCounter" 41 | ], 42 | "failureMessages": [], 43 | "fullName": "ClickCounter counts multiple clicks", 44 | "status": "passed", 45 | "title": "counts multiple clicks" 46 | }, 47 | { 48 | "ancestorTitles": [ 49 | "ClickCounter" 50 | ], 51 | "failureMessages": [], 52 | "fullName": "ClickCounter passes multiple snapshots in a single test", 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "ancestorTitles": [ 58 | "ClickCounter" 59 | ], 60 | "failureMessages": [], 61 | "fullName": "ClickCounter renders with default props", 62 | "status": "passed", 63 | "title": "renders with default props" 64 | } 65 | ], 66 | "message": "", 67 | "name": "/src/__tests__/ClickCounter.spec.js", 68 | "status": "passed", 69 | "summary": "" 70 | } 71 | ], 72 | "wasInterrupted": false 73 | } 74 | -------------------------------------------------------------------------------- /jest-integration/tests/cleanup/4-revalidate-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/1-create-initial-snapshots/ClickCounter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | import jestSnapshot from 'jest-snapshot'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | it('renders with default props', function () { 14 | 15 | const renderer = TestRenderer.create(); 16 | expect(renderer, 'to match snapshot'); 17 | }); 18 | 19 | // We've removed all other tests, as the onClick won't work without the binding 20 | // but the point of this test it to check that the test notices the binding is gone 21 | }); 22 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/1-create-initial-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 1, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 1, 11 | "snapshot": { 12 | "added": 1, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 1, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 0, 20 | "total": 1, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter renders with default props", 35 | "status": "passed", 36 | "title": "renders with default props" 37 | } 38 | ], 39 | "message": "", 40 | "name": "/src/__tests__/ClickCounter.spec.js", 41 | "status": "passed", 42 | "summary": "" 43 | } 44 | ], 45 | "wasInterrupted": false 46 | } 47 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/1-create-initial-snapshots/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.spec.js src/__tests__/ 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/1-create-initial-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/2-remove-event-binding/ClickCounter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class ClickCounter extends Component { 5 | 6 | constructor() { 7 | super(); 8 | this.state = { count: 0 }; 9 | // For this test, we remove the onClick this binding 10 | // this.onClick = this.onClick.bind(this); 11 | } 12 | 13 | onClick() { 14 | this.setState({ 15 | count: this.state.count + 1 16 | }); 17 | } 18 | 19 | render() { 20 | return ( 21 | 22 | ); 23 | } 24 | } 25 | 26 | ClickCounter.propTypes = { 27 | className: PropTypes.string 28 | }; 29 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/2-remove-event-binding/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 1, 3 | "numFailedTests": 1, 4 | "numPassedTestSuites": 0, 5 | "numPassedTests": 0, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 1, 11 | "openHandles": [], 12 | "snapshot": { 13 | "added": 0, 14 | "didUpdate": false, 15 | "failure": true, 16 | "filesAdded": 0, 17 | "filesRemoved": 0, 18 | "filesUnmatched": 1, 19 | "filesUpdated": 0, 20 | "matched": 0, 21 | "total": 1, 22 | "unchecked": 0, 23 | "uncheckedKeysByFile": [], 24 | "unmatched": 1, 25 | "updated": 0 26 | }, 27 | "success": false, 28 | "testResults": [ 29 | { 30 | "assertionResults": [ 31 | { 32 | "ancestorTitles": [ 33 | "ClickCounter" 34 | ], 35 | "failureMessages": [ 36 | "UnexpectedError: \nexpected \n" 37 | ], 38 | "fullName": "ClickCounter renders with default props", 39 | "location": null, 40 | "status": "failed", 41 | "title": "renders with default props" 42 | } 43 | ], 44 | "message": " ● ClickCounter › renders with default props\n\n UnexpectedError: \n expected \n\n 14 | \n 15 | const renderer = TestRenderer.create();\n > 16 | expect(renderer, 'to match snapshot');\n | ^\n 17 | });\n 18 | \n 19 | // We've removed all other tests, as the onClick won't work without the binding\n", 45 | "name": "/src/__tests__/ClickCounter.spec.js", 46 | "status": "failed", 47 | "summary": "" 48 | } 49 | ], 50 | "wasInterrupted": false 51 | } 52 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/2-remove-event-binding/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.js src 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/2-remove-event-binding/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/3-update-without-binding/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 1, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 1, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": true, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 1, 19 | "matched": 0, 20 | "total": 1, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 1 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter renders with default props", 35 | "status": "passed", 36 | "title": "renders with default props" 37 | } 38 | ], 39 | "message": "", 40 | "name": "/src/__tests__/ClickCounter.spec.js", 41 | "status": "passed", 42 | "summary": "" 43 | } 44 | ], 45 | "wasInterrupted": false 46 | } 47 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/3-update-without-binding/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn run test-update 4 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/4-add-binding-back/ClickCounter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class ClickCounter extends Component { 5 | 6 | constructor() { 7 | super(); 8 | this.state = { count: 0 }; 9 | // This time the binding is back 10 | this.onClick = this.onClick.bind(this); 11 | } 12 | 13 | onClick() { 14 | this.setState({ 15 | count: this.state.count + 1 16 | }); 17 | } 18 | 19 | render() { 20 | return ( 21 | 22 | ); 23 | } 24 | } 25 | 26 | ClickCounter.propTypes = { 27 | className: PropTypes.string 28 | }; 29 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/4-add-binding-back/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 1, 3 | "numFailedTests": 1, 4 | "numPassedTestSuites": 0, 5 | "numPassedTests": 0, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 1, 11 | "openHandles": [], 12 | "snapshot": { 13 | "added": 0, 14 | "didUpdate": false, 15 | "failure": true, 16 | "filesAdded": 0, 17 | "filesRemoved": 0, 18 | "filesUnmatched": 1, 19 | "filesUpdated": 0, 20 | "matched": 0, 21 | "total": 1, 22 | "unchecked": 0, 23 | "uncheckedKeysByFile": [], 24 | "unmatched": 1, 25 | "updated": 0 26 | }, 27 | "success": false, 28 | "testResults": [ 29 | { 30 | "assertionResults": [ 31 | { 32 | "ancestorTitles": [ 33 | "ClickCounter" 34 | ], 35 | "failureMessages": [ 36 | "UnexpectedError: \nexpected \n" 37 | ], 38 | "fullName": "ClickCounter renders with default props", 39 | "location": null, 40 | "status": "failed", 41 | "title": "renders with default props" 42 | } 43 | ], 44 | "message": " ● ClickCounter › renders with default props\n\n UnexpectedError: \n expected \n\n 14 | \n 15 | const renderer = TestRenderer.create();\n > 16 | expect(renderer, 'to match snapshot');\n | ^\n 17 | });\n 18 | \n 19 | // We've removed all other tests, as the onClick won't work without the binding\n", 45 | "name": "/src/__tests__/ClickCounter.spec.js", 46 | "status": "failed", 47 | "summary": "" 48 | } 49 | ], 50 | "wasInterrupted": false 51 | } 52 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/4-add-binding-back/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.js src 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/4-add-binding-back/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/5-update-with-binding/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 1, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 1, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": true, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 1, 19 | "matched": 0, 20 | "total": 1, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 1 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter renders with default props", 35 | "status": "passed", 36 | "title": "renders with default props" 37 | } 38 | ], 39 | "message": "", 40 | "name": "/src/__tests__/ClickCounter.spec.js", 41 | "status": "passed", 42 | "summary": "" 43 | } 44 | ], 45 | "wasInterrupted": false 46 | } 47 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/5-update-with-binding/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn run test-update 4 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/6-revalidate-new-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 1, 5 | "numPassedTests": 1, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 1, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": false, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 0, 19 | "matched": 1, 20 | "total": 1, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 0 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "assertionResults": [ 29 | { 30 | "ancestorTitles": [ 31 | "ClickCounter" 32 | ], 33 | "failureMessages": [], 34 | "fullName": "ClickCounter renders with default props", 35 | "status": "passed", 36 | "title": "renders with default props" 37 | } 38 | ], 39 | "message": "", 40 | "name": "/src/__tests__/ClickCounter.spec.js", 41 | "status": "passed", 42 | "summary": "" 43 | } 44 | ], 45 | "wasInterrupted": false 46 | } 47 | -------------------------------------------------------------------------------- /jest-integration/tests/functions/6-revalidate-new-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/1-create-initial-snapshots/ClickCounter-other.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | import jestSnapshot from 'jest-snapshot'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | 14 | it('counts a single click', function () { 15 | // this test has the same name as the test in the other main spec file 16 | // but this changes the output, to ensure that the snapshots are being stored 17 | // correctly per test file 18 | const renderer = TestRenderer.create(); 19 | expect(renderer, 20 | 'with event click', 21 | 'with event click', 22 | 'to match snapshot'); 23 | }); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/1-create-initial-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 2, 5 | "numPassedTests": 5, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 2, 10 | "numTotalTests": 5, 11 | "snapshot": { 12 | "added": 6, 13 | "failure": false, 14 | "filesAdded": 2, 15 | "filesRemoved": 0, 16 | "filesUnmatched": 0, 17 | "filesUpdated": 0, 18 | "matched": 0, 19 | "total": 6, 20 | "unchecked": 0, 21 | "unmatched": 0, 22 | "updated": 0 23 | }, 24 | "success": true, 25 | "testResults": [ 26 | { 27 | "message": "", 28 | "name": "/src/__tests__/ClickCounter-other.spec.js", 29 | "summary": "", 30 | "status": "passed", 31 | "assertionResults": [ 32 | { 33 | "status": "passed", 34 | "title": "counts a single click" 35 | } 36 | ] 37 | }, 38 | { 39 | "message": "", 40 | "name": "/src/__tests__/ClickCounter.spec.js", 41 | "summary": "", 42 | "status": "passed", 43 | "assertionResults": [ 44 | { 45 | "status": "passed", 46 | "title": "counts a single click" 47 | }, 48 | { 49 | "status": "passed", 50 | "title": "counts multiple clicks" 51 | }, 52 | { 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "status": "passed", 58 | "title": "renders with default props" 59 | } 60 | ] 61 | } 62 | ], 63 | "wasInterrupted": false 64 | } 65 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/1-create-initial-snapshots/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter-other.spec.js src/__tests__/ 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/1-create-initial-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/2-validate-existing-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 2, 5 | "numPassedTests": 5, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 2, 10 | "numTotalTests": 5, 11 | "snapshot": { 12 | "added": 0, 13 | "failure": false, 14 | "filesAdded": 0, 15 | "filesRemoved": 0, 16 | "filesUnmatched": 0, 17 | "filesUpdated": 0, 18 | "matched": 6, 19 | "total": 6, 20 | "unchecked": 0, 21 | "unmatched": 0, 22 | "updated": 0 23 | }, 24 | "success": true, 25 | "testResults": [ 26 | { 27 | "message": "", 28 | "name": "/src/__tests__/ClickCounter-other.spec.js", 29 | "summary": "", 30 | "status": "passed", 31 | "assertionResults": [ 32 | { 33 | "status": "passed", 34 | "title": "counts a single click" 35 | } 36 | ] 37 | }, 38 | { 39 | "message": "", 40 | "name": "/src/__tests__/ClickCounter.spec.js", 41 | "summary": "", 42 | "status": "passed", 43 | "assertionResults": [ 44 | { 45 | "status": "passed", 46 | "title": "counts a single click" 47 | }, 48 | { 49 | "status": "passed", 50 | "title": "counts multiple clicks" 51 | }, 52 | { 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "status": "passed", 58 | "title": "renders with default props" 59 | } 60 | ] 61 | } 62 | ], 63 | "wasInterrupted": false 64 | } 65 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/2-validate-existing-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/3-change-in-code/ClickCounter-other.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | import jestSnapshot from 'jest-snapshot'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | 14 | it('counts a single click', function () { 15 | // Changing the output for this test as well, then we have two changes in two separate test files 16 | const renderer = TestRenderer.create(); 17 | expect(renderer, 18 | 'with event click', 19 | 'with event click', 20 | 'with event click', 21 | 'to match snapshot'); 22 | }); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/3-change-in-code/ClickCounter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import TestRenderer from 'react-test-renderer'; 4 | import Unexpected from 'unexpected'; 5 | import jestSnapshot from 'jest-snapshot'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-test-renderer'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | it('renders with default props', function () { 14 | 15 | const renderer = TestRenderer.create(); 16 | expect(renderer, 'to match snapshot'); 17 | }); 18 | 19 | it('counts a single click', function () { 20 | const renderer = TestRenderer.create(); 21 | expect(renderer, 'with event click', 'to match snapshot'); 22 | }); 23 | 24 | it('counts multiple clicks', function () { 25 | const renderer = TestRenderer.create(); 26 | expect(renderer, 27 | 'with event click', 28 | 'with event click', 29 | 'with event click', 30 | 'with event click', 31 | 'to match snapshot'); 32 | }); 33 | 34 | it('passes multiple snapshots in a single test', function () { 35 | let renderer = TestRenderer.create(); 36 | expect(renderer, 'to match snapshot'); 37 | renderer = TestRenderer.create(); 38 | expect(renderer, 39 | 'with event click', 40 | 'with event click', 41 | 'with event click', 42 | 'to match snapshot'); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/3-change-in-code/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.spec.js src/__tests__/ 4 | cp $1/ClickCounter-other.spec.js src/__tests__/ 5 | 6 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/3-change-in-code/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/4-update-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 2, 5 | "numPassedTests": 5, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 2, 10 | "numTotalTests": 5, 11 | "snapshot": { 12 | "added": 0, 13 | "didUpdate": true, 14 | "failure": false, 15 | "filesAdded": 0, 16 | "filesRemoved": 0, 17 | "filesUnmatched": 0, 18 | "filesUpdated": 2, 19 | "matched": 4, 20 | "total": 6, 21 | "unchecked": 0, 22 | "unmatched": 0, 23 | "updated": 2 24 | }, 25 | "success": true, 26 | "testResults": [ 27 | { 28 | "message": "", 29 | "name": "/src/__tests__/ClickCounter-other.spec.js", 30 | "summary": "", 31 | "status": "passed", 32 | "assertionResults": [ 33 | { 34 | "status": "passed", 35 | "title": "counts a single click" 36 | } 37 | ] 38 | }, 39 | { 40 | "message": "", 41 | "name": "/src/__tests__/ClickCounter.spec.js", 42 | "summary": "", 43 | "status": "passed", 44 | "assertionResults": [ 45 | { 46 | "status": "passed", 47 | "title": "counts a single click" 48 | }, 49 | { 50 | "status": "passed", 51 | "title": "counts multiple clicks" 52 | }, 53 | { 54 | "status": "passed", 55 | "title": "passes multiple snapshots in a single test" 56 | }, 57 | { 58 | "status": "passed", 59 | "title": "renders with default props" 60 | } 61 | ] 62 | } 63 | ], 64 | "wasInterrupted": false 65 | } 66 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/4-update-snapshots/no_expectation: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bruderstein/unexpected-react/e7cbb1a00de5b413147af96761007b45ec08b88f/jest-integration/tests/multiple/4-update-snapshots/no_expectation -------------------------------------------------------------------------------- /jest-integration/tests/multiple/4-update-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn run test-update 4 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/5-revalidate-snapshots/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 0, 3 | "numFailedTests": 0, 4 | "numPassedTestSuites": 2, 5 | "numPassedTests": 5, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 2, 10 | "numTotalTests": 5, 11 | "snapshot": { 12 | "added": 0, 13 | "failure": false, 14 | "filesAdded": 0, 15 | "filesRemoved": 0, 16 | "filesUnmatched": 0, 17 | "filesUpdated": 0, 18 | "matched": 6, 19 | "total": 6, 20 | "unchecked": 0, 21 | "unmatched": 0, 22 | "updated": 0 23 | }, 24 | "success": true, 25 | "testResults": [ 26 | { 27 | "message": "", 28 | "name": "/src/__tests__/ClickCounter-other.spec.js", 29 | "summary": "", 30 | "status": "passed", 31 | "assertionResults": [ 32 | { 33 | "status": "passed", 34 | "title": "counts a single click" 35 | } 36 | ] 37 | }, 38 | { 39 | "message": "", 40 | "name": "/src/__tests__/ClickCounter.spec.js", 41 | "summary": "", 42 | "status": "passed", 43 | "assertionResults": [ 44 | { 45 | "status": "passed", 46 | "title": "counts a single click" 47 | }, 48 | { 49 | "status": "passed", 50 | "title": "counts multiple clicks" 51 | }, 52 | { 53 | "status": "passed", 54 | "title": "passes multiple snapshots in a single test" 55 | }, 56 | { 57 | "status": "passed", 58 | "title": "renders with default props" 59 | } 60 | ] 61 | } 62 | ], 63 | "wasInterrupted": false 64 | } 65 | -------------------------------------------------------------------------------- /jest-integration/tests/multiple/5-revalidate-snapshots/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/tests/wrong-require/1-failures/ClickCounter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClickCounter from '../ClickCounter'; 3 | import Unexpected from 'unexpected'; 4 | import jestSnapshot from 'jest-snapshot'; 5 | import { createRenderer } from 'react-test-renderer/shallow'; 6 | 7 | import UnexpectedReact from '../../unexpected-react-non-jest'; 8 | 9 | const expect = Unexpected.clone().use(UnexpectedReact); 10 | 11 | describe('ClickCounter', function () { 12 | 13 | it('renders with default props', function () { 14 | const renderer = createRenderer(); 15 | renderer.render(); 16 | // This will fail as we've not included the unexpected-react/jest 17 | expect(renderer, 'to match snapshot'); 18 | }); 19 | 20 | it('renders with `when rendered`', function () { 21 | // This will also fail, but should include the `when rendered` message 22 | expect(, 'when rendered', 'to match snapshot'); 23 | }); 24 | 25 | it('renders with default props with to satisfy', function () { 26 | const renderer = createRenderer(); 27 | renderer.render(); 28 | // This will fail as we've not included the unexpected-react/jest 29 | expect(renderer, 'to satisfy snapshot'); 30 | }); 31 | 32 | it('renders with `when rendered to satisfy`', function () { 33 | // This will also fail, but should include the `when rendered` message 34 | expect(, 'when rendered', 'to satisfy snapshot'); 35 | }); 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /jest-integration/tests/wrong-require/1-failures/expectedOutput.json: -------------------------------------------------------------------------------- 1 | { 2 | "numFailedTestSuites": 1, 3 | "numFailedTests": 4, 4 | "numPassedTestSuites": 0, 5 | "numPassedTests": 0, 6 | "numPendingTestSuites": 0, 7 | "numPendingTests": 0, 8 | "numRuntimeErrorTestSuites": 0, 9 | "numTotalTestSuites": 1, 10 | "numTotalTests": 4, 11 | "openHandles": [], 12 | "snapshot": { 13 | "added": 0, 14 | "didUpdate": false, 15 | "failure": false, 16 | "filesAdded": 0, 17 | "filesRemoved": 0, 18 | "filesUnmatched": 0, 19 | "filesUpdated": 0, 20 | "matched": 0, 21 | "total": 0, 22 | "unchecked": 0, 23 | "uncheckedKeysByFile": [], 24 | "unmatched": 0, 25 | "updated": 0 26 | }, 27 | "success": false, 28 | "testResults": [ 29 | { 30 | "assertionResults": [ 31 | { 32 | "ancestorTitles": [ 33 | "ClickCounter" 34 | ], 35 | "failureMessages": [ 36 | "UnexpectedError: \nexpected when rendered\nTo use the `to satisfy snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require('unexpected-react/jest');`\n" 37 | ], 38 | "fullName": "ClickCounter renders with `when rendered to satisfy`", 39 | "location": null, 40 | "status": "failed", 41 | "title": "renders with `when rendered to satisfy`" 42 | }, 43 | { 44 | "ancestorTitles": [ 45 | "ClickCounter" 46 | ], 47 | "failureMessages": [ 48 | "UnexpectedError: \nexpected when rendered\nTo use the `to match snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require('unexpected-react/jest');`\n" 49 | ], 50 | "fullName": "ClickCounter renders with `when rendered`", 51 | "location": null, 52 | "status": "failed", 53 | "title": "renders with `when rendered`" 54 | }, 55 | { 56 | "ancestorTitles": [ 57 | "ClickCounter" 58 | ], 59 | "failureMessages": [ 60 | "UnexpectedError: \nTo use the `to match snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require('unexpected-react/jest');`\n" 61 | ], 62 | "fullName": "ClickCounter renders with default props", 63 | "location": null, 64 | "status": "failed", 65 | "title": "renders with default props" 66 | }, 67 | { 68 | "ancestorTitles": [ 69 | "ClickCounter" 70 | ], 71 | "failureMessages": [ 72 | "UnexpectedError: \nTo use the `to satisfy snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require('unexpected-react/jest');`\n" 73 | ], 74 | "fullName": "ClickCounter renders with default props with to satisfy", 75 | "location": null, 76 | "status": "failed", 77 | "title": "renders with default props with to satisfy" 78 | } 79 | ], 80 | "message": " ● ClickCounter › renders with default props\n\n UnexpectedError: \n To use the `to match snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require('unexpected-react/jest');`\n\n 15 | renderer.render();\n 16 | // This will fail as we've not included the unexpected-react/jest\n > 17 | expect(renderer, 'to match snapshot');\n | ^\n 18 | });\n 19 | \n 20 | it('renders with `when rendered`', function () {\n", 81 | "name": "/src/__tests__/ClickCounter.spec.js", 82 | "status": "failed", 83 | "summary": "" 84 | } 85 | ], 86 | "wasInterrupted": false 87 | } 88 | -------------------------------------------------------------------------------- /jest-integration/tests/wrong-require/1-failures/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/ClickCounter.spec.js src/__tests__/ 4 | 5 | -------------------------------------------------------------------------------- /jest-integration/tests/wrong-require/1-failures/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | yarn test 4 | -------------------------------------------------------------------------------- /jest-integration/update-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 2 ]; then 4 | echo "Usage: $0 tests// " 5 | return; 6 | fi 7 | 8 | if [ -d $1 ]; then 9 | STEPNAME=$(basename $1) 10 | TESTDIR=$(dirname $1) 11 | TESTNAME=$(basename $TESTDIR) 12 | 13 | if [ "$2" = "stderr" ]; then 14 | cp "output/$TESTNAME/$STEPNAME/stderr_clean" "tests/$TESTNAME/$STEPNAME/expected_stderr" 15 | elif [ "$2" = "json" ]; then 16 | cp "output/$TESTNAME/$STEPNAME/testRunOutput_clean.json" "tests/$TESTNAME/$STEPNAME/expectedOutput.json" 17 | elif [ "$2" = "stdout" ]; then 18 | cp "output/$TESTNAME/$STEPNAME/stdout_clean" "tests/$TESTNAME/$STEPNAME/expected_stdout" 19 | else 20 | echo "Must specify to update 'stdout', 'stderr' or 'json' as the second parameter" 21 | exit 1 22 | fi 23 | 24 | echo Updated $TESTNAME $STEPNAME; 25 | else 26 | echo Test $TESTNAME step $STEPNAME was not found 27 | fi 28 | -------------------------------------------------------------------------------- /jest-integration/useReleasedUnexpectedReact/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp $1/unexpected-react.js . 4 | cp $1/unexpected-react-test-renderer.js . 5 | yarn add unexpected-react@latest 6 | 7 | -------------------------------------------------------------------------------- /jest-integration/useReleasedUnexpectedReact/unexpected-react-test-renderer.js: -------------------------------------------------------------------------------- 1 | module.exports = require('unexpected-react/test-renderer-jest'); 2 | -------------------------------------------------------------------------------- /jest-integration/useReleasedUnexpectedReact/unexpected-react.js: -------------------------------------------------------------------------------- 1 | module.exports = require('unexpected-react/jest'); 2 | -------------------------------------------------------------------------------- /jest.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/jest'); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unexpected-react", 3 | "version": "6.0.2", 4 | "description": "Plugin for unexpected, to allow for assertions on the React.js virtual DOM, and the shallow and test renderers", 5 | "scripts": { 6 | "build": "babel src -d lib", 7 | "prepublish": "npm run build", 8 | "preparepublish": "npm run build && npm test", 9 | "test-main": "mocha --require @babel/register src/tests/general/*.spec.js src/tests/regressions/*.spec.js", 10 | "test-error": "mocha --require @babel/register src/tests/errors/*.spec.js", 11 | "test-testrenderer": "mocha --require @babel/register src/tests/testRenderer/*.spec.js", 12 | "test-documentation": "npm run test-documentation-index && npm run test-documentation-standard && npm run test-documentation-testrenderer", 13 | "test-documentation-index": "mocha --require @babel/register --require unexpected-markdown --require ./bootstrap-unexpected-markdown documentation", 14 | "test-documentation-standard": "mocha --require @babel/register --require unexpected-markdown --require ./bootstrap-unexpected-markdown --recursive documentation/assertions/ReactElement documentation/assertions/RenderedReactElement", 15 | "test-documentation-testrenderer": "mocha --require @babel/register --require unexpected-markdown --require ./bootstrap-unexpected-markdown-test-renderer --recursive documentation/assertions/ReactTestRenderer", 16 | "test-jest-integration": "cd jest-integration && ./run.sh", 17 | "test-release": "cd jest-integration && ./run.sh --use-released", 18 | "lint": "eslint src", 19 | "generate-site-reactelement": "generate-site --require ./bootstrap-documentation-generation.js --assertions assertions/ReactElement/*.md --output site-reactelement", 20 | "generate-site-renderedreactelement": "generate-site --require ./bootstrap-documentation-generation.js --assertions assertions/RenderedReactElement/*.md --output site-renderedreactelement", 21 | "generate-site-reacttestrenderer": "generate-site --require ./bootstrap-documentation-generation-testrenderer.js --assertions assertions/ReactTestRenderer/*.md --output site-testrenderer", 22 | "generate-site": "npm run generate-site-reactelement && npm run generate-site-renderedreactelement && npm run generate-site-reacttestrenderer && gulp", 23 | "deploy-site": "deploy-site.sh", 24 | "test": "npm run test-main && npm run test-testrenderer && npm run test-error && npm run test-documentation && npm run test-jest-integration", 25 | "coveralls": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- --require babel-core/register src/tests/*.spec.js &&cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage || true" 26 | }, 27 | "main": "lib/unexpected-react.js", 28 | "repository": "https://github.com/bruderstein/unexpected-react.git", 29 | "license": "MIT", 30 | "keywords": [ 31 | "unexpected-plugin", 32 | "unexpected", 33 | "testing", 34 | "react", 35 | "reactjs", 36 | "unit-test", 37 | "virtualDOM", 38 | "test", 39 | "react-test-renderer" 40 | ], 41 | "peerDependencies": { 42 | "react": "^16.9.0", 43 | "react-test-renderer": "^16.9.0" 44 | }, 45 | "devDependencies": { 46 | "@babel/cli": "^7.7.4", 47 | "@babel/core": "^7.7.4", 48 | "@babel/preset-env": "^7.7.4", 49 | "@babel/preset-react": "^7.7.4", 50 | "@babel/register": "^7.7.4", 51 | "babel-eslint": "^6.1.2", 52 | "babel-preset-react": "6.5.0", 53 | "bluebird": "^3.4.6", 54 | "coveralls": "^2.11.9", 55 | "create-react-class": "^15.6.0", 56 | "eslint": "^3.4.0", 57 | "eslint-plugin-react": "^6.2.0", 58 | "gulp": "^3.9.1", 59 | "gulp-cheerio": "^0.6.2", 60 | "gulp-file": "^0.3.0", 61 | "gulp-json-editor": "^2.2.1", 62 | "immutable": "^3.7.6", 63 | "istanbul": "^0.4.3", 64 | "jest": "^20.0.4", 65 | "jsdom": "^11.1.0", 66 | "jsdom-global": "^3.0.2", 67 | "magicpen": "^5.7.0", 68 | "mocha": "^2.3.3", 69 | "mocha-lcov-reporter": "^1.2.0", 70 | "mock-fs": "^4.2.0", 71 | "object-assign": "^4.0.1", 72 | "prop-types": "^15.5.8", 73 | "react": "^16.12.0", 74 | "react-create-class": "^1.0.0", 75 | "react-dom": "^16.12.0", 76 | "react-test-renderer": "^16.12.0", 77 | "sinon": "^1.17.6", 78 | "unexpected": "^11.0.0-4", 79 | "unexpected-documentation-site-generator": "^4.6.1", 80 | "unexpected-markdown": "^1.7.4", 81 | "unexpected-sinon": "^10.5.0" 82 | }, 83 | "dependencies": { 84 | "js-writer": "^1.3.0", 85 | "magicpen-prism": "^4.1.1", 86 | "unexpected-htmllike": "^2.2.0", 87 | "unexpected-htmllike-jsx-adapter": "^1.0.3", 88 | "unexpected-htmllike-raw-adapter": "^1.0.1", 89 | "unexpected-htmllike-reactrendered-adapter": "^4.0.0", 90 | "unexpected-htmllike-testrenderer-adapter": "^1.0.2" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /react-native.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/react-native'); 2 | -------------------------------------------------------------------------------- /src/assertions/deepAgainstRawAssertions.js: -------------------------------------------------------------------------------- 1 | import RenderHook from 'react-render-hook'; 2 | import UnexpectedHtmlLike from 'unexpected-htmllike'; 3 | import RenderedReactElementAdapter from 'unexpected-htmllike-reactrendered-adapter'; 4 | import ReactElementAdapter from 'unexpected-htmllike-jsx-adapter'; 5 | import RawAdapter from 'unexpected-htmllike-raw-adapter'; 6 | import React from 'react'; 7 | import { findDOMNode } from 'react-dom'; 8 | import AssertionGenerator from './AssertionGenerator'; 9 | import { triggerEvent } from './deepAssertions'; 10 | 11 | function checkAttached(expect) { 12 | if (!RenderHook.isAttached) { 13 | expect.errorMode = 'bubble'; 14 | expect.fail(output => { 15 | return output.error('The global rendering hook is not attached') 16 | .nl().text('This probably means React was required before unexpected-react. Check that unexpected-react is required first'); 17 | }); 18 | } 19 | } 20 | 21 | 22 | function getOptions(expect) { 23 | 24 | return { 25 | ActualAdapter: RenderedReactElementAdapter, 26 | QueryAdapter: ReactElementAdapter, 27 | ExpectedAdapter: RawAdapter, 28 | actualTypeName: 'RenderedReactElement', 29 | queryTypeName: 'ReactElement', 30 | expectedTypeName: 'ReactRawObjectElement', 31 | getRenderOutput: component => { 32 | if (component && component.element && 33 | component.data && 34 | component.data.type && 35 | component.data.nodeType) { 36 | // The component is already the data node 37 | // This can happen when mixing events and queried for 38 | return component; 39 | } 40 | checkAttached(expect); 41 | return RenderHook.findComponent(component); 42 | }, 43 | actualRenderOutputType: 'RenderedReactElementData', 44 | getDiffInputFromRenderOutput: renderOutput => renderOutput, 45 | rewrapResult: (renderer, target) => target, 46 | wrapResultForReturn: (component, target) => ((target && target.element.getPublicInstance()) || component), 47 | triggerEvent: triggerEvent.bind(null, expect), 48 | canTriggerEventsOnOutputType: true 49 | }; 50 | } 51 | 52 | function installInto(expect) { 53 | const assertionGenerator = new AssertionGenerator(getOptions(expect)); 54 | assertionGenerator.installInto(expect); 55 | 56 | expect.addAssertion(' to have been injected', function (expect) { 57 | checkAttached(expect); 58 | }); 59 | 60 | return assertionGenerator; 61 | } 62 | 63 | function installAsAlternative(expect, mainAssertionGenerator) { 64 | const generatorOptions = getOptions(expect); 65 | const assertionGenerator = new AssertionGenerator({ mainAssertionGenerator, ...generatorOptions }); 66 | assertionGenerator.installAlternativeExpected(expect); 67 | } 68 | 69 | export { installInto, installAsAlternative, triggerEvent }; 70 | -------------------------------------------------------------------------------- /src/assertions/deepAssertions.js: -------------------------------------------------------------------------------- 1 | import RenderHook from 'react-render-hook'; 2 | import UnexpectedHtmlLike from 'unexpected-htmllike'; 3 | import RenderedReactElementAdapter from 'unexpected-htmllike-reactrendered-adapter'; 4 | import ReactElementAdapter from 'unexpected-htmllike-jsx-adapter'; 5 | import React from 'react'; 6 | import TestUtils from 'react-dom/test-utils'; 7 | import { findDOMNode } from 'react-dom'; 8 | import AssertionGenerator from './AssertionGenerator'; 9 | 10 | function checkAttached(expect) { 11 | if (!RenderHook.isAttached) { 12 | expect.errorMode = 'bubble'; 13 | expect.fail(output => { 14 | return output.error('The global rendering hook is not attached') 15 | .nl().text('This probably means React was required before unexpected-react. Check that unexpected-react is required first'); 16 | }); 17 | } 18 | } 19 | 20 | function triggerEvent(expect, component, target, eventName, eventArgs) { 21 | let componentData; 22 | if (component && 23 | component.data && 24 | component.data.type && 25 | component.data.nodeType) { 26 | componentData = component; 27 | } else { 28 | componentData = RenderHook.findComponent(component); 29 | } 30 | let targetDOM = findDOMNode(componentData.internalInstance.stateNode); 31 | if (target) { 32 | targetDOM = findDOMNode(target.internalInstance.stateNode); 33 | } 34 | if (typeof TestUtils.Simulate[eventName] !== 'function') { 35 | 36 | return expect.fail({ 37 | diff: function (output) { 38 | return output.error('Event ').text("'" + eventName + "'").error(' is not supported by TestUtils.Simulate'); 39 | } 40 | }); 41 | } 42 | TestUtils.Simulate[eventName](targetDOM, eventArgs); 43 | } 44 | 45 | function installInto(expect) { 46 | 47 | const assertionGenerator = new AssertionGenerator({ 48 | ActualAdapter: RenderedReactElementAdapter, 49 | QueryAdapter: ReactElementAdapter, 50 | ExpectedAdapter: ReactElementAdapter, 51 | actualTypeName: 'RenderedReactElement', 52 | queryTypeName: 'ReactElement', 53 | expectedTypeName: 'ReactElement', 54 | getRenderOutput: component => { 55 | if (component && 56 | component.data && 57 | component.data.type && 58 | component.data.nodeType) { 59 | // The component is already the data node 60 | // This can happen when mixing events and queried for 61 | return component; 62 | } 63 | checkAttached(expect); 64 | return RenderHook.findComponent(component); 65 | }, 66 | actualRenderOutputType: 'RenderedReactElementData', 67 | getDiffInputFromRenderOutput: renderOutput => renderOutput, 68 | rewrapResult: (renderer, target) => target, 69 | wrapResultForReturn: (component, target) => ((target && target.internalInstance.stateNode) || component), 70 | triggerEvent: triggerEvent.bind(null, expect), 71 | canTriggerEventsOnOutputType: true 72 | }); 73 | assertionGenerator.installInto(expect); 74 | 75 | expect.addAssertion(' to have been injected', function (expect) { 76 | checkAttached(expect); 77 | }); 78 | 79 | class StatelessWrapper extends React.Component { 80 | render() { 81 | return this.props.children; 82 | } 83 | } 84 | 85 | expect.addAssertion(' when deeply rendered ', function (expect, subject) { 86 | let component; 87 | if (subject.type && subject.type.prototype && typeof subject.type.prototype.render === 'function') { 88 | component = TestUtils.renderIntoDocument(subject); 89 | } else { 90 | // Stateless component 91 | component = TestUtils.renderIntoDocument({subject}); 92 | component = RenderHook.findComponent(component); 93 | if (component) { 94 | component = component && component.data.children[0] && RenderHook.findInternalComponent(component.data.children[0]); 95 | } else { 96 | expect.errorMode = 'nested'; 97 | expect.fail({ 98 | message(output) { 99 | return output.error('Cannot find rendered stateless component. Are you sure you passed a real component to `when deeply rendered`'); 100 | } 101 | }); 102 | } 103 | } 104 | return expect.shift(component); 105 | }); 106 | 107 | expect.addAssertion(' to [exactly] deeply render [with all children] [with all wrappers] [with all classes] [with all attributes] as ', function (expect, subject, expected) { 108 | if (this.flags.exactly) { 109 | return expect(subject, 'when deeply rendered', 'to have exactly rendered', expected); 110 | } 111 | return expect(subject, 'when deeply rendered to have rendered [with all children] [with all wrappers] [with all classes] [with all attributes]', expected); 112 | }); 113 | } 114 | 115 | export { installInto, triggerEvent }; 116 | -------------------------------------------------------------------------------- /src/assertions/jestSnapshotStandardRendererAssertions.js: -------------------------------------------------------------------------------- 1 | import ReactRenderHook from 'react-render-hook'; 2 | import RawAdapter from 'unexpected-htmllike-raw-adapter'; 3 | import ReactElementAdapter from 'unexpected-htmllike-jsx-adapter'; 4 | import RenderedReactElementAdapter from 'unexpected-htmllike-reactrendered-adapter'; 5 | import { triggerEvent } from './shallowAssertions'; 6 | import { triggerEvent as triggerDeepEvent } from './deepAssertions' 7 | import { compareSnapshot } from '../helpers/snapshots'; 8 | 9 | 10 | function installInto(expect) { 11 | 12 | const rawAdapter = new RawAdapter({ convertToString: true, concatTextContent: true }); 13 | const shallowAdapter = new ReactElementAdapter({ convertToString: true }); 14 | const renderedReactAdapter = new RenderedReactElementAdapter({ convertToString: true, concatTextContent: true }); 15 | expect.addAssertion(' to match snapshot', 16 | function (expect, subject) { 17 | compareSnapshot(expect, this.flags, shallowAdapter, subject, subject.getRenderOutput()); 18 | } 19 | ); 20 | 21 | expect.addAssertion(' to match snapshot', 22 | function (expect, subject) { 23 | triggerEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs); 24 | expect(subject.renderer, 'to match snapshot'); 25 | } 26 | ); 27 | 28 | expect.addAssertion(' to match snapshot', 29 | function (expect, subject) { 30 | compareSnapshot(expect, this.flags, renderedReactAdapter, subject, ReactRenderHook.findComponent(subject)); 31 | } 32 | ); 33 | 34 | expect.addAssertion(' to match snapshot', 35 | function (expect, subject) { 36 | triggerDeepEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs); 37 | expect(subject.renderer, 'to match snapshot'); 38 | } 39 | ); 40 | 41 | expect.addAssertion(' to satisfy snapshot', 42 | function (expect, subject) { 43 | compareSnapshot(expect, { satisfy: true }, shallowAdapter, subject, subject.getRenderOutput()); 44 | } 45 | ); 46 | 47 | expect.addAssertion(' to satisfy snapshot', 48 | function (expect, subject) { 49 | triggerEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs); 50 | expect(subject.renderer, 'to satisfy snapshot'); 51 | } 52 | ); 53 | 54 | expect.addAssertion(' to satisfy snapshot', 55 | function (expect, subject) { 56 | compareSnapshot(expect, { satisfy: true }, renderedReactAdapter, subject, ReactRenderHook.findComponent(subject)); 57 | } 58 | ); 59 | 60 | expect.addAssertion(' to satisfy snapshot', 61 | function (expect, subject) { 62 | triggerDeepEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs); 63 | expect(subject.renderer, 'to satisfy snapshot'); 64 | } 65 | ); 66 | } 67 | 68 | module.exports = { installInto }; 69 | -------------------------------------------------------------------------------- /src/assertions/jestSnapshotTestRendererAssertions.js: -------------------------------------------------------------------------------- 1 | import { compareSnapshot } from '../helpers/snapshots'; 2 | import { triggerEvent } from './testRendererAgainstRawAssertions'; 3 | import ReactTestAdapter from 'unexpected-htmllike-testrenderer-adapter' 4 | 5 | function installInto(expect) { 6 | 7 | const reactTestAdapter = new ReactTestAdapter({ convertToString: true, concatStringContent: true }); 8 | 9 | expect.addAssertion(' to match snapshot', 10 | function (expect, subject) { 11 | compareSnapshot(expect, { }, reactTestAdapter, subject, subject.toJSON()); 12 | } 13 | ); 14 | 15 | expect.addAssertion(' to match snapshot', 16 | function (expect, subject) { 17 | triggerEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs); 18 | expect.errorMode = 'bubble'; 19 | expect(subject.renderer, 'to match snapshot'); 20 | } 21 | ); 22 | 23 | expect.addAssertion(' to satisfy snapshot', 24 | function (expect, subject) { 25 | compareSnapshot(expect, { satisfy: true }, reactTestAdapter, subject, subject.toJSON()); 26 | } 27 | ); 28 | 29 | expect.addAssertion(' to satisfy snapshot', 30 | function (expect, subject) { 31 | triggerEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs); 32 | expect.errorMode = 'bubble'; 33 | expect(subject.renderer, 'to satisfy snapshot'); 34 | } 35 | ); 36 | } 37 | 38 | module.exports = { installInto }; 39 | -------------------------------------------------------------------------------- /src/assertions/shallowAgainstRawAssertions.js: -------------------------------------------------------------------------------- 1 | import RenderHook from 'react-render-hook'; 2 | import ReactElementAdapter from 'unexpected-htmllike-jsx-adapter'; 3 | import RawAdapter from 'unexpected-htmllike-raw-adapter'; 4 | import React from 'react'; 5 | import TestUtils from 'react-dom/test-utils'; 6 | import AssertionGenerator from './AssertionGenerator'; 7 | import { triggerEvent } from './shallowAssertions'; 8 | 9 | function getOptions(expect) { 10 | return { 11 | ActualAdapter: ReactElementAdapter, 12 | QueryAdapter: ReactElementAdapter, 13 | ExpectedAdapter: RawAdapter, 14 | actualTypeName: 'ReactShallowRenderer', 15 | queryTypeName: 'ReactElement', 16 | expectedTypeName: 'ReactRawObjectElement', 17 | getRenderOutput: renderer => renderer.getRenderOutput(), 18 | actualRenderOutputType: 'ReactElement', 19 | getDiffInputFromRenderOutput: renderOutput => renderOutput, 20 | rewrapResult: (renderer, target) => target, 21 | triggerEvent: triggerEvent.bind(expect) 22 | }; 23 | } 24 | 25 | function installInto(expect) { 26 | const assertionGenerator = new AssertionGenerator(getOptions(expect)); 27 | assertionGenerator.installInto(expect); 28 | return assertionGenerator; 29 | } 30 | 31 | function installAsAlternative(expect, mainAssertionGenerator) { 32 | const generatorOptions = getOptions(expect); 33 | const assertionGenerator = new AssertionGenerator({ mainAssertionGenerator, ...generatorOptions }); 34 | assertionGenerator.installAlternativeExpected(expect); 35 | } 36 | 37 | export { installInto, installAsAlternative}; 38 | -------------------------------------------------------------------------------- /src/assertions/snapshotFunctionAssertions.js: -------------------------------------------------------------------------------- 1 | import { getFunctionArgs } from '../helpers/snapshots'; 2 | 3 | function installInto(expect) { 4 | 5 | expect.addAssertion(' to satisfy ', function (expect, subject, value) { 6 | expect(functionToString(subject), 'to equal', snapshotFunctionToString(value)); 7 | }); 8 | 9 | expect.addAssertion(' to equal ', function (expect, subject, value) { 10 | expect(functionToString(subject), 'to equal', snapshotFunctionToString(value)); 11 | }); 12 | 13 | function functionToString(func) { 14 | return `function ${func.name}(${getFunctionArgs(func)}) { /* function body */ }`; 15 | } 16 | 17 | function snapshotFunctionToString(func) { 18 | return `function ${func.name}(${func.args}) { /* function body */ }` 19 | } 20 | 21 | } 22 | 23 | module.exports = { installInto }; -------------------------------------------------------------------------------- /src/assertions/snapshotFunctionType.js: -------------------------------------------------------------------------------- 1 | import { FUNCTION_ID } from '../helpers/snapshots'; 2 | 3 | function installInto(expect) { 4 | 5 | expect.addType({ 6 | name: 'jest-snapshot-function', 7 | base: 'object', 8 | identify: function (value) { 9 | return value && typeof value === 'object' && value.$functype === FUNCTION_ID; 10 | }, 11 | inspect: function (value, depth, output) { 12 | return output.clone().text('function ').cyan(value.name).text('(').text(value.args).text(') { /* function body */ }') 13 | } 14 | }); 15 | } 16 | 17 | module.exports = { installInto }; 18 | -------------------------------------------------------------------------------- /src/assertions/testRendererAgainstRawAssertions.js: -------------------------------------------------------------------------------- 1 | import RawAdapter from 'unexpected-htmllike-raw-adapter'; 2 | import TestRendererAdapter from 'unexpected-htmllike-testrenderer-adapter'; 3 | import * as TestRendererTypeWrapper from '../types/test-renderer-type-wrapper'; 4 | import AssertionGenerator from './AssertionGenerator'; 5 | 6 | function triggerEvent(expect, renderer, target, eventName, eventArgs) { 7 | 8 | if (!target) { 9 | target = renderer.toJSON(); 10 | } 11 | 12 | const handlerPropName = 'on' + eventName[0].toUpperCase() + eventName.substr(1); 13 | const handler = target.props[handlerPropName]; 14 | if (typeof handler !== 'function') { 15 | return expect.fail({ 16 | diff: function (output) { 17 | return output.error('No handler function prop ').text("'" + handlerPropName + "'").error(' on the target element'); 18 | } 19 | }); 20 | } 21 | handler(eventArgs); 22 | return renderer; 23 | } 24 | 25 | function getOptions(expect) { 26 | return { 27 | ActualAdapter: TestRendererAdapter, 28 | ExpectedAdapter: RawAdapter, 29 | actualTypeName: 'ReactTestRenderer', 30 | expectedTypeName: 'ReactRawObjectElement', 31 | getRenderOutput: renderer => TestRendererTypeWrapper.getTestRendererOutputWrapper(renderer), 32 | actualRenderOutputType: 'ReactTestRendererOutput', 33 | getDiffInputFromRenderOutput: renderOutput => TestRendererTypeWrapper.getRendererOutputJson(renderOutput), 34 | rewrapResult: (renderer, target) => TestRendererTypeWrapper.rewrapResult(renderer, target), 35 | triggerEvent: triggerEvent.bind(expect) 36 | }; 37 | } 38 | 39 | function installInto(expect) { 40 | const assertionGenerator = new AssertionGenerator(getOptions(expect)); 41 | assertionGenerator.installInto(expect); 42 | } 43 | 44 | function installAsAlternative(expect, mainAssertionGenerator) { 45 | const generatorOptions = getOptions(expect); 46 | const assertionGenerator = new AssertionGenerator({ mainAssertionGenerator, ...generatorOptions }); 47 | assertionGenerator.installAlternativeExpected(expect); 48 | } 49 | 50 | export { installInto, installAsAlternative, triggerEvent }; 51 | -------------------------------------------------------------------------------- /src/assertions/testRendererAssertions.js: -------------------------------------------------------------------------------- 1 | import ReactElementAdapter from 'unexpected-htmllike-jsx-adapter'; 2 | import TestRendererAdapter from 'unexpected-htmllike-testrenderer-adapter'; 3 | import * as TestRendererTypeWrapper from '../types/test-renderer-type-wrapper'; 4 | import AssertionGenerator from './AssertionGenerator'; 5 | 6 | 7 | function installInto(expect) { 8 | 9 | function triggerEvent(renderer, target, eventName, eventArgs) { 10 | 11 | if (!target) { 12 | target = renderer.toJSON(); 13 | } 14 | 15 | const handlerPropName = 'on' + eventName[0].toUpperCase() + eventName.substr(1); 16 | const handler = target.props[handlerPropName]; 17 | if (typeof handler !== 'function') { 18 | return expect.fail({ 19 | diff: function (output) { 20 | return output.error('No handler function prop ').text("'" + handlerPropName + "'").error(' on the target element'); 21 | } 22 | }); 23 | } 24 | handler(eventArgs); 25 | return renderer; 26 | } 27 | 28 | const assertionGenerator = new AssertionGenerator({ 29 | ActualAdapter: TestRendererAdapter, 30 | QueryAdapter: ReactElementAdapter, 31 | ExpectedAdapter: ReactElementAdapter, 32 | actualTypeName: 'ReactTestRenderer', 33 | queryTypeName: 'ReactElement', 34 | expectedTypeName: 'ReactElement', 35 | getRenderOutput: renderer => TestRendererTypeWrapper.getTestRendererOutputWrapper(renderer), 36 | actualRenderOutputType: 'ReactTestRendererOutput', 37 | getDiffInputFromRenderOutput: renderOutput => TestRendererTypeWrapper.getRendererOutputJson(renderOutput), 38 | rewrapResult: (renderer, target) => TestRendererTypeWrapper.rewrapResult(renderer, target), 39 | triggerEvent: triggerEvent 40 | }); 41 | assertionGenerator.installInto(expect); 42 | 43 | return assertionGenerator; 44 | } 45 | 46 | export { installInto }; 47 | -------------------------------------------------------------------------------- /src/helpers/snapshotLoader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import fs from 'fs'; 4 | 5 | function defaultLoader(snapshotPath) { 6 | if (fs.statSync(snapshotPath).isFile()) { 7 | delete require.cache[snapshotPath]; 8 | return require(snapshotPath); 9 | } 10 | return null; 11 | } 12 | 13 | let loader = defaultLoader; 14 | 15 | function loadSnapshot(snapshotPath) { 16 | let content; 17 | try { 18 | if (fs.statSync(snapshotPath).isFile()) { 19 | content = loader(snapshotPath); 20 | } 21 | } catch (e) { 22 | content = null; 23 | } 24 | return content; 25 | } 26 | 27 | function injectLoader(newLoader) { 28 | loader = newLoader; 29 | } 30 | 31 | export { loadSnapshot, injectLoader }; 32 | -------------------------------------------------------------------------------- /src/jest.js: -------------------------------------------------------------------------------- 1 | import RenderHook from 'react-render-hook'; 2 | 3 | import types from './types/types'; 4 | import domTypes from './types/dom-types'; 5 | import * as deepAssertions from './assertions/deepAssertions'; 6 | import * as deepAgainstRawAssertions from './assertions/deepAgainstRawAssertions'; 7 | import * as shallowAssertions from './assertions/shallowAssertions'; 8 | import * as shallowAgainstRawAssertions from './assertions/shallowAgainstRawAssertions'; 9 | import * as jestSnapshotStandardRendererAssertions from './assertions/jestSnapshotStandardRendererAssertions'; 10 | import * as snapshotFunctionType from './assertions/snapshotFunctionType'; 11 | import * as snapshotFunctionAssertions from './assertions/snapshotFunctionAssertions'; 12 | 13 | 14 | module.exports = { 15 | name: 'unexpected-react', 16 | 17 | installInto(expect) { 18 | 19 | expect.installPlugin(require('magicpen-prism')); 20 | 21 | types.installInto(expect); 22 | domTypes.installInto(expect); 23 | const mainAssertionGenerator = shallowAssertions.installInto(expect); 24 | shallowAgainstRawAssertions.installAsAlternative(expect, mainAssertionGenerator); 25 | 26 | const deepMainAssertionGenerator = deepAssertions.installInto(expect); 27 | deepAgainstRawAssertions.installAsAlternative(expect, deepMainAssertionGenerator); 28 | jestSnapshotStandardRendererAssertions.installInto(expect); 29 | snapshotFunctionType.installInto(expect); 30 | snapshotFunctionAssertions.installInto(expect); 31 | }, 32 | 33 | clearAll() { 34 | RenderHook.clearAll(); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/react-native.js: -------------------------------------------------------------------------------- 1 | import types from './types/types'; 2 | import * as shallowAssertions from './assertions/shallowAssertions'; 3 | 4 | 5 | module.exports = { 6 | name: 'unexpected-react', 7 | 8 | installInto(expect) { 9 | 10 | expect.installPlugin(require('magicpen-prism')); 11 | 12 | types.installInto(expect); 13 | shallowAssertions.installInto(expect); 14 | 15 | expect.addAssertion(' to (match|satisfy) snapshot', function (expect) { 16 | 17 | expect.errorMode = 'bubble'; 18 | expect.fail({ 19 | message: function (output) { 20 | return output.text('To use the ') 21 | .error('`to ') 22 | .error(this.flags.match ? 'match' : 'satisfy') 23 | .error(' snapshot`') 24 | .text(' assertion with the test renderer, require unexpected-react as `require(\'unexpected-react/test-rendered-jest\');`'); 25 | } 26 | }); 27 | }); 28 | 29 | expect.addAssertion( 30 | [ 31 | ' to match snapshot', 32 | ' to satisfy snapshot' 33 | ], 34 | function (expect) { 35 | expect.errorMode = 'bubble'; 36 | expect.fail({ 37 | message: (output) => { 38 | return output.text('To use the `') 39 | .error(this.testDescription) 40 | .text('` assertion with the shallow and full DOM renderers, require unexpected-react as `require(\'unexpected-react/jest\');`'); 41 | }, 42 | diff: (output) => { 43 | return output; 44 | } 45 | }); 46 | }); 47 | }, 48 | 49 | clearAll() {} 50 | }; 51 | -------------------------------------------------------------------------------- /src/reactEventNames.js: -------------------------------------------------------------------------------- 1 | // Extracted from react-dom 3.9.3: 2 | // Object.keys(require('react-dom/lib/SimpleEventPlugin').eventTypes) 3 | export default [ 4 | 'abort', 5 | 'animationEnd', 6 | 'animationIteration', 7 | 'animationStart', 8 | 'blur', 9 | 'canPlay', 10 | 'canPlayThrough', 11 | 'click', 12 | 'contextMenu', 13 | 'copy', 14 | 'cut', 15 | 'doubleClick', 16 | 'drag', 17 | 'dragEnd', 18 | 'dragEnter', 19 | 'dragExit', 20 | 'dragLeave', 21 | 'dragOver', 22 | 'dragStart', 23 | 'drop', 24 | 'durationChange', 25 | 'emptied', 26 | 'encrypted', 27 | 'ended', 28 | 'error', 29 | 'focus', 30 | 'input', 31 | 'invalid', 32 | 'keyDown', 33 | 'keyPress', 34 | 'keyUp', 35 | 'load', 36 | 'loadedData', 37 | 'loadedMetadata', 38 | 'loadStart', 39 | 'mouseDown', 40 | 'mouseMove', 41 | 'mouseOut', 42 | 'mouseOver', 43 | 'mouseUp', 44 | 'paste', 45 | 'pause', 46 | 'play', 47 | 'playing', 48 | 'progress', 49 | 'rateChange', 50 | 'reset', 51 | 'scroll', 52 | 'seeked', 53 | 'seeking', 54 | 'stalled', 55 | 'submit', 56 | 'suspend', 57 | 'timeUpdate', 58 | 'touchCancel', 59 | 'touchEnd', 60 | 'touchMove', 61 | 'touchStart', 62 | 'transitionEnd', 63 | 'volumeChange', 64 | 'waiting', 65 | 'wheel' 66 | ]; 67 | -------------------------------------------------------------------------------- /src/test-renderer-jest.js: -------------------------------------------------------------------------------- 1 | import types from './types/types'; 2 | import * as testRendererAssertions from './assertions/testRendererAssertions'; 3 | import * as testRendererAgainstRawAssertions from './assertions/testRendererAgainstRawAssertions'; 4 | import * as jestSnapshotAssertions from './assertions/jestSnapshotTestRendererAssertions'; 5 | import * as snapshotFunctionType from './assertions/snapshotFunctionType'; 6 | import * as snapshotFunctionAssertions from './assertions/snapshotFunctionAssertions'; 7 | 8 | module.exports = { 9 | name: 'unexpected-react-test-renderer', 10 | 11 | installInto(expect) { 12 | 13 | expect.installPlugin(require('magicpen-prism')); 14 | 15 | types.installInto(expect); 16 | 17 | // This is a bit of a hack. The AssertionGenerator generates a type for context to add the pending event, 18 | // and this type must be re-used when adding further assertions with a different expected type 19 | // - in this case that's the RawAdapter type rather than the ReactElement type. 20 | 21 | // It works, but it's ugly. It would be nicer to split the AssertionGenerator out further 22 | // such that this could be less ugly - not sure how that would look though. 23 | 24 | // This /may/ be solved by the upcoming (possibly already existing!) expect.context interface. 25 | // When that's available, we won't need the intermediate type for pending events, and we can just 26 | // add the pending event to the context and have the main assertions handle it. 27 | 28 | // But we can't rely on that yet, I don't think 29 | 30 | const mainAssertionGenerator = testRendererAssertions.installInto(expect); 31 | testRendererAgainstRawAssertions.installAsAlternative(expect, mainAssertionGenerator); 32 | 33 | jestSnapshotAssertions.installInto(expect); 34 | snapshotFunctionType.installInto(expect); 35 | snapshotFunctionAssertions.installInto(expect); 36 | 37 | expect.addAssertion(' to match snapshot', function (expect, subject) { 38 | expect.errorMode = 'bubble'; 39 | expect.fail({ 40 | message: function (output) { 41 | return output.text('To assert snapshots, use the testRenderer directly, not the result of `.toJSON()`') 42 | .nl().i() 43 | .text('e.g.') 44 | .nl().i() 45 | .text(' const testRenderer = ReactTestRenderer.create();').nl().i() 46 | .text(' expect(testRenderer, \'to match snapshot\');'); 47 | } 48 | }); 49 | }); 50 | }, 51 | 52 | clearAll() { 53 | // No-op. Left in so that tests can easily use either interface 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/test-renderer.js: -------------------------------------------------------------------------------- 1 | import types from './types/types'; 2 | import * as testRendererAssertions from './assertions/testRendererAssertions'; 3 | 4 | module.exports = { 5 | name: 'unexpected-react-test-renderer', 6 | 7 | installInto(expect) { 8 | 9 | expect.installPlugin(require('magicpen-prism')); 10 | 11 | types.installInto(expect); 12 | testRendererAssertions.installInto(expect); 13 | 14 | expect.addAssertion([ 15 | ' to match snapshot', 16 | ' to satisfy snapshot', 17 | ], function (expect) { 18 | 19 | expect.errorMode = 'bubble'; 20 | expect.fail({ 21 | message: function (output) { 22 | return output.text('To use the `') 23 | .error(expect.testDescription) 24 | .text('` assertion with the test renderer, require unexpected-react as `require(\'unexpected-react/test-renderer-jest\');`'); 25 | } 26 | }); 27 | }); 28 | 29 | expect.addAssertion([ 30 | ' to match snapshot', 31 | ' to satisfy snapshot', 32 | ], function (expect) { 33 | 34 | expect.errorMode = 'bubble'; 35 | expect.fail({ 36 | message: function (output) { 37 | return output.text('To use the `') 38 | .error(expect.testDescription) 39 | .text('` assertion with the test renderer, require unexpected-react as `require(\'unexpected-react/test-renderer-jest\');`') 40 | .nl().i() 41 | .nl().i() 42 | .text('Also, don\'t pass the JSON, pass the test renderer directly'); 43 | } 44 | }); 45 | }); 46 | 47 | }, 48 | 49 | clearAll() { 50 | // No-op. Left in so that tests can easily use either interface 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /src/tests/components/ClickCounter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class ClickCounter extends Component { 5 | 6 | constructor() { 7 | super(); 8 | this.state = { count: 0 }; 9 | this.onClick = this.onClick.bind(this); 10 | } 11 | 12 | onClick() { 13 | this.setState({ 14 | count: this.state.count + 1 15 | }); 16 | } 17 | 18 | render() { 19 | 20 | // This is built like this so the prop is only defined if it's provided, so we don't even pass an undefined prop 21 | const extraProps = {}; 22 | if (this.props.ariaLabel) { 23 | extraProps.ariaLabel = this.props.ariaLabel; 24 | } 25 | 26 | return ( 27 | 30 | ); 31 | } 32 | } 33 | 34 | ClickCounter.propTypes = { 35 | className: PropTypes.string 36 | } -------------------------------------------------------------------------------- /src/tests/components/Select.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react'; 3 | import PropTypes from 'prop-types'; 4 | import SelectOption from './SelectOption'; 5 | 6 | class Select extends Component { 7 | 8 | constructor() { 9 | super(); 10 | this.state = { 11 | open: false 12 | }; 13 | 14 | this.showMenu = this.showMenu.bind(this); 15 | } 16 | 17 | showMenu() { 18 | this.setState({ 19 | open: true 20 | }); 21 | } 22 | 23 | render() { 24 | 25 | let content = null; 26 | if (this.state.open) { 27 | const options = this.props.options.map(option => 28 | 29 | ); 30 | content =
    {options}
; 31 | } else { 32 | content = this.props.selected && this.props.selected.label; 33 | } 34 | 35 | return ( 36 |
37 | {content} 38 |
39 | ); 40 | } 41 | } 42 | 43 | Select.propTypes = { 44 | options: PropTypes.array, 45 | selected: PropTypes.shape({ 46 | label: PropTypes.string 47 | }) 48 | }; 49 | 50 | module.exports = Select; -------------------------------------------------------------------------------- /src/tests/components/SelectOption.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react'; 3 | import PropTypes from 'prop-types'; 4 | 5 | class SelectOption extends Component { 6 | 7 | render() { 8 | return ( 9 |
  • 10 | {this.props.label} 11 |
  • ); 12 | } 13 | } 14 | 15 | SelectOption.propTypes = { 16 | label: PropTypes.string 17 | }; 18 | 19 | module.exports = SelectOption; -------------------------------------------------------------------------------- /src/tests/components/TwoClickCounters.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import ClickCounter from './ClickCounter'; 3 | 4 | export default class TwoClickCounters extends Component { 5 | 6 | render() { 7 | return ( 8 |
    9 | 10 | 11 |
    12 | ) 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/tests/errors/out-of-order.spec.js: -------------------------------------------------------------------------------- 1 | 2 | /* These tests check that the right error message appears when requiring the modules in the wrong order 3 | * These tests can therefore not be run in conjunction with the other tests, and must be run separately 4 | */ 5 | 6 | const EmulateDom = require( '../helpers/emulateDom'); 7 | 8 | const React = require('react'); 9 | const TestUtils = require('react-dom/test-utils'); 10 | 11 | const Unexpected = require('unexpected'); 12 | const UnexpectedReact = require('../../unexpected-react'); 13 | 14 | const expect = Unexpected.clone() 15 | .use(UnexpectedReact); 16 | 17 | class TestComp extends React.Component { 18 | render() { 19 | return
    dummy
    ; 20 | } 21 | }; 22 | 23 | const EXPECTED_ERROR_MESSAGE = `The global rendering hook is not attached 24 | This probably means React was required before unexpected-react. Check that unexpected-react is required first`; 25 | 26 | describe('unexpected-react included after react', () => { 27 | 28 | it('throws the message when asserting `React to have been injected`', () => { 29 | 30 | expect(() => expect(React, 'to have been injected'), 'to error', EXPECTED_ERROR_MESSAGE); 31 | }); 32 | 33 | describe('with `to have rendered`', () => { 34 | 35 | it('throws a helpful error message', () => { 36 | var component = TestUtils.renderIntoDocument(); 37 | 38 | expect(() => expect(component, 'to have rendered',
    dummy
    ), 'to error', EXPECTED_ERROR_MESSAGE); 39 | }); 40 | }); 41 | 42 | describe('with `to contain`', () => { 43 | 44 | it('throws a helpful error message', () => { 45 | var component = TestUtils.renderIntoDocument(); 46 | 47 | expect(() => expect(component, 'to contain',
    dummy
    ), 'to error', EXPECTED_ERROR_MESSAGE); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/tests/fixtures/functions.js: -------------------------------------------------------------------------------- 1 | 2 | function bound1() { /* stuff */ } 3 | function bound2() { return 42; } 4 | function bound3(a, b) { return a + b; } 5 | 6 | var someObject = {}; 7 | 8 | // These are all helper functions that return a new instance of a function of the given type 9 | // They are in this separate file such that when running with wallaby, they don't get instrumented (which makes them all different!) 10 | module.exports = { 11 | anonymous: () => function () { /* stuff */ }, 12 | anonymousContent: () => function () { return 42; }, 13 | anonymousContentArgs: () => function (a, b) { return a + b; }, 14 | named: () => function doStuff() { /* stuff */ }, 15 | namedContent: () => function doStuff() { return 42; }, 16 | namedContentArgs: () => function doStuff(a, b) { 17 | // comment 18 | return a + b; 19 | }, 20 | bound: () => bound1.bind(someObject), 21 | boundContent: () => bound2.bind(someObject), 22 | boundContentArgs: () => bound3.bind(someObject) 23 | }; -------------------------------------------------------------------------------- /src/tests/fixtures/multiple.snapshot: -------------------------------------------------------------------------------- 1 | exports['multi test one 1'] = { type: 'button', props: { onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 0, ' times' ] }; 2 | exports['multi test two 1'] = { type: 'button', props: { onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 1, ' times' ] }; 3 | exports['multi test two 2'] = { type: 'button', props: { onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 2, ' times' ] }; 4 | -------------------------------------------------------------------------------- /src/tests/fixtures/multipleclasses.snapshot: -------------------------------------------------------------------------------- 1 | exports['multiple classes 1'] = { 2 | type: 'button', props: { className: 'one two three', onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 0, ' times' ] 3 | } 4 | 5 | exports['multiple classes click 1'] = { 6 | type: 'button', props: { className: 'one two three', onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 1, ' times' ] 7 | } 8 | -------------------------------------------------------------------------------- /src/tests/fixtures/single.snapshot: -------------------------------------------------------------------------------- 1 | 2 | exports['single test name 1'] = { type: 'button', props: { onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 0, ' times' ] }; 3 | exports['single test name 2'] = { type: 'button', props: { onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 1, ' times' ] }; 4 | -------------------------------------------------------------------------------- /src/tests/fixtures/twoclicks.snapshot: -------------------------------------------------------------------------------- 1 | exports['two counters 1'] = { 2 | type: 'TwoClickCounters', 3 | props: {}, 4 | children: [ 5 | { type: 'div', props: {}, children: [ 6 | { type: 'ClickCounter', props: { className: 'one' }, children: 7 | [ 8 | { type: 'button', props: { className: 'one', onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 0, ' times' ] } 9 | ] 10 | }, 11 | { type: 'ClickCounter', props: { className: 'two' }, children: 12 | [ 13 | { type: 'button', props: { className: 'two', onClick: { $functype: '$FUNC$bc*(!CDKRRz195123$', name: 'bound onClick', args: '' } }, children: [ 'Clicked ', 0, ' times' ] } 14 | ] 15 | } 16 | ] 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/tests/general/Select.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a set of "normal" tests for some sample component 3 | * They are meant to demonstrate the use, but also be a check that everything works 4 | * in the context of a normal project, how people will/should use it 5 | * 6 | * These tests should never break, without breaking other more specific tests somewhere else 7 | */ 8 | 9 | const EmulateDom = require( '../helpers/emulateDom'); 10 | 11 | const Unexpected = require('unexpected'); 12 | const UnexpectedReact = require('../../unexpected-react'); 13 | 14 | const React = require('react'); 15 | const TestUtils = require('react-dom/test-utils'); 16 | const { findDOMNode } = require('react-dom'); 17 | 18 | const Select = require('./../components/Select'); 19 | const SelectOption = require('./../components/SelectOption'); 20 | 21 | const expect = Unexpected.clone() 22 | .use(UnexpectedReact); 23 | 24 | 25 | describe('Select', () => { 26 | 27 | let component; 28 | beforeEach(() => { 29 | 30 | const options = [ 31 | { label: 'one', value: 1 }, 32 | { label: 'two', value: 2 }, 33 | { label: 'three', value: 3 } 34 | ]; 35 | component = TestUtils.renderIntoDocument(