Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Support context components in react-test-renderer #12151

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions packages/react-test-renderer/src/ReactTestRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
HostPortal,
HostText,
HostRoot,
ContextConsumer,
ContextProvider,
} from 'shared/ReactTypeOfWork';
import invariant from 'fbjs/lib/invariant';

Expand Down Expand Up @@ -367,6 +369,9 @@ function toTree(node: ?Fiber) {
return node.stateNode.text;
case Fragment:
return childrenToTree(node.child);
case ContextConsumer:
case ContextProvider:
return toTree(node.child);
default:
invariant(
false,
Expand All @@ -393,6 +398,8 @@ const validWrapperTypes = new Set([
FunctionalComponent,
ClassComponent,
HostComponent,
ContextProvider,
ContextConsumer,
]);

class ReactTestInstance {
Expand Down Expand Up @@ -432,7 +439,7 @@ class ReactTestInstance {
}

get props(): Object {
return this._currentFiber().memoizedProps;
return this._currentFiber().memoizedProps || {};
}

get parent(): ?ReactTestInstance {
Expand Down Expand Up @@ -463,6 +470,8 @@ class ReactTestInstance {
children.push('' + node.memoizedProps);
break;
case Fragment:
case ContextConsumer:
case ContextProvider:
descend = true;
break;
default:
Expand Down Expand Up @@ -545,7 +554,6 @@ function findAll(
): Array<ReactTestInstance> {
const deep = options ? options.deep : true;
const results = [];

if (predicate(root)) {
results.push(root);
if (!deep) {
Expand Down Expand Up @@ -606,7 +614,6 @@ const ReactTestRendererFiber = {
);
invariant(root != null, 'something went wrong');
TestRenderer.updateContainer(element, root, null, null);

const entry = {
root: undefined, // makes flow happy
// we define a 'getter' for 'root' below using 'Object.defineProperty'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,30 @@ describe('ReactTestRenderer', () => {
);
});

it('toTree() handles ContextConsumer and ContextProvider components', () => {
const {Consumer, Provider} = React.createContext('foo');

const renderer = ReactTestRenderer.create(
<Provider value="bar">
<Consumer>{value => <div>{value}</div>}</Consumer>
</Provider>,
);

const tree = renderer.toTree();

cleanNodeOrArray(tree);

expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: 'div',
nodeType: 'host',
instance: null,
props: {},
rendered: ['bar'],
}),
);
});

it('root instance and createNodeMock ref return the same value', () => {
const createNodeMock = ref => ({node: ref});
let refInst = null;
Expand Down Expand Up @@ -879,4 +903,30 @@ describe('ReactTestRenderer', () => {
'world',
]);
});

it('can update Providers and Consumers', () => {
const {Consumer, Provider} = React.createContext('foo');

const renderer = ReactTestRenderer.create(
<Provider value="bar">
<Consumer>{value => <div>{value}</div>}</Consumer>
</Provider>,
);

expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['bar'],
props: {},
});
renderer.update(
<Provider value="corge">
<Consumer>{value => <div>{value}</div>}</Consumer>
</Provider>,
);
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['corge'],
props: {},
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ const RCTView = 'RCTView';
const View = props => <RCTView {...props} />;

describe('ReactTestRendererTraversal', () => {
let Consumer, Provider;

beforeEach(() => {
jest.resetModules();
ReactTestRenderer = require('react-test-renderer');
const context = React.createContext('corge');
Consumer = context.Consumer;
Provider = context.Provider;
});

class Example extends React.Component {
Expand All @@ -37,6 +42,9 @@ describe('ReactTestRendererTraversal', () => {
<View void="void" />
<View void="void" />
</ExampleNull>
<Provider value="corge">
<Consumer>{value => <View value={value} />}</Consumer>
</Provider>
</View>
</View>
);
Expand All @@ -54,7 +62,7 @@ describe('ReactTestRendererTraversal', () => {

// assert .props, .type and .parent attributes
const foo = render.root.find(hasFooProp);
expect(foo.props.children).toHaveLength(7);
expect(foo.props.children).toHaveLength(8);
expect(foo.type).toBe(View);
expect(render.root.parent).toBe(null);
expect(foo.children[0].parent).toBe(foo);
Expand All @@ -69,13 +77,17 @@ describe('ReactTestRendererTraversal', () => {
const hasNullProp = node => node.props.hasOwnProperty('null');
const hasVoidProp = node => node.props.hasOwnProperty('void');
const hasItselfProp = node => node.props.hasOwnProperty('itself');
const hasProviderType = node => node.type === Provider;
const hasConsumerType = node => node.type === Consumer;

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(hasProviderType)).toThrow(); // 0 matches
expect(() => render.root.find(hasConsumerType)).toThrow(); // 0 matches

// same assertion as .find(), but confirm length
expect(render.root.findAll(hasFooProp, {deep: false})).toHaveLength(1);
Expand Down Expand Up @@ -119,10 +131,12 @@ describe('ReactTestRendererTraversal', () => {
// note: there are clearly multiple <View /> in general, but there
// is only one being rendered at root node level
expect(() => render.root.findByType(ExampleNull)).toThrow(); // 2 matches
expect(() => render.root.findByType(Provider)).toThrow(); // 0 matches
expect(() => render.root.findByType(Consumer)).toThrow(); // 0 matches

expect(render.root.findAllByType(ExampleFn)).toHaveLength(1);
expect(render.root.findAllByType(View, {deep: false})).toHaveLength(1);
expect(render.root.findAllByType(View)).toHaveLength(7);
expect(render.root.findAllByType(View)).toHaveLength(8);
expect(render.root.findAllByType(ExampleNull)).toHaveLength(2);

const nulls = render.root.findAllByType(ExampleNull);
Expand Down