[assert helpers] ReactFlight (#31860)

This commit is contained in:
Ricky
2024-12-20 12:41:30 -05:00
committed by GitHub
parent 26297f5383
commit 99471c02dd
+474 -166
View File
@@ -1467,13 +1467,12 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render(<App />);
await expect(async () => {
await act(() => {
startTransition(() => {
ReactNoop.render(ReactNoopFlightClient.read(transport));
});
await act(() => {
startTransition(() => {
ReactNoop.render(ReactNoopFlightClient.read(transport));
});
}).toErrorDev(
});
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n' +
'\n' +
'Check the render method of `Component`. See https://react.dev/link/warning-keys for more information.\n' +
@@ -1483,7 +1482,7 @@ describe('ReactFlight', () => {
? ''
: ' in Indirection (at **)\n') +
' in App (at **)',
);
]);
});
it('should trigger the inner most error boundary inside a Client Component', async () => {
@@ -1541,17 +1540,47 @@ describe('ReactFlight', () => {
return 123;
},
};
expect(() => {
const transport = ReactNoopFlightServer.render(<input value={obj} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<input value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a toJSON instance is passed to a host component child', () => {
@@ -1560,43 +1589,123 @@ describe('ReactFlight', () => {
return 123;
}
}
expect(() => {
const transport = ReactNoopFlightServer.render(
<div>Womp womp: {new MyError('spaghetti')}</div>,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<div>Womp womp: {new MyError('spaghetti')}</div>,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a host component', () => {
expect(() => {
const transport = ReactNoopFlightServer.render(<input value={Math} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<input value={Math} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if an object with symbols is passed to a host component', () => {
expect(() => {
const transport = ReactNoopFlightServer.render(
<input value={{[Symbol.iterator]: {}}} />,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<input value={{[Symbol.iterator]: {}}} />,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a toJSON instance is passed to a Client Component', () => {
@@ -1609,14 +1718,47 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(<Client value={obj} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported.',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<Client value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a toJSON instance is passed to a Client Component child', () => {
@@ -1629,19 +1771,49 @@ describe('ReactFlight', () => {
return <div>{children}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client>Current date: {obj}</Client>,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<Client>Current date: {obj}</Client>,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a Client Component', () => {
@@ -1649,16 +1821,44 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(<Client value={Math} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<Client value={Math} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if an object with symbols is passed to a Client Component', () => {
@@ -1666,16 +1866,46 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.',
{withoutStack: true},
assertConsoleErrorDev([]);
const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^\n',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a nested object in Client Component', () => {
@@ -1683,18 +1913,41 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client value={{hello: Math, title: <h1>hi</h1>}} />,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' {hello: Math, title: <h1/>}\n' +
' ^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />,
);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a nested array in Client Component', () => {
@@ -1702,20 +1955,40 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client
value={['looooong string takes up noise', Math, <h1>hi</h1>]}
/>,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<Client value={['looooong string takes up noise', Math, <h1>hi</h1>]} />,
);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should NOT warn in DEV for key getters', () => {
@@ -1729,63 +2002,100 @@ describe('ReactFlight', () => {
key: "this has a key but parent doesn't",
});
}
expect(() => {
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(NoKey)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
}).toErrorDev('Each child in a list should have a unique "key" prop.');
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(NoKey)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
]);
}
});
// @gate !__DEV__ || enableOwnerStacks
it('should warn in DEV a child is missing keys on a fragment', () => {
expect(() => {
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(ReactServer.Fragment)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
}).toErrorDev('Each child in a list should have a unique "key" prop.');
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(ReactServer.Fragment)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
]);
}
});
it('should warn in DEV a child is missing keys in client component', async () => {
function ParentClient({children}) {
return children;
}
const Parent = clientReference(ParentClient);
await expect(async () => {
await act(async () => {
const Parent = clientReference(ParentClient);
const transport = ReactNoopFlightServer.render(
<Parent>{Array(6).fill(<div>no key</div>)}</Parent>,
);
ReactNoopFlightClient.read(transport);
await act(async () => {
ReactNoop.render(await ReactNoopFlightClient.read(transport));
});
}).toErrorDev(
gate(flags => flags.enableOwnerStacks)
? 'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.'
: 'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.',
);
ReactNoop.render(await ReactNoopFlightClient.read(transport));
});
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
}
});
it('should error if a class instance is passed to a host component', () => {
@@ -3135,19 +3445,17 @@ describe('ReactFlight', () => {
},
);
let transport;
expect(() => {
// Reset the modules so that we get a new overridden console on top of the
// one installed by expect. This ensures that we still emit console.error
// calls.
jest.resetModules();
jest.mock('react', () => require('react/react.react-server'));
ReactServer = require('react');
ReactNoopFlightServer = require('react-noop-renderer/flight-server');
transport = ReactNoopFlightServer.render({
root: ReactServer.createElement(App),
});
}).toErrorDev('err');
// Reset the modules so that we get a new overridden console on top of the
// one installed by expect. This ensures that we still emit console.error
// calls.
jest.resetModules();
jest.mock('react', () => require('react/react.react-server'));
ReactServer = require('react');
ReactNoopFlightServer = require('react-noop-renderer/flight-server');
const transport = ReactNoopFlightServer.render({
root: ReactServer.createElement(App),
});
assertConsoleErrorDev(['Error: err']);
expect(mockConsoleLog).toHaveBeenCalledTimes(1);
expect(mockConsoleLog.mock.calls[0][0]).toBe('hi');