├── .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 |
Not clicked
111 |
112 |
113 | {this.state.clickTestClicked ? 'Button was clicked' : 'Not clicked'}
114 |
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 |
143 | Button was clicked { count } times
144 |
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 |
Not clicked
110 |
111 |
112 | {this.state.clickTestClicked ? 'Button was clicked' : 'Not clicked'}
113 |
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 |
142 | Button was clicked { count } times
143 |
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 one four
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 one three
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 one three
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 | one two three
49 |
50 | to have rendered one four
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 | one two three
90 |
91 | to have rendered with all children one three
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 | one two three
117 |
118 | to have exactly rendered one three
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 one four
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 one three
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 one three
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 |
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 | Button was clicked 1 times
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 |
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 | Button was clicked 1 times
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', Button was clicked 1 times );
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', Button was clicked 1 times );
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 |
Not clicked
92 |
Button was clicked
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 | one two three
48 |
49 | to have rendered one four
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 | one two three
89 |
90 | to have rendered with all children one three
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 | one two three
116 |
117 | to have exactly rendered one three
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', Button was clicked 1 times );
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 |
Not clicked
88 |
Button was clicked
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 | one two three
53 |
54 |
55 | to have rendered one four
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 | one two three
98 |
99 |
100 | to have rendered with all children one three
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 | one two three
131 |
132 |
133 | to have exactly rendered one three
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', Button was clicked 1 times );
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 `` inside the `TodoItem` with the `id` of `2`
127 |
128 | ```js
129 | expect(
130 | component,
131 | 'with event click',
132 | 'on', ,
133 | 'to contain',
134 |
135 |
136 | Completed!
137 |
138 |
139 | );
140 | ```
141 |
142 | When no `eventTarget` is specified, the event is triggered on the top level element specified in the `on` clause.
143 |
--------------------------------------------------------------------------------
/jest-integration/baseTemplate/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unexpected-react-jest-integration-tests",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "16.0.0",
7 | "react-dom": "16.0.0",
8 | "react-test-renderer": "16.0.0"
9 | },
10 | "devDependencies": {
11 | "jest": "*",
12 | "unexpected": "^10.22.2"
13 | },
14 | "scripts": {
15 | "test": "jest --ci=false --json --outputFile testRunOutput.json",
16 | "test-update": "jest --ci=false --json --outputFile testRunOutput.json -u"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/jest-integration/baseTemplate/src/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 | return (
20 | Clicked {this.state.count} times
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\n Clicked 4 times\n \nwith event click with event click 'with event click' with event click 'to match snapshot'\n\n\n Clicked 4 times // -Clicked 4 times\n // +Clicked 3 times\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 Clicked 4 times\n \n with event click with event click 'with event click' with event click 'to match snapshot'\n\n \n Clicked 4 times // -Clicked 4 times\n // +Clicked 3 times\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 | Clicked {this.state.count} times
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 to match snapshot\n\n\n Clicked 0 times\n \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 to match snapshot\n\n \n Clicked 0 times\n \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 | Clicked {this.state.count} times
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 to match snapshot\n\n\n Clicked 0 times\n \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 to match snapshot\n\n \n Clicked 0 times\n \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 |
28 | Clicked {this.state.count} times
29 |
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 = ;
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( );
36 | });
37 |
38 | it('should render a div.Select', () => {
39 |
40 | return expect(component, 'to have rendered',
);
41 | });
42 |
43 | it('should not show any options initially', () => {
44 |
45 | return expect(component, 'not to contain', );
46 | });
47 |
48 | it('should show the menu when clicked', () => {
49 |
50 | TestUtils.Simulate.click(findDOMNode(component));
51 | return expect(component, 'to have rendered',
52 |
53 |
54 |
55 |
56 |
);
57 | });
58 |
59 | it('renders the options', () => {
60 |
61 | TestUtils.Simulate.click(findDOMNode(component));
62 | return expect(component, 'to have rendered',
63 |
64 |
one
65 | two
66 | three
67 | );
68 | });
69 |
70 |
71 | it('renders a particular option with a matching id', () => {
72 |
73 | TestUtils.Simulate.click(findDOMNode(component));
74 |
75 | return expect(component, 'to contain',
76 | two
77 | );
78 | });
79 |
80 | it('renders a particular option using a regex check', function () {
81 |
82 | // Sometimes this test runs very slowly, I don't know why.
83 | // Increasing the mocha timeout here to make sure we don't get wobbly results from Travis
84 | this.timeout(5000);
85 | TestUtils.Simulate.click(findDOMNode(component));
86 |
87 | return expect(component, 'to contain',
88 | { expect.it('to match', /th/) }
89 | );
90 | });
91 |
92 | it('renders with the right class', () => {
93 |
94 | TestUtils.Simulate.click(findDOMNode(component));
95 |
96 | return expect(component, 'to contain',
97 |
98 | );
99 | });
100 | });
101 |
102 |
--------------------------------------------------------------------------------
/src/tests/general/incorrect-require/standard-instead-of-jest.spec.js:
--------------------------------------------------------------------------------
1 |
2 | import EmulateDom from '../../helpers/emulateDom';
3 |
4 | import Unexpected from 'unexpected';
5 | import UnexpectedReact from '../../../unexpected-react';
6 |
7 | import React from 'react';
8 | import TestUtils from 'react-dom/test-utils';
9 |
10 | import ClickCounter from '../../components/ClickCounter';
11 |
12 | const expect = Unexpected.clone().use(UnexpectedReact);
13 |
14 | describe('standard-instead-of-jest', function () {
15 |
16 | it('shows a helpful error message when asserting using `to match snapshot`', function () {
17 | expect(() => expect( , 'to match snapshot'), 'to throw',
18 | [
19 | 'To use the `to match snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require(\'unexpected-react/jest\');`',
20 | '',
21 | ''
22 | ].join('\n')
23 | );
24 | });
25 |
26 | it('shows a helpful error message when asserting using `to satisfy snapshot`', function () {
27 | expect(() => expect( , 'to satisfy snapshot'), 'to throw',
28 | [
29 | 'To use the `to satisfy snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require(\'unexpected-react/jest\');`',
30 | '',
31 | ''
32 | ].join('\n')
33 | );
34 | });
35 |
36 | it('shows a helpful error message after shallow rendering when asserting using `to match snapshot`', function () {
37 | expect(() => expect( , 'when rendered', 'to match snapshot'), 'to throw',
38 | [
39 | 'expected when rendered',
40 | 'To use the `to match snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require(\'unexpected-react/jest\');`',
41 | '',
42 | ''
43 | ].join('\n')
44 | );
45 | });
46 |
47 | it('shows a helpful error message when asserting using `to satisfy snapshot`', function () {
48 | expect(() => expect( , 'when rendered', 'to satisfy snapshot'), 'to throw',
49 | [
50 | 'expected when rendered',
51 | 'To use the `to satisfy snapshot` assertion with the shallow and full DOM renderers, require unexpected-react as `require(\'unexpected-react/jest\');`',
52 | '',
53 | ''
54 | ].join('\n')
55 | );
56 | });
57 |
58 | });
59 |
--------------------------------------------------------------------------------
/src/tests/helpers/emulateDom.js:
--------------------------------------------------------------------------------
1 | if (typeof document === 'undefined') {
2 |
3 | /*
4 | const jsdom = require('jsdom').JSDOM;
5 | global.document = new jsdom('');
6 | global.window = global.document.defaultView;
7 |
8 | for (let key in global.window) {
9 | if (!global[key]) {
10 | global[key] = global.window[key];
11 | }
12 | }
13 | */
14 | require('jsdom-global')();
15 | // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
16 | // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
17 |
18 | // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
19 |
20 | // MIT license
21 |
22 | (function() {
23 | var lastTime = 0;
24 | var vendors = ['ms', 'moz', 'webkit', 'o'];
25 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
26 | window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
27 | window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
28 | || window[vendors[x]+'CancelRequestAnimationFrame'];
29 | }
30 |
31 | if (!window.requestAnimationFrame)
32 | window.requestAnimationFrame = function(callback, element) {
33 | var currTime = new Date().getTime();
34 | var timeToCall = Math.max(0, 16 - (currTime - lastTime));
35 | var id = window.setTimeout(function() { callback(currTime + timeToCall); },
36 | timeToCall);
37 | lastTime = currTime + timeToCall;
38 | return id;
39 | };
40 |
41 | if (!window.cancelAnimationFrame)
42 | window.cancelAnimationFrame = function(id) {
43 | clearTimeout(id);
44 | };
45 | global.requestAnimationFrame = window.requestAnimationFrame;
46 | global.cancelAnimationFrame = window.cancelAnimationFrame;
47 | }());
48 | }
49 |
--------------------------------------------------------------------------------
/src/tests/helpers/mock-jasmine.js:
--------------------------------------------------------------------------------
1 | global.jasmine = {
2 | matchersUtil: {}
3 | };
--------------------------------------------------------------------------------
/src/tests/regressions/dangerouslySetHtml.spec.js:
--------------------------------------------------------------------------------
1 | const EmulateDom = require( '../helpers/emulateDom');
2 |
3 | const Unexpected = require('unexpected');
4 | const UnexpectedReact = require('../../unexpected-react');
5 |
6 | const React = require('react');
7 |
8 | const expect = Unexpected.clone()
9 | .use(UnexpectedReact);
10 |
11 | function MailBodyReset({ content }) {
12 | return (
13 |
17 | );
18 | }
19 |
20 | it('should dangerouslySetInnerHTML the content', () => expect(
21 | ,
22 | 'to deeply render as',
23 | Hello World'
27 | }}
28 | />
29 | ));
30 |
31 |
--------------------------------------------------------------------------------
/src/tests/regressions/issue28.spec.js:
--------------------------------------------------------------------------------
1 | const EmulateDom = require( '../helpers/emulateDom');
2 |
3 | const Unexpected = require('unexpected');
4 | const UnexpectedReact = require('../../unexpected-react');
5 |
6 | const React = require('react');
7 | const { createRenderer } = require('react-test-renderer/shallow');
8 | const Immutable = require('immutable');
9 |
10 | const expect = Unexpected
11 | .clone()
12 | .use(UnexpectedReact);
13 |
14 |
15 | function ListEntry(props) {
16 | return (
{props.name}
);
17 | }
18 | function List(props) {
19 | return (
20 |
List
21 | {props.list.map(listItem => ( ))}
22 | );
23 | }
24 |
25 | describe('issue 28 - immutable components in shallow renderer', function () {
26 |
27 | it('renders the immutable mapped components', function () {
28 |
29 | const renderer = createRenderer();
30 | const immutableList = Immutable.fromJS(['test1', 'test2']);
31 | renderer.render(
);
32 |
33 | expect(renderer, 'to have rendered',
34 |
35 |
List
36 |
37 |
38 |
39 | );
40 | });
41 |
42 | });
43 |
--------------------------------------------------------------------------------
/src/tests/regressions/issue31.spec.js:
--------------------------------------------------------------------------------
1 | const Unexpected = require('unexpected');
2 | const UnexpectedReact = require('../../unexpected-react');
3 |
4 | const expect = Unexpected
5 | .clone()
6 | .use(UnexpectedReact);
7 |
8 | describe('issue 31 - asserting on objects with no prototype', function () {
9 |
10 | it('handles objects without __prop__', function () {
11 | var result = {
12 | id: '666',
13 | name: 'Chuck Norris'
14 | };
15 | result.__proto__ = null;
16 |
17 | return expect(result, 'to satisfy', {
18 | id: '666',
19 | name: 'Chuck Norris'
20 | });
21 | });
22 |
23 | });
24 |
--------------------------------------------------------------------------------
/src/tests/regressions/issue34.spec.js:
--------------------------------------------------------------------------------
1 | import unexpectedReact from '../../unexpected-react';
2 | import React, { Component } from 'react';
3 | import { createRenderer } from 'react-test-renderer/shallow';
4 | import unexpected from 'unexpected';
5 |
6 | class Foo extends Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.state = {
11 | focus: false
12 | };
13 |
14 | this.handleFocus = this.handleFocus.bind(this);
15 | this.handleBlur = this.handleBlur.bind(this);
16 | }
17 |
18 | handleFocus(e) {
19 | this.setState({ focus: true });
20 | }
21 |
22 | handleBlur(e) {
23 | this.setState({ focus: false });
24 | }
25 |
26 | render() {
27 | const {
28 | focus
29 | } = this.state;
30 |
31 | return (
32 |
33 | {focus &&
34 |
35 | with focus
36 |
37 | }
38 |
39 | );
40 | }
41 | }
42 |
43 | const expect = unexpected
44 | .clone()
45 | .use(unexpectedReact);
46 |
47 | describe('issue 34', function () {
48 | let renderer;
49 |
50 | before(() => {
51 | expect.addAssertion('
when focussed ', (expect, renderer) => {
52 | const { props: { onFocus } } = renderer.getRenderOutput();
53 | onFocus();
54 | return expect.shift(renderer);
55 | });
56 | expect.addAssertion(' when blurred ', (expect, renderer) => {
57 | const { props: { onBlur } } = renderer.getRenderOutput();
58 | onBlur();
59 | return expect.shift(renderer);
60 | });
61 | });
62 |
63 | beforeEach(() => {
64 | renderer = createRenderer();
65 | });
66 |
67 | describe('with event', function () {
68 | it(`renders div.with-focus on focus`, function () {
69 | renderer.render( );
70 |
71 | return expect(renderer, 'with event focus', 'to contain', (
72 |
73 | with focus
74 |
75 | ));
76 | });
77 |
78 | it(`does not render div.with-focus' on blur`, function () {
79 | renderer.render( );
80 |
81 | return expect(renderer, 'with event focus', 'with event blur', 'not to contain', (
82 |
83 | ));
84 | });
85 | });
86 |
87 | describe('custom', function () {
88 | it(`renders div.with-focus on focus`, function () {
89 | renderer.render( );
90 |
91 | return expect(renderer, 'when focussed', 'to contain', (
92 |
93 | with focus
94 |
95 | ));
96 | });
97 |
98 | it(`does not render div.with-focus on blur`, function () {
99 | renderer.render( );
100 |
101 | return expect(renderer, 'when focussed', 'when blurred', 'not to contain', (
102 |
103 | ));
104 | });
105 | });
106 | });
--------------------------------------------------------------------------------
/src/tests/regressions/issue9.spec.js:
--------------------------------------------------------------------------------
1 | const EmulateDom = require( '../helpers/emulateDom');
2 |
3 | const Unexpected = require('unexpected');
4 | const UnexpectedReact = require('../../unexpected-react');
5 |
6 | const React = require('react');
7 | const PropTypes = require('prop-types');
8 | const TestUtils = require('react-dom/test-utils');
9 |
10 | const expect = Unexpected
11 | .clone()
12 | .use(UnexpectedReact);
13 |
14 | expect.output.preferredWidth = 80;
15 |
16 | /**
17 | * This is a regression test for bruderstein/unexpected-react#9
18 | * Unit tests for the issue added in unexpected-htmllike
19 | */
20 |
21 | class LiElement extends React.Component {
22 | render () {
23 | return {this.props.name} ;
24 | }
25 | }
26 |
27 | LiElement.propTypes = {
28 | name: PropTypes.string
29 | };
30 |
31 | class UlElement extends React.Component {
32 | render () {
33 | return (
34 |
35 | { this.props.items.map(i => ) }
36 |
37 | );
38 | }
39 | }
40 |
41 | UlElement.propTypes = {
42 | items: PropTypes.array
43 | };
44 |
45 |
46 | describe('Test', function () {
47 | const items = [
48 | { id: 0, name: 'Banana' },
49 | { id: 1, name: 'Chocolate' },
50 | { id: 2, name: 'Mustard' }
51 | ];
52 |
53 | it('should render liElement', function () {
54 | let component = TestUtils.renderIntoDocument(
55 |
56 | );
57 |
58 | return expect(() => expect(component, 'to have rendered with all children', (
59 |
60 | {items[0].name}
61 | {items[2].name}
62 | {items[1].name}
63 |
64 | )), 'to error',
65 | 'expected\n' +
66 | '\n' +
71 | ' \n' +
72 | ' Banana \n' +
73 | ' Chocolate \n' +
74 | ' Mustard \n' +
75 | ' \n' +
76 | ' \n' +
77 | 'to have rendered with all children \n' +
78 | '\n' +
79 | '\n' +
84 | ' \n' +
85 | ' \n' +
86 | ' Banana \n' +
87 | ' \n' +
88 | ' \n' +
89 | ' \n' +
90 | ' Chocolate // -Chocolate\n' +
91 | ' // +Mustard\n' +
92 | ' \n' +
93 | ' \n' +
94 | ' \n' +
95 | ' \n' +
96 | ' Mustard // -Mustard\n' +
97 | ' // +Chocolate\n' +
98 | ' \n' +
99 | ' \n' +
100 | ' \n' +
101 | ' ');
102 | });
103 | });
--------------------------------------------------------------------------------
/src/tests/testRenderer/dummy.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bruderstein/unexpected-react/e7cbb1a00de5b413147af96761007b45ec08b88f/src/tests/testRenderer/dummy.js
--------------------------------------------------------------------------------
/src/tests/testRenderer/incorrect-require/test-renderer-instead-of-test-renderer-jest.spec.js:
--------------------------------------------------------------------------------
1 | import Unexpected from 'unexpected';
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import ReactTestRenderer from 'react-test-renderer';
6 | import UnexpectedReactTest from '../../../test-renderer';
7 |
8 | import ClickCounter from '../../components/ClickCounter';
9 |
10 | const expect = Unexpected.clone()
11 | .installPlugin(UnexpectedReactTest);
12 |
13 | expect.output.preferredWidth = 80;
14 |
15 | describe('test-renderer-instead-of-test-renderer-jest', function () {
16 |
17 | it('shows a helpful error message when asserting using `to match snapshot`', function () {
18 | const testRenderer = ReactTestRenderer.create( );
19 | expect(() => expect(testRenderer, 'to match snapshot'), 'to throw',
20 | 'To use the `to match snapshot` assertion with the test renderer, require unexpected-react as `require(\'unexpected-react/test-renderer-jest\');`'
21 | );
22 | });
23 |
24 | it('shows a helpful error message when asserting using `to satisfy snapshot`', function () {
25 | const testRenderer = ReactTestRenderer.create( );
26 | expect(() => expect(testRenderer, 'to satisfy snapshot'), 'to throw',
27 | 'To use the `to satisfy snapshot` assertion with the test renderer, require unexpected-react as `require(\'unexpected-react/test-renderer-jest\');`'
28 | );
29 | });
30 |
31 | it('shows a helpful error message when asserting using `to match snapshot` and the JSON output', function () {
32 | const testRenderer = ReactTestRenderer.create( );
33 | expect(() => expect(testRenderer.toJSON(), 'to match snapshot'), 'to throw',
34 | [
35 | 'To use the `to match snapshot` assertion with the test renderer, require unexpected-react as `require(\'unexpected-react/test-renderer-jest\');`',
36 | '',
37 | 'Also, don\'t pass the JSON, pass the test renderer directly'
38 | ].join('\n')
39 | );
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/src/types/dom-types.js:
--------------------------------------------------------------------------------
1 | import GlobalHook from 'react-render-hook';
2 | import React from 'react';
3 | import UnexpectedHtmlLike from 'unexpected-htmllike';
4 | import RenderedReactElementAdapter from 'unexpected-htmllike-reactrendered-adapter';
5 |
6 | function installInto(expect) {
7 |
8 | const renderedReactElementAdapter = new RenderedReactElementAdapter({
9 | convertToString: true,
10 | concatTextContent: true
11 | });
12 | const htmlLikeRenderedReactElement = UnexpectedHtmlLike(renderedReactElementAdapter);
13 |
14 | expect.addType({
15 |
16 | name: 'RenderedReactElement',
17 |
18 | identify(value) {
19 | return (typeof value === 'object' &&
20 | value !== null &&
21 | (value._reactInternalInstance || value._reactInternalComponent) &&
22 | (typeof value.setState === 'function' || typeof value.updater === 'object' /* stateless components */));
23 | },
24 |
25 | inspect(value, depth, output, inspect) {
26 | const data = GlobalHook.findComponent(value);
27 | return htmlLikeRenderedReactElement.inspect(data, depth, output, inspect);
28 | }
29 | });
30 |
31 | expect.addType({
32 | name: 'RenderedReactElementData',
33 |
34 | identify(value) {
35 |
36 | return (typeof value === 'object' &&
37 | value !== null &&
38 | value.internalInstance &&
39 | value.data &&
40 | value.data.type &&
41 | value.data.nodeType);
42 | },
43 |
44 | inspect(value, depth, output, inspect) {
45 | return htmlLikeRenderedReactElement.inspect(value, depth, output, inspect);
46 | }
47 | });
48 | }
49 |
50 | export default { installInto };
51 |
--------------------------------------------------------------------------------
/src/types/test-renderer-type-wrapper.js:
--------------------------------------------------------------------------------
1 | const TEST_RENDER_OUTPUT = { renderOutput: 'Dummy object value to identify test renderer output JSON' };
2 |
3 | function getTestRendererOutputWrapper(testRenderer) {
4 | return {
5 | _isTestRenderOutput: TEST_RENDER_OUTPUT,
6 | json: testRenderer.toJSON(),
7 | renderer: testRenderer // We keep the renderer around, so we can reuse the renderer for further events
8 | };
9 | }
10 |
11 | function isTestRendererOutputWrapper(value) {
12 | return value && typeof value === 'object' &&
13 | value._isTestRenderOutput === TEST_RENDER_OUTPUT;
14 | }
15 |
16 | function getRendererOutputJson(value) {
17 | return value.json;
18 | }
19 |
20 | function rewrapResult(wrapper, newJson) {
21 | return {
22 | _isTestRenderOutput: TEST_RENDER_OUTPUT,
23 | json: newJson,
24 | renderer: wrapper.renderer
25 | };
26 | }
27 |
28 | export {
29 | getTestRendererOutputWrapper,
30 | isTestRendererOutputWrapper,
31 | getRendererOutputJson,
32 | rewrapResult
33 | };
34 |
--------------------------------------------------------------------------------
/src/types/types.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import UnexpectedHtmlLike from 'unexpected-htmllike';
3 | import ReactElementAdapter from 'unexpected-htmllike-jsx-adapter';
4 | import TestRendererAdapter from 'unexpected-htmllike-testrenderer-adapter';
5 | import RawAdapter from 'unexpected-htmllike-raw-adapter';
6 | import * as TestRendererTypeWrapper from './test-renderer-type-wrapper';
7 |
8 | function installInto(expect) {
9 |
10 | const reactElementAdapter = new ReactElementAdapter({ convertToString: true, concatTextContent: true });
11 | const htmlLikeReactElement = UnexpectedHtmlLike(reactElementAdapter);
12 | const testRendererAdapter = new TestRendererAdapter({ convertToString: true, concatTextContent: true });
13 | const htmlLikeTestRenderer = UnexpectedHtmlLike(testRendererAdapter);
14 | const rawAdapter = new RawAdapter({ convertToString: true, concatTextContent: true });
15 | const htmlLikeRaw = UnexpectedHtmlLike(rawAdapter);
16 |
17 |
18 | expect.addType({
19 | name: 'ReactElement',
20 |
21 | identify: function (value) {
22 | return React.isValidElement(value) ||
23 | (typeof value === 'object' &&
24 | value !== null &&
25 | (typeof value.type === 'function' || typeof value.type === 'string') &&
26 | typeof value.hasOwnProperty === 'function' &&
27 | value.hasOwnProperty('props') &&
28 | value.hasOwnProperty('ref') &&
29 | value.hasOwnProperty('key'));
30 | },
31 |
32 | inspect: function (value, depth, output, inspect) {
33 |
34 | return htmlLikeReactElement.inspect(value, depth, output, inspect);
35 | }
36 | });
37 |
38 |
39 | expect.addType({
40 |
41 | name: 'ReactModule',
42 |
43 | identify(value) {
44 |
45 | return (typeof value === 'object' &&
46 | value !== null &&
47 | typeof value.hasOwnProperty === 'function' &&
48 | value.hasOwnProperty('createElement') &&
49 | value.hasOwnProperty('cloneElement') &&
50 | value.hasOwnProperty('createFactory') &&
51 | value.hasOwnProperty('isValidElement'));
52 | },
53 |
54 | inspect(value, depth, output) {
55 | output.text('<>');
56 | }
57 |
58 | });
59 |
60 |
61 | expect.addType({
62 | name: 'ReactShallowRenderer',
63 | base: 'object',
64 | identify: function (value) {
65 | return typeof value === 'object' &&
66 | value !== null &&
67 | typeof value.getRenderOutput === 'function';
68 | },
69 |
70 | inspect: function (value, depth, output, inspect) {
71 | output.append(inspect(value.getRenderOutput()));
72 | }
73 | });
74 |
75 |
76 |
77 | expect.addType({
78 | name: 'ReactTestRenderer',
79 | base: 'object',
80 | identify: function (value) {
81 | return value && typeof value === 'object' &&
82 | typeof value.hasOwnProperty === 'function' &&
83 | typeof value.toJSON === 'function' &&
84 | typeof value.unmount === 'function' &&
85 | typeof value.update === 'function' &&
86 | typeof value.getInstance === 'function';
87 | },
88 |
89 | inspect: function (value, depth, output, inspect) {
90 | output.append(inspect(TestRendererTypeWrapper.getTestRendererOutputWrapper(value)));
91 | }
92 | });
93 |
94 | expect.addType({
95 | name: 'ReactTestRendererOutput',
96 | base: 'object',
97 | identify: function (value) {
98 | return TestRendererTypeWrapper.isTestRendererOutputWrapper(value);
99 | },
100 |
101 | inspect: function (value, depth, output, inspect) {
102 | return htmlLikeTestRenderer.inspect(TestRendererTypeWrapper.getRendererOutputJson(value), depth, output, inspect);
103 | }
104 | });
105 |
106 | expect.addType({
107 | name: 'RawReactTestRendererJson',
108 | base: 'object',
109 | identify: function (value) {
110 | return value && typeof value === 'object' && value.props && value.children && value.type;
111 | }
112 | });
113 |
114 | expect.addType({
115 | name: 'ReactRawObjectElement',
116 | base: 'RawReactTestRendererJson',
117 | identify: function (value) {
118 | return rawAdapter.isRawElement(value);
119 | },
120 |
121 | inspect: function (value, depth, output, inspect) {
122 | return htmlLikeRaw.inspect(value, depth, output, inspect);
123 | }
124 | });
125 |
126 | }
127 |
128 | export default { installInto };
129 |
--------------------------------------------------------------------------------
/src/unexpected-react.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 shallowAssertions from './assertions/shallowAssertions';
7 |
8 |
9 | module.exports = {
10 | name: 'unexpected-react',
11 |
12 | installInto(expect) {
13 |
14 | expect.installPlugin(require('magicpen-prism'));
15 |
16 | types.installInto(expect);
17 | domTypes.installInto(expect);
18 | shallowAssertions.installInto(expect);
19 | deepAssertions.installInto(expect);
20 |
21 | expect.addAssertion(' to (match|satisfy) snapshot', function (expect) {
22 |
23 | expect.errorMode = 'bubble';
24 | expect.fail({
25 | message: function (output) {
26 | return output.text('To use the ')
27 | .error('`to ')
28 | .error(this.flags.match ? 'match' : 'satisfy')
29 | .error(' snapshot`')
30 | .text(' assertion with the test renderer, require unexpected-react as `require(\'unexpected-react/test-rendered-jest\');`');
31 | }
32 | });
33 | });
34 |
35 | expect.addAssertion(
36 | [
37 | ' to match snapshot',
38 | ' to satisfy snapshot'
39 | ],
40 | function (expect) {
41 | expect.errorMode = 'bubble';
42 | expect.fail({
43 | message: (output) => {
44 | return output.text('To use the `')
45 | .error(this.testDescription)
46 | .text('` assertion with the shallow and full DOM renderers, require unexpected-react as `require(\'unexpected-react/jest\');`');
47 | },
48 | diff: (output) => {
49 | return output;
50 | }
51 | });
52 | });
53 | },
54 |
55 | clearAll() {
56 | RenderHook.clearAll();
57 | }
58 | };
59 |
--------------------------------------------------------------------------------
/test-renderer-jest.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/test-renderer-jest');
--------------------------------------------------------------------------------
/test-renderer.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/test-renderer');
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --timeout 10000
2 |
--------------------------------------------------------------------------------
/wallaby-testrenderer.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var Babel = require('babel-core');
4 |
5 | module.exports = function (wallaby) {
6 |
7 | return {
8 | files: [
9 | {
10 | pattern: 'src/tests/fixtures/*.js',
11 | instrument: false
12 | },
13 | 'src/**/*.js',
14 | {
15 | pattern: 'src/tests/**/*.spec.js',
16 | ignore: true
17 | },
18 | {
19 | pattern: 'src/tests/fixtures/*.snapshot',
20 | instrument: false
21 | },
22 | {
23 | pattern: 'src/react-devtools/**/*.js',
24 | instrument: false
25 | },
26 | {
27 | pattern: 'src/tests/helpers/**/*.js',
28 | instrument: false
29 | },
30 | {
31 | pattern: 'src/react-devtools/frontend/**/*.js',
32 | ignore: true
33 | },
34 | {
35 | pattern: 'src/react-devtools/plugins/**/*.js',
36 | ignore: true
37 | }],
38 |
39 | tests: ['src/tests/testRenderer/**/*.spec.js'],
40 | env: {
41 | type: 'node',
42 | runner: 'node'
43 | },
44 | debug:true,
45 |
46 | compilers: {
47 | 'src/**/*.js': wallaby.compilers.babel({
48 | babel: Babel
49 | }),
50 | 'src/**/*.jsx': wallaby.compilers.babel({
51 | babel: Babel
52 | })
53 | }
54 | };
55 | };
56 |
--------------------------------------------------------------------------------
/wallaby.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var Babel = require('babel-core');
4 |
5 | module.exports = function (wallaby) {
6 |
7 | return {
8 | files: [
9 | {
10 | pattern: 'src/tests/fixtures/*.js',
11 | instrument: false
12 | },
13 | 'src/**/*.js',
14 | {
15 | pattern: 'src/tests/fixtures/*.snapshot',
16 | instrument: false
17 | },
18 | {
19 | pattern: 'src/tests/**/*.spec.js',
20 | ignore: true
21 | },
22 | {
23 | pattern: 'src/tests/helpers/**/*.js',
24 | instrument: false
25 | },
26 | {
27 | pattern: 'src/react-devtools/**/*.js',
28 | instrument: false
29 | },
30 | {
31 | pattern: 'src/react-devtools/frontend/**/*.js',
32 | ignore: true
33 | },
34 | {
35 | pattern: 'src/react-devtools/plugins/**/*.js',
36 | ignore: true
37 | }],
38 |
39 | tests: ['src/tests/general/**/*.spec.js', 'src/tests/regressions/**/*.spec.js'],
40 | env: {
41 | type: 'node',
42 | runner: 'node'
43 | },
44 |
45 | compilers: {
46 | 'src/**/*.js': wallaby.compilers.babel({
47 | babel: Babel
48 | }),
49 | 'src/**/*.jsx': wallaby.compilers.babel({
50 | babel: Babel
51 | })
52 | }
53 | };
54 | };
55 |
--------------------------------------------------------------------------------