/*** Copyright (c) Meta Platforms, Inc. and affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.** @emails react-core* @jest-environment node*/'use strict';
const React = require('react');
let ReactTestRenderer;
let Context;
const RCTView = 'RCTView';
const View = props => <RCTView {...props} />;
describe('ReactTestRendererTraversal', () => {beforeEach(() => {jest.resetModules();
ReactTestRenderer = require('react-test-renderer');Context = React.createContext(null);
});class Example extends React.Component {
render() {return (<View><View foo="foo"><View bar="bar" /><View bar="bar" baz="baz" itself="itself" /><View /><ExampleSpread bar="bar" /><ExampleFn bar="bar" bing="bing" /><ExampleNull bar="bar" /><ExampleNull null="null"><View void="void" /><View void="void" /></ExampleNull><React.Profiler id="test" onRender={() => {}}>
<ExampleForwardRef qux="qux" /></React.Profiler>
<><><Context.Provider value={null}>
<Context.Consumer>
{() => <View nested={true} />}</Context.Consumer>
</Context.Provider>
</><View nested={true} /><View nested={true} /></></View></View>);}}class ExampleSpread extends React.Component {
render = () => <View {...this.props} />;
}const ExampleFn = props => <View baz="baz" />;const ExampleNull = props => null;const ExampleForwardRef = React.forwardRef((props, ref) => (
<View {...props} ref={ref} />
));it('initializes', () => {const render = ReactTestRenderer.create(<Example />);
const hasFooProp = node => node.props.hasOwnProperty('foo');
// assert .props, .type and .parent attributes
const foo = render.root.find(hasFooProp);
expect(foo.props.children).toHaveLength(9);
expect(foo.type).toBe(View);
expect(render.root.parent).toBe(null);
expect(foo.children[0].parent).toBe(foo);
});it('searches via .find() / .findAll()', () => {
const render = ReactTestRenderer.create(<Example />);
const hasFooProp = node => node.props.hasOwnProperty('foo');
const hasBarProp = node => node.props.hasOwnProperty('bar');
const hasBazProp = node => node.props.hasOwnProperty('baz');
const hasBingProp = node => node.props.hasOwnProperty('bing');
const hasNullProp = node => node.props.hasOwnProperty('null');
const hasVoidProp = node => node.props.hasOwnProperty('void');
const hasItselfProp = node => node.props.hasOwnProperty('itself');
const hasNestedProp = node => node.props.hasOwnProperty('nested');
expect(() => render.root.find(hasFooProp)).not.toThrow(); // 1 match
expect(() => render.root.find(hasBarProp)).toThrow(); // >1 matches
expect(() => render.root.find(hasBazProp)).toThrow(); // >1 matches
expect(() => render.root.find(hasBingProp)).not.toThrow(); // 1 match
expect(() => render.root.find(hasNullProp)).not.toThrow(); // 1 match
expect(() => render.root.find(hasVoidProp)).toThrow(); // 0 matches
expect(() => render.root.find(hasNestedProp)).toThrow(); // >1 matches
// same assertion as .find(), but confirm length
expect(render.root.findAll(hasFooProp, {deep: false})).toHaveLength(1);
expect(render.root.findAll(hasBarProp, {deep: false})).toHaveLength(5);
expect(render.root.findAll(hasBazProp, {deep: false})).toHaveLength(2);
expect(render.root.findAll(hasBingProp, {deep: false})).toHaveLength(1);
expect(render.root.findAll(hasNullProp, {deep: false})).toHaveLength(1);
expect(render.root.findAll(hasVoidProp, {deep: false})).toHaveLength(0);
expect(render.root.findAll(hasNestedProp, {deep: false})).toHaveLength(3);
// note: with {deep: true}, .findAll() will continue to
// search children, even after finding a matchexpect(render.root.findAll(hasFooProp)).toHaveLength(2);
expect(render.root.findAll(hasBarProp)).toHaveLength(9);
expect(render.root.findAll(hasBazProp)).toHaveLength(4);
expect(render.root.findAll(hasBingProp)).toHaveLength(1); // no spread
expect(render.root.findAll(hasNullProp)).toHaveLength(1); // no spread
expect(render.root.findAll(hasVoidProp)).toHaveLength(0);
expect(render.root.findAll(hasNestedProp, {deep: false})).toHaveLength(3);
const bing = render.root.find(hasBingProp);
expect(bing.find(hasBarProp)).toBe(bing);
expect(bing.find(hasBingProp)).toBe(bing);
expect(bing.findAll(hasBazProp, {deep: false})).toHaveLength(1);
expect(bing.findAll(hasBazProp)).toHaveLength(2);
const foo = render.root.find(hasFooProp);
expect(foo.findAll(hasFooProp, {deep: false})).toHaveLength(1);
expect(foo.findAll(hasFooProp)).toHaveLength(2);
const itself = foo.find(hasItselfProp);
expect(itself.find(hasBarProp)).toBe(itself);
expect(itself.find(hasBazProp)).toBe(itself);
expect(itself.findAll(hasBazProp, {deep: false})).toHaveLength(1);
expect(itself.findAll(hasBazProp)).toHaveLength(2);
});it('searches via .findByType() / .findAllByType()', () => {
const render = ReactTestRenderer.create(<Example />);
expect(() => render.root.findByType(ExampleFn)).not.toThrow(); // 1 match
expect(() => render.root.findByType(View)).not.toThrow(); // 1 match
expect(() => render.root.findByType(ExampleForwardRef)).not.toThrow(); // 1 match
// note: there are clearly multiple <View /> in general, but there// is only one being rendered at root node levelexpect(() => render.root.findByType(ExampleNull)).toThrow(); // 2 matches
expect(render.root.findAllByType(ExampleFn)).toHaveLength(1);
expect(render.root.findAllByType(View, {deep: false})).toHaveLength(1);
expect(render.root.findAllByType(View)).toHaveLength(11);
expect(render.root.findAllByType(ExampleNull)).toHaveLength(2);
expect(render.root.findAllByType(ExampleForwardRef)).toHaveLength(1);
const nulls = render.root.findAllByType(ExampleNull);
expect(nulls[0].findAllByType(View)).toHaveLength(0);
expect(nulls[1].findAllByType(View)).toHaveLength(0);
const fn = render.root.findAllByType(ExampleFn);
expect(fn[0].findAllByType(View)).toHaveLength(1);
});it('searches via .findByProps() / .findAllByProps()', () => {
const render = ReactTestRenderer.create(<Example />);
const foo = 'foo';const bar = 'bar';const baz = 'baz';const qux = 'qux';expect(() => render.root.findByProps({foo})).not.toThrow(); // 1 match
expect(() => render.root.findByProps({bar})).toThrow(); // >1 matches
expect(() => render.root.findByProps({baz})).toThrow(); // >1 matches
expect(() => render.root.findByProps({qux})).not.toThrow(); // 1 match
expect(render.root.findAllByProps({foo}, {deep: false})).toHaveLength(1);
expect(render.root.findAllByProps({bar}, {deep: false})).toHaveLength(5);
expect(render.root.findAllByProps({baz}, {deep: false})).toHaveLength(2);
expect(render.root.findAllByProps({qux}, {deep: false})).toHaveLength(1);
expect(render.root.findAllByProps({foo})).toHaveLength(2);
expect(render.root.findAllByProps({bar})).toHaveLength(9);
expect(render.root.findAllByProps({baz})).toHaveLength(4);
expect(render.root.findAllByProps({qux})).toHaveLength(3);
});it('skips special nodes', () => {const render = ReactTestRenderer.create(<Example />);
expect(render.root.findAllByType(React.Fragment)).toHaveLength(0);
expect(render.root.findAllByType(Context.Consumer)).toHaveLength(0);
expect(render.root.findAllByType(Context.Provider)).toHaveLength(0);
const expectedParent = render.root.findByProps({foo: 'foo'}, {deep: false})
.children[0];
const nestedViews = render.root.findAllByProps(
{nested: true},{deep: false},);expect(nestedViews.length).toBe(3);
expect(nestedViews[0].parent).toBe(expectedParent);
expect(nestedViews[1].parent).toBe(expectedParent);
expect(nestedViews[2].parent).toBe(expectedParent);
});it('can have special nodes as roots', () => {const FR = React.forwardRef((props, ref) => <section {...props} />);
expect(ReactTestRenderer.create(
<FR><div /><div /></FR>,).root.findAllByType('div').length,
).toBe(2);
expect(ReactTestRenderer.create(
<><div /><div /></>,).root.findAllByType('div').length,
).toBe(2);
expect(ReactTestRenderer.create(
<React.Fragment key="foo">
<div /><div /></React.Fragment>,
).root.findAllByType('div').length,
).toBe(2);
expect(ReactTestRenderer.create(
<React.StrictMode>
<div /><div /></React.StrictMode>,
).root.findAllByType('div').length,
).toBe(2);
expect(ReactTestRenderer.create(
<Context.Provider value={null}>
<div /><div /></Context.Provider>,
).root.findAllByType('div').length,
).toBe(2);
});});