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
;
}
}
const inst = ReactTestRenderer.create(
, {
createNodeMock: () => 'foo',
});
expect(() => inst.unmount()).not.toThrow();
});
it('supports unmounting inner instances', async () => {
let count = 0;
class Foo extends React.Component {
componentWillUnmount() {
count++;
}
render() {
return
;
}
}
let inst;
await act(() => {
inst = ReactTestRenderer.create(
,
{
createNodeMock: () => 'foo',
},
);
});
await act(() => {
inst.unmount();
});
expect(count).toEqual(1);
});
it('supports updates when using refs', async () => {
const log = [];
const createNodeMock = element => {
log.push(element.type);
return element.type;
};
class Foo extends React.Component {
render() {
return this.props.useDiv ? (
) : (
);
}
}
let inst;
await act(() => {
inst = ReactTestRenderer.create(
, {
createNodeMock,
});
});
await act(() => {
inst.update(
);
});
expect(log).toEqual(['div', 'span']);
});
it('supports error boundaries', async () => {
const log = [];
class Angry extends React.Component {
render() {
log.push('Angry render');
throw new Error('Please, do not render me.');
}
componentDidMount() {
log.push('Angry componentDidMount');
}
componentWillUnmount() {
log.push('Angry componentWillUnmount');
}
}
class Boundary extends React.Component {
constructor(props) {
super(props);
this.state = {error: false};
}
render() {
log.push('Boundary render');
if (!this.state.error) {
return (
);
} else {
return
Happy Birthday!
;
}
}
componentDidMount() {
log.push('Boundary componentDidMount');
}
componentWillUnmount() {
log.push('Boundary componentWillUnmount');
}
onClick() {
/* do nothing */
}
componentDidCatch() {
log.push('Boundary componentDidCatch');
this.setState({error: true});
}
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
, {
unstable_isConcurrent: true,
});
});
expect(renderer.toJSON()).toEqual({
type: 'div',
props: {},
children: ['Happy Birthday!'],
});
expect(log).toEqual([
'Boundary render',
'Angry render',
'Boundary render',
'Angry render',
'Boundary componentDidMount',
'Boundary componentDidCatch',
'Boundary render',
]);
});
it('can update text nodes', async () => {
class Component extends React.Component {
render() {
return
{this.props.children}
;
}
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
Hi);
});
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['Hi'],
props: {},
});
await act(() => {
renderer.update(
{['Hi', 'Bye']});
});
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['Hi', 'Bye'],
props: {},
});
await act(() => {
renderer.update(
Bye);
});
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['Bye'],
props: {},
});
await act(() => {
renderer.update(
{42});
});
expect(renderer.toJSON()).toEqual({
type: 'div',
children: ['42'],
props: {},
});
await act(() => {
renderer.update(
,
);
});
expect(renderer.toJSON()).toEqual({
type: 'div',
children: [
{
type: 'div',
children: null,
props: {},
},
],
props: {},
});
});
it('toTree() renders simple components returning host components', async () => {
const Qoo = () =>
Hello World!;
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
const tree = renderer.toTree();
cleanNodeOrArray(tree);
expect(prettyFormat(tree)).toEqual(
prettyFormat({
nodeType: 'component',
type: Qoo,
props: {},
instance: null,
rendered: {
nodeType: 'host',
type: 'span',
props: {className: 'Qoo'},
instance: null,
rendered: ['Hello World!'],
},
}),
);
});
it('toTree() handles nested Fragments', async () => {
const Foo = () => (
<>
<>foo>
>
);
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
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', async () => {
class Foo extends React.Component {
render() {
return null;
}
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
const tree = renderer.toTree();
expect(tree.instance).toBeInstanceOf(Foo);
cleanNodeOrArray(tree);
expect(tree).toEqual({
type: Foo,
nodeType: 'component',
props: {},
instance: null,
rendered: null,
});
});
it('toTree() handles simple components that return arrays', async () => {
const Foo = ({children}) => children;
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
One
Two
,
);
});
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', async () => {
class Foo extends React.Component {
render() {
return this.props.children;
}
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
,
);
});
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', async () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
<>
<>
One
Two
<>
Three
>
>
Four
>,
);
});
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', async () => {
const createNodeMock = ref => ({node: ref});
let refInst = null;
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
(refInst = ref)} />,
{createNodeMock},
);
});
const root = renderer.getInstance();
expect(root).toEqual(refInst);
});
it('toTree() renders complicated trees of composites and hosts', async () => {
// SFC returning host. no children props.
const Qoo = () =>
Hello World!;
// SFC returning host. passes through children.
const Foo = ({className, children}) => (
Literal
{children}
);
// class composite returning composite. passes through children.
class Bar extends React.Component {
render() {
const {special, children} = this.props;
return
{children};
}
}
// class composite return composite. no children props.
class Bam extends React.Component {
render() {
return (
);
}
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
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);
expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: Bam,
nodeType: 'component',
props: {},
instance: null,
rendered: {
type: Bar,
nodeType: 'component',
props: {special: true},
instance: null,
rendered: {
type: Foo,
nodeType: 'component',
props: {className: 'special'},
instance: null,
rendered: {
type: 'div',
nodeType: 'host',
props: {className: 'Foo special'},
instance: null,
rendered: [
{
type: 'span',
nodeType: 'host',
props: {className: 'Foo2'},
instance: null,
rendered: ['Literal'],
},
{
type: Qoo,
nodeType: 'component',
props: {},
instance: null,
rendered: {
type: 'span',
nodeType: 'host',
props: {className: 'Qoo'},
instance: null,
rendered: ['Hello World!'],
},
},
],
},
},
},
}),
);
});
it('can update text nodes when rendered as root', async () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(['Hello', 'world']);
});
expect(renderer.toJSON()).toEqual(['Hello', 'world']);
await act(() => {
renderer.update(42);
});
expect(renderer.toJSON()).toEqual('42');
await act(() => {
renderer.update([42, 'world']);
});
expect(renderer.toJSON()).toEqual(['42', 'world']);
});
it('can render and update root fragments', async () => {
const Component = props => props.children;
let renderer;
await act(() => {
renderer = ReactTestRenderer.create([
Hi,
Bye,
]);
});
expect(renderer.toJSON()).toEqual(['Hi', 'Bye']);
await act(() => {
renderer.update(
);
});
expect(renderer.toJSON()).toEqual({
type: 'div',
children: null,
props: {},
});
await act(() => {
renderer.update([
goodbye
, 'world']);
});
expect(renderer.toJSON()).toEqual([
{
type: 'div',
children: ['goodbye'],
props: {},
},
'world',
]);
});
it('supports context providers and consumers', async () => {
const {Consumer, Provider} = React.createContext('a');
function Child(props) {
return props.value;
}
function App() {
return (
{value => }
);
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
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', async () => {
function Child(props) {
return props.value;
}
function App(props) {
return (
);
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
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', async () => {
const InnerRefed = React.forwardRef((props, ref) => (
));
let refFn;
class App extends React.Component {
render() {
refFn = inst => {
this.ref = inst;
};
return
;
}
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
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: {
ref: refFn,
},
rendered: [],
type: 'span',
},
],
type: 'div',
},
type: App,
}),
);
});
it('can concurrently render context with a "primary" renderer', async () => {
const Context = React.createContext(null);
const Indirection = React.Fragment;
const App = () => (
{() => null}
);
ReactNoop.render(
);
await waitForAll([]);
await act(() => {
ReactTestRenderer.create(
);
});
});
it('calling findByType() with an invalid component will fall back to "Unknown" for component name', async () => {
const App = () => null;
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
);
});
const NonComponent = {};
expect(() => {
renderer.root.findByType(NonComponent);
}).toThrowError(`No instances found with node type: "Unknown"`);
});
});