'use strict';
const path = require('path');
import {patchSetImmediate} from '../../../../scripts/jest/patchSetImmediate';
let React;
let ReactServer;
let cache;
let ReactServerDOMServer;
let ReactServerDOMClient;
let Stream;
const streamOptions = {
objectMode: true,
};
const repoRoot = path.resolve(__dirname, '../../../../');
function normalizeStack(stack) {
if (!stack) {
return stack;
}
const copy = [];
for (let i = 0; i < stack.length; i++) {
const [name, file, line, col, enclosingLine, enclosingCol] = stack[i];
copy.push([
name,
file.replace(repoRoot, ''),
line,
col,
enclosingLine,
enclosingCol,
]);
}
return copy;
}
function normalizeIOInfo(ioInfo) {
const {debugTask, debugStack, debugLocation, ...copy} = ioInfo;
if (ioInfo.stack) {
copy.stack = normalizeStack(ioInfo.stack);
}
if (ioInfo.owner) {
copy.owner = normalizeDebugInfo(ioInfo.owner);
}
if (typeof ioInfo.start === 'number') {
copy.start = 0;
}
if (typeof ioInfo.end === 'number') {
copy.end = 0;
}
const promise = ioInfo.value;
if (promise) {
promise.then();
if (promise.status === 'fulfilled') {
copy.value = {
value: promise.value,
};
} else if (promise.status === 'rejected') {
copy.value = {
reason: promise.reason,
};
} else {
copy.value = {
status: promise.status,
};
}
}
return copy;
}
function normalizeDebugInfo(debugInfo) {
if (Array.isArray(debugInfo.stack)) {
const {debugTask, debugStack, debugLocation, ...copy} = debugInfo;
copy.stack = normalizeStack(debugInfo.stack);
if (debugInfo.owner) {
copy.owner = normalizeDebugInfo(debugInfo.owner);
}
if (debugInfo.awaited) {
copy.awaited = normalizeIOInfo(copy.awaited);
}
if (debugInfo.props) {
copy.props = {};
}
return copy;
} else if (typeof debugInfo.time === 'number') {
return {...debugInfo, time: 0};
} else if (debugInfo.awaited) {
return {...debugInfo, awaited: normalizeIOInfo(debugInfo.awaited)};
} else {
return debugInfo;
}
}
function getDebugInfo(obj) {
const debugInfo = obj._debugInfo;
if (debugInfo) {
const copy = [];
for (let i = 0; i < debugInfo.length; i++) {
copy.push(normalizeDebugInfo(debugInfo[i]));
}
return copy;
}
return debugInfo;
}
function filterStackFrame(filename, functionName) {
return (
filename !== '' &&
!filename.startsWith('node:') &&
!filename.includes('node_modules') &&
(!filename.includes('/packages/') || filename.includes('/__tests__/')) &&
!filename.includes('/build/')
);
}
describe('ReactFlightAsyncDebugInfo', () => {
beforeEach(() => {
jest.resetModules();
jest.useRealTimers();
patchSetImmediate();
global.console = require('console');
jest.mock('react', () => require('react/react.react-server'));
jest.mock('react-server-dom-webpack/server', () =>
require('react-server-dom-webpack/server.node'),
);
ReactServer = require('react');
ReactServerDOMServer = require('react-server-dom-webpack/server');
cache = ReactServer.cache;
jest.resetModules();
jest.useRealTimers();
patchSetImmediate();
__unmockReact();
jest.unmock('react-server-dom-webpack/server');
jest.mock('react-server-dom-webpack/client', () =>
require('react-server-dom-webpack/client.node'),
);
React = require('react');
ReactServerDOMClient = require('react-server-dom-webpack/client');
Stream = require('stream');
});
function finishLoadingStream(readable) {
return new Promise(resolve => {
if (readable.readableEnded) {
resolve();
} else {
readable.on('end', () => resolve());
}
});
}
function delay(timeout) {
return new Promise(resolve => {
setTimeout(resolve, timeout);
});
}
function fetchThirdParty(Component) {
const stream = ReactServerDOMServer.renderToPipeableStream(
<Component />,
{},
{
environmentName: 'third-party',
},
);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
return result;
}
it('can track async information when awaited', async () => {
async function getData(text) {
await delay(1);
const promise = delay(2);
await Promise.all([promise]);
return text.toUpperCase();
}
async function Component() {
const result = await getData('hi');
const moreData = getData('seb');
return <InnerComponent text={result} promise={moreData} />;
}
async function InnerComponent({text, promise}) {
return text + ', ' + (await promise);
}
const stream = ReactServerDOMServer.renderToPipeableStream(<Component />);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('HI, SEB');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
202,
109,
182,
50,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
202,
109,
182,
50,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
184,
13,
183,
5,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
191,
26,
190,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
202,
109,
182,
50,
],
],
},
"stack": [
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
184,
13,
183,
5,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
191,
26,
190,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
202,
109,
182,
50,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
185,
21,
183,
5,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
191,
20,
190,
5,
],
],
"start": 0,
"value": {
"value": [
,
],
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
202,
109,
182,
50,
],
],
},
"stack": [
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
186,
21,
183,
5,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
191,
20,
190,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "InnerComponent",
"props": {},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
193,
60,
190,
5,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
202,
109,
182,
50,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
185,
21,
183,
5,
],
],
"start": 0,
"value": {
"status": "halted",
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "InnerComponent",
"props": {},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
193,
60,
190,
5,
],
],
},
"stack": [
[
"InnerComponent",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
199,
35,
196,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
it('can track async information when use()d', async () => {
async function getData(text) {
await delay(1);
return text.toUpperCase();
}
function Component() {
const result = ReactServer.use(getData('hi'));
const moreData = getData('seb');
return <InnerComponent text={result} promise={moreData} />;
}
function InnerComponent({text, promise}) {
return text + ', ' + ReactServer.use(promise);
}
const stream = ReactServerDOMServer.renderToPipeableStream(
<Component />,
{},
{
filterStackFrame,
},
);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('HI, SEB');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
557,
40,
538,
49,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
557,
40,
538,
49,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
540,
13,
539,
5,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
545,
36,
544,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
557,
40,
538,
49,
],
],
},
"stack": [
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
540,
13,
539,
5,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
545,
36,
544,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "InnerComponent",
"props": {},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
547,
60,
544,
5,
],
],
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
557,
40,
538,
49,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
540,
13,
539,
5,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
546,
22,
544,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "InnerComponent",
"props": {},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
547,
60,
544,
5,
],
],
},
"stack": [
[
"InnerComponent",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
553,
40,
550,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
it('can track the start of I/O when no native promise is used', async () => {
function Component() {
const callbacks = [];
setTimeout(function timer() {
callbacks.forEach(callback => callback('hi'));
}, 5);
return {
then(callback) {
callbacks.push(callback);
},
};
}
const stream = ReactServerDOMServer.renderToPipeableStream(<Component />);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('hi');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
820,
109,
807,
67,
],
],
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "setTimeout",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
820,
109,
807,
67,
],
],
},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
810,
7,
808,
5,
],
],
"start": 0,
},
"env": "Server",
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
it('can ingores the start of I/O when immediately resolved non-native promise is awaited', async () => {
async function Component() {
return await {
then(callback) {
callback('hi');
},
};
}
const stream = ReactServerDOMServer.renderToPipeableStream(<Component />);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('hi');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
916,
109,
907,
94,
],
],
},
{
"time": 0,
},
]
`);
}
});
it('forwards debugInfo from awaited Promises', async () => {
async function Component() {
let resolve;
const promise = new Promise(r => (resolve = r));
promise._debugInfo = [
{time: performance.now()},
{
name: 'Virtual Component',
},
{time: performance.now()},
];
const promise2 = promise.then(value => value);
promise2._debugInfo = [
{time: performance.now()},
{
name: 'Virtual Component2',
},
{time: performance.now()},
];
resolve('hi');
const result = await promise2;
return result.toUpperCase();
}
const stream = ReactServerDOMServer.renderToPipeableStream(<Component />);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('HI');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
989,
109,
965,
50,
],
],
},
{
"time": 0,
},
{
"name": "Virtual Component",
},
{
"time": 0,
},
{
"time": 0,
},
{
"name": "Virtual Component2",
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
it('forwards async debug info one environment to the next', async () => {
async function getData() {
await delay(1);
await delay(2);
return 'hi';
}
async function ThirdPartyComponent() {
const data = await getData();
return data;
}
async function Component() {
const data = await fetchThirdParty(ThirdPartyComponent);
return data.toUpperCase();
}
const stream = ReactServerDOMServer.renderToPipeableStream(<Component />);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('HI');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1073,
109,
1056,
63,
],
],
},
{
"time": 0,
},
{
"env": "third-party",
"key": null,
"name": "ThirdPartyComponent",
"props": {},
"stack": [
[
"fetchThirdParty",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
167,
40,
165,
3,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1069,
24,
1068,
5,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "third-party",
"name": "delay",
"owner": {
"env": "third-party",
"key": null,
"name": "ThirdPartyComponent",
"props": {},
"stack": [
[
"fetchThirdParty",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
167,
40,
165,
3,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1069,
24,
1068,
5,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1058,
13,
1057,
5,
],
[
"ThirdPartyComponent",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1064,
24,
1063,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "third-party",
"owner": {
"env": "third-party",
"key": null,
"name": "ThirdPartyComponent",
"props": {},
"stack": [
[
"fetchThirdParty",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
167,
40,
165,
3,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1069,
24,
1068,
5,
],
],
},
"stack": [
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1058,
13,
1057,
5,
],
[
"ThirdPartyComponent",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1064,
24,
1063,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "third-party",
"name": "delay",
"owner": {
"env": "third-party",
"key": null,
"name": "ThirdPartyComponent",
"props": {},
"stack": [
[
"fetchThirdParty",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
167,
40,
165,
3,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1069,
24,
1068,
5,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1059,
13,
1057,
5,
],
[
"ThirdPartyComponent",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1064,
18,
1063,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "third-party",
"owner": {
"env": "third-party",
"key": null,
"name": "ThirdPartyComponent",
"props": {},
"stack": [
[
"fetchThirdParty",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
167,
40,
165,
3,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1069,
24,
1068,
5,
],
],
},
"stack": [
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1059,
13,
1057,
5,
],
[
"ThirdPartyComponent",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1064,
18,
1063,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
it('can track cached entries awaited in later components', async () => {
const getData = cache(async function getData(text) {
await delay(1);
return text.toUpperCase();
});
async function Child() {
const greeting = await getData('hi');
return greeting + ', Seb';
}
async function Component() {
await getData('hi');
return <Child />;
}
const stream = ReactServerDOMServer.renderToPipeableStream(
<Component />,
{},
{
filterStackFrame,
},
);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('HI, Seb');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1389,
40,
1372,
62,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1389,
40,
1372,
62,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1374,
13,
1373,
25,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1384,
13,
1383,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1389,
40,
1372,
62,
],
],
},
"stack": [
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1374,
13,
1373,
25,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1384,
13,
1383,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Child",
"props": {},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1385,
60,
1383,
5,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1389,
40,
1372,
62,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1374,
13,
1373,
25,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1384,
13,
1383,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Child",
"props": {},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1385,
60,
1383,
5,
],
],
},
"stack": [
[
"Child",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1379,
28,
1378,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
it('can track cached entries used in child position', async () => {
const getData = cache(async function getData(text) {
await delay(1);
return text.toUpperCase();
});
function Child() {
return getData('hi');
}
function Component() {
ReactServer.use(getData('hi'));
return <Child />;
}
const stream = ReactServerDOMServer.renderToPipeableStream(
<Component />,
{},
{
filterStackFrame,
},
);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('HI');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1658,
40,
1642,
57,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1658,
40,
1642,
57,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1644,
13,
1643,
25,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1653,
23,
1652,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1658,
40,
1642,
57,
],
],
},
"stack": [
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1644,
13,
1643,
25,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1653,
23,
1652,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Child",
"props": {},
"stack": [
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1654,
60,
1652,
5,
],
],
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Component",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1658,
40,
1642,
57,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"getData",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1644,
13,
1643,
25,
],
[
"Component",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1653,
23,
1652,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
it('can track implicit returned promises that are blocked by previous data', async () => {
async function delayTwice() {
await delay('', 20);
await delay('', 10);
}
async function delayTrice() {
const p = delayTwice();
await delay('', 40);
return p;
}
async function Bar({children}) {
await delayTrice();
return 'hi';
}
const stream = ReactServerDOMServer.renderToPipeableStream(
<Bar />,
{},
{
filterStackFrame,
},
);
const readable = new Stream.PassThrough(streamOptions);
const result = ReactServerDOMClient.createFromNodeStream(readable, {
moduleMap: {},
moduleLoading: {},
});
stream.pipe(readable);
expect(await result).toBe('hi');
await finishLoadingStream(readable);
if (
__DEV__ &&
gate(
flags =>
flags.enableComponentPerformanceTrack && flags.enableAsyncDebugInfo,
)
) {
expect(getDebugInfo(result)).toMatchInlineSnapshot(`
[
{
"time": 0,
},
{
"env": "Server",
"key": null,
"name": "Bar",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1900,
40,
1882,
80,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Bar",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1900,
40,
1882,
80,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"delayTrice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1890,
13,
1888,
5,
],
[
"Bar",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1895,
13,
1894,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Bar",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1900,
40,
1882,
80,
],
],
},
"stack": [
[
"delayTrice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1890,
13,
1888,
5,
],
[
"Bar",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1895,
13,
1894,
5,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Bar",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1900,
40,
1882,
80,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"delayTwice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1884,
13,
1883,
5,
],
[
"delayTrice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1889,
15,
1888,
5,
],
[
"Bar",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1895,
13,
1894,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Bar",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1900,
40,
1882,
80,
],
],
},
"stack": [
[
"delayTwice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1884,
13,
1883,
5,
],
[
"delayTrice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1889,
15,
1888,
5,
],
[
"Bar",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1895,
13,
1894,
5,
],
],
},
{
"time": 0,
},
{
"awaited": {
"end": 0,
"env": "Server",
"name": "delay",
"owner": {
"env": "Server",
"key": null,
"name": "Bar",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1900,
40,
1882,
80,
],
],
},
"stack": [
[
"delay",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
160,
12,
159,
3,
],
[
"delayTwice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1885,
13,
1883,
5,
],
],
"start": 0,
"value": {
"value": undefined,
},
},
"env": "Server",
"owner": {
"env": "Server",
"key": null,
"name": "Bar",
"props": {},
"stack": [
[
"Object.<anonymous>",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1900,
40,
1882,
80,
],
],
},
"stack": [
[
"delayTwice",
"/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1885,
13,
1883,
5,
],
],
},
{
"time": 0,
},
{
"time": 0,
},
]
`);
}
});
});