38 | );
39 | }
40 |
41 | export function Stateless({ msg }) {
42 | return {msg}
43 | }
44 |
45 | export function StatelessWrapper({ msg }) {
46 | return ;
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/jest-integration/baseTemplate/src/__tests__/ClickCounter.spec.js:
--------------------------------------------------------------------------------
1 | import Preact, { h } from 'preact';
2 | import ClickCounter from '../ClickCounter';
3 | import Unexpected from 'unexpected';
4 |
5 | import UnexpectedPreact from '../../unexpected-preact';
6 |
7 | const expect = Unexpected.clone().use(UnexpectedPreact);
8 |
9 | describe('ClickCounter', function () {
10 |
11 | it('renders with default props', function () {
12 | expect(, 'when rendered', 'to match snapshot');
13 | });
14 |
15 | it('counts a single click', function () {
16 | expect(,
17 | 'when rendered',
18 | 'with event', 'click', 'to match snapshot');
19 | });
20 |
21 | it('counts multiple clicks', function () {
22 | expect(,
23 | 'when rendered',
24 | 'with event', 'click',
25 | 'with event', 'click',
26 | 'with event', 'click',
27 | 'to match snapshot');
28 | });
29 |
30 | it('passes multiple snapshots in a single test', function () {
31 | expect(, 'when rendered', 'to match snapshot');
32 | expect(,
33 | 'when rendered',
34 | 'with event', 'click',
35 | 'with event', 'click',
36 | 'with event', 'click',
37 | 'to match snapshot');
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/jest-integration/tests/basics/3-change-in-code/ClickCounter.spec.js:
--------------------------------------------------------------------------------
1 | import Preact, { h } from 'preact';
2 | import ClickCounter from '../ClickCounter';
3 | import Unexpected from 'unexpected';
4 |
5 | import UnexpectedPreact from '../../unexpected-preact';
6 |
7 | const expect = Unexpected.clone().use(UnexpectedPreact);
8 |
9 | describe('ClickCounter', function () {
10 |
11 | it('renders with default props', function () {
12 | expect(, 'when rendered', 'to match snapshot');
13 | });
14 |
15 | it('counts a single click', function () {
16 | expect(,
17 | 'when rendered',
18 | 'with event', 'click', 'to match snapshot');
19 | });
20 |
21 | it('counts multiple clicks', function () {
22 | expect(,
23 | 'when rendered',
24 | 'with event', 'click',
25 | 'with event', 'click',
26 | 'with event', 'click',
27 | 'with event', 'click',
28 | 'to match snapshot');
29 | });
30 |
31 | it('passes multiple snapshots in a single test', function () {
32 | expect(, 'when rendered', 'to match snapshot');
33 | expect(,
34 | 'when rendered',
35 | 'with event', 'click',
36 | 'with event', 'click',
37 | 'with event', 'click',
38 | 'to match snapshot');
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/jest-integration/tests/multiple/3-change-in-code/ClickCounter.spec.js:
--------------------------------------------------------------------------------
1 | import Preact, { h } from 'preact';
2 | import ClickCounter from '../ClickCounter';
3 | import Unexpected from 'unexpected';
4 |
5 | import UnexpectedPreact from '../../unexpected-preact';
6 |
7 | const expect = Unexpected.clone().use(UnexpectedPreact);
8 |
9 | describe('ClickCounter', function () {
10 |
11 | it('renders with default props', function () {
12 | expect(, 'when rendered', 'to match snapshot');
13 | });
14 |
15 | it('counts a single click', function () {
16 | expect(,
17 | 'when rendered',
18 | 'with event', 'click', 'to match snapshot');
19 | });
20 |
21 | it('counts multiple clicks', function () {
22 | expect(,
23 | 'when rendered',
24 | 'with event', 'click',
25 | 'with event', 'click',
26 | 'with event', 'click',
27 | 'with event', 'click',
28 | 'to match snapshot');
29 | });
30 |
31 | it('passes multiple snapshots in a single test', function () {
32 | expect(, 'when rendered', 'to match snapshot');
33 | expect(,
34 | 'when rendered',
35 | 'with event', 'click',
36 | 'with event', 'click',
37 | 'with event', 'click',
38 | 'to match snapshot');
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/src/unexpected-preact.js:
--------------------------------------------------------------------------------
1 | import types from './types/types';
2 | import * as deepAssertions from './assertions/deepAssertions';
3 |
4 |
5 | const Preact = require('preact');
6 | Preact.options.debounceRendering = function (fn) { return fn(); };
7 |
8 |
9 |
10 | module.exports = {
11 | name: 'unexpected-preact',
12 |
13 | installInto(expect) {
14 |
15 | expect.installPlugin(require('magicpen-prism'));
16 |
17 | types.installInto(expect);
18 | deepAssertions.installInto(expect);
19 |
20 |
21 | expect.addAssertion([
22 | ' to match snapshot',
23 | ' to match snapshot',
24 | ' to satisfy snapshot',
25 | ' to satisfy snapshot'
26 | ],
27 | function (expect) {
28 | expect.errorMode = 'bubble';
29 | expect.fail({
30 | message: function (output) {
31 | return output.error('To use snapshot assertions in jest, use \'unexpected-preact/jest\' to require or import unexpected-preact');
32 | },
33 | diff: function (output) {
34 | return output.error('To use snapshot assertions in jest, use \'unexpected-preact/jest\' to require or import unexpected-preact');
35 | }
36 | });
37 | }
38 | );
39 | },
40 |
41 | };
42 |
--------------------------------------------------------------------------------
/jest-integration/tests/wrong-require/1-failures/ClickCounter.spec.js:
--------------------------------------------------------------------------------
1 | import Preact, { h } from 'preact';
2 | import ClickCounter from '../ClickCounter';
3 | import Unexpected from 'unexpected';
4 |
5 | import UnexpectedPreact from '../../unexpected-preact-non-jest';
6 |
7 | const expect = Unexpected.clone().use(UnexpectedPreact);
8 |
9 | describe('ClickCounter', function () {
10 |
11 | it('renders with default props', function () {
12 | // This will fail as we've not included the unexpected-react/jest
13 | const container = document.createElement('div');
14 | const instance = Preact.render(, container);
15 | expect(instance, 'to match snapshot');
16 | });
17 |
18 | it('renders with `when rendered`', function () {
19 | // This will also fail, but should include the `when rendered` message
20 | expect(, 'when rendered', 'to match snapshot');
21 | });
22 |
23 | it('renders with default props with to satisfy', function () {
24 | const container = document.createElement('div');
25 | const instance = Preact.render(, container);
26 | // This will fail as we've not included the unexpected-react/jest
27 | expect(instance, 'to satisfy snapshot');
28 | });
29 |
30 | it('renders with `when rendered to satisfy`', function () {
31 | // This will also fail, but should include the `when rendered` message
32 | expect(, 'when rendered', 'to satisfy snapshot');
33 | });
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/documentation/assertions/PreactElement/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 container DOM node by hand:
21 | ```js
22 | expect(,
23 | 'when rendered',
24 | 'to have rendered',
25 |
15 | );
16 | }
17 | };
18 |
19 | ```
20 |
21 | ```js
22 | // This will pass, as `two` can be found in the component's output
23 | expect(,
24 | 'when rendered',
25 | 'to contain', two);
26 | ```
27 |
28 | Notice that the extra `className="middle"` in the `two` is ignored,
29 | in a similar way to the `to have rendered` assertion.
30 |
31 | You can override this behaviour by using `'to contain exactly'`, and `'to contain with all children'`
32 |
33 |
34 | ```js
35 | // This will fail, as `two` cannot be found in the renderers output, due to
36 | // the missing `className="middle"` prop
37 | expect(,
38 | 'when rendered',
39 | 'to contain exactly', two);
40 | ```
41 |
42 | ```output
43 | expected
44 |
45 |
46 | one
47 | two
48 | three
49 |
50 |
51 | to contain exactly two
52 |
53 | the best match was
54 |
56 | two
57 |
58 | ```
59 |
60 | The same thing applies to children for `'to contain'` as for `'to have rendered'`.
61 |
62 |
--------------------------------------------------------------------------------
/src/assertions/jestSnapshotStandardRendererAssertions.js:
--------------------------------------------------------------------------------
1 | import RawAdapter from 'unexpected-htmllike-raw-adapter';
2 | import PreactElementAdapter from 'unexpected-htmllike-preact-adapter';
3 | import PreactRenderedAdapter from 'unexpected-htmllike-preactrendered-adapter';
4 | import { triggerEvent } from './deepAssertions'
5 | import { compareSnapshot } from '../helpers/snapshots';
6 |
7 |
8 | function installInto(expect) {
9 |
10 | const rawAdapter = new RawAdapter({ convertToString: true, concatTextContent: true });
11 | const preactAdapter = new PreactElementAdapter({ convertToString: true });
12 | const renderedPreactAdapter = new PreactRenderedAdapter({ convertToString: true, concatTextContent: true });
13 |
14 | expect.addAssertion(' to match snapshot',
15 | function (expect, subject) {
16 | compareSnapshot(expect, this.flags, renderedPreactAdapter, subject, PreactRenderedAdapter.wrapRootNode(subject));
17 | }
18 | );
19 |
20 | expect.addAssertion(' to match snapshot',
21 | function (expect, subject) {
22 | triggerEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs);
23 | expect(subject.renderer, 'to match snapshot');
24 | }
25 | );
26 |
27 | expect.addAssertion(' to satisfy snapshot',
28 | function (expect, subject) {
29 | compareSnapshot(expect, { satisfy: true }, renderedPreactAdapter, subject, PreactRenderedAdapter.wrapRootNode(subject));
30 | }
31 | );
32 |
33 | expect.addAssertion(' to satisfy snapshot',
34 | function (expect, subject) {
35 | triggerEvent(expect, subject.renderer, subject.target, subject.eventName, subject.eventArgs);
36 | expect(subject.renderer, 'to satisfy snapshot');
37 | }
38 | );
39 | }
40 |
41 | module.exports = { installInto };
42 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unexpected-preact",
3 | "version": "2.0.4",
4 | "description": "Assertion library for preact.js - sister project to unexpected-react",
5 | "main": "lib/unexpected-preact.js",
6 | "repository": "https://github.com/bruderstein/unexpected-preact.git",
7 | "scripts": {
8 | "test": "mocha --compilers js:babel-register src/**/*.spec.js",
9 | "integration-test": "cd jest-integration && ./run.sh",
10 | "build": "babel src -d lib --source-maps",
11 | "prepublish": "npm run build",
12 | "generate-site": "generate-site --require ./bootstrap-documentation-generation.js",
13 | "deploy-site": "deploy-site.sh"
14 | },
15 | "keywords": [
16 | "preact",
17 | "preact.js",
18 | "testing",
19 | "unit test",
20 | "assertion"
21 | ],
22 | "author": "Dave Brotherstone",
23 | "license": "MIT",
24 | "dependencies": {
25 | "js-writer": "^1.2.0",
26 | "magicpen-prism": "^2.3.0",
27 | "unexpected-htmllike": "^2.1.2",
28 | "unexpected-htmllike-preact-adapter": "^1.2.2",
29 | "unexpected-htmllike-preactrendered-adapter": "^1.3.0",
30 | "unexpected-htmllike-raw-adapter": "^1.0.1"
31 | },
32 | "devDependencies": {
33 | "babel-cli": "^6.24.1",
34 | "babel-core": "^6.9.1",
35 | "babel-plugin-transform-object-rest-spread": "^6.23.0",
36 | "babel-preset-es2015": "^6.9.0",
37 | "babel-preset-react": "^6.5.0",
38 | "babel-register": "^6.24.0",
39 | "bluebird": "^3.5.0",
40 | "jest-matchers": "^19.0.0",
41 | "jsdom": "^9.12.0",
42 | "mocha": "^3.2.0",
43 | "mock-fs": "^4.2.0",
44 | "preact": "^8.1.0",
45 | "preact-compat": "^3.15.0",
46 | "sinon": "^2.1.0",
47 | "unexpected": "^10.26.3",
48 | "unexpected-documentation-site-generator": "^4.4.0",
49 | "unexpected-markdown": "^1.7.2",
50 | "unexpected-sinon": "^10.7.1"
51 | },
52 | "peerDependencies": {
53 | "preact": ">= 7.0.0 <= 9.0.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/documentation/assertions/RenderedPreactElement/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-preact` 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-preact as `require('unexpected-preact/jest')`
4 |
5 |
6 | ```js
7 | class MyComponent extends Component {
8 | render () {
9 | return (
10 |
11 | one
12 | two
13 | three
14 |
15 | );
16 | }
17 | }
18 | ```
19 |
20 |
21 | We can validate it matches the snapshot when it's rendered. If no snapshot exists, it will be automatically created the first time it is run.
22 |
23 | ```js#evaluate:false
24 | expect(, 'when rendered', 'to match snapshot');
25 | ```
26 |
27 | If in the future the component output changes, the error will be highlighted (using the same error highlighting used in the rest of unexpected-preact).
28 |
29 | 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`.
30 |
31 | ### Events
32 | Triggered events still works, and can be combined with matching snaphots.
33 |
34 | e.g.
35 |
36 | ```js#evaluate:false
37 |
38 | expect(,
39 | 'when rendered',
40 | 'with event click',
41 | 'to match snapshot'
42 | );
43 | ```
44 |
45 | ### Matching
46 |
47 | 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`.
48 |
49 |
--------------------------------------------------------------------------------
/documentation/assertions/RenderedPreactElement/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 | expect(
7 |
8 |
9 |
10 |
11 | ,
12 | 'when rendered',
13 | 'queried for',
14 |
15 | {3}
16 |
,
17 | 'to have rendered',
18 |
19 | Buy groceries
20 |
21 | );
22 | ```
23 |
24 | Here we're searching for a `div` representing a todo item with the id 3. Because
25 | props are checked with `to satisfy`, extra data in this object is ignored.
26 |
27 | You can use `to have rendered` or `to contain` with all the options as usual following a `queried for`.
28 |
29 | It is also possible to extract the found component, by using the value of the returned promise from `expect`.
30 |
31 |
32 | ```js#async:true
33 | return expect(
34 |
35 |
36 |
37 |
38 | ,
39 | 'when rendered',
40 | 'queried for',
41 |
42 | ).then(todoItem => {
43 | expect(todoItem.props.label, 'to equal', 'Buy groceries');
44 | });
45 | ```
46 |
47 | ## queryTarget
48 |
49 | If you want to find a target nested inside a parent element, use `queryTarget` in the query.
50 | e.g. This `queried for` clause returns the `span` inside the `TodoItem`
51 |
52 | ```js
53 | expect(
54 |
55 |
56 |
57 |
58 | ,
59 | 'queried for',
60 |
61 |
62 |
63 |
64 | ,
65 | 'to have rendered',
66 | Buy groceries
67 | );
68 | ```
69 |
--------------------------------------------------------------------------------
/documentation/assertions/RenderedPreactElement/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-preact` 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-preact as `require('unexpected-preact/jest')`
4 |
5 | ```js
6 | class MyComponent extends Component {
7 | render () {
8 | return (
9 |
10 | one
11 | two
12 | three
13 |
14 | );
15 | }
16 | }
17 | ```
18 |
19 |
20 | We can validate it satisfies the snapshot when it's rendered. If no snapshot exists, it will be automatically created the first time it is run.
21 |
22 | ```js#evaluate:false
23 | expect(, 'when rendered', 'to satisfy snapshot');
24 | ```
25 |
26 | 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).
27 |
28 | 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`.
29 |
30 | ### Events
31 | Triggered events still works, and can be combined with matching snaphots.
32 |
33 | e.g.
34 |
35 | ```js#evaluate:false
36 |
37 | expect(,
38 | 'when rendered',
39 | 'with event click',
40 | 'to satisfy snapshot'
41 | );
42 | ```
43 |
44 | ### Matching
45 |
46 | 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.
47 |
48 | If you'd prefer to match the template exactly (order of classes is still ignored), see the assertion `to match snapshot`.
49 |
--------------------------------------------------------------------------------
/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 | "snapshot": {
12 | "added": 0,
13 | "failure": true,
14 | "filesAdded": 0,
15 | "filesRemoved": 0,
16 | "filesUnmatched": 1,
17 | "filesUpdated": 0,
18 | "matched": 4,
19 | "total": 5,
20 | "unchecked": 0,
21 | "unmatched": 1,
22 | "updated": 0
23 | },
24 | "success": false,
25 | "testResults": [
26 | {
27 | "assertionResults": [
28 | {
29 | "failureMessages": [],
30 | "status": "passed",
31 | "title": "counts a single click"
32 | },
33 | {
34 | "failureMessages": [
35 | "UnexpectedError: \nexpected \nwhen rendered with event 'click', 'with event' click 'with event', 'click', 'with event', 'click', 'to match snapshot'\n\n\n"
36 | ],
37 | "status": "failed",
38 | "title": "counts multiple clicks"
39 | },
40 | {
41 | "failureMessages": [],
42 | "status": "passed",
43 | "title": "passes multiple snapshots in a single test"
44 | },
45 | {
46 | "failureMessages": [],
47 | "status": "passed",
48 | "title": "renders with default props"
49 | }
50 | ],
51 | "message": " ● ClickCounter › counts multiple clicks\n\n UnexpectedError: \n expected \n when rendered with event 'click', 'with event' click 'with event', 'click', 'with event', 'click', 'to match snapshot'\n \n \n",
52 | "name": "/src/__tests__/ClickCounter.spec.js",
53 | "status": "failed",
54 | "summary": ""
55 | }
56 | ],
57 | "wasInterrupted": false
58 | }
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # unexpected-preact
2 |
3 | The [preact.js](http://preactjs.com) version of [unexpected-react](http://bruderstein.github.io/unexpected-react)
4 |
5 | ## Installation
6 |
7 | `npm install --save-dev unexpected unexpected-preact`
8 |
9 | ## Usage
10 |
11 | ES6:
12 | ```js
13 | import unexpected from 'unexpected';
14 | import unexpectedPreact from 'unexpected-preact';
15 |
16 | const expect = unexpected.clone().use(unexpectedPreact);
17 | ```
18 |
19 | ES5
20 | ```js
21 | var unexpected = require('unexpected');
22 | var unexpectedPreact = require('unexpected-preact');
23 |
24 | var expect = unexpected.clone().use(unexpectedPreact);
25 | ```
26 |
27 | **For Jest, require/import `unexpected-preact/jest`**
28 |
29 | With jest, you can use the snapshot test functionality - see the [`'to match snapshot'`](https://bruderstein.github.io/unexpected-preact/assertions/RenderedPreactElement/to-match-snapshot/) assertion
30 |
31 | Example test
32 | ```js
33 | it('increases the count on click', function () {
34 | expect(,
35 | 'when rendered',
36 | 'with event', 'click', 'on', ,
37 | 'to have rendered',
38 |
39 | Clicked 1 times
40 |
41 |
);
42 | });
43 | ```
44 |
45 |
46 | Read the [full documentation for the assertions](http://bruderstein.github.io/unexpected-preact/)
47 |
48 | Only deep (DOM) rendering is possible with preact, but you still get the full virtual tree as you see in the react-devtools, with all HTML elements and custom components.
49 |
50 |
51 | ### FAQ
52 |
53 | Q: I get an error about SVGElement is not defined with Preact v6 and jest
54 |
55 | A: Just define a global SVGElement function before you use Preact to render something
56 |
57 | ```js
58 | if (!window.SVGElement) window.SVGElement = function () {};
59 | ```
60 |
61 | ### Status
62 |
63 | Whilst this should be considered beta, it is based on unexpected-react and the supporting libraries, which have been used for
64 | production tests for well over a year in many large projects. We've also got a very comprehensive test suite and integration
65 | test suite, so if something were fundamentally broken we'd know quickly.
66 |
67 | This library is maintained, and welcomes PRs and issues - please raise an issue if you have questions!
68 |
69 | ### License
70 | MIT
71 |
72 |
--------------------------------------------------------------------------------
/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 | "snapshot": {
12 | "added": 0,
13 | "failure": true,
14 | "filesAdded": 0,
15 | "filesRemoved": 0,
16 | "filesUnmatched": 1,
17 | "filesUpdated": 0,
18 | "matched": 0,
19 | "total": 1,
20 | "unchecked": 0,
21 | "unmatched": 1,
22 | "updated": 0
23 | },
24 | "success": false,
25 | "testResults": [
26 | {
27 | "assertionResults": [
28 | {
29 | "failureMessages": [
30 | "UnexpectedError: \nexpected when rendered to match snapshot\n\n\n"
31 | ],
32 | "status": "failed",
33 | "title": "renders with default props"
34 | }
35 | ],
36 | "message": " ● ClickCounter › renders with default props\n\n UnexpectedError: \n expected when rendered to match snapshot\n \n \n",
37 | "name": "/src/__tests__/ClickCounter.spec.js",
38 | "status": "failed",
39 | "summary": ""
40 | }
41 | ],
42 | "wasInterrupted": false
43 | }
44 |
--------------------------------------------------------------------------------
/src/assertions/deepAgainstRawAssertions.js:
--------------------------------------------------------------------------------
1 | import UnexpectedHtmlLike from 'unexpected-htmllike';
2 | import PreactRenderedAdapter from 'unexpected-htmllike-preactrendered-adapter';
3 | import PreactElementAdapter from 'unexpected-htmllike-preact-adapter';
4 | import RawAdapter from 'unexpected-htmllike-raw-adapter';
5 | import Preact from 'preact';
6 | import AssertionGenerator from './AssertionGenerator';
7 | import { triggerEvent } from './deepAssertions';
8 |
9 | function getOptions(expect) {
10 | // Override the classAttributeName as we're always comparing against `class` here
11 | RawAdapter.prototype.classAttributeName = 'class';
12 |
13 | return {
14 | ActualAdapter: PreactRenderedAdapter,
15 | QueryAdapter: PreactElementAdapter,
16 | ExpectedAdapter: RawAdapter,
17 | actualTypeName: 'RenderedPreactElement',
18 | queryTypeName: 'PreactElement',
19 | expectedTypeName: 'ReactRawObjectElement',
20 | getRenderOutput: component => {
21 | if (component &&
22 | typeof component === 'object' &&
23 | (component.type === PreactRenderedAdapter.COMPONENT_TYPE ||
24 | component.type === PreactRenderedAdapter.NODE_TYPE)) {
25 | return component;
26 | }
27 | return PreactRenderedAdapter.wrapRootNode(component);
28 | },
29 | actualRenderOutputType: 'RenderedPreactElementWrapper',
30 | getDiffInputFromRenderOutput: renderOutput => renderOutput,
31 | rewrapResult: (renderer, target) => target,
32 | wrapResultForReturn: (component, target) => {
33 | const result = (target || component);
34 | if (!result) {
35 | return result;
36 | }
37 | if (result.type === PreactRenderedAdapter.COMPONENT_TYPE) {
38 | return result.component;
39 | }
40 | if (result.type === PreactRenderedAdapter.NODE_TYPE) {
41 | return result.node;
42 | }
43 | return result;
44 | },
45 | triggerEvent: triggerEvent.bind(null, expect),
46 | canTriggerEventsOnOutputType: true
47 | };
48 | }
49 |
50 | function installInto(expect) {
51 | const assertionGenerator = new AssertionGenerator(getOptions(expect));
52 | assertionGenerator.installInto(expect);
53 |
54 | return assertionGenerator;
55 | }
56 |
57 | function installAsAlternative(expect, mainAssertionGenerator) {
58 | const generatorOptions = getOptions(expect);
59 | const assertionGenerator = new AssertionGenerator({ mainAssertionGenerator, ...generatorOptions });
60 | assertionGenerator.installAlternativeExpected(expect);
61 | }
62 |
63 | export { installInto, installAsAlternative, triggerEvent };
64 |
--------------------------------------------------------------------------------
/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 | "snapshot": {
12 | "added": 0,
13 | "failure": false,
14 | "filesAdded": 0,
15 | "filesRemoved": 0,
16 | "filesUnmatched": 0,
17 | "filesUpdated": 0,
18 | "matched": 0,
19 | "total": 0,
20 | "unchecked": 0,
21 | "unmatched": 0,
22 | "updated": 0
23 | },
24 | "success": false,
25 | "testResults": [
26 | {
27 | "assertionResults": [
28 | {
29 | "failureMessages": [
30 | "UnexpectedError: \nexpected when rendered to satisfy snapshot\n\nTo use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n"
31 | ],
32 | "status": "failed",
33 | "title": "renders with `when rendered to satisfy`"
34 | },
35 | {
36 | "failureMessages": [
37 | "UnexpectedError: \nexpected when rendered to match snapshot\n\nTo use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n"
38 | ],
39 | "status": "failed",
40 | "title": "renders with `when rendered`"
41 | },
42 | {
43 | "failureMessages": [
44 | "UnexpectedError: \nTo use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n\nTo use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n"
45 | ],
46 | "status": "failed",
47 | "title": "renders with default props"
48 | },
49 | {
50 | "failureMessages": [
51 | "UnexpectedError: \nTo use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n\nTo use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n"
52 | ],
53 | "status": "failed",
54 | "title": "renders with default props with to satisfy"
55 | }
56 | ],
57 | "message": " ● ClickCounter › renders with default props\n\n UnexpectedError: \n To use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n \n To use snapshot assertions in jest, use 'unexpected-preact/jest' to require or import unexpected-preact\n",
58 | "name": "/src/__tests__/ClickCounter.spec.js",
59 | "status": "failed",
60 | "summary": ""
61 | }
62 | ],
63 | "wasInterrupted": false
64 | }
65 |
--------------------------------------------------------------------------------
/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 | "snapshot": {
12 | "added": 0,
13 | "failure": true,
14 | "filesAdded": 0,
15 | "filesRemoved": 0,
16 | "filesUnmatched": 1,
17 | "filesUpdated": 0,
18 | "matched": 0,
19 | "total": 1,
20 | "unchecked": 0,
21 | "unmatched": 1,
22 | "updated": 0
23 | },
24 | "success": false,
25 | "testResults": [
26 | {
27 | "assertionResults": [
28 | {
29 | "failureMessages": [
30 | "UnexpectedError: \nexpected when rendered to match snapshot\n\n\n"
31 | ],
32 | "status": "failed",
33 | "title": "renders with default props"
34 | }
35 | ],
36 | "message": " ● ClickCounter › renders with default props\n\n UnexpectedError: \n expected when rendered to match snapshot\n \n \n",
37 | "name": "/src/__tests__/ClickCounter.spec.js",
38 | "status": "failed",
39 | "summary": ""
40 | }
41 | ],
42 | "wasInterrupted": false
43 | }
44 |
--------------------------------------------------------------------------------
/src/types/types.js:
--------------------------------------------------------------------------------
1 |
2 | import { h } from 'preact';
3 | import UnexpectedHtmlLike from 'unexpected-htmllike';
4 | import RawAdapter from 'unexpected-htmllike-raw-adapter';
5 | import PreactElementAdapter from 'unexpected-htmllike-preact-adapter';
6 | import PreactRenderedAdapter from 'unexpected-htmllike-preactrendered-adapter';
7 |
8 | const PreactVNode = Object.getPrototypeOf(h('div'));
9 |
10 | function installInto(expect) {
11 |
12 | const preactRenderedAdapter = new PreactRenderedAdapter({ includeKeyProp: true, convertToString: true, concatTextContent: true });
13 | const htmlLikePreactRendered = UnexpectedHtmlLike(preactRenderedAdapter);
14 | const rawAdapter = new RawAdapter({ convertToString: true, concatTextContent: true });
15 | const htmlLikeRaw = UnexpectedHtmlLike(rawAdapter);
16 | const preactAdapter = new PreactElementAdapter({ includeKeyProp: true });
17 | const htmlLikePreactElement = UnexpectedHtmlLike(preactAdapter);
18 |
19 | expect.addType({
20 |
21 | name: 'RenderedPreactElement',
22 |
23 | base: 'object',
24 | identify(value) {
25 | return typeof value === 'object' &&
26 | value !== null &&
27 | (typeof value._component === 'object' ||
28 | typeof value.__preact_attr_ === 'object' ||
29 | (value.base && // Following for component instance returned from preact-compat render
30 | value.hasOwnProperty('props') &&
31 | value.hasOwnProperty('context') &&
32 | typeof value.setState === 'function'));
33 | },
34 |
35 | inspect(value, depth, output, inspect) {
36 | return htmlLikePreactRendered.inspect(PreactRenderedAdapter.wrapNode(value), depth, output, inspect);
37 | }
38 | });
39 |
40 | expect.addType({
41 | name: 'RenderedPreactElementWrapper',
42 |
43 | identify(value) {
44 | return typeof value === 'object' &&
45 | value !== null &&
46 | (value.type === PreactRenderedAdapter.COMPONENT_TYPE ||
47 | value.type === PreactRenderedAdapter.NODE_TYPE
48 | );
49 | },
50 |
51 | inspect(value, depth, output, inspect) {
52 | return htmlLikePreactRendered.inspect(value, depth, output, inspect);
53 | }
54 |
55 | });
56 |
57 |
58 | expect.addType({
59 | name: 'PreactElement',
60 |
61 | identify: function (value) {
62 | return (typeof value === 'object' &&
63 | value !== null &&
64 | Object.getPrototypeOf(value) === PreactVNode);
65 | },
66 |
67 | inspect: function (value, depth, output, inspect) {
68 | return htmlLikePreactElement.inspect(value, depth, output, inspect);
69 | }
70 | });
71 |
72 | expect.addType({
73 | name: 'ReactRawObjectElement',
74 | base: 'object',
75 | identify: function (value) {
76 | return rawAdapter.isRawElement(value);
77 | },
78 |
79 | inspect: function (value, depth, output, inspect) {
80 | return htmlLikeRaw.inspect(value, depth, output, inspect);
81 | }
82 | });
83 | }
84 |
85 | export default { installInto };
86 |
--------------------------------------------------------------------------------
/jest-integration/tests/multiple/3-change-in-code/expectedOutput.json:
--------------------------------------------------------------------------------
1 | {
2 | "numFailedTestSuites": 2,
3 | "numFailedTests": 2,
4 | "numPassedTestSuites": 0,
5 | "numPassedTests": 3,
6 | "numPendingTestSuites": 0,
7 | "numPendingTests": 0,
8 | "numRuntimeErrorTestSuites": 0,
9 | "numTotalTestSuites": 2,
10 | "numTotalTests": 5,
11 | "snapshot": {
12 | "added": 0,
13 | "failure": true,
14 | "filesAdded": 0,
15 | "filesRemoved": 0,
16 | "filesUnmatched": 2,
17 | "filesUpdated": 0,
18 | "matched": 4,
19 | "total": 6,
20 | "unchecked": 0,
21 | "unmatched": 2,
22 | "updated": 0
23 | },
24 | "success": false,
25 | "testResults": [
26 | {
27 | "assertionResults": [
28 | {
29 | "failureMessages": [
30 | "UnexpectedError: \nexpected \nwhen rendered with event click 'with event click', 'with event click', 'to match snapshot'\n\n\n"
31 | ],
32 | "status": "failed",
33 | "title": "counts a single click"
34 | }
35 | ],
36 | "message": " ● ClickCounter › counts a single click\n\n UnexpectedError: \n expected \n when rendered with event click 'with event click', 'with event click', 'to match snapshot'\n \n \n",
37 | "name": "/src/__tests__/ClickCounter-other.spec.js",
38 | "status": "failed",
39 | "summary": ""
40 | },
41 | {
42 | "assertionResults": [
43 | {
44 | "failureMessages": [],
45 | "status": "passed",
46 | "title": "counts a single click"
47 | },
48 | {
49 | "failureMessages": [
50 | "UnexpectedError: \nexpected \nwhen rendered with event 'click', 'with event' click 'with event', 'click', 'with event', 'click', 'to match snapshot'\n\n\n"
51 | ],
52 | "status": "failed",
53 | "title": "counts multiple clicks"
54 | },
55 | {
56 | "failureMessages": [],
57 | "status": "passed",
58 | "title": "passes multiple snapshots in a single test"
59 | },
60 | {
61 | "failureMessages": [],
62 | "status": "passed",
63 | "title": "renders with default props"
64 | }
65 | ],
66 | "message": " ● ClickCounter › counts multiple clicks\n\n UnexpectedError: \n expected \n when rendered with event 'click', 'with event' click 'with event', 'click', 'with event', 'click', 'to match snapshot'\n \n \n",
67 | "name": "/src/__tests__/ClickCounter.spec.js",
68 | "status": "failed",
69 | "summary": ""
70 | }
71 | ],
72 | "wasInterrupted": false
73 | }
74 |
--------------------------------------------------------------------------------
/documentation/assertions/RenderedPreactElement/with-event.md:
--------------------------------------------------------------------------------
1 | ## `with event` .... [`on`]
2 |
3 | `with event` can trigger events on your components. This is done by dispatching real browser events.
4 |
5 | e.g. with a button that counts it's own clicks
6 |
7 | ```js
8 |
9 | expect(,
10 | 'when rendered',
11 | 'with event', 'click',
12 | 'to have rendered', );
13 | ```
14 |
15 | If you want to trigger an event on a specific component, (i.e. not the top level component), use `on`
16 | after the event.
17 |
18 | ```js
19 | const todoList = (
20 |
21 |
22 |
23 |
24 |
25 | );
26 |
27 | expect(
28 | todoList,
29 | 'when rendered',
30 | 'with event', 'click', 'on', ,
31 | 'to contain',
32 |
33 | Buy groceries
34 |
35 | );
36 | ```
37 |
38 | To pass arguments to the event, simply include the event object after the event name. As real browser events are used, arguments must be supported by the event type.
39 |
40 | ```js
41 | expect(
42 | todoList,
43 | 'when rendered',
44 | 'with event mouseDown', { clientX: 150, clientY: 50 }, 'on', ,
45 | 'to contain',
46 |
47 | Buy groceries
48 |
49 | );
50 | ```
51 |
52 | This will call the function passed in the `onMouseDown` prop of the ``.
53 |
54 | ## Multiple events
55 |
56 | To call multiple events, simple list them one after the other:
57 |
58 |
59 | ```js
60 | expect(
61 | todoList,
62 | 'when rendered',
63 | 'with event', 'click', { clientX: 150, clientY: 50 }, 'on', ,
64 | 'with event', 'click', { clientX: 50, clientY: 50 }, 'on', ,
65 | 'to have rendered',
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | );
75 | ```
76 |
77 | You can optionally add `and` before the second and further events, to make it easier to read:
78 |
79 | ```js
80 | expect(
81 | todoList,
82 | 'when rendered',
83 | 'with event', 'click', { clientX: 150, clientY: 50 }, 'on', ,
84 | 'and with event', 'click', { clientX: 50, clientY: 50 }, 'on', ,
85 | 'to have rendered',
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | );
95 | ```
96 |
97 | You can extract the renderer after an event by using the result of the promise returned from `expect`
98 |
99 | ```js#async:true
100 | return expect(
101 | todoList,
102 | 'when rendered',
103 | 'with event', 'mouseDown', { clientX: 150, clientY: 50 }, 'on',
104 | ).then(component => {
105 | expect(
106 | component,
107 | 'to contain',
108 |
109 |
110 |
111 | );
112 | });
113 | ```
114 |
115 | ## eventTarget
116 |
117 | You can add an `eventTarget` prop to the expected to trigger the event on a child component.
118 | e.g. This will trigger the click in the `