diff --git a/packages/react-dom/src/__tests__/ReactTestUtils-test.js b/packages/react-dom/src/__tests__/ReactTestUtils-test.js
index 8b1bccac4416a..4433626f25acb 100644
--- a/packages/react-dom/src/__tests__/ReactTestUtils-test.js
+++ b/packages/react-dom/src/__tests__/ReactTestUtils-test.js
@@ -9,7 +9,6 @@
'use strict';
-import ReactShallowRenderer from 'react-test-renderer/shallow';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ReactDOMServer from 'react-dom/server';
@@ -383,48 +382,6 @@ describe('ReactTestUtils', () => {
);
});
- it('should throw when attempting to use a React element', () => {
- class SomeComponent extends React.Component {
- render() {
- return
hello, world.
;
- }
- }
-
- const handler = jest.fn().mockName('spy');
- const shallowRenderer = ReactShallowRenderer.createRenderer();
- const result = shallowRenderer.render(
- hello, world.
;
- }
- }
-
- const handler = jest.fn().mockName('spy');
- const container = document.createElement('div');
- const instance = ReactDOM.render(
- {}}
- onClick={this.handleUserClick}
- className={this.state.clicked ? 'clicked' : ''}
- />
- );
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- let result = shallowRenderer.getRenderOutput();
- expect(result.type).toEqual('div');
- expect(result.props.className).toEqual('');
- result.props.onClick();
-
- result = shallowRenderer.getRenderOutput();
- expect(result.type).toEqual('div');
- expect(result.props.className).toEqual('clicked');
- });
-
- it('can initialize state via static getDerivedStateFromProps', () => {
- class SimpleComponent extends React.Component {
- state = {
- count: 1,
- };
-
- static getDerivedStateFromProps(props, prevState) {
- return {
- count: prevState.count + props.incrementBy,
- other: 'foobar',
- };
- }
-
- render() {
- return (
-
{`count:${this.state.count}, other:${this.state.other}`}
- );
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
count:3, other:foobar
);
- });
-
- it('can setState in componentWillMount when shallow rendering', () => {
- class SimpleComponent extends React.Component {
- UNSAFE_componentWillMount() {
- this.setState({groovy: 'doovy'});
- }
-
- render() {
- return
{this.state.groovy}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
doovy
);
- });
-
- it('can setState in componentWillMount repeatedly when shallow rendering', () => {
- class SimpleComponent extends React.Component {
- state = {
- separator: '-',
- };
-
- UNSAFE_componentWillMount() {
- this.setState({groovy: 'doovy'});
- this.setState({doovy: 'groovy'});
- }
-
- render() {
- const {groovy, doovy, separator} = this.state;
-
- return
{`${groovy}${separator}${doovy}`}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
doovy-groovy
);
- });
-
- it('can setState in componentWillMount with an updater function repeatedly when shallow rendering', () => {
- class SimpleComponent extends React.Component {
- state = {
- separator: '-',
- };
-
- UNSAFE_componentWillMount() {
- this.setState(state => ({groovy: 'doovy'}));
- this.setState(state => ({doovy: state.groovy}));
- }
-
- render() {
- const {groovy, doovy, separator} = this.state;
-
- return
{`${groovy}${separator}${doovy}`}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
doovy-doovy
);
- });
-
- it('can setState in componentWillReceiveProps when shallow rendering', () => {
- class SimpleComponent extends React.Component {
- state = {count: 0};
-
- UNSAFE_componentWillReceiveProps(nextProps) {
- if (nextProps.updateState) {
- this.setState({count: 1});
- }
- }
-
- render() {
- return
{this.state.count}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(0);
-
- result = shallowRenderer.render(
);
- expect(result.props.children).toEqual(1);
- });
-
- it('can update state with static getDerivedStateFromProps when shallow rendering', () => {
- class SimpleComponent extends React.Component {
- state = {count: 1};
-
- static getDerivedStateFromProps(nextProps, prevState) {
- if (nextProps.updateState) {
- return {count: nextProps.incrementBy + prevState.count};
- }
-
- return null;
- }
-
- render() {
- return
{this.state.count}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(1);
-
- result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(3);
-
- result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(3);
- });
-
- it('should not override state with stale values if prevState is spread within getDerivedStateFromProps', () => {
- class SimpleComponent extends React.Component {
- state = {value: 0};
-
- static getDerivedStateFromProps(nextProps, prevState) {
- return {...prevState};
- }
-
- updateState = () => {
- this.setState(state => ({value: state.value + 1}));
- };
-
- render() {
- return
{`value:${this.state.value}`}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
);
- expect(result).toEqual(
value:0
);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.updateState();
- result = shallowRenderer.getRenderOutput();
- expect(result).toEqual(
value:1
);
- });
-
- it('should pass previous state to shouldComponentUpdate even with getDerivedStateFromProps', () => {
- class SimpleComponent extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- value: props.value,
- };
- }
-
- static getDerivedStateFromProps(nextProps, prevState) {
- if (nextProps.value === prevState.value) {
- return null;
- }
- return {value: nextProps.value};
- }
-
- shouldComponentUpdate(nextProps, nextState) {
- return nextState.value !== this.state.value;
- }
-
- render() {
- return
{`value:${this.state.value}`}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const initialResult = shallowRenderer.render(
-
,
- );
- expect(initialResult).toEqual(
value:initial
);
- const updatedResult = shallowRenderer.render(
-
,
- );
- expect(updatedResult).toEqual(
value:updated
);
- });
-
- it('can setState with an updater function', () => {
- let instance;
-
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
-
- render() {
- instance = this;
- return (
-
- {this.state.counter}
-
- );
- }
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
);
- expect(result.props.children).toEqual(0);
-
- instance.setState((state, props) => {
- return {counter: props.defaultCount + 1};
- });
-
- result = shallowRenderer.getRenderOutput();
- expect(result.props.children).toEqual(2);
- });
-
- it('can access component instance from setState updater function', done => {
- let instance;
-
- class SimpleComponent extends React.Component {
- state = {};
-
- render() {
- instance = this;
- return null;
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- instance.setState(function updater(state, props) {
- expect(this).toBe(instance);
- done();
- });
- });
-
- it('can setState with a callback', () => {
- let instance;
-
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
- render() {
- instance = this;
- return
{this.state.counter}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result.props.children).toBe(0);
-
- const callback = jest.fn(function() {
- expect(this).toBe(instance);
- });
-
- instance.setState({counter: 1}, callback);
-
- const updated = shallowRenderer.getRenderOutput();
- expect(updated.props.children).toBe(1);
- expect(callback).toHaveBeenCalled();
- });
-
- it('can replaceState with a callback', () => {
- let instance;
-
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
- render() {
- instance = this;
- return
{this.state.counter}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result.props.children).toBe(0);
-
- const callback = jest.fn(function() {
- expect(this).toBe(instance);
- });
-
- // No longer a public API, but we can test that it works internally by
- // reaching into the updater.
- shallowRenderer._updater.enqueueReplaceState(
- instance,
- {counter: 1},
- callback,
- );
-
- const updated = shallowRenderer.getRenderOutput();
- expect(updated.props.children).toBe(1);
- expect(callback).toHaveBeenCalled();
- });
-
- it('can forceUpdate with a callback', () => {
- let instance;
-
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
- render() {
- instance = this;
- return
{this.state.counter}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result.props.children).toBe(0);
-
- const callback = jest.fn(function() {
- expect(this).toBe(instance);
- });
-
- instance.forceUpdate(callback);
-
- const updated = shallowRenderer.getRenderOutput();
- expect(updated.props.children).toBe(0);
- expect(callback).toHaveBeenCalled();
- });
-
- it('can pass context when shallowly rendering', () => {
- class SimpleComponent extends React.Component {
- static contextTypes = {
- name: PropTypes.string,
- };
-
- render() {
- return
{this.context.name}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
, {
- name: 'foo',
- });
- expect(result).toEqual(
foo
);
- });
-
- it('should track context across updates', () => {
- class SimpleComponent extends React.Component {
- static contextTypes = {
- foo: PropTypes.string,
- };
-
- state = {
- bar: 'bar',
- };
-
- render() {
- return
{`${this.context.foo}:${this.state.bar}`}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
, {
- foo: 'foo',
- });
- expect(result).toEqual(
foo:bar
);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.setState({bar: 'baz'});
-
- result = shallowRenderer.getRenderOutput();
- expect(result).toEqual(
foo:baz
);
- });
-
- it('should filter context by contextTypes', () => {
- class SimpleComponent extends React.Component {
- static contextTypes = {
- foo: PropTypes.string,
- };
- render() {
- return
{`${this.context.foo}:${this.context.bar}`}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
, {
- foo: 'foo',
- bar: 'bar',
- });
- expect(result).toEqual(
foo:undefined
);
- });
-
- it('can fail context when shallowly rendering', () => {
- class SimpleComponent extends React.Component {
- static contextTypes = {
- name: PropTypes.string.isRequired,
- };
-
- render() {
- return
{this.context.name}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- expect(() => shallowRenderer.render(
)).toErrorDev(
- 'Warning: Failed context type: The context `name` is marked as ' +
- 'required in `SimpleComponent`, but its value is `undefined`.\n' +
- ' in SimpleComponent (at **)',
- );
- });
-
- it('should warn about propTypes (but only once)', () => {
- class SimpleComponent extends React.Component {
- render() {
- return React.createElement('div', null, this.props.name);
- }
- }
-
- SimpleComponent.propTypes = {
- name: PropTypes.string.isRequired,
- };
-
- const shallowRenderer = createRenderer();
- expect(() =>
- shallowRenderer.render(React.createElement(SimpleComponent, {name: 123})),
- ).toErrorDev(
- 'Warning: Failed prop type: Invalid prop `name` of type `number` ' +
- 'supplied to `SimpleComponent`, expected `string`.\n' +
- ' in SimpleComponent',
- );
- });
-
- it('should enable rendering of cloned element', () => {
- class SimpleComponent extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- bar: 'bar',
- };
- }
-
- render() {
- return
{`${this.props.foo}:${this.state.bar}`}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- const el =
;
- let result = shallowRenderer.render(el);
- expect(result).toEqual(
foo:bar
);
-
- const cloned = React.cloneElement(el, {foo: 'baz'});
- result = shallowRenderer.render(cloned);
- expect(result).toEqual(
baz:bar
);
- });
-
- it('this.state should be updated on setState callback inside componentWillMount', () => {
- let stateSuccessfullyUpdated = false;
-
- class Component extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = {
- hasUpdatedState: false,
- };
- }
-
- UNSAFE_componentWillMount() {
- this.setState(
- {hasUpdatedState: true},
- () => (stateSuccessfullyUpdated = this.state.hasUpdatedState),
- );
- }
-
- render() {
- return
{this.props.children}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(stateSuccessfullyUpdated).toBe(true);
- });
-
- it('should handle multiple callbacks', () => {
- const mockFn = jest.fn();
- const shallowRenderer = createRenderer();
-
- class Component extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = {
- foo: 'foo',
- };
- }
-
- UNSAFE_componentWillMount() {
- this.setState({foo: 'bar'}, () => mockFn());
- this.setState({foo: 'foobar'}, () => mockFn());
- }
-
- render() {
- return
{this.state.foo}
;
- }
- }
-
- shallowRenderer.render(
);
-
- expect(mockFn).toHaveBeenCalledTimes(2);
-
- // Ensure the callback queue is cleared after the callbacks are invoked
- const mountedInstance = shallowRenderer.getMountedInstance();
- mountedInstance.setState({foo: 'bar'}, () => mockFn());
- expect(mockFn).toHaveBeenCalledTimes(3);
- });
-
- it('should call the setState callback even if shouldComponentUpdate = false', done => {
- const mockFn = jest.fn().mockReturnValue(false);
-
- class Component extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = {
- hasUpdatedState: false,
- };
- }
-
- shouldComponentUpdate() {
- return mockFn();
- }
-
- render() {
- return
{this.state.hasUpdatedState}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- const mountedInstance = shallowRenderer.getMountedInstance();
- mountedInstance.setState({hasUpdatedState: true}, () => {
- expect(mockFn).toBeCalled();
- expect(mountedInstance.state.hasUpdatedState).toBe(true);
- done();
- });
- });
-
- it('throws usefully when rendering badly-typed elements', () => {
- const shallowRenderer = createRenderer();
-
- const renderAndVerifyWarningAndError = (Component, typeString) => {
- expect(() => {
- expect(() => shallowRenderer.render(
)).toErrorDev(
- 'React.createElement: type is invalid -- expected a string ' +
- '(for built-in components) or a class/function (for composite components) ' +
- `but got: ${typeString}.`,
- );
- }).toThrowError(
- 'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
- `components, but the provided element type was \`${typeString}\`.`,
- );
- };
-
- renderAndVerifyWarningAndError(undefined, 'undefined');
- renderAndVerifyWarningAndError(null, 'null');
- renderAndVerifyWarningAndError([], 'array');
- renderAndVerifyWarningAndError({}, 'object');
- });
-
- it('should have initial state of null if not defined', () => {
- class SomeComponent extends React.Component {
- render() {
- return
;
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- expect(shallowRenderer.getMountedInstance().state).toBeNull();
- });
-
- it('should invoke both deprecated and new lifecycles if both are present', () => {
- const log = [];
-
- class Component extends React.Component {
- componentWillMount() {
- log.push('componentWillMount');
- }
- componentWillReceiveProps() {
- log.push('componentWillReceiveProps');
- }
- componentWillUpdate() {
- log.push('componentWillUpdate');
- }
- UNSAFE_componentWillMount() {
- log.push('UNSAFE_componentWillMount');
- }
- UNSAFE_componentWillReceiveProps() {
- log.push('UNSAFE_componentWillReceiveProps');
- }
- UNSAFE_componentWillUpdate() {
- log.push('UNSAFE_componentWillUpdate');
- }
- render() {
- return null;
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
-
- log.length = 0;
-
- shallowRenderer.render(
);
- expect(log).toEqual([
- 'componentWillReceiveProps',
- 'UNSAFE_componentWillReceiveProps',
- 'componentWillUpdate',
- 'UNSAFE_componentWillUpdate',
- ]);
- });
-
- it('should stop the update when setState returns null or undefined', () => {
- const log = [];
- let instance;
- class Component extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- count: 0,
- };
- }
- render() {
- log.push('render');
- instance = this;
- return null;
- }
- }
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- log.length = 0;
- instance.setState(() => null);
- instance.setState(() => undefined);
- instance.setState(null);
- instance.setState(undefined);
- expect(log).toEqual([]);
- instance.setState(state => ({count: state.count + 1}));
- expect(log).toEqual(['render']);
- });
-
- it('should not get this in a function component', () => {
- const logs = [];
- function Foo() {
- logs.push(this);
- return
foo
;
- }
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(logs).toEqual([undefined]);
- });
-
- it('should handle memo', () => {
- function Foo() {
- return
foo
;
- }
- const MemoFoo = React.memo(Foo);
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- });
-
- it('should enable React.memo to prevent a re-render', () => {
- const logs = [];
- const Foo = React.memo(({count}) => {
- logs.push(`Foo: ${count}`);
- return
{count}
;
- });
- const Bar = React.memo(({count}) => {
- logs.push(`Bar: ${count}`);
- return
{count}
;
- });
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(logs).toEqual(['Foo: 1']);
- logs.length = 0;
- // Rendering the same element with the same props should be prevented
- shallowRenderer.render(
);
- expect(logs).toEqual([]);
- // A different element with the same props should cause a re-render
- shallowRenderer.render(
);
- expect(logs).toEqual(['Bar: 1']);
- });
-
- it('should respect a custom comparison function with React.memo', () => {
- let renderCount = 0;
- function areEqual(props, nextProps) {
- return props.foo === nextProps.foo;
- }
- const Foo = React.memo(({foo, bar}) => {
- renderCount++;
- return (
-
- {foo} {bar}
-
- );
- }, areEqual);
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(renderCount).toBe(1);
- // Change a prop that the comparison function ignores
- shallowRenderer.render(
);
- expect(renderCount).toBe(1);
- shallowRenderer.render(
);
- expect(renderCount).toBe(2);
- });
-
- it('should not call the comparison function with React.memo on the initial render', () => {
- const areEqual = jest.fn(() => false);
- const SomeComponent = React.memo(({foo}) => {
- return
{foo}
;
- }, areEqual);
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(areEqual).not.toHaveBeenCalled();
- expect(shallowRenderer.getRenderOutput()).toEqual(
{1}
);
- });
-
- it('should handle memo(forwardRef())', () => {
- const testRef = React.createRef();
- const SomeComponent = React.forwardRef((props, ref) => {
- expect(ref).toEqual(testRef);
- return (
-
-
-
-
- );
- });
-
- const SomeMemoComponent = React.memo(SomeComponent);
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
-
- expect(result.type).toBe('div');
- expect(result.props.children).toEqual([
-
,
-
,
- ]);
- });
-
- it('should warn for forwardRef(memo())', () => {
- const testRef = React.createRef();
- const SomeMemoComponent = React.memo(({foo}) => {
- return
{foo}
;
- });
- const shallowRenderer = createRenderer();
- expect(() => {
- expect(() => {
- const SomeComponent = React.forwardRef(SomeMemoComponent);
- shallowRenderer.render(
);
- }).toErrorDev(
- 'Warning: forwardRef requires a render function but received ' +
- 'a `memo` component. Instead of forwardRef(memo(...)), use ' +
- 'memo(forwardRef(...))',
- {withoutStack: true},
- );
- }).toThrowError(
- 'forwardRef requires a render function but was given object.',
- );
- });
-
- it('should let you change type', () => {
- function Foo({prop}) {
- return
Foo {prop}
;
- }
- function Bar({prop}) {
- return
Bar {prop}
;
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Foo {'foo1'}
);
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Foo {'foo2'}
);
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Bar {'bar1'}
);
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Bar {'bar2'}
);
- });
-
- it('should let you change class type', () => {
- class Foo extends React.Component {
- render() {
- return
Foo {this.props.prop}
;
- }
- }
- class Bar extends React.Component {
- render() {
- return
Bar {this.props.prop}
;
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Foo {'foo1'}
);
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Foo {'foo2'}
);
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Bar {'bar1'}
);
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
Bar {'bar2'}
);
- });
-});
diff --git a/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js b/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js
deleted file mode 100644
index 64854d3d6d6de..0000000000000
--- a/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js
+++ /dev/null
@@ -1,487 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its 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';
-
-import * as React from 'react';
-import ReactShallowRenderer from 'react-test-renderer/shallow';
-
-const createRenderer = ReactShallowRenderer.createRenderer;
-
-describe('ReactShallowRenderer with hooks', () => {
- it('should work with useState', () => {
- function SomeComponent({defaultName}) {
- const [name] = React.useState(defaultName);
-
- return (
-
-
- Your name is: {name}
-
-
- );
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
-
,
- );
-
- expect(result).toEqual(
-
-
- Your name is: Dominic
-
-
,
- );
-
- result = shallowRenderer.render(
-
,
- );
-
- expect(result).toEqual(
-
-
- Your name is: Dominic
-
-
,
- );
- });
-
- it('should work with updating a value from useState', () => {
- function SomeComponent({defaultName}) {
- const [name, updateName] = React.useState(defaultName);
-
- if (name !== 'Dan') {
- updateName('Dan');
- }
-
- return (
-
-
- Your name is: {name}
-
-
- );
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
-
,
- );
-
- expect(result).toEqual(
-
-
- Your name is: Dan
-
-
,
- );
- });
-
- it('should work with updating a derived value from useState', () => {
- let _updateName;
-
- function SomeComponent({defaultName}) {
- const [name, updateName] = React.useState(defaultName);
- const [prevName, updatePrevName] = React.useState(defaultName);
- const [letter, updateLetter] = React.useState(name[0]);
-
- _updateName = updateName;
-
- if (name !== prevName) {
- updatePrevName(name);
- updateLetter(name[0]);
- }
-
- return (
-
-
- Your name is: {name + ' (' + letter + ')'}
-
-
- );
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
-
,
- );
- expect(result).toEqual(
-
-
- Your name is: Sophie (S)
-
-
,
- );
-
- result = shallowRenderer.render(
);
- expect(result).toEqual(
-
-
- Your name is: Sophie (S)
-
-
,
- );
-
- _updateName('Dan');
- expect(shallowRenderer.getRenderOutput()).toEqual(
-
-
- Your name is: Dan (D)
-
-
,
- );
- });
-
- it('should work with useReducer', () => {
- function reducer(state, action) {
- switch (action.type) {
- case 'increment':
- return {count: state.count + 1};
- case 'decrement':
- return {count: state.count - 1};
- }
- }
-
- function SomeComponent(props) {
- const [state] = React.useReducer(reducer, props, p => ({
- count: p.initialCount,
- }));
-
- return (
-
-
- The counter is at: {state.count.toString()}
-
-
- );
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
);
-
- expect(result).toEqual(
-
-
- The counter is at: 0
-
-
,
- );
-
- result = shallowRenderer.render(
);
-
- expect(result).toEqual(
-
-
- The counter is at: 0
-
-
,
- );
- });
-
- it('should work with a dispatched state change for a useReducer', () => {
- function reducer(state, action) {
- switch (action.type) {
- case 'increment':
- return {count: state.count + 1};
- case 'decrement':
- return {count: state.count - 1};
- }
- }
-
- function SomeComponent(props) {
- const [state, dispatch] = React.useReducer(reducer, props, p => ({
- count: p.initialCount,
- }));
-
- if (state.count === 0) {
- dispatch({type: 'increment'});
- }
-
- return (
-
-
- The counter is at: {state.count.toString()}
-
-
- );
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
-
- expect(result).toEqual(
-
-
- The counter is at: 1
-
-
,
- );
- });
-
- it('should not trigger effects', () => {
- const effectsCalled = [];
-
- function SomeComponent({defaultName}) {
- React.useEffect(() => {
- effectsCalled.push('useEffect');
- });
-
- React.useLayoutEffect(() => {
- effectsCalled.push('useEffect');
- });
-
- return
Hello world
;
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- expect(effectsCalled).toEqual([]);
- });
-
- it('should work with useRef', () => {
- function SomeComponent() {
- const randomNumberRef = React.useRef({number: Math.random()});
-
- return (
-
-
The random number is: {randomNumberRef.current.number}
-
- );
- }
-
- const shallowRenderer = createRenderer();
- const firstResult = shallowRenderer.render(
);
- const secondResult = shallowRenderer.render(
);
-
- expect(firstResult).toEqual(secondResult);
- });
-
- it('should work with useMemo', () => {
- function SomeComponent() {
- const randomNumber = React.useMemo(() => {
- return {number: Math.random()};
- }, []);
-
- return (
-
-
The random number is: {randomNumber.number}
-
- );
- }
-
- const shallowRenderer = createRenderer();
- const firstResult = shallowRenderer.render(
);
- const secondResult = shallowRenderer.render(
);
-
- expect(firstResult).toEqual(secondResult);
- });
-
- it('should work with useContext', () => {
- const SomeContext = React.createContext('default');
-
- function SomeComponent() {
- const value = React.useContext(SomeContext);
-
- return (
-
- );
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
-
- expect(result).toEqual(
-
,
- );
- });
-
- it('should not leak state when component type changes', () => {
- function SomeComponent({defaultName}) {
- const [name] = React.useState(defaultName);
-
- return (
-
-
- Your name is: {name}
-
-
- );
- }
-
- function SomeOtherComponent({defaultName}) {
- const [name] = React.useState(defaultName);
-
- return (
-
-
- Your name is: {name}
-
-
- );
- }
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
-
,
- );
- expect(result).toEqual(
-
-
- Your name is: Dominic
-
-
,
- );
-
- result = shallowRenderer.render(
);
- expect(result).toEqual(
-
-
- Your name is: Dan
-
-
,
- );
- });
-
- it('should work with forwardRef + any hook', () => {
- const SomeComponent = React.forwardRef((props, ref) => {
- const randomNumberRef = React.useRef({number: Math.random()});
-
- return (
-
-
The random number is: {randomNumberRef.current.number}
-
- );
- });
-
- const shallowRenderer = createRenderer();
- const firstResult = shallowRenderer.render(
);
- const secondResult = shallowRenderer.render(
);
-
- expect(firstResult).toEqual(secondResult);
- });
-
- it('should update a value from useState outside the render', () => {
- let _dispatch;
-
- function SomeComponent({defaultName}) {
- const [count, dispatch] = React.useReducer(
- (s, a) => (a === 'inc' ? s + 1 : s),
- 0,
- );
- const [name, updateName] = React.useState(defaultName);
- _dispatch = () => dispatch('inc');
-
- return (
-
updateName('Dan')}>
-
- Your name is: {name} ({count})
-
-
- );
- }
-
- const shallowRenderer = createRenderer();
- const element =
;
- const result = shallowRenderer.render(element);
- expect(result.props.children).toEqual(
-
- Your name is: Dominic ({0})
-
,
- );
-
- result.props.onClick();
- let updated = shallowRenderer.render(element);
- expect(updated.props.children).toEqual(
-
- Your name is: Dan ({0})
-
,
- );
-
- _dispatch('foo');
- updated = shallowRenderer.render(element);
- expect(updated.props.children).toEqual(
-
- Your name is: Dan ({1})
-
,
- );
-
- _dispatch('inc');
- updated = shallowRenderer.render(element);
- expect(updated.props.children).toEqual(
-
- Your name is: Dan ({2})
-
,
- );
- });
-
- it('should ignore a foreign update outside the render', () => {
- let _updateCountForFirstRender;
-
- function SomeComponent() {
- const [count, updateCount] = React.useState(0);
- if (!_updateCountForFirstRender) {
- _updateCountForFirstRender = updateCount;
- }
- return count;
- }
-
- const shallowRenderer = createRenderer();
- const element =
;
- let result = shallowRenderer.render(element);
- expect(result).toEqual(0);
- _updateCountForFirstRender(1);
- result = shallowRenderer.render(element);
- expect(result).toEqual(1);
-
- shallowRenderer.unmount();
- result = shallowRenderer.render(element);
- expect(result).toEqual(0);
- _updateCountForFirstRender(1); // Should be ignored.
- result = shallowRenderer.render(element);
- expect(result).toEqual(0);
- });
-
- it('should not forget render phase updates', () => {
- let _updateCount;
-
- function SomeComponent() {
- const [count, updateCount] = React.useState(0);
- _updateCount = updateCount;
- if (count < 5) {
- updateCount(x => x + 1);
- }
- return count;
- }
-
- const shallowRenderer = createRenderer();
- const element =
;
- let result = shallowRenderer.render(element);
- expect(result).toEqual(5);
-
- _updateCount(10);
- result = shallowRenderer.render(element);
- expect(result).toEqual(10);
-
- _updateCount(x => x + 1);
- result = shallowRenderer.render(element);
- expect(result).toEqual(11);
-
- _updateCount(x => x - 10);
- result = shallowRenderer.render(element);
- expect(result).toEqual(5);
- });
-});
diff --git a/packages/react-test-renderer/src/__tests__/ReactShallowRendererMemo-test.js b/packages/react-test-renderer/src/__tests__/ReactShallowRendererMemo-test.js
deleted file mode 100644
index a0c0f7fc46139..0000000000000
--- a/packages/react-test-renderer/src/__tests__/ReactShallowRendererMemo-test.js
+++ /dev/null
@@ -1,1514 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its 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';
-
-import * as PropTypes from 'prop-types';
-import * as React from 'react';
-import ReactShallowRenderer from 'react-test-renderer/shallow';
-
-const createRenderer = ReactShallowRenderer.createRenderer;
-
-describe('ReactShallowRendererMemo', () => {
- it('should call all of the legacy lifecycle hooks', () => {
- const logs = [];
- const logger = message => () => logs.push(message) || true;
-
- const SomeComponent = React.memo(
- class SomeComponent extends React.Component {
- UNSAFE_componentWillMount = logger('componentWillMount');
- componentDidMount = logger('componentDidMount');
- UNSAFE_componentWillReceiveProps = logger('componentWillReceiveProps');
- shouldComponentUpdate = logger('shouldComponentUpdate');
- UNSAFE_componentWillUpdate = logger('componentWillUpdate');
- componentDidUpdate = logger('componentDidUpdate');
- componentWillUnmount = logger('componentWillUnmount');
- render() {
- return
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- // Calling cDU might lead to problems with host component references.
- // Since our components aren't really mounted, refs won't be available.
- expect(logs).toEqual(['componentWillMount']);
-
- logs.splice(0);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.setState({});
-
- expect(logs).toEqual(['shouldComponentUpdate', 'componentWillUpdate']);
-
- logs.splice(0);
-
- shallowRenderer.render(
);
-
- // The previous shallow renderer did not trigger cDU for props changes.
- expect(logs).toEqual([
- 'componentWillReceiveProps',
- 'shouldComponentUpdate',
- 'componentWillUpdate',
- ]);
- });
-
- it('should call all of the new lifecycle hooks', () => {
- const logs = [];
- const logger = message => () => logs.push(message) || true;
-
- const SomeComponent = React.memo(
- class SomeComponent extends React.Component {
- state = {};
- static getDerivedStateFromProps = logger('getDerivedStateFromProps');
- componentDidMount = logger('componentDidMount');
- shouldComponentUpdate = logger('shouldComponentUpdate');
- componentDidUpdate = logger('componentDidUpdate');
- componentWillUnmount = logger('componentWillUnmount');
- render() {
- return
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- // Calling cDU might lead to problems with host component references.
- // Since our components aren't really mounted, refs won't be available.
- expect(logs).toEqual(['getDerivedStateFromProps']);
-
- logs.splice(0);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.setState({});
-
- expect(logs).toEqual(['getDerivedStateFromProps', 'shouldComponentUpdate']);
-
- logs.splice(0);
-
- shallowRenderer.render(
);
-
- // The previous shallow renderer did not trigger cDU for props changes.
- expect(logs).toEqual(['getDerivedStateFromProps', 'shouldComponentUpdate']);
- });
-
- it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present', () => {
- const Component = React.memo(
- class Component extends React.Component {
- state = {};
- static getDerivedStateFromProps() {
- return null;
- }
- componentWillMount() {
- throw Error('unexpected');
- }
- componentWillReceiveProps() {
- throw Error('unexpected');
- }
- componentWillUpdate() {
- throw Error('unexpected');
- }
- render() {
- return null;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- });
-
- it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', () => {
- const Component = React.memo(
- class Component extends React.Component {
- getSnapshotBeforeUpdate() {
- return null;
- }
- componentWillMount() {
- throw Error('unexpected');
- }
- componentWillReceiveProps() {
- throw Error('unexpected');
- }
- componentWillUpdate() {
- throw Error('unexpected');
- }
- render() {
- return null;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- shallowRenderer.render(
);
- });
-
- it('should not call getSnapshotBeforeUpdate or componentDidUpdate when updating since refs wont exist', () => {
- const Component = React.memo(
- class Component extends React.Component {
- getSnapshotBeforeUpdate() {
- throw Error('unexpected');
- }
- componentDidUpdate() {
- throw Error('unexpected');
- }
- render() {
- return null;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- shallowRenderer.render(
);
- });
-
- it('should only render 1 level deep', () => {
- const Parent = React.memo(function Parent() {
- return (
-
-
-
- );
- });
-
- function Child() {
- throw Error('This component should not render');
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(React.createElement(Parent));
- });
-
- it('should have shallow rendering', () => {
- const SomeComponent = React.memo(
- class SomeComponent extends React.Component {
- render() {
- return (
-
-
-
-
- );
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
-
- expect(result.type).toBe('div');
- expect(result.props.children).toEqual([
-
,
-
,
- ]);
- });
-
- it('should handle Profiler', () => {
- const SomeComponent = React.memo(
- class SomeComponent extends React.Component {
- render() {
- return (
-
-
-
-
-
-
- );
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
-
- expect(result.type).toBe(React.Profiler);
- expect(result.props.children).toEqual(
-
-
-
-
,
- );
- });
-
- it('should enable shouldComponentUpdate to prevent a re-render', () => {
- let renderCounter = 0;
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {update: false};
- shouldComponentUpdate(nextProps, nextState) {
- return this.state.update !== nextState.update;
- }
- render() {
- renderCounter++;
- return
{`${renderCounter}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
1
);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.setState({update: false});
- expect(shallowRenderer.getRenderOutput()).toEqual(
1
);
-
- instance.setState({update: true});
- expect(shallowRenderer.getRenderOutput()).toEqual(
2
);
- });
-
- it('should enable PureComponent to prevent a re-render', () => {
- let renderCounter = 0;
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.PureComponent {
- state = {update: false};
- render() {
- renderCounter++;
- return
{`${renderCounter}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(shallowRenderer.getRenderOutput()).toEqual(
1
);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.setState({update: false});
- expect(shallowRenderer.getRenderOutput()).toEqual(
1
);
-
- instance.setState({update: true});
- expect(shallowRenderer.getRenderOutput()).toEqual(
2
);
- });
-
- it('should not run shouldComponentUpdate during forced update', () => {
- let scuCounter = 0;
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {count: 1};
- shouldComponentUpdate() {
- scuCounter++;
- return false;
- }
- render() {
- return
{`${this.state.count}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(scuCounter).toEqual(0);
- expect(shallowRenderer.getRenderOutput()).toEqual(
1
);
-
- // Force update the initial state. sCU should not fire.
- const instance = shallowRenderer.getMountedInstance();
- instance.forceUpdate();
- expect(scuCounter).toEqual(0);
- expect(shallowRenderer.getRenderOutput()).toEqual(
1
);
-
- // Setting state updates the instance, but doesn't re-render
- // because sCU returned false.
- instance.setState(state => ({count: state.count + 1}));
- expect(scuCounter).toEqual(1);
- expect(instance.state.count).toEqual(2);
- expect(shallowRenderer.getRenderOutput()).toEqual(
1
);
-
- // A force update updates the render output, but doesn't call sCU.
- instance.forceUpdate();
- expect(scuCounter).toEqual(1);
- expect(instance.state.count).toEqual(2);
- expect(shallowRenderer.getRenderOutput()).toEqual(
2
);
- });
-
- it('should rerender when calling forceUpdate', () => {
- let renderCounter = 0;
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- render() {
- renderCounter += 1;
- return
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(renderCounter).toEqual(1);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.forceUpdate();
- expect(renderCounter).toEqual(2);
- });
-
- it('should shallow render a function component', () => {
- function SomeComponent(props, context) {
- return (
-
-
{props.foo}
-
{context.bar}
-
-
-
- );
- }
- const SomeMemoComponent = React.memo(SomeComponent);
-
- SomeComponent.contextTypes = {
- bar: PropTypes.string,
- };
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
, {
- bar: 'BAR',
- });
-
- expect(result.type).toBe('div');
- expect(result.props.children).toEqual([
-
FOO
,
-
BAR
,
-
,
-
,
- ]);
- });
-
- it('should shallow render a component returning strings directly from render', () => {
- const Text = React.memo(({value}) => value);
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual('foo');
- });
-
- it('should shallow render a component returning numbers directly from render', () => {
- const Text = React.memo(({value}) => value);
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(10);
- });
-
- it('should shallow render a fragment', () => {
- class SomeComponent extends React.Component {
- render() {
- return
;
- }
- }
- class Fragment extends React.Component {
- render() {
- return [
,
,
];
- }
- }
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual([
-
,
-
,
-
,
- ]);
- });
-
- it('should shallow render a React.fragment', () => {
- class SomeComponent extends React.Component {
- render() {
- return
;
- }
- }
- class Fragment extends React.Component {
- render() {
- return (
- <>
-
-
-
- >
- );
- }
- }
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
- <>
-
-
-
- >,
- );
- });
-
- it('should throw for invalid elements', () => {
- class SomeComponent extends React.Component {
- render() {
- return
;
- }
- }
-
- const shallowRenderer = createRenderer();
- expect(() => shallowRenderer.render(SomeComponent)).toThrowError(
- 'ReactShallowRenderer render(): Invalid component element. Instead of ' +
- 'passing a component class, make sure to instantiate it by passing it ' +
- 'to React.createElement.',
- );
- expect(() => shallowRenderer.render(
)).toThrowError(
- 'ReactShallowRenderer render(): Shallow rendering works only with ' +
- 'custom components, not primitives (div). Instead of calling ' +
- '`.render(el)` and inspecting the rendered output, look at `el.props` ' +
- 'directly instead.',
- );
- });
-
- it('should have shallow unmounting', () => {
- const componentWillUnmount = jest.fn();
-
- class SomeComponent extends React.Component {
- componentWillUnmount = componentWillUnmount;
- render() {
- return
;
- }
- }
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- shallowRenderer.unmount();
-
- expect(componentWillUnmount).toBeCalled();
- });
-
- it('can shallow render to null', () => {
- class SomeComponent extends React.Component {
- render() {
- return null;
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
-
- expect(result).toBe(null);
- });
-
- it('can shallow render with a ref', () => {
- class SomeComponent extends React.Component {
- render() {
- return
;
- }
- }
-
- const shallowRenderer = createRenderer();
- // Shouldn't crash.
- shallowRenderer.render(
);
- });
-
- it('lets you update shallowly rendered components', () => {
- class SomeComponent extends React.Component {
- state = {clicked: false};
-
- onClick = () => {
- this.setState({clicked: true});
- };
-
- render() {
- const className = this.state.clicked ? 'was-clicked' : '';
-
- if (this.props.aNew === 'prop') {
- return (
-
- Test link
-
- );
- } else {
- return (
-
-
-
-
- );
- }
- }
- }
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result.type).toBe('div');
- expect(result.props.children).toEqual([
-
,
-
,
- ]);
-
- const updatedResult = shallowRenderer.render(
);
- expect(updatedResult.type).toBe('a');
-
- const mockEvent = {};
- updatedResult.props.onClick(mockEvent);
-
- const updatedResultCausedByClick = shallowRenderer.getRenderOutput();
- expect(updatedResultCausedByClick.type).toBe('a');
- expect(updatedResultCausedByClick.props.className).toBe('was-clicked');
- });
-
- it('can access the mounted component instance', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- someMethod = () => {
- return this.props.n;
- };
-
- render() {
- return
{this.props.n}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(shallowRenderer.getMountedInstance().someMethod()).toEqual(5);
- });
-
- it('can shallowly render components with contextTypes', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- static contextTypes = {
- name: PropTypes.string,
- };
-
- render() {
- return
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
);
- });
-
- it('passes expected params to legacy component lifecycle methods', () => {
- const componentDidUpdateParams = [];
- const componentWillReceivePropsParams = [];
- const componentWillUpdateParams = [];
- const setStateParams = [];
- const shouldComponentUpdateParams = [];
-
- const initialProp = {prop: 'init prop'};
- const initialState = {state: 'init state'};
- const initialContext = {context: 'init context'};
- const updatedState = {state: 'updated state'};
- const updatedProp = {prop: 'updated prop'};
- const updatedContext = {context: 'updated context'};
-
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = initialState;
- }
- static contextTypes = {
- context: PropTypes.string,
- };
- componentDidUpdate(...args) {
- componentDidUpdateParams.push(...args);
- }
- UNSAFE_componentWillReceiveProps(...args) {
- componentWillReceivePropsParams.push(...args);
- this.setState((...innerArgs) => {
- setStateParams.push(...innerArgs);
- return updatedState;
- });
- }
- UNSAFE_componentWillUpdate(...args) {
- componentWillUpdateParams.push(...args);
- }
- shouldComponentUpdate(...args) {
- shouldComponentUpdateParams.push(...args);
- return true;
- }
- render() {
- return null;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
- React.createElement(SimpleComponent, initialProp),
- initialContext,
- );
- expect(componentDidUpdateParams).toEqual([]);
- expect(componentWillReceivePropsParams).toEqual([]);
- expect(componentWillUpdateParams).toEqual([]);
- expect(setStateParams).toEqual([]);
- expect(shouldComponentUpdateParams).toEqual([]);
-
- // Lifecycle hooks should be invoked with the correct prev/next params on update.
- shallowRenderer.render(
- React.createElement(SimpleComponent, updatedProp),
- updatedContext,
- );
- expect(componentWillReceivePropsParams).toEqual([
- updatedProp,
- updatedContext,
- ]);
- expect(setStateParams).toEqual([initialState, initialProp]);
- expect(shouldComponentUpdateParams).toEqual([
- updatedProp,
- updatedState,
- updatedContext,
- ]);
- expect(componentWillUpdateParams).toEqual([
- updatedProp,
- updatedState,
- updatedContext,
- ]);
- expect(componentDidUpdateParams).toEqual([]);
- });
-
- it('passes expected params to new component lifecycle methods', () => {
- const componentDidUpdateParams = [];
- const getDerivedStateFromPropsParams = [];
- const shouldComponentUpdateParams = [];
-
- const initialProp = {prop: 'init prop'};
- const initialState = {state: 'init state'};
- const initialContext = {context: 'init context'};
- const updatedProp = {prop: 'updated prop'};
- const updatedContext = {context: 'updated context'};
-
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = initialState;
- }
- static contextTypes = {
- context: PropTypes.string,
- };
- componentDidUpdate(...args) {
- componentDidUpdateParams.push(...args);
- }
- static getDerivedStateFromProps(...args) {
- getDerivedStateFromPropsParams.push(args);
- return null;
- }
- shouldComponentUpdate(...args) {
- shouldComponentUpdateParams.push(...args);
- return true;
- }
- render() {
- return null;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
-
- // The only lifecycle hook that should be invoked on initial render
- // Is the static getDerivedStateFromProps() methods
- shallowRenderer.render(
- React.createElement(SimpleComponent, initialProp),
- initialContext,
- );
- expect(getDerivedStateFromPropsParams).toEqual([
- [initialProp, initialState],
- ]);
- expect(componentDidUpdateParams).toEqual([]);
- expect(shouldComponentUpdateParams).toEqual([]);
-
- // Lifecycle hooks should be invoked with the correct prev/next params on update.
- shallowRenderer.render(
- React.createElement(SimpleComponent, updatedProp),
- updatedContext,
- );
- expect(getDerivedStateFromPropsParams).toEqual([
- [initialProp, initialState],
- [updatedProp, initialState],
- ]);
- expect(shouldComponentUpdateParams).toEqual([
- updatedProp,
- initialState,
- updatedContext,
- ]);
- expect(componentDidUpdateParams).toEqual([]);
- });
-
- it('can shallowly render components with ref as function', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {clicked: false};
-
- handleUserClick = () => {
- this.setState({clicked: true});
- };
-
- render() {
- return (
-
{}}
- onClick={this.handleUserClick}
- className={this.state.clicked ? 'clicked' : ''}
- />
- );
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- let result = shallowRenderer.getRenderOutput();
- expect(result.type).toEqual('div');
- expect(result.props.className).toEqual('');
- result.props.onClick();
-
- result = shallowRenderer.getRenderOutput();
- expect(result.type).toEqual('div');
- expect(result.props.className).toEqual('clicked');
- });
-
- it('can initialize state via static getDerivedStateFromProps', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {
- count: 1,
- };
-
- static getDerivedStateFromProps(props, prevState) {
- return {
- count: prevState.count + props.incrementBy,
- other: 'foobar',
- };
- }
-
- render() {
- return (
-
{`count:${this.state.count}, other:${this.state.other}`}
- );
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
count:3, other:foobar
);
- });
-
- it('can setState in componentWillMount when shallow rendering', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- UNSAFE_componentWillMount() {
- this.setState({groovy: 'doovy'});
- }
-
- render() {
- return
{this.state.groovy}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
doovy
);
- });
-
- it('can setState in componentWillMount repeatedly when shallow rendering', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {
- separator: '-',
- };
-
- UNSAFE_componentWillMount() {
- this.setState({groovy: 'doovy'});
- this.setState({doovy: 'groovy'});
- }
-
- render() {
- const {groovy, doovy, separator} = this.state;
-
- return
{`${groovy}${separator}${doovy}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
doovy-groovy
);
- });
-
- it('can setState in componentWillMount with an updater function repeatedly when shallow rendering', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {
- separator: '-',
- };
-
- UNSAFE_componentWillMount() {
- this.setState(state => ({groovy: 'doovy'}));
- this.setState(state => ({doovy: state.groovy}));
- }
-
- render() {
- const {groovy, doovy, separator} = this.state;
-
- return
{`${groovy}${separator}${doovy}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result).toEqual(
doovy-doovy
);
- });
-
- it('can setState in componentWillReceiveProps when shallow rendering', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {count: 0};
-
- UNSAFE_componentWillReceiveProps(nextProps) {
- if (nextProps.updateState) {
- this.setState({count: 1});
- }
- }
-
- render() {
- return
{this.state.count}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(0);
-
- result = shallowRenderer.render(
);
- expect(result.props.children).toEqual(1);
- });
-
- it('can update state with static getDerivedStateFromProps when shallow rendering', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {count: 1};
-
- static getDerivedStateFromProps(nextProps, prevState) {
- if (nextProps.updateState) {
- return {count: nextProps.incrementBy + prevState.count};
- }
-
- return null;
- }
-
- render() {
- return
{this.state.count}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(1);
-
- result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(3);
-
- result = shallowRenderer.render(
-
,
- );
- expect(result.props.children).toEqual(3);
- });
-
- it('should not override state with stale values if prevState is spread within getDerivedStateFromProps', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {value: 0};
-
- static getDerivedStateFromProps(nextProps, prevState) {
- return {...prevState};
- }
-
- updateState = () => {
- this.setState(state => ({value: state.value + 1}));
- };
-
- render() {
- return
{`value:${this.state.value}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
);
- expect(result).toEqual(
value:0
);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.updateState();
- result = shallowRenderer.getRenderOutput();
- expect(result).toEqual(
value:1
);
- });
-
- it('should pass previous state to shouldComponentUpdate even with getDerivedStateFromProps', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- value: props.value,
- };
- }
-
- static getDerivedStateFromProps(nextProps, prevState) {
- if (nextProps.value === prevState.value) {
- return null;
- }
- return {value: nextProps.value};
- }
-
- shouldComponentUpdate(nextProps, nextState) {
- return nextState.value !== this.state.value;
- }
-
- render() {
- return
{`value:${this.state.value}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const initialResult = shallowRenderer.render(
-
,
- );
- expect(initialResult).toEqual(
value:initial
);
- const updatedResult = shallowRenderer.render(
-
,
- );
- expect(updatedResult).toEqual(
value:updated
);
- });
-
- it('can setState with an updater function', () => {
- let instance;
-
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
-
- render() {
- instance = this;
- return (
-
- {this.state.counter}
-
- );
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
);
- expect(result.props.children).toEqual(0);
-
- instance.setState((state, props) => {
- return {counter: props.defaultCount + 1};
- });
-
- result = shallowRenderer.getRenderOutput();
- expect(result.props.children).toEqual(2);
- });
-
- it('can access component instance from setState updater function', done => {
- let instance;
-
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {};
-
- render() {
- instance = this;
- return null;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- instance.setState(function updater(state, props) {
- expect(this).toBe(instance);
- done();
- });
- });
-
- it('can setState with a callback', () => {
- let instance;
-
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
- render() {
- instance = this;
- return
{this.state.counter}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result.props.children).toBe(0);
-
- const callback = jest.fn(function() {
- expect(this).toBe(instance);
- });
-
- instance.setState({counter: 1}, callback);
-
- const updated = shallowRenderer.getRenderOutput();
- expect(updated.props.children).toBe(1);
- expect(callback).toHaveBeenCalled();
- });
-
- it('can replaceState with a callback', () => {
- let instance;
-
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
- render() {
- instance = this;
- return
{this.state.counter}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result.props.children).toBe(0);
-
- const callback = jest.fn(function() {
- expect(this).toBe(instance);
- });
-
- // No longer a public API, but we can test that it works internally by
- // reaching into the updater.
- shallowRenderer._updater.enqueueReplaceState(
- instance,
- {counter: 1},
- callback,
- );
-
- const updated = shallowRenderer.getRenderOutput();
- expect(updated.props.children).toBe(1);
- expect(callback).toHaveBeenCalled();
- });
-
- it('can forceUpdate with a callback', () => {
- let instance;
-
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- state = {
- counter: 0,
- };
- render() {
- instance = this;
- return
{this.state.counter}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
);
- expect(result.props.children).toBe(0);
-
- const callback = jest.fn(function() {
- expect(this).toBe(instance);
- });
-
- instance.forceUpdate(callback);
-
- const updated = shallowRenderer.getRenderOutput();
- expect(updated.props.children).toBe(0);
- expect(callback).toHaveBeenCalled();
- });
-
- it('can pass context when shallowly rendering', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- static contextTypes = {
- name: PropTypes.string,
- };
-
- render() {
- return
{this.context.name}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
, {
- name: 'foo',
- });
- expect(result).toEqual(
foo
);
- });
-
- it('should track context across updates', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- static contextTypes = {
- foo: PropTypes.string,
- };
-
- state = {
- bar: 'bar',
- };
-
- render() {
- return
{`${this.context.foo}:${this.state.bar}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- let result = shallowRenderer.render(
, {
- foo: 'foo',
- });
- expect(result).toEqual(
foo:bar
);
-
- const instance = shallowRenderer.getMountedInstance();
- instance.setState({bar: 'baz'});
-
- result = shallowRenderer.getRenderOutput();
- expect(result).toEqual(
foo:baz
);
- });
-
- it('should filter context by contextTypes', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- static contextTypes = {
- foo: PropTypes.string,
- };
- render() {
- return
{`${this.context.foo}:${this.context.bar}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const result = shallowRenderer.render(
, {
- foo: 'foo',
- bar: 'bar',
- });
- expect(result).toEqual(
foo:undefined
);
- });
-
- it('can fail context when shallowly rendering', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- static contextTypes = {
- name: PropTypes.string.isRequired,
- };
-
- render() {
- return
{this.context.name}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- expect(() => shallowRenderer.render(
)).toErrorDev(
- 'Warning: Failed context type: The context `name` is marked as ' +
- 'required in `SimpleComponent`, but its value is `undefined`.\n' +
- ' in SimpleComponent (at **)',
- );
- });
-
- it('should warn about propTypes (but only once)', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- };
-
- render() {
- return React.createElement('div', null, this.props.name);
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- expect(() =>
- shallowRenderer.render(React.createElement(SimpleComponent, {name: 123})),
- ).toErrorDev(
- 'Warning: Failed prop type: Invalid prop `name` of type `number` ' +
- 'supplied to `SimpleComponent`, expected `string`.\n' +
- ' in SimpleComponent',
- );
- });
-
- it('should enable rendering of cloned element', () => {
- const SimpleComponent = React.memo(
- class SimpleComponent extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- bar: 'bar',
- };
- }
-
- render() {
- return
{`${this.props.foo}:${this.state.bar}`}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- const el =
;
- let result = shallowRenderer.render(el);
- expect(result).toEqual(
foo:bar
);
-
- const cloned = React.cloneElement(el, {foo: 'baz'});
- result = shallowRenderer.render(cloned);
- expect(result).toEqual(
baz:bar
);
- });
-
- it('this.state should be updated on setState callback inside componentWillMount', () => {
- let stateSuccessfullyUpdated = false;
-
- const Component = React.memo(
- class Component extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = {
- hasUpdatedState: false,
- };
- }
-
- UNSAFE_componentWillMount() {
- this.setState(
- {hasUpdatedState: true},
- () => (stateSuccessfullyUpdated = this.state.hasUpdatedState),
- );
- }
-
- render() {
- return
{this.props.children}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(stateSuccessfullyUpdated).toBe(true);
- });
-
- it('should handle multiple callbacks', () => {
- const mockFn = jest.fn();
- const shallowRenderer = createRenderer();
-
- const Component = React.memo(
- class Component extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = {
- foo: 'foo',
- };
- }
-
- UNSAFE_componentWillMount() {
- this.setState({foo: 'bar'}, () => mockFn());
- this.setState({foo: 'foobar'}, () => mockFn());
- }
-
- render() {
- return
{this.state.foo}
;
- }
- },
- );
-
- shallowRenderer.render(
);
-
- expect(mockFn).toHaveBeenCalledTimes(2);
-
- // Ensure the callback queue is cleared after the callbacks are invoked
- const mountedInstance = shallowRenderer.getMountedInstance();
- mountedInstance.setState({foo: 'bar'}, () => mockFn());
- expect(mockFn).toHaveBeenCalledTimes(3);
- });
-
- it('should call the setState callback even if shouldComponentUpdate = false', done => {
- const mockFn = jest.fn().mockReturnValue(false);
-
- const Component = React.memo(
- class Component extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.state = {
- hasUpdatedState: false,
- };
- }
-
- shouldComponentUpdate() {
- return mockFn();
- }
-
- render() {
- return
{this.state.hasUpdatedState}
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- const mountedInstance = shallowRenderer.getMountedInstance();
- mountedInstance.setState({hasUpdatedState: true}, () => {
- expect(mockFn).toBeCalled();
- expect(mountedInstance.state.hasUpdatedState).toBe(true);
- done();
- });
- });
-
- it('throws usefully when rendering badly-typed elements', () => {
- const shallowRenderer = createRenderer();
-
- const renderAndVerifyWarningAndError = (Component, typeString) => {
- expect(() => {
- expect(() => shallowRenderer.render(
)).toErrorDev(
- 'React.createElement: type is invalid -- expected a string ' +
- '(for built-in components) or a class/function (for composite components) ' +
- `but got: ${typeString}.`,
- );
- }).toThrowError(
- 'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
- `components, but the provided element type was \`${typeString}\`.`,
- );
- };
-
- renderAndVerifyWarningAndError(undefined, 'undefined');
- renderAndVerifyWarningAndError(null, 'null');
- renderAndVerifyWarningAndError([], 'array');
- renderAndVerifyWarningAndError({}, 'object');
- });
-
- it('should have initial state of null if not defined', () => {
- const SomeComponent = React.memo(
- class SomeComponent extends React.Component {
- render() {
- return
;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
-
- expect(shallowRenderer.getMountedInstance().state).toBeNull();
- });
-
- it('should invoke both deprecated and new lifecycles if both are present', () => {
- const log = [];
-
- const Component = React.memo(
- class Component extends React.Component {
- componentWillMount() {
- log.push('componentWillMount');
- }
- componentWillReceiveProps() {
- log.push('componentWillReceiveProps');
- }
- componentWillUpdate() {
- log.push('componentWillUpdate');
- }
- UNSAFE_componentWillMount() {
- log.push('UNSAFE_componentWillMount');
- }
- UNSAFE_componentWillReceiveProps() {
- log.push('UNSAFE_componentWillReceiveProps');
- }
- UNSAFE_componentWillUpdate() {
- log.push('UNSAFE_componentWillUpdate');
- }
- render() {
- return null;
- }
- },
- );
-
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
-
- log.length = 0;
-
- shallowRenderer.render(
);
- expect(log).toEqual([
- 'componentWillReceiveProps',
- 'UNSAFE_componentWillReceiveProps',
- 'componentWillUpdate',
- 'UNSAFE_componentWillUpdate',
- ]);
- });
-
- it('should stop the update when setState returns null or undefined', () => {
- const log = [];
- let instance;
- const Component = React.memo(
- class Component extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- count: 0,
- };
- }
- render() {
- log.push('render');
- instance = this;
- return null;
- }
- },
- );
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- log.length = 0;
- instance.setState(() => null);
- instance.setState(() => undefined);
- instance.setState(null);
- instance.setState(undefined);
- expect(log).toEqual([]);
- instance.setState(state => ({count: state.count + 1}));
- expect(log).toEqual(['render']);
- });
-
- it('should not get this in a function component', () => {
- const logs = [];
- const Foo = React.memo(function Foo() {
- logs.push(this);
- return
foo
;
- });
- const shallowRenderer = createRenderer();
- shallowRenderer.render(
);
- expect(logs).toEqual([undefined]);
- });
-});
diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js
index 484a1288f8489..d1f9fbd71ce70 100644
--- a/scripts/rollup/forks.js
+++ b/scripts/rollup/forks.js
@@ -36,13 +36,6 @@ const __EXPERIMENTAL__ =
// algorithm because 1) require.resolve doesn't work with ESM modules, and 2)
// the behavior is easier to predict.
const forks = Object.freeze({
- // NOTE: This is hard-coded to the main entry point of the (third-party)
- // react-shallow-renderer package.
- './node_modules/react-shallow-renderer/index.js': () => {
- // Use ESM build of `react-shallow-renderer`.
- return './node_modules/react-shallow-renderer/esm/index.js';
- },
-
// Without this fork, importing `shared/ReactSharedInternals` inside
// the `react` package itself would not work due to a cyclical dependency.
'./packages/shared/ReactSharedInternals.js': (