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

1023 lines
25 KiB
JavaScript
Raw Normal View History

2016-06-02 02:17:10 +08:00
/**
* Copyright (c) 2013-present, Facebook, Inc.
2016-06-02 02:17:10 +08:00
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
2016-06-02 02:17:10 +08:00
*
* @emails react-core
* @jest-environment node
2016-06-02 02:17:10 +08:00
*/
'use strict';
Add stack unwinding phase for handling errors (#12201) * Add stack unwinding phase for handling errors A rewrite of error handling, with semantics that more closely match stack unwinding. Errors that are thrown during the render phase unwind to the nearest error boundary, like before. But rather than synchronously unmount the children before retrying, we restart the failed subtree within the same render phase. The failed children are still unmounted (as if all their keys changed) but without an extra commit. Commit phase errors are different. They work by scheduling an error on the update queue of the error boundary. When we enter the render phase, the error is popped off the queue. The rest of the algorithm is the same. This approach is designed to work for throwing non-errors, too, though that feature is not implemented yet. * Add experimental getDerivedStateFromCatch lifecycle Fires during the render phase, so you can recover from an error within the same pass. This aligns error boundaries more closely with try-catch semantics. Let's keep this behind a feature flag until a future release. For now, the recommendation is to keep using componentDidCatch. Eventually, the advice will be to use getDerivedStateFromCatch for handling errors and componentDidCatch only for logging. * Reconcile twice to remount failed children, instead of using a boolean * Handle effect immediately after its thrown This way we don't have to store the thrown values on the effect list. * ReactFiberIncompleteWork -> ReactFiberUnwindWork * Remove startTime * Remove TypeOfException We don't need it yet. We'll reconsider once we add another exception type. * Move replay to outer catch block This moves it out of the hot path.
2018-02-24 09:38:42 +08:00
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
const React = require('react');
const ReactTestRenderer = require('react-test-renderer');
const prettyFormat = require('pretty-format');
2016-06-02 02:17:10 +08:00
// Isolate noop renderer
jest.resetModules();
const ReactNoop = require('react-noop-renderer');
// Kind of hacky, but we nullify all the instances to test the tree structure
// with jasmine's deep equality function, and test the instances separate. We
// also delete children props because testing them is more annoying and not
// really important to verify.
function cleanNodeOrArray(node) {
if (!node) {
return;
}
if (Array.isArray(node)) {
node.forEach(cleanNodeOrArray);
return;
}
if (node && node.instance) {
node.instance = null;
}
if (node && node.props && node.props.children) {
// eslint-disable-next-line no-unused-vars
const {children, ...props} = node.props;
node.props = props;
}
if (Array.isArray(node.rendered)) {
node.rendered.forEach(cleanNodeOrArray);
} else if (typeof node.rendered === 'object') {
cleanNodeOrArray(node.rendered);
}
}
2016-09-07 06:18:42 +08:00
describe('ReactTestRenderer', () => {
it('renders a simple component', () => {
2016-06-02 02:17:10 +08:00
function Link() {
return <a role="link" />;
}
const renderer = ReactTestRenderer.create(<Link />);
2016-06-02 02:17:10 +08:00
expect(renderer.toJSON()).toEqual({
type: 'a',
2017-03-14 08:05:18 +08:00
props: {role: 'link'},
2016-06-02 02:17:10 +08:00
children: null,
});
});
2016-09-07 06:18:42 +08:00
it('renders a top-level empty component', () => {
function Empty() {
return null;
}
const renderer = ReactTestRenderer.create(<Empty />);
expect(renderer.toJSON()).toEqual(null);
});
2016-09-07 06:18:42 +08:00
it('exposes a type flag', () => {
function Link() {
return <a role="link" />;
}
const renderer = ReactTestRenderer.create(<Link />);
const object = renderer.toJSON();
expect(object.$$typeof).toBe(Symbol.for('react.test.json'));
// $$typeof should not be enumerable.
for (const key in object) {
if (object.hasOwnProperty(key)) {
expect(key).not.toBe('$$typeof');
}
}
});
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
it('can render a composite component', () => {
class Component extends React.Component {
render() {
return (
<div className="purple">
<Child />
</div>
);
}
}
const Child = () => {
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
return <moo />;
};
const renderer = ReactTestRenderer.create(<Component />);
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
expect(renderer.toJSON()).toEqual({
type: 'div',
2017-03-14 08:05:18 +08:00
props: {className: 'purple'},
children: [{type: 'moo', props: {}, children: null}],
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
});
});
2016-09-07 06:18:42 +08:00
it('renders some basics with an update', () => {
let renders = 0;
class Component extends React.Component {
state = {x: 3};
render() {
2016-06-02 02:17:10 +08:00
renders++;
return (
<div className="purple">
{this.state.x}
<Child />
<Null />
</div>
);
}
componentDidMount() {
2016-06-02 02:17:10 +08:00
this.setState({x: 7});
}
}
2016-06-02 02:17:10 +08:00
const Child = () => {
renders++;
return <moo />;
};
const Null = () => {
renders++;
return null;
};
2016-06-02 02:17:10 +08:00
const renderer = ReactTestRenderer.create(<Component />);
2016-06-02 02:17:10 +08:00
expect(renderer.toJSON()).toEqual({
type: 'div',
2017-03-14 08:05:18 +08:00
props: {className: 'purple'},
children: ['7', {type: 'moo', props: {}, children: null}],
2016-06-02 02:17:10 +08:00
});
expect(renders).toBe(6);
});
2016-09-07 06:18:42 +08:00
it('exposes the instance', () => {
2016-06-02 02:17:10 +08:00
class Mouse extends React.Component {
constructor() {
super();
this.state = {mouse: 'mouse'};
}
handleMoose() {
this.setState({mouse: 'moose'});
}
render() {
return <div>{this.state.mouse}</div>;
}
}
const renderer = ReactTestRenderer.create(<Mouse />);
2016-06-02 02:17:10 +08:00
expect(renderer.toJSON()).toEqual({
type: 'div',
props: {},
children: ['mouse'],
});
const mouse = renderer.getInstance();
2016-06-02 02:17:10 +08:00
mouse.handleMoose();
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['moose'],
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
props: {},
2016-06-02 02:17:10 +08:00
});
});
2016-09-07 06:18:42 +08:00
it('updates types', () => {
const renderer = ReactTestRenderer.create(<div>mouse</div>);
expect(renderer.toJSON()).toEqual({
type: 'div',
props: {},
children: ['mouse'],
});
renderer.update(<span>mice</span>);
expect(renderer.toJSON()).toEqual({
type: 'span',
props: {},
children: ['mice'],
});
});
2016-09-07 06:18:42 +08:00
it('updates children', () => {
const renderer = ReactTestRenderer.create(
<div>
<span key="a">A</span>
<span key="b">B</span>
<span key="c">C</span>
2017-03-14 08:05:18 +08:00
</div>,
);
expect(renderer.toJSON()).toEqual({
type: 'div',
props: {},
children: [
{type: 'span', props: {}, children: ['A']},
{type: 'span', props: {}, children: ['B']},
{type: 'span', props: {}, children: ['C']},
],
});
renderer.update(
<div>
<span key="d">D</span>
<span key="c">C</span>
<span key="b">B</span>
2017-03-14 08:05:18 +08:00
</div>,
);
expect(renderer.toJSON()).toEqual({
type: 'div',
props: {},
children: [
{type: 'span', props: {}, children: ['D']},
{type: 'span', props: {}, children: ['C']},
{type: 'span', props: {}, children: ['B']},
],
});
});
2016-09-07 06:18:42 +08:00
it('does the full lifecycle', () => {
const log = [];
class Log extends React.Component {
render() {
log.push('render ' + this.props.name);
return <div />;
}
componentDidMount() {
log.push('mount ' + this.props.name);
}
componentWillUnmount() {
log.push('unmount ' + this.props.name);
}
}
const renderer = ReactTestRenderer.create(<Log key="foo" name="Foo" />);
renderer.update(<Log key="bar" name="Bar" />);
renderer.unmount();
expect(log).toEqual([
'render Foo',
'mount Foo',
'render Bar',
'unmount Foo',
'mount Bar',
'unmount Bar',
]);
});
2016-09-07 06:18:42 +08:00
it('gives a ref to native components', () => {
const log = [];
2017-03-14 08:05:18 +08:00
ReactTestRenderer.create(<div ref={r => log.push(r)} />);
expect(log).toEqual([null]);
});
2016-09-07 06:18:42 +08:00
it('warns correctly for refs on SFCs', () => {
function Bar() {
return <div>Hello, world</div>;
}
class Foo extends React.Component {
render() {
return <Bar ref="foo" />;
}
}
class Baz extends React.Component {
render() {
return <div ref="baz" />;
}
}
ReactTestRenderer.create(<Baz />);
expect(() => ReactTestRenderer.create(<Foo />)).toWarnDev(
'Warning: Stateless function components cannot be given refs. Attempts ' +
'to access this ref will fail.\n\nCheck the render method of `Foo`.\n' +
' in Bar (at **)\n' +
' in Foo (at **)',
);
});
it('allows an optional createNodeMock function', () => {
const mockDivInstance = {appendChild: () => {}};
const mockInputInstance = {focus: () => {}};
const mockListItemInstance = {click: () => {}};
const mockAnchorInstance = {hover: () => {}};
const log = [];
class Foo extends React.Component {
componentDidMount() {
log.push(this.refs.bar);
}
render() {
2017-03-14 08:05:18 +08:00
return <a ref="bar">Hello, world</a>;
}
}
function createNodeMock(element) {
switch (element.type) {
case 'div':
return mockDivInstance;
case 'input':
return mockInputInstance;
case 'li':
return mockListItemInstance;
case 'a':
return mockAnchorInstance;
default:
return {};
}
}
2017-03-14 08:05:18 +08:00
ReactTestRenderer.create(<div ref={r => log.push(r)} />, {createNodeMock});
ReactTestRenderer.create(<input ref={r => log.push(r)} />, {
createNodeMock,
});
ReactTestRenderer.create(
<div>
<span>
<ul>
2017-03-14 08:05:18 +08:00
<li ref={r => log.push(r)} />
</ul>
<ul>
2017-03-14 08:05:18 +08:00
<li ref={r => log.push(r)} />
<li ref={r => log.push(r)} />
</ul>
</span>
</div>,
{createNodeMock, foobar: true},
);
2017-03-14 08:05:18 +08:00
ReactTestRenderer.create(<Foo />, {createNodeMock});
ReactTestRenderer.create(<div ref={r => log.push(r)} />);
ReactTestRenderer.create(<div ref={r => log.push(r)} />, {});
expect(log).toEqual([
mockDivInstance,
mockInputInstance,
mockListItemInstance,
mockListItemInstance,
mockListItemInstance,
mockAnchorInstance,
null,
null,
]);
});
it('supports unmounting when using refs', () => {
class Foo extends React.Component {
render() {
return <div ref="foo" />;
}
}
2017-03-14 08:05:18 +08:00
const inst = ReactTestRenderer.create(<Foo />, {
createNodeMock: () => 'foo',
});
expect(() => inst.unmount()).not.toThrow();
});
it('supports unmounting inner instances', () => {
let count = 0;
class Foo extends React.Component {
componentWillUnmount() {
count++;
}
render() {
return <div />;
}
}
const inst = ReactTestRenderer.create(
<div>
<Foo />
</div>,
{
createNodeMock: () => 'foo',
},
);
expect(() => inst.unmount()).not.toThrow();
expect(count).toEqual(1);
});
it('supports updates when using refs', () => {
const log = [];
const createNodeMock = element => {
log.push(element.type);
return element.type;
};
class Foo extends React.Component {
render() {
2017-03-14 08:05:18 +08:00
return this.props.useDiv ? <div ref="foo" /> : <span ref="foo" />;
}
}
2017-03-14 08:05:18 +08:00
const inst = ReactTestRenderer.create(<Foo useDiv={true} />, {
createNodeMock,
});
inst.update(<Foo useDiv={false} />);
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
expect(log).toEqual(['div', 'span']);
});
2016-09-07 06:18:42 +08:00
it('supports error boundaries', () => {
const log = [];
class Angry extends React.Component {
render() {
2016-08-26 09:11:20 +08:00
log.push('Angry render');
throw new Error('Please, do not render me.');
}
2016-08-26 09:11:20 +08:00
componentDidMount() {
log.push('Angry componentDidMount');
}
componentWillUnmount() {
log.push('Angry componentWillUnmount');
}
}
class Boundary extends React.Component {
constructor(props) {
super(props);
this.state = {error: false};
}
render() {
2016-08-26 09:11:20 +08:00
log.push('Boundary render');
if (!this.state.error) {
2016-08-26 09:11:20 +08:00
return (
<div>
<button onClick={this.onClick}>ClickMe</button>
<Angry />
</div>
2016-08-26 09:11:20 +08:00
);
} else {
2016-08-26 09:11:20 +08:00
return <div>Happy Birthday!</div>;
}
}
2016-08-26 09:11:20 +08:00
componentDidMount() {
log.push('Boundary componentDidMount');
}
componentWillUnmount() {
log.push('Boundary componentWillUnmount');
}
onClick() {
/* do nothing */
}
componentDidCatch() {
Add stack unwinding phase for handling errors (#12201) * Add stack unwinding phase for handling errors A rewrite of error handling, with semantics that more closely match stack unwinding. Errors that are thrown during the render phase unwind to the nearest error boundary, like before. But rather than synchronously unmount the children before retrying, we restart the failed subtree within the same render phase. The failed children are still unmounted (as if all their keys changed) but without an extra commit. Commit phase errors are different. They work by scheduling an error on the update queue of the error boundary. When we enter the render phase, the error is popped off the queue. The rest of the algorithm is the same. This approach is designed to work for throwing non-errors, too, though that feature is not implemented yet. * Add experimental getDerivedStateFromCatch lifecycle Fires during the render phase, so you can recover from an error within the same pass. This aligns error boundaries more closely with try-catch semantics. Let's keep this behind a feature flag until a future release. For now, the recommendation is to keep using componentDidCatch. Eventually, the advice will be to use getDerivedStateFromCatch for handling errors and componentDidCatch only for logging. * Reconcile twice to remount failed children, instead of using a boolean * Handle effect immediately after its thrown This way we don't have to store the thrown values on the effect list. * ReactFiberIncompleteWork -> ReactFiberUnwindWork * Remove startTime * Remove TypeOfException We don't need it yet. We'll reconsider once we add another exception type. * Move replay to outer catch block This moves it out of the hot path.
2018-02-24 09:38:42 +08:00
log.push('Boundary componentDidCatch');
this.setState({error: true});
}
}
const renderer = ReactTestRenderer.create(<Boundary />);
expect(renderer.toJSON()).toEqual({
type: 'div',
props: {},
children: ['Happy Birthday!'],
});
expect(log).toEqual([
'Boundary render',
'Angry render',
'Boundary componentDidMount',
Add stack unwinding phase for handling errors (#12201) * Add stack unwinding phase for handling errors A rewrite of error handling, with semantics that more closely match stack unwinding. Errors that are thrown during the render phase unwind to the nearest error boundary, like before. But rather than synchronously unmount the children before retrying, we restart the failed subtree within the same render phase. The failed children are still unmounted (as if all their keys changed) but without an extra commit. Commit phase errors are different. They work by scheduling an error on the update queue of the error boundary. When we enter the render phase, the error is popped off the queue. The rest of the algorithm is the same. This approach is designed to work for throwing non-errors, too, though that feature is not implemented yet. * Add experimental getDerivedStateFromCatch lifecycle Fires during the render phase, so you can recover from an error within the same pass. This aligns error boundaries more closely with try-catch semantics. Let's keep this behind a feature flag until a future release. For now, the recommendation is to keep using componentDidCatch. Eventually, the advice will be to use getDerivedStateFromCatch for handling errors and componentDidCatch only for logging. * Reconcile twice to remount failed children, instead of using a boolean * Handle effect immediately after its thrown This way we don't have to store the thrown values on the effect list. * ReactFiberIncompleteWork -> ReactFiberUnwindWork * Remove startTime * Remove TypeOfException We don't need it yet. We'll reconsider once we add another exception type. * Move replay to outer catch block This moves it out of the hot path.
2018-02-24 09:38:42 +08:00
'Boundary componentDidCatch',
'Boundary render',
]);
});
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
it('can update text nodes', () => {
class Component extends React.Component {
render() {
return <div>{this.props.children}</div>;
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
}
}
const renderer = ReactTestRenderer.create(<Component>Hi</Component>);
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['Hi'],
props: {},
});
renderer.update(<Component>{['Hi', 'Bye']}</Component>);
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['Hi', 'Bye'],
props: {},
});
renderer.update(<Component>Bye</Component>);
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['Bye'],
props: {},
});
renderer.update(<Component>{42}</Component>);
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['42'],
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
props: {},
});
renderer.update(
<Component>
<div />
</Component>,
);
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
expect(renderer.toJSON()).toEqual({
type: 'div',
2017-03-14 08:05:18 +08:00
children: [
{
type: 'div',
children: null,
props: {},
},
],
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
props: {},
});
});
it('toTree() renders simple components returning host components', () => {
const Qoo = () => <span className="Qoo">Hello World!</span>;
const renderer = ReactTestRenderer.create(<Qoo />);
const tree = renderer.toTree();
cleanNodeOrArray(tree);
2017-03-14 08:05:18 +08:00
expect(prettyFormat(tree)).toEqual(
prettyFormat({
nodeType: 'component',
type: Qoo,
props: {},
instance: null,
2017-03-14 08:05:18 +08:00
rendered: {
nodeType: 'host',
type: 'span',
props: {className: 'Qoo'},
instance: null,
rendered: ['Hello World!'],
},
}),
);
});
it('toTree() handles nested Fragments', () => {
const Foo = () => (
<React.Fragment>
<React.Fragment>foo</React.Fragment>
</React.Fragment>
);
const renderer = ReactTestRenderer.create(<Foo />);
const tree = renderer.toTree();
cleanNodeOrArray(tree);
expect(prettyFormat(tree)).toEqual(
prettyFormat({
nodeType: 'component',
type: Foo,
instance: null,
props: {},
rendered: 'foo',
}),
);
});
it('toTree() handles null rendering components', () => {
class Foo extends React.Component {
render() {
return null;
}
}
const renderer = ReactTestRenderer.create(<Foo />);
const tree = renderer.toTree();
expect(tree.instance).toBeInstanceOf(Foo);
cleanNodeOrArray(tree);
expect(tree).toEqual({
type: Foo,
nodeType: 'component',
2017-03-14 08:05:18 +08:00
props: {},
instance: null,
rendered: null,
});
});
it('toTree() handles simple components that return arrays', () => {
const Foo = ({children}) => children;
const renderer = ReactTestRenderer.create(
<Foo>
<div>One</div>
<div>Two</div>
</Foo>,
);
const tree = renderer.toTree();
cleanNodeOrArray(tree);
expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: Foo,
nodeType: 'component',
props: {},
instance: null,
rendered: [
{
instance: null,
nodeType: 'host',
props: {},
rendered: ['One'],
type: 'div',
},
{
instance: null,
nodeType: 'host',
props: {},
rendered: ['Two'],
type: 'div',
},
],
}),
);
});
it('toTree() handles complicated tree of arrays', () => {
class Foo extends React.Component {
render() {
return this.props.children;
}
}
const renderer = ReactTestRenderer.create(
<div>
<Foo>
<div>One</div>
<div>Two</div>
<Foo>
<div>Three</div>
</Foo>
</Foo>
<div>Four</div>
</div>,
);
const tree = renderer.toTree();
cleanNodeOrArray(tree);
expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: 'div',
instance: null,
nodeType: 'host',
props: {},
rendered: [
{
type: Foo,
nodeType: 'component',
props: {},
instance: null,
rendered: [
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['One'],
},
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Two'],
},
{
type: Foo,
nodeType: 'component',
props: {},
instance: null,
rendered: {
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Three'],
},
},
],
},
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Four'],
},
],
}),
);
});
it('toTree() handles complicated tree of fragments', () => {
const renderer = ReactTestRenderer.create(
<React.Fragment>
<React.Fragment>
<div>One</div>
<div>Two</div>
<React.Fragment>
<div>Three</div>
</React.Fragment>
</React.Fragment>
<div>Four</div>
</React.Fragment>,
);
const tree = renderer.toTree();
cleanNodeOrArray(tree);
expect(prettyFormat(tree)).toEqual(
prettyFormat([
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['One'],
},
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Two'],
},
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Three'],
},
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Four'],
},
]),
);
});
it('root instance and createNodeMock ref return the same value', () => {
const createNodeMock = ref => ({node: ref});
let refInst = null;
const renderer = ReactTestRenderer.create(
<div ref={ref => (refInst = ref)} />,
{createNodeMock},
);
const root = renderer.getInstance();
expect(root).toEqual(refInst);
});
it('toTree() renders complicated trees of composites and hosts', () => {
// SFC returning host. no children props.
const Qoo = () => <span className="Qoo">Hello World!</span>;
// SFC returning host. passes through children.
const Foo = ({className, children}) => (
<div className={'Foo ' + className}>
<span className="Foo2">Literal</span>
{children}
</div>
);
// class composite returning composite. passes through children.
class Bar extends React.Component {
render() {
2017-03-14 08:05:18 +08:00
const {special, children} = this.props;
return <Foo className={special ? 'special' : 'normal'}>{children}</Foo>;
}
}
// class composite return composite. no children props.
class Bam extends React.Component {
render() {
return (
<Bar special={true}>
<Qoo />
</Bar>
);
}
}
const renderer = ReactTestRenderer.create(<Bam />);
const tree = renderer.toTree();
// we test for the presence of instances before nulling them out
expect(tree.instance).toBeInstanceOf(Bam);
expect(tree.rendered.instance).toBeInstanceOf(Bar);
cleanNodeOrArray(tree);
2017-03-14 08:05:18 +08:00
expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: Bam,
nodeType: 'component',
2017-03-14 08:05:18 +08:00
props: {},
instance: null,
rendered: {
2017-03-14 08:05:18 +08:00
type: Bar,
nodeType: 'component',
2017-03-14 08:05:18 +08:00
props: {special: true},
instance: null,
rendered: {
2017-03-14 08:05:18 +08:00
type: Foo,
nodeType: 'component',
props: {className: 'special'},
instance: null,
2017-03-14 08:05:18 +08:00
rendered: {
type: 'div',
nodeType: 'host',
props: {className: 'Foo special'},
instance: null,
rendered: [
{
type: 'span',
nodeType: 'host',
2017-03-14 08:05:18 +08:00
props: {className: 'Foo2'},
instance: null,
2017-03-14 08:05:18 +08:00
rendered: ['Literal'],
},
2017-03-14 08:05:18 +08:00
{
type: Qoo,
nodeType: 'component',
props: {},
instance: null,
rendered: {
type: 'span',
nodeType: 'host',
props: {className: 'Qoo'},
instance: null,
rendered: ['Hello World!'],
},
},
],
},
},
},
2017-03-14 08:05:18 +08:00
}),
);
});
it('can update text nodes when rendered as root', () => {
const renderer = ReactTestRenderer.create(['Hello', 'world']);
expect(renderer.toJSON()).toEqual(['Hello', 'world']);
renderer.update(42);
expect(renderer.toJSON()).toEqual('42');
renderer.update([42, 'world']);
expect(renderer.toJSON()).toEqual(['42', 'world']);
});
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
it('can render and update root fragments', () => {
const Component = props => props.children;
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
const renderer = ReactTestRenderer.create([
<Component key="a">Hi</Component>,
<Component key="b">Bye</Component>,
]);
expect(renderer.toJSON()).toEqual(['Hi', 'Bye']);
renderer.update(<div />);
expect(renderer.toJSON()).toEqual({
type: 'div',
children: null,
props: {},
});
renderer.update([<div key="a">goodbye</div>, 'world']);
expect(renderer.toJSON()).toEqual([
{
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
type: 'div',
children: ['goodbye'],
[Fiber] Implement test renderer (#8628) * ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
2017-01-12 03:19:32 +08:00
props: {},
},
'world',
]);
});
it('supports context providers and consumers', () => {
const {Consumer, Provider} = React.createContext('a');
function Child(props) {
return props.value;
}
function App() {
return (
<Provider value="b">
<Consumer>{value => <Child value={value} />}</Consumer>
</Provider>
);
}
const renderer = ReactTestRenderer.create(<App />);
const child = renderer.root.findByType(Child);
expect(child.children).toEqual(['b']);
expect(prettyFormat(renderer.toTree())).toEqual(
prettyFormat({
instance: null,
nodeType: 'component',
props: {},
rendered: {
instance: null,
nodeType: 'component',
props: {
value: 'b',
},
rendered: 'b',
type: Child,
},
type: App,
}),
);
});
it('supports modes', () => {
function Child(props) {
return props.value;
}
function App(props) {
return (
<React.StrictMode>
<Child value={props.value} />
</React.StrictMode>
);
}
const renderer = ReactTestRenderer.create(<App value="a" />);
const child = renderer.root.findByType(Child);
expect(child.children).toEqual(['a']);
expect(prettyFormat(renderer.toTree())).toEqual(
prettyFormat({
instance: null,
nodeType: 'component',
props: {
value: 'a',
},
rendered: {
instance: null,
nodeType: 'component',
props: {
value: 'a',
},
rendered: 'a',
type: Child,
},
type: App,
}),
);
});
it('supports forwardRef', () => {
const InnerRefed = React.forwardRef((props, ref) => (
<div>
<span ref={ref} />
</div>
));
class App extends React.Component {
render() {
return <InnerRefed ref={r => (this.ref = r)} />;
}
}
const renderer = ReactTestRenderer.create(<App />);
const tree = renderer.toTree();
cleanNodeOrArray(tree);
expect(prettyFormat(tree)).toEqual(
prettyFormat({
instance: null,
nodeType: 'component',
props: {},
rendered: {
instance: null,
nodeType: 'host',
props: {},
rendered: [
{
instance: null,
nodeType: 'host',
props: {},
rendered: [],
type: 'span',
},
],
type: 'div',
},
type: App,
}),
);
});
it('can concurrently render context with a "primary" renderer', () => {
const Context = React.createContext(null);
const Indirection = React.Fragment;
const App = () => (
<Context.Provider>
<Indirection>
<Context.Consumer>{() => null}</Context.Consumer>
</Indirection>
</Context.Provider>
);
ReactNoop.render(<App />);
ReactNoop.flush();
ReactTestRenderer.create(<App />);
});
2016-06-02 02:17:10 +08:00
});