-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
/
createClientRender.js
118 lines (102 loc) · 3.36 KB
/
createClientRender.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/* eslint-env mocha */
import React from 'react';
import PropTypes from 'prop-types';
import {
act,
buildQueries,
cleanup,
createEvent,
fireEvent as rtlFireEvent,
queries,
render as testingLibraryRender,
} from '@testing-library/react/pure';
// holes are *All* selectors which aren't necessary for id selectors
const [queryDescriptionOf, , getDescriptionOf, , findDescriptionOf] = buildQueries(
function queryAllDescriptionsOf(container, element) {
return container.querySelectorAll(`#${element.getAttribute('aria-describedby')}`);
},
function getMultipleError() {
return `Found multiple descriptions. An element should be described by a unique element.`;
},
function getMissingError() {
return `Found no describing element.`;
},
);
const customQueries = { queryDescriptionOf, getDescriptionOf, findDescriptionOf };
/**
*
* @param {React.ReactElement} element
* @param {object} [options]
* @param {boolean} [options.baseElement] - https://testing-library.com/docs/react-testing-library/api#baseelement-1
* @param {boolean} [options.disableUnnmount] - if true does not cleanup before mount
* @param {boolean} [options.strict] - wrap in React.StrictMode?
* @returns {import('@testing-library/react').RenderResult<typeof queries & typeof customQueries> & { setProps(props: object): void}}
* TODO: type return RenderResult in setProps
*/
function clientRender(element, options = {}) {
const { baseElement, strict = false, wrapper: InnerWrapper = React.Fragment } = options;
const Mode = strict ? React.StrictMode : React.Fragment;
function Wrapper({ children }) {
return (
<Mode>
<InnerWrapper>{children}</InnerWrapper>
</Mode>
);
}
Wrapper.propTypes = { children: PropTypes.node };
const result = testingLibraryRender(element, {
baseElement,
queries: { ...queries, ...customQueries },
wrapper: Wrapper,
});
/**
* convenience helper. Better than repeating all props.
*/
result.setProps = function setProps(props) {
result.rerender(React.cloneElement(element, props));
return result;
};
return result;
}
export function createClientRender(globalOptions = {}) {
const { strict: globalStrict } = globalOptions;
afterEach(() => {
act(() => {
cleanup();
});
});
return function configuredClientRender(element, options = {}) {
const { strict = globalStrict, ...localOptions } = options;
return clientRender(element, { ...localOptions, strict });
};
}
const fireEvent = Object.assign(rtlFireEvent, {
// polyfill event.key for chrome 49 (supported in Material-UI v4)
// for user-interactions react does the polyfilling but manually created
// events don't have this luxury
keyDown(element, options = {}) {
const event = createEvent.keyDown(element, options);
Object.defineProperty(event, 'key', {
get() {
return options.key || '';
},
});
rtlFireEvent(element, event);
},
keyUp(element, options = {}) {
const event = createEvent.keyUp(element, options);
Object.defineProperty(event, 'key', {
get() {
return options.key || '';
},
});
rtlFireEvent(element, event);
},
});
export * from '@testing-library/react/pure';
export { act, cleanup, fireEvent };
export function render() {
throw new Error(
"Don't use `render` directly. Instead use the return value from `createClientRender`",
);
}