Skip to content

Commit c0d103c

Browse files
author
Brian Vaughn
committed
Improved handling for mixed children case
1 parent a89d655 commit c0d103c

File tree

4 files changed

+59
-13
lines changed

4 files changed

+59
-13
lines changed

packages/react-test-renderer/src/ReactTestHostConfig.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ export function removeChild(
8686
parentInstance: Instance | Container,
8787
child: Instance | TextInstance,
8888
): void {
89+
// Detect and ignore ReactDOM.createPortal() usage.
90+
// Test renderer's toJSON() method knows how to handle this case.
91+
if (parentInstance instanceof HTMLElement) {
92+
return;
93+
}
8994
const index = parentInstance.children.indexOf(child);
9095
parentInstance.children.splice(index, 1);
9196
}

packages/react-test-renderer/src/ReactTestRenderer.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,18 @@ function toJSON(inst: Instance | TextInstance): ReactTestRendererNode {
7373
const {children, ...props} = inst.props;
7474
/* eslint-enable */
7575
let renderedChildren = null;
76-
if (inst.children && inst.children.length) {
77-
renderedChildren = inst.children.map(toJSON);
78-
} else if (inst.props != null && inst.props.children != null) {
79-
// The element's children are from another renderer (e.g. ReactDOM.createPortal)
76+
if (inst.props != null && inst.props.children != null) {
77+
// At least some of this element's children are from another renderer
78+
// (e.g. ReactDOM.createPortal)
79+
// In this case, treat all children as potentially from the other renderer.
80+
// If we don't, the JSON representation may contain overlaps.
8081
renderedChildren = React.Children.toArray(inst.props.children).map(
8182
reactElementToJSON,
8283
);
84+
} else if (inst.children && inst.children.length) {
85+
renderedChildren = inst.children.map(toJSON);
8386
}
87+
8488
const json: ReactTestRendererJSON = {
8589
type: inst.type,
8690
props: props,
@@ -97,10 +101,14 @@ function toJSON(inst: Instance | TextInstance): ReactTestRendererNode {
97101

98102
function reactElementToJSON(inst: any): ReactTestRendererNode {
99103
if (typeof inst === 'object') {
104+
/* eslint-disable no-unused-vars */
105+
// We don't include the `children` prop in JSON.
106+
// Instead, we will include the actual rendered children.
107+
const {children, ...props} = inst.props != null ? inst.props : {};
100108
const type = typeOf(inst);
101109
return {
102110
type: type == null ? 'unknown' : type.toString(),
103-
props: inst.props || {},
111+
props,
104112
children: React.Children.toArray(
105113
inst.children || inst.props.children,
106114
).map(reactElementToJSON),

packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,20 @@ jest.resetModules();
1717
const ReactTestRenderer = require('react-test-renderer');
1818

1919
describe('ReactTestRenderer', () => {
20-
it('should support ReactDOM portal', () => {
20+
it('should support ReactDOM portal usage', () => {
2121
const container = document.createElement('div');
22-
const rendered = ReactTestRenderer.create(
23-
<div>{ReactDOM.createPortal(<span>Hi!</span>, container)}</div>,
22+
let rendered = ReactTestRenderer.create(
23+
<div>
24+
{ReactDOM.createPortal(<span>Rendered by ReactDOM</span>, container)}
25+
</div>,
26+
);
27+
expect(rendered.toJSON()).toMatchSnapshot();
28+
29+
rendered.update(
30+
<div>
31+
<span>Rendered by ReactTestRenderer</span>
32+
{ReactDOM.createPortal(<span>Rendered by ReactDOM</span>, container)}
33+
</div>,
2434
);
2535
expect(rendered.toJSON()).toMatchSnapshot();
2636
});

packages/react-test-renderer/src/__tests__/__snapshots__/ReactTestRenderer-test.js.snap

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,39 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`ReactTestRenderer should support ReactDOM portal 1`] = `
3+
exports[`ReactTestRenderer should support ReactDOM portal usage 1`] = `
44
<div>
55
Object {
66
"children": Array [
77
Object {
88
"children": Array [
9-
"Hi!",
9+
"Rendered by ReactDOM",
1010
],
11-
"props": Object {
12-
"children": "Hi!",
13-
},
11+
"props": Object {},
12+
"type": "Symbol(react.element)",
13+
},
14+
],
15+
"props": Object {},
16+
"type": "Symbol(react.portal)",
17+
}
18+
</div>
19+
`;
20+
21+
exports[`ReactTestRenderer should support ReactDOM portal usage 2`] = `
22+
<div>
23+
Object {
24+
"children": Array [
25+
"Rendered by ReactTestRenderer",
26+
],
27+
"props": Object {},
28+
"type": "Symbol(react.element)",
29+
}
30+
Object {
31+
"children": Array [
32+
Object {
33+
"children": Array [
34+
"Rendered by ReactDOM",
35+
],
36+
"props": Object {},
1437
"type": "Symbol(react.element)",
1538
},
1639
],

0 commit comments

Comments
 (0)