mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Codemod tests to waitFor pattern (2/?) (#26296)
This converts some of our test suite to use the `waitFor` test pattern, instead of the `expect(Scheduler).toFlushAndYield` pattern. Most of these changes are automated with jscodeshift, with some slight manual cleanup in certain cases. See #26285 for full context.
This commit is contained in:
@@ -18,6 +18,8 @@ let Scheduler;
|
||||
let Suspense;
|
||||
let TextResource;
|
||||
let textResourceShouldFail;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
|
||||
describe('ReactCache', () => {
|
||||
beforeEach(() => {
|
||||
@@ -33,6 +35,10 @@ describe('ReactCache', () => {
|
||||
ReactTestRenderer = require('react-test-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
TextResource = createResource(
|
||||
([text, ms = 0]) => {
|
||||
let listeners = null;
|
||||
@@ -105,7 +111,7 @@ describe('ReactCache', () => {
|
||||
}
|
||||
}
|
||||
|
||||
it('throws a promise if the requested value is not in the cache', () => {
|
||||
it('throws a promise if the requested value is not in the cache', async () => {
|
||||
function App() {
|
||||
return (
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
@@ -118,11 +124,11 @@ describe('ReactCache', () => {
|
||||
unstable_isConcurrent: true,
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Suspend! [Hi]', 'Loading...']);
|
||||
await waitForAll(['Suspend! [Hi]', 'Loading...']);
|
||||
|
||||
jest.advanceTimersByTime(100);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [Hi]']);
|
||||
expect(Scheduler).toFlushAndYield(['Hi']);
|
||||
assertLog(['Promise resolved [Hi]']);
|
||||
await waitForAll(['Hi']);
|
||||
});
|
||||
|
||||
it('throws an error on the subsequent read if the promise is rejected', async () => {
|
||||
@@ -138,22 +144,22 @@ describe('ReactCache', () => {
|
||||
unstable_isConcurrent: true,
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Suspend! [Hi]', 'Loading...']);
|
||||
await waitForAll(['Suspend! [Hi]', 'Loading...']);
|
||||
|
||||
textResourceShouldFail = true;
|
||||
jest.advanceTimersByTime(100);
|
||||
expect(Scheduler).toHaveYielded(['Promise rejected [Hi]']);
|
||||
assertLog(['Promise rejected [Hi]']);
|
||||
|
||||
expect(Scheduler).toFlushAndThrow('Failed to load: Hi');
|
||||
expect(Scheduler).toHaveYielded(['Error! [Hi]', 'Error! [Hi]']);
|
||||
assertLog(['Error! [Hi]', 'Error! [Hi]']);
|
||||
|
||||
// Should throw again on a subsequent read
|
||||
root.update(<App />);
|
||||
expect(Scheduler).toFlushAndThrow('Failed to load: Hi');
|
||||
expect(Scheduler).toHaveYielded(['Error! [Hi]', 'Error! [Hi]']);
|
||||
assertLog(['Error! [Hi]', 'Error! [Hi]']);
|
||||
});
|
||||
|
||||
it('warns if non-primitive key is passed to a resource without a hash function', () => {
|
||||
it('warns if non-primitive key is passed to a resource without a hash function', async () => {
|
||||
const BadTextResource = createResource(([text, ms = 0]) => {
|
||||
return new Promise((resolve, reject) =>
|
||||
setTimeout(() => {
|
||||
@@ -177,8 +183,8 @@ describe('ReactCache', () => {
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield(['App', 'Loading...']);
|
||||
expect(async () => {
|
||||
await waitForAll(['App', 'Loading...']);
|
||||
}).toErrorDev([
|
||||
'Invalid key type. Expected a string, number, symbol, or ' +
|
||||
'boolean, but instead received: Hi,100\n\n' +
|
||||
@@ -186,7 +192,7 @@ describe('ReactCache', () => {
|
||||
'function as the second argument to createResource().',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toFlushAndYield(['App', 'Loading...']);
|
||||
await waitForAll(['App', 'Loading...']);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -204,19 +210,19 @@ describe('ReactCache', () => {
|
||||
unstable_isConcurrent: true,
|
||||
},
|
||||
);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend! [1]',
|
||||
'Suspend! [2]',
|
||||
'Suspend! [3]',
|
||||
'Loading...',
|
||||
]);
|
||||
jest.advanceTimersByTime(100);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Promise resolved [1]',
|
||||
'Promise resolved [2]',
|
||||
'Promise resolved [3]',
|
||||
]);
|
||||
expect(Scheduler).toFlushAndYield([1, 2, 3]);
|
||||
await waitForAll([1, 2, 3]);
|
||||
expect(root).toMatchRenderedOutput('123');
|
||||
|
||||
// Render 1, 4, 5
|
||||
@@ -228,18 +234,10 @@ describe('ReactCache', () => {
|
||||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
1,
|
||||
'Suspend! [4]',
|
||||
'Suspend! [5]',
|
||||
'Loading...',
|
||||
]);
|
||||
await waitForAll([1, 'Suspend! [4]', 'Suspend! [5]', 'Loading...']);
|
||||
jest.advanceTimersByTime(100);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Promise resolved [4]',
|
||||
'Promise resolved [5]',
|
||||
]);
|
||||
expect(Scheduler).toFlushAndYield([1, 4, 5]);
|
||||
assertLog(['Promise resolved [4]', 'Promise resolved [5]']);
|
||||
await waitForAll([1, 4, 5]);
|
||||
expect(root).toMatchRenderedOutput('145');
|
||||
|
||||
// We've now rendered values 1, 2, 3, 4, 5, over our limit of 3. The least
|
||||
@@ -253,7 +251,7 @@ describe('ReactCache', () => {
|
||||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
// 1 is still cached
|
||||
1,
|
||||
// 2 and 3 suspend because they were evicted from the cache
|
||||
@@ -262,11 +260,8 @@ describe('ReactCache', () => {
|
||||
'Loading...',
|
||||
]);
|
||||
jest.advanceTimersByTime(100);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Promise resolved [2]',
|
||||
'Promise resolved [3]',
|
||||
]);
|
||||
expect(Scheduler).toFlushAndYield([1, 2, 3]);
|
||||
assertLog(['Promise resolved [2]', 'Promise resolved [3]']);
|
||||
await waitForAll([1, 2, 3]);
|
||||
expect(root).toMatchRenderedOutput('123');
|
||||
});
|
||||
|
||||
@@ -287,18 +282,15 @@ describe('ReactCache', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Loading...']);
|
||||
await waitForAll(['Loading...']);
|
||||
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Promise resolved [B]',
|
||||
'Promise resolved [A]',
|
||||
]);
|
||||
expect(Scheduler).toFlushAndYield(['Result']);
|
||||
assertLog(['Promise resolved [B]', 'Promise resolved [A]']);
|
||||
await waitForAll(['Result']);
|
||||
expect(root).toMatchRenderedOutput('Result');
|
||||
});
|
||||
|
||||
it('if a thenable resolves multiple times, does not update the first cached value', () => {
|
||||
it('if a thenable resolves multiple times, does not update the first cached value', async () => {
|
||||
let resolveThenable;
|
||||
const BadTextResource = createResource(
|
||||
([text, ms = 0]) => {
|
||||
@@ -349,7 +341,7 @@ describe('ReactCache', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Suspend! [Hi]', 'Loading...']);
|
||||
await waitForAll(['Suspend! [Hi]', 'Loading...']);
|
||||
|
||||
resolveThenable('Hi');
|
||||
// This thenable improperly resolves twice. We should not update the
|
||||
@@ -365,8 +357,8 @@ describe('ReactCache', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
expect(Scheduler).toFlushAndYield(['Hi']);
|
||||
assertLog([]);
|
||||
await waitForAll(['Hi']);
|
||||
expect(root).toMatchRenderedOutput('Hi');
|
||||
});
|
||||
|
||||
|
||||
+9
-6
@@ -20,6 +20,7 @@ let ReactNoopFlightClient;
|
||||
let ErrorBoundary;
|
||||
let NoErrorExpected;
|
||||
let Scheduler;
|
||||
let assertLog;
|
||||
|
||||
describe('ReactFlight', () => {
|
||||
beforeEach(() => {
|
||||
@@ -33,6 +34,8 @@ describe('ReactFlight', () => {
|
||||
ReactNoopFlightClient = require('react-noop-renderer/flight-client');
|
||||
act = require('jest-react').act;
|
||||
Scheduler = require('scheduler');
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
ErrorBoundary = class extends React.Component {
|
||||
state = {hasError: false, error: null};
|
||||
@@ -808,13 +811,13 @@ describe('ReactFlight', () => {
|
||||
const ClientDoublerModuleRef = clientReference(ClientDoubler);
|
||||
|
||||
const transport = ReactNoopFlightServer.render(<App />);
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
assertLog([]);
|
||||
|
||||
await act(async () => {
|
||||
ReactNoop.render(await ReactNoopFlightClient.read(transport));
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['ClientDoubler']);
|
||||
assertLog(['ClientDoubler']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<div prop=":S1:">:S1:</div>
|
||||
@@ -997,7 +1000,7 @@ describe('ReactFlight', () => {
|
||||
|
||||
const transport = ReactNoopFlightServer.render(<Foo />);
|
||||
|
||||
expect(Scheduler).toHaveYielded(['suspended']);
|
||||
assertLog(['suspended']);
|
||||
|
||||
await act(async () => {
|
||||
resolve();
|
||||
@@ -1005,7 +1008,7 @@ describe('ReactFlight', () => {
|
||||
jest.runAllImmediates();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['rendered']);
|
||||
assertLog(['rendered']);
|
||||
|
||||
await act(async () => {
|
||||
ServerContext._currentRenderer = null;
|
||||
@@ -1045,7 +1048,7 @@ describe('ReactFlight', () => {
|
||||
|
||||
const transport = ReactNoopFlightServer.render(model);
|
||||
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
assertLog([]);
|
||||
|
||||
await act(async () => {
|
||||
ServerContext._currentRenderer = null;
|
||||
@@ -1054,7 +1057,7 @@ describe('ReactFlight', () => {
|
||||
ReactNoop.render(flightModel.foo);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['ClientBar']);
|
||||
assertLog(['ClientBar']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span>hi this is server</span>);
|
||||
|
||||
expect(() => {
|
||||
|
||||
+5
-1
@@ -19,6 +19,7 @@ describe('React hooks DevTools integration', () => {
|
||||
let overrideHookState;
|
||||
let scheduleUpdate;
|
||||
let setSuspenseHandler;
|
||||
let waitForAll;
|
||||
|
||||
global.IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
@@ -41,6 +42,9 @@ describe('React hooks DevTools integration', () => {
|
||||
ReactTestRenderer = require('react-test-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
|
||||
act = ReactTestRenderer.act;
|
||||
});
|
||||
|
||||
@@ -256,7 +260,7 @@ describe('React hooks DevTools integration', () => {
|
||||
),
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
// Ensure we timeout any suspense time.
|
||||
jest.advanceTimersByTime(1000);
|
||||
const fiber = renderer.root._currentFiber().child;
|
||||
|
||||
@@ -20,6 +20,10 @@ describe('Timeline profiler', () => {
|
||||
let store;
|
||||
let unmountFns;
|
||||
let utils;
|
||||
let waitFor;
|
||||
let waitForAll;
|
||||
let waitForPaint;
|
||||
let assertLog;
|
||||
|
||||
beforeEach(() => {
|
||||
utils = require('./utils');
|
||||
@@ -44,6 +48,12 @@ describe('Timeline profiler', () => {
|
||||
ReactDOMClient = require('react-dom/client');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitForPaint = InternalTestUtils.waitForPaint;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
store = global.store;
|
||||
});
|
||||
|
||||
@@ -151,7 +161,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark concurrent render without suspends or state updates', () => {
|
||||
it('should mark concurrent render without suspends or state updates', async () => {
|
||||
renderRootHelper(<div />);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
@@ -162,7 +172,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -196,8 +206,7 @@ describe('Timeline profiler', () => {
|
||||
renderRootHelper(<Foo />);
|
||||
});
|
||||
|
||||
// Do one step of work.
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Foo']);
|
||||
await waitFor(['Foo']);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -291,7 +300,11 @@ describe('Timeline profiler', () => {
|
||||
});
|
||||
|
||||
it('should mark concurrent render with suspense that resolves', async () => {
|
||||
const fakeSuspensePromise = Promise.resolve(true);
|
||||
let resolveFakePromise;
|
||||
const fakeSuspensePromise = new Promise(
|
||||
resolve => (resolveFakePromise = resolve),
|
||||
);
|
||||
|
||||
function Example() {
|
||||
throw fakeSuspensePromise;
|
||||
}
|
||||
@@ -310,7 +323,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -333,7 +346,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
await fakeSuspensePromise;
|
||||
await resolveFakePromise();
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
"--suspense-resolved-0-Example",
|
||||
@@ -342,7 +355,11 @@ describe('Timeline profiler', () => {
|
||||
});
|
||||
|
||||
it('should mark concurrent render with suspense that rejects', async () => {
|
||||
const fakeSuspensePromise = Promise.reject(new Error('error'));
|
||||
let rejectFakePromise;
|
||||
const fakeSuspensePromise = new Promise(
|
||||
(_, reject) => (rejectFakePromise = reject),
|
||||
);
|
||||
|
||||
function Example() {
|
||||
throw fakeSuspensePromise;
|
||||
}
|
||||
@@ -361,7 +378,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -384,7 +401,10 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
await expect(fakeSuspensePromise).rejects.toThrow();
|
||||
await expect(() => {
|
||||
rejectFakePromise(new Error('error'));
|
||||
return fakeSuspensePromise;
|
||||
}).rejects.toThrow();
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
"--suspense-rejected-0-Example",
|
||||
@@ -392,7 +412,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark cascading class component state updates', () => {
|
||||
it('should mark cascading class component state updates', async () => {
|
||||
class Example extends React.Component {
|
||||
state = {didMount: false};
|
||||
componentDidMount() {
|
||||
@@ -413,7 +433,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -446,7 +466,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark cascading class component force updates', () => {
|
||||
it('should mark cascading class component force updates', async () => {
|
||||
class Example extends React.Component {
|
||||
componentDidMount() {
|
||||
this.forceUpdate();
|
||||
@@ -466,7 +486,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -499,7 +519,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark render phase state updates for class component', () => {
|
||||
it('should mark render phase state updates for class component', async () => {
|
||||
class Example extends React.Component {
|
||||
state = {didRender: false};
|
||||
render() {
|
||||
@@ -525,7 +545,7 @@ describe('Timeline profiler', () => {
|
||||
errorMessage = message;
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(errorMessage).toContain(
|
||||
@@ -552,7 +572,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark render phase force updates for class component', () => {
|
||||
it('should mark render phase force updates for class component', async () => {
|
||||
let forced = false;
|
||||
class Example extends React.Component {
|
||||
render() {
|
||||
@@ -579,7 +599,7 @@ describe('Timeline profiler', () => {
|
||||
errorMessage = message;
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(errorMessage).toContain(
|
||||
@@ -606,7 +626,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark cascading layout updates', () => {
|
||||
it('should mark cascading layout updates', async () => {
|
||||
function Example() {
|
||||
const [didMount, setDidMount] = React.useState(false);
|
||||
React.useLayoutEffect(() => {
|
||||
@@ -625,7 +645,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -660,7 +680,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark cascading passive updates', () => {
|
||||
it('should mark cascading passive updates', async () => {
|
||||
function Example() {
|
||||
const [didMount, setDidMount] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
@@ -671,7 +691,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
renderRootHelper(<Example />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -709,7 +729,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark render phase updates', () => {
|
||||
it('should mark render phase updates', async () => {
|
||||
function Example() {
|
||||
const [didRender, setDidRender] = React.useState(false);
|
||||
if (!didRender) {
|
||||
@@ -720,7 +740,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
renderRootHelper(<Example />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -840,7 +860,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -927,10 +947,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
const unmount = renderRootHelper(<ComponentWithEffects />);
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
'layout 1 mount',
|
||||
'layout 2 mount',
|
||||
]);
|
||||
await waitForPaint(['layout 1 mount', 'layout 2 mount']);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -957,7 +974,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'passive 1 mount',
|
||||
'passive 2 mount',
|
||||
'passive 3 mount',
|
||||
@@ -978,11 +995,11 @@ describe('Timeline profiler', () => {
|
||||
|
||||
clearPendingMarks();
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
unmount();
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'layout 1 unmount',
|
||||
'layout 2 unmount',
|
||||
'passive 1 unmount',
|
||||
@@ -1063,7 +1080,7 @@ describe('Timeline profiler', () => {
|
||||
}
|
||||
|
||||
renderRootHelper(<App />);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
clearedMarks.splice(0);
|
||||
|
||||
@@ -1102,7 +1119,7 @@ describe('Timeline profiler', () => {
|
||||
}
|
||||
|
||||
renderRootHelper(<App />);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
clearedMarks.splice(0);
|
||||
|
||||
@@ -1110,7 +1127,7 @@ describe('Timeline profiler', () => {
|
||||
event.initEvent('mouseover', true, true);
|
||||
dispatchAndSetCurrentEvent(targetRef.current, event);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expect(clearedMarks).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -1324,11 +1341,11 @@ describe('Timeline profiler', () => {
|
||||
});
|
||||
|
||||
// Do one step of work.
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Foo']);
|
||||
await waitFor(['Foo']);
|
||||
|
||||
// Finish flushing so React commits;
|
||||
// Unless we do this, the ProfilerStore won't collect Profiling data.
|
||||
expect(Scheduler).toFlushAndYield(['Bar']);
|
||||
await waitForAll(['Bar']);
|
||||
|
||||
// Since we yielded, the batch should report two separate "render" chunks.
|
||||
const batch = getBatchOfWork(0);
|
||||
@@ -1359,13 +1376,13 @@ describe('Timeline profiler', () => {
|
||||
</React.Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toHaveYielded(['suspended']);
|
||||
assertLog(['suspended']);
|
||||
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
resolveFn();
|
||||
await suspensePromise;
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['resolved']);
|
||||
await waitForAll(['resolved']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
|
||||
@@ -1417,13 +1434,13 @@ describe('Timeline profiler', () => {
|
||||
</React.Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toHaveYielded(['suspended']);
|
||||
assertLog(['suspended']);
|
||||
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
rejectFn();
|
||||
await expect(suspensePromise).rejects.toThrow();
|
||||
|
||||
expect(Scheduler).toHaveYielded(['rejected']);
|
||||
assertLog(['rejected']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
|
||||
@@ -1475,13 +1492,13 @@ describe('Timeline profiler', () => {
|
||||
</React.Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['suspended']);
|
||||
await waitForAll(['suspended']);
|
||||
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
resolveFn();
|
||||
await suspensePromise;
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['resolved']);
|
||||
await waitForAll(['resolved']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
|
||||
@@ -1533,13 +1550,13 @@ describe('Timeline profiler', () => {
|
||||
</React.Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['suspended']);
|
||||
await waitForAll(['suspended']);
|
||||
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
rejectFn();
|
||||
await expect(suspensePromise).rejects.toThrow();
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['rejected']);
|
||||
await waitForAll(['rejected']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
|
||||
@@ -1566,7 +1583,7 @@ describe('Timeline profiler', () => {
|
||||
expect(timelineData.componentMeasures).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should mark cascading class component state updates', () => {
|
||||
it('should mark cascading class component state updates', async () => {
|
||||
class Example extends React.Component {
|
||||
state = {didMount: false};
|
||||
componentDidMount() {
|
||||
@@ -1583,7 +1600,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
renderRootHelper(<Example />);
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint(['mount', 'update']);
|
||||
await waitForPaint(['mount', 'update']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
|
||||
@@ -1626,7 +1643,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark cascading class component force updates', () => {
|
||||
it('should mark cascading class component force updates', async () => {
|
||||
let forced = false;
|
||||
class Example extends React.Component {
|
||||
componentDidMount() {
|
||||
@@ -1642,7 +1659,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
renderRootHelper(<Example />);
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint(['mount', 'force update']);
|
||||
await waitForPaint(['mount', 'force update']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
|
||||
@@ -1683,7 +1700,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark render phase state updates for class component', () => {
|
||||
it('should mark render phase state updates for class component', async () => {
|
||||
class Example extends React.Component {
|
||||
state = {didRender: false};
|
||||
render() {
|
||||
@@ -1705,7 +1722,7 @@ describe('Timeline profiler', () => {
|
||||
errorMessage = message;
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['first render', 'second render']);
|
||||
await waitForAll(['first render', 'second render']);
|
||||
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(errorMessage).toContain(
|
||||
@@ -1753,7 +1770,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark render phase force updates for class component', () => {
|
||||
it('should mark render phase force updates for class component', async () => {
|
||||
let forced = false;
|
||||
class Example extends React.Component {
|
||||
render() {
|
||||
@@ -1774,7 +1791,7 @@ describe('Timeline profiler', () => {
|
||||
errorMessage = message;
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['render', 'force update']);
|
||||
await waitForAll(['render', 'force update']);
|
||||
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(errorMessage).toContain(
|
||||
@@ -1820,7 +1837,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark cascading layout updates', () => {
|
||||
it('should mark cascading layout updates', async () => {
|
||||
function Example() {
|
||||
const [didMount, setDidMount] = React.useState(false);
|
||||
React.useLayoutEffect(() => {
|
||||
@@ -1834,7 +1851,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
renderRootHelper(<Example />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['mount', 'update']);
|
||||
await waitForAll(['mount', 'update']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
|
||||
@@ -1884,7 +1901,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark cascading passive updates', () => {
|
||||
it('should mark cascading passive updates', async () => {
|
||||
function Example() {
|
||||
const [didMount, setDidMount] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
@@ -1897,7 +1914,7 @@ describe('Timeline profiler', () => {
|
||||
}
|
||||
|
||||
renderRootHelper(<Example />);
|
||||
expect(Scheduler).toFlushAndYield(['mount', 'update']);
|
||||
await waitForAll(['mount', 'update']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
|
||||
@@ -1947,7 +1964,7 @@ describe('Timeline profiler', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should mark render phase updates', () => {
|
||||
it('should mark render phase updates', async () => {
|
||||
function Example() {
|
||||
const [didRender, setDidRender] = React.useState(false);
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
@@ -1959,7 +1976,7 @@ describe('Timeline profiler', () => {
|
||||
}
|
||||
|
||||
renderRootHelper(<Example />);
|
||||
expect(Scheduler).toFlushAndYield(['mount', 'update']);
|
||||
await waitForAll(['mount', 'update']);
|
||||
|
||||
const timelineData = stopProfilingAndGetTimelineData();
|
||||
// Render phase updates should be retried as part of the same batch.
|
||||
@@ -2026,7 +2043,7 @@ describe('Timeline profiler', () => {
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'ErrorBoundary render',
|
||||
'ExampleThatThrows',
|
||||
'ExampleThatThrows',
|
||||
@@ -2122,7 +2139,7 @@ describe('Timeline profiler', () => {
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'ErrorBoundary render',
|
||||
'ExampleThatThrows',
|
||||
'ExampleThatThrows',
|
||||
@@ -2253,22 +2270,19 @@ describe('Timeline profiler', () => {
|
||||
|
||||
const unmount = renderRootHelper(<ComponentWithEffects />);
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
'layout 1 mount',
|
||||
'layout 2 mount',
|
||||
]);
|
||||
await waitForPaint(['layout 1 mount', 'layout 2 mount']);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'passive 1 mount',
|
||||
'passive 2 mount',
|
||||
'passive 3 mount',
|
||||
]);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
unmount();
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'layout 1 unmount',
|
||||
'layout 2 unmount',
|
||||
'passive 1 unmount',
|
||||
@@ -2465,7 +2479,7 @@ describe('Timeline profiler', () => {
|
||||
|
||||
renderRootHelper(<CommponentWithChildren initialRender={false} />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Render ComponentWithChildren',
|
||||
'Render Child',
|
||||
'Render Child',
|
||||
|
||||
@@ -15,6 +15,7 @@ let ReactDOM;
|
||||
let ReactDOMClient;
|
||||
let Scheduler;
|
||||
let act;
|
||||
let waitForAll;
|
||||
|
||||
const setUntrackedInputValue = Object.getOwnPropertyDescriptor(
|
||||
HTMLInputElement.prototype,
|
||||
@@ -33,6 +34,9 @@ describe('ReactDOMFiberAsync', () => {
|
||||
act = require('jest-react').act;
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
|
||||
document.body.appendChild(container);
|
||||
});
|
||||
|
||||
@@ -592,7 +596,7 @@ describe('ReactDOMFiberAsync', () => {
|
||||
expect(containerC.textContent).toEqual('Finished');
|
||||
});
|
||||
|
||||
it('updates flush without yielding in the next event', () => {
|
||||
it('updates flush without yielding in the next event', async () => {
|
||||
const root = ReactDOMClient.createRoot(container);
|
||||
|
||||
function Text(props) {
|
||||
@@ -612,7 +616,7 @@ describe('ReactDOMFiberAsync', () => {
|
||||
expect(container.textContent).toEqual('');
|
||||
|
||||
// Everything should render immediately in the next event
|
||||
expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
|
||||
await waitForAll(['A', 'B', 'C']);
|
||||
expect(container.textContent).toEqual('ABC');
|
||||
});
|
||||
|
||||
|
||||
+88
-78
@@ -38,6 +38,10 @@ let buffer = '';
|
||||
let hasErrored = false;
|
||||
let fatalError = undefined;
|
||||
let renderOptions;
|
||||
let waitFor;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
let waitForPaint;
|
||||
|
||||
function resetJSDOM(markup) {
|
||||
// Test Environment
|
||||
@@ -65,6 +69,12 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
PropTypes = require('prop-types');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForPaint = InternalTestUtils.waitForPaint;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
if (gate(flags => flags.source)) {
|
||||
// The `with-selector` module composes the main `use-sync-external-store`
|
||||
// entrypoint. In the compiled artifacts, this is resolved to the `shim`
|
||||
@@ -562,7 +572,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
|
||||
|
||||
// Now we can client render it instead.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expectErrors(
|
||||
errors,
|
||||
[
|
||||
@@ -684,7 +694,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
|
||||
|
||||
// Now we can client render it instead.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expectErrors(
|
||||
errors,
|
||||
@@ -843,7 +853,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
|
||||
|
||||
// Now we can client render it instead.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expectErrors(
|
||||
errors,
|
||||
@@ -1161,7 +1171,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
|
||||
// We still can't render it on the client.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expectErrors(
|
||||
errors,
|
||||
[
|
||||
@@ -1883,7 +1893,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
|
||||
|
||||
// That will let us client render it instead.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expectErrors(
|
||||
errors,
|
||||
[
|
||||
@@ -2139,7 +2149,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['server']);
|
||||
assertLog(['server']);
|
||||
|
||||
ReactDOMClient.hydrateRoot(container, <App />, {
|
||||
onRecoverableError(error) {
|
||||
@@ -2149,9 +2159,9 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
await expect(async () => {
|
||||
// The first paint switches to client rendering due to mismatch
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
await waitForPaint([
|
||||
'client',
|
||||
'Log recoverable error: Hydration failed because the initial ' +
|
||||
'UI does not match what was rendered on the server.',
|
||||
@@ -2224,7 +2234,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['server']);
|
||||
assertLog(['server']);
|
||||
|
||||
ReactDOMClient.hydrateRoot(container, <App />, {
|
||||
onRecoverableError(error) {
|
||||
@@ -2235,9 +2245,9 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
|
||||
// The first paint uses the client due to mismatch forcing client render
|
||||
expect(() => {
|
||||
await expect(async () => {
|
||||
// The first paint switches to client rendering due to mismatch
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
await waitForPaint([
|
||||
'client',
|
||||
'Log recoverable error: Hydration failed because the initial ' +
|
||||
'UI does not match what was rendered on the server.',
|
||||
@@ -2304,7 +2314,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
assertLog(['Yay!']);
|
||||
|
||||
const span = container.getElementsByTagName('span')[0];
|
||||
|
||||
@@ -2319,8 +2329,8 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
// An error logged but instead of surfacing it to the UI, we switched
|
||||
// to client rendering.
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Yay!',
|
||||
'Hydration error',
|
||||
'There was an error while hydrating. Because the error happened ' +
|
||||
@@ -2394,7 +2404,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
assertLog(['Yay!']);
|
||||
|
||||
const [span1, span2, span3] = container.getElementsByTagName('span');
|
||||
|
||||
@@ -2409,7 +2419,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
// An error logged but instead of surfacing it to the UI, we switched
|
||||
// to client rendering.
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Yay!',
|
||||
'Hydration error',
|
||||
'There was an error while hydrating this Suspense boundary. Switched to client rendering.',
|
||||
@@ -2484,7 +2494,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
assertLog(['Yay!']);
|
||||
|
||||
// Hydrate the tree. Child will throw during render.
|
||||
isClient = true;
|
||||
@@ -2497,7 +2507,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
// Because we failed to recover from the error, onRecoverableError
|
||||
// shouldn't be called.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual('Oops!');
|
||||
|
||||
expectErrors(errors, [], []);
|
||||
@@ -2541,7 +2551,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['[s!] Oops.']);
|
||||
assertLog(['[s!] Oops.']);
|
||||
|
||||
// The server could not complete this boundary, so we'll retry on the client.
|
||||
const serverFallback = container.getElementsByTagName('p')[0];
|
||||
@@ -2555,7 +2565,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
// This should not report any errors yet.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<p>Loading...</p>
|
||||
@@ -2573,7 +2583,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await act(async () => {
|
||||
resolveText('Yay!');
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Yay!',
|
||||
'[c!] The server could not finish this Suspense boundary, ' +
|
||||
'likely due to an error during server rendering. ' +
|
||||
@@ -2626,7 +2636,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['[s!] Oops.']);
|
||||
assertLog(['[s!] Oops.']);
|
||||
|
||||
// The server could not complete this boundary, so we'll retry on the client.
|
||||
const serverFallback = container.getElementsByTagName('p')[0];
|
||||
@@ -2640,7 +2650,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
// This should not report any errors yet.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<p>Loading...</p>
|
||||
@@ -2667,7 +2677,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await act(async () => {
|
||||
resolveText('Yay!');
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Yay! (red)',
|
||||
'[c!] The server could not finish this Suspense boundary, ' +
|
||||
'likely due to an error during server rendering. ' +
|
||||
@@ -2727,7 +2737,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['[s!] Oops.']);
|
||||
assertLog(['[s!] Oops.']);
|
||||
|
||||
const serverFallback = container.getElementsByTagName('p')[0];
|
||||
expect(serverFallback.innerHTML).toBe('Loading...');
|
||||
@@ -2744,7 +2754,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
);
|
||||
// This should not report any errors yet.
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<p>Loading...</p>
|
||||
@@ -2763,7 +2773,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
root.render(<App fallbackText="More loading..." />);
|
||||
Scheduler.unstable_flushAll();
|
||||
jest.runAllTimers();
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'[c!] The server could not finish this Suspense boundary, ' +
|
||||
'likely due to an error during server rendering. ' +
|
||||
'Switched to client rendering.',
|
||||
@@ -2781,7 +2791,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await act(async () => {
|
||||
resolveText('Yay!');
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield(['Yay!']);
|
||||
await waitForAll(['Yay!']);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<span>Yay!</span>
|
||||
@@ -2849,7 +2859,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yay!']);
|
||||
assertLog(['Yay!']);
|
||||
|
||||
const [span1, span2, span3] = container.getElementsByTagName('span');
|
||||
|
||||
@@ -2864,7 +2874,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
|
||||
// An error logged but instead of surfacing it to the UI, we switched
|
||||
// to client rendering.
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Hydration error',
|
||||
'There was an error while hydrating this Suspense boundary. Switched ' +
|
||||
'to client rendering.',
|
||||
@@ -2880,7 +2890,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await act(async () => {
|
||||
resolveText('Yay!');
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield(['Yay!']);
|
||||
await waitForAll(['Yay!']);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<span />
|
||||
@@ -2937,13 +2947,13 @@ describe('ReactDOMFizzServer', () => {
|
||||
});
|
||||
|
||||
// Partially render A, but yield before the render has finished
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Oops!', 'Oops!']);
|
||||
await waitFor(['Oops!', 'Oops!']);
|
||||
|
||||
// React will try rendering again synchronously. During the retry, A will
|
||||
// not throw. This simulates a concurrent data race that is fixed by
|
||||
// blocking the main thread.
|
||||
shouldThrow = false;
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
// Finish initial render attempt
|
||||
'B',
|
||||
|
||||
@@ -3001,7 +3011,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
const {pipe} = renderToPipeableStream(<App />);
|
||||
pipe(writable);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A', 'B']);
|
||||
assertLog(['A', 'B']);
|
||||
|
||||
// Hydrate the tree. Child will throw during hydration, but not when it
|
||||
// falls back to client rendering.
|
||||
@@ -3014,7 +3024,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'A',
|
||||
'B',
|
||||
|
||||
@@ -3151,7 +3161,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expectErrors(
|
||||
errors,
|
||||
@@ -3232,7 +3242,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expectErrors(
|
||||
errors,
|
||||
@@ -3299,7 +3309,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
describe('error escaping', () => {
|
||||
@@ -3442,7 +3452,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push({error, errorInfo});
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
// If escaping were not done we would get a message that says "bad hash"
|
||||
expectErrors(
|
||||
@@ -3729,7 +3739,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
// Now that the boundary resolves to it's children the hydration completes and discovers that there is a mismatch requiring
|
||||
// client-side rendering.
|
||||
await clientResolve();
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<p>A</p>
|
||||
@@ -3808,8 +3818,8 @@ describe('ReactDOMFizzServer', () => {
|
||||
// Now that the boundary resolves to it's children the hydration completes and discovers that there is a mismatch requiring
|
||||
// client-side rendering.
|
||||
await clientResolve();
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Logged recoverable error: Text content does not match server-rendered HTML.',
|
||||
'Logged recoverable error: There was an error while hydrating this Suspense boundary. Switched to client rendering.',
|
||||
]);
|
||||
@@ -3823,7 +3833,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
// @gate enableClientRenderFallbackOnTextMismatch
|
||||
@@ -3867,7 +3877,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Logged recoverable error: Text content does not match server-rendered HTML.',
|
||||
'Logged recoverable error: Text content does not match server-rendered HTML.',
|
||||
'Logged recoverable error: Text content does not match server-rendered HTML.',
|
||||
@@ -3882,7 +3892,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
if (__DEV__) {
|
||||
expect(mockError.mock.calls.length).toBe(1);
|
||||
expect(mockError.mock.calls[0]).toEqual([
|
||||
@@ -3958,7 +3968,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Logged recoverable error: uh oh',
|
||||
'Logged recoverable error: Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'Logged recoverable error: Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
@@ -3973,7 +3983,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
// @gate __DEV__
|
||||
@@ -4050,7 +4060,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'throwing: first error',
|
||||
// this repeated first error is the invokeGuardedCallback throw
|
||||
'throwing: first error',
|
||||
@@ -4081,7 +4091,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(mockError.mock.calls).toEqual([]);
|
||||
} finally {
|
||||
console.error = originalConsoleError;
|
||||
@@ -4181,7 +4191,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'suspending',
|
||||
'throwing: first error',
|
||||
// There is no repeated first error because we already suspended and no
|
||||
@@ -4202,7 +4212,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await unsuspend();
|
||||
// Since our client components only throw on the very first render there are no
|
||||
// new throws in this pass
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
expect(mockError.mock.calls).toEqual([]);
|
||||
} finally {
|
||||
@@ -4304,7 +4314,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'throwing: first error',
|
||||
// duplicate because first error is re-done in invokeGuardedCallback
|
||||
'throwing: first error',
|
||||
@@ -4331,7 +4341,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await unsuspend();
|
||||
// Since our client components only throw on the very first render there are no
|
||||
// new throws in this pass
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(mockError.mock.calls).toEqual([]);
|
||||
} finally {
|
||||
console.error = originalConsoleError;
|
||||
@@ -4365,7 +4375,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4374,7 +4384,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
|
||||
resolveText('A');
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4411,7 +4421,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4421,7 +4431,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
|
||||
resolve({default: () => <p>lazy</p>});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4566,7 +4576,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4629,7 +4639,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div id="app-div">
|
||||
@@ -4679,7 +4689,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div id="app-div">{['h', 'ello', 'w', 'orld']}</div>,
|
||||
@@ -4724,7 +4734,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div id="app-div">{['h', 'ello', 'w', 'orld']}</div>,
|
||||
@@ -4762,7 +4772,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4800,7 +4810,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4857,7 +4867,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div id="app-div">
|
||||
@@ -4883,7 +4893,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
'<div id="app-div">start<!--$-->firststartfirst suspendedfirstend<!--/$--><!--$-->secondstart<b>second suspended</b><!--/$-->end</div>',
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div id="app-div">
|
||||
@@ -4939,7 +4949,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -4985,7 +4995,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
|
||||
});
|
||||
@@ -5009,7 +5019,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
expect(getVisibleChildren(container)).toEqual(<title>hello</title>);
|
||||
});
|
||||
@@ -5044,7 +5054,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
if (gate(flags => flags.enableFloat)) {
|
||||
expect(errors).toEqual([]);
|
||||
// with float, the title doesn't render on the client or on the server
|
||||
@@ -5117,7 +5127,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(errors).toEqual([]);
|
||||
if (gate(flags => flags.enableFloat)) {
|
||||
// object titles are toStringed when float is on
|
||||
@@ -5171,7 +5181,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual('ABC');
|
||||
|
||||
ReactDOMClient.hydrateRoot(container, <App />);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual('ABC');
|
||||
});
|
||||
|
||||
@@ -5219,7 +5229,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
ContextA._currentRenderer = null;
|
||||
ServerContext._currentRenderer = null;
|
||||
ReactDOMClient.hydrateRoot(container, <App />);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(['AB', 'C']);
|
||||
});
|
||||
|
||||
@@ -5273,7 +5283,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual('ABCD');
|
||||
|
||||
ReactDOMClient.hydrateRoot(container, <App />);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual('ABCD');
|
||||
});
|
||||
|
||||
@@ -5350,7 +5360,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
reportedClientErrors.push(error);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual('Oops!');
|
||||
expect(reportedClientErrors.length).toBe(1);
|
||||
if (__DEV__) {
|
||||
@@ -5383,7 +5393,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual('Hi');
|
||||
|
||||
ReactDOMClient.hydrateRoot(container, <App />);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual('Hi');
|
||||
});
|
||||
|
||||
@@ -5437,7 +5447,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
expect(getVisibleChildren(container)).toEqual(<button>0</button>);
|
||||
|
||||
ReactDOMClient.hydrateRoot(container, <App />);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(<button>0</button>);
|
||||
|
||||
ref.current.dispatchEvent(
|
||||
@@ -5502,8 +5512,8 @@ describe('ReactDOMFizzServer', () => {
|
||||
errors.push(error);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev(
|
||||
[
|
||||
'Expected server HTML to contain a matching <span> in <div>',
|
||||
|
||||
+23
-19
@@ -22,6 +22,7 @@ let container;
|
||||
let buffer = '';
|
||||
let hasErrored = false;
|
||||
let fatalError = undefined;
|
||||
let waitForAll;
|
||||
|
||||
describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
beforeEach(() => {
|
||||
@@ -33,6 +34,9 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
ReactDOMFizzServer = require('react-dom/server');
|
||||
Stream = require('stream');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
|
||||
// Test Environment
|
||||
const jsdom = new JSDOM(
|
||||
'<!DOCTYPE html><html><head></head><body><div id="container">',
|
||||
@@ -155,7 +159,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
// The text mismatch should be *silently* fixed. Even in production.
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
@@ -195,7 +199,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<span>
|
||||
@@ -236,8 +240,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
|
||||
]);
|
||||
@@ -283,7 +287,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<span>{'Client'}</span>
|
||||
@@ -319,8 +323,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
|
||||
]);
|
||||
@@ -367,8 +371,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
|
||||
]);
|
||||
@@ -418,8 +422,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
|
||||
]);
|
||||
@@ -467,8 +471,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
|
||||
@@ -521,7 +525,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<span class="server" style="opacity:0" data-serveronly="server-only" />
|
||||
@@ -558,7 +562,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(getVisibleChildren(container)).toEqual(
|
||||
<div>
|
||||
<p>Server HTML</p>
|
||||
@@ -591,8 +595,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
|
||||
]);
|
||||
@@ -637,8 +641,8 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
|
||||
Scheduler.unstable_yieldValue(error.message);
|
||||
},
|
||||
});
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await expect(async () => {
|
||||
await waitForAll([
|
||||
'Hydration failed because the initial UI does not match what was rendered on the server.',
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
|
||||
]);
|
||||
|
||||
+78
-68
@@ -33,6 +33,8 @@ let buffer = '';
|
||||
let hasErrored = false;
|
||||
let fatalError = undefined;
|
||||
let renderOptions;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
|
||||
function resetJSDOM(markup) {
|
||||
// Test Environment
|
||||
@@ -63,6 +65,10 @@ describe('ReactDOMFloat', () => {
|
||||
Stream = require('stream');
|
||||
Suspense = React.Suspense;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
textCache = new Map();
|
||||
|
||||
resetJSDOM('<!DOCTYPE html><html><head></head><body><div id="container">');
|
||||
@@ -259,10 +265,14 @@ describe('ReactDOMFloat', () => {
|
||||
root.render(children);
|
||||
return expect(() => {
|
||||
try {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
// TODO: Migrate this to waitForAll()
|
||||
Scheduler.unstable_flushAll();
|
||||
assertLog([]);
|
||||
} catch (e) {
|
||||
try {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
// TODO: Migrate this to waitForAll()
|
||||
Scheduler.unstable_flushAll();
|
||||
assertLog([]);
|
||||
} catch (f) {}
|
||||
}
|
||||
});
|
||||
@@ -283,11 +293,11 @@ describe('ReactDOMFloat', () => {
|
||||
</>,
|
||||
);
|
||||
try {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
} catch (e) {
|
||||
// for DOMExceptions that happen when expecting this test to fail we need
|
||||
// to clear the scheduler first otherwise the expected failure will fail
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
throw e;
|
||||
}
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
@@ -351,7 +361,7 @@ describe('ReactDOMFloat', () => {
|
||||
<body>foo</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -476,7 +486,7 @@ describe('ReactDOMFloat', () => {
|
||||
<script async={true} src="foo" />
|
||||
</>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -494,7 +504,7 @@ describe('ReactDOMFloat', () => {
|
||||
<script data-new="new" async={true} src="foo" />
|
||||
</>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
// we don't see the attribute because the resource is the same and was not reconstructed
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
@@ -671,7 +681,7 @@ describe('ReactDOMFloat', () => {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -968,7 +978,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
@@ -1107,7 +1117,7 @@ body {
|
||||
errors.push(err.digest);
|
||||
},
|
||||
});
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -1157,7 +1167,7 @@ body {
|
||||
<body>Hello</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -1627,7 +1637,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -1649,7 +1659,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -1694,7 +1704,7 @@ body {
|
||||
<Throw />
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -2327,8 +2337,8 @@ body {
|
||||
);
|
||||
|
||||
const root = ReactDOMClient.hydrateRoot(document, <App url="foo" />);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev([
|
||||
'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
|
||||
'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
|
||||
@@ -2343,8 +2353,8 @@ body {
|
||||
);
|
||||
|
||||
root.render(<App url="bar" />);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev([
|
||||
'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
|
||||
'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
|
||||
@@ -2397,8 +2407,8 @@ body {
|
||||
);
|
||||
|
||||
const root = ReactDOMClient.hydrateRoot(document, <App url="foo" />);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev(
|
||||
'ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered something with type "boolean" instead. Try removing this option or passing a string value instead.',
|
||||
);
|
||||
@@ -2414,8 +2424,8 @@ body {
|
||||
);
|
||||
|
||||
root.render(<App url="bar" />);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev(
|
||||
'ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered something with type "boolean" instead. Try removing this option or passing a string value instead.',
|
||||
);
|
||||
@@ -2502,7 +2512,7 @@ body {
|
||||
);
|
||||
}
|
||||
ReactDOMClient.hydrateRoot(document, <ClientApp />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -2724,7 +2734,7 @@ body {
|
||||
}
|
||||
|
||||
ReactDOMClient.hydrateRoot(document, <ClientApp />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -2754,7 +2764,7 @@ body {
|
||||
|
||||
const root = ReactDOMClient.createRoot(document);
|
||||
root.render(<App />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -2829,7 +2839,7 @@ body {
|
||||
}
|
||||
|
||||
ReactDOMClient.hydrateRoot(document, <ClientApp />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -2858,7 +2868,7 @@ body {
|
||||
|
||||
const root = ReactDOMClient.createRoot(document);
|
||||
root.render(<App />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3050,7 +3060,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
@@ -3088,7 +3098,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
@@ -3171,7 +3181,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3206,7 +3216,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
root.render(
|
||||
<html>
|
||||
@@ -3214,7 +3224,7 @@ body {
|
||||
<body>hello world</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3256,8 +3266,8 @@ body {
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev(
|
||||
[
|
||||
'Warning: Text content did not match. Server: "server" Client: "client"',
|
||||
@@ -3308,8 +3318,8 @@ body {
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev(
|
||||
[
|
||||
'Warning: Text content did not match. Server: "server" Client: "client"',
|
||||
@@ -3342,7 +3352,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3364,7 +3374,7 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
// The reason we do not see preloads in the head is they are inserted synchronously
|
||||
// during render and then when the new singleton mounts it resets it's content, retaining only styles
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
@@ -3401,7 +3411,7 @@ body {
|
||||
container
|
||||
</>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3461,7 +3471,7 @@ body {
|
||||
container
|
||||
</>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3533,7 +3543,7 @@ body {
|
||||
);
|
||||
}
|
||||
root.render(<ClientApp />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3596,7 +3606,7 @@ body {
|
||||
container = document.getElementById('container');
|
||||
const root = ReactDOMClient.createRoot(container);
|
||||
root.render(<App />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -3672,7 +3682,7 @@ body {
|
||||
</svg>
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document.body)).toEqual(
|
||||
<div>
|
||||
<svg>
|
||||
@@ -3718,7 +3728,7 @@ body {
|
||||
</noscript>
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document.body)).toEqual(
|
||||
<div>
|
||||
{/* On the client, <noscript> never renders children */}
|
||||
@@ -3793,8 +3803,8 @@ body {
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev([
|
||||
'React encountered a <link rel="stylesheet" href="foo" ... /> with a `precedence` prop that also included the `onLoad` and `onError` props. The presence of loading and error handlers indicates an intent to manage the stylesheet loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.',
|
||||
]);
|
||||
@@ -4064,7 +4074,7 @@ background-color: green;
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
@@ -4095,7 +4105,7 @@ background-color: green;
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -4493,7 +4503,7 @@ background-color: green;
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
// The async script with onLoad is inserted in the right place but does not cause the hydration
|
||||
// to fail.
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
@@ -4560,7 +4570,7 @@ background-color: green;
|
||||
</svg>
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document.body)).toEqual(
|
||||
<div>
|
||||
<svg>
|
||||
@@ -4606,7 +4616,7 @@ background-color: green;
|
||||
</noscript>
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document.body)).toEqual(
|
||||
<div>
|
||||
{/* On the client, <noscript> never renders children */}
|
||||
@@ -4708,7 +4718,7 @@ background-color: green;
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -4723,7 +4733,7 @@ background-color: green;
|
||||
<body />
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
@@ -4742,7 +4752,7 @@ background-color: green;
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
expect(getMeaningfulChildren(document.head)).toEqual(
|
||||
<meta name="foo" data-foo="data" content="bar" />,
|
||||
@@ -4750,7 +4760,7 @@ background-color: green;
|
||||
expect(getMeaningfulChildren(container)).toEqual(<div />);
|
||||
|
||||
root.render(<div />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document.head)).toEqual(undefined);
|
||||
});
|
||||
|
||||
@@ -4784,7 +4794,7 @@ background-color: green;
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -4799,7 +4809,7 @@ background-color: green;
|
||||
<body />
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
@@ -4818,7 +4828,7 @@ background-color: green;
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
expect(getMeaningfulChildren(document.head)).toEqual(
|
||||
<link rel="foo" data-foo="data" href="foo" />,
|
||||
@@ -4826,7 +4836,7 @@ background-color: green;
|
||||
expect(getMeaningfulChildren(container)).toEqual(<div />);
|
||||
|
||||
root.render(<div />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document.head)).toEqual(undefined);
|
||||
});
|
||||
|
||||
@@ -4860,7 +4870,7 @@ background-color: green;
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -4875,7 +4885,7 @@ background-color: green;
|
||||
<body />
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
@@ -4894,7 +4904,7 @@ background-color: green;
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
expect(getMeaningfulChildren(document.head)).toEqual(
|
||||
<title data-foo="foo">a title</title>,
|
||||
@@ -4902,7 +4912,7 @@ background-color: green;
|
||||
expect(getMeaningfulChildren(container)).toEqual(<div />);
|
||||
|
||||
root.render(<div />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document.head)).toEqual(undefined);
|
||||
});
|
||||
|
||||
@@ -5031,7 +5041,7 @@ background-color: green;
|
||||
<meta name="after" />
|
||||
</>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
@@ -5051,7 +5061,7 @@ background-color: green;
|
||||
{null}
|
||||
</>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head />
|
||||
@@ -5157,8 +5167,8 @@ background-color: green;
|
||||
},
|
||||
);
|
||||
try {
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await expect(async () => {
|
||||
await waitForAll([]);
|
||||
}).toErrorDev(
|
||||
[
|
||||
'Warning: Text content did not match. Server: "server" Client: "client"',
|
||||
@@ -5169,7 +5179,7 @@ background-color: green;
|
||||
} catch (e) {
|
||||
// When gates are false this test fails on a DOMException if you don't clear the scheduler after catching.
|
||||
// When gates are true this branch should not be hit
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
throw e;
|
||||
}
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
|
||||
@@ -13,6 +13,7 @@ let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let JSXDEVRuntime;
|
||||
let waitForAll;
|
||||
|
||||
describe('ReactDeprecationWarnings', () => {
|
||||
beforeEach(() => {
|
||||
@@ -20,6 +21,8 @@ describe('ReactDeprecationWarnings', () => {
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
if (__DEV__) {
|
||||
JSXDEVRuntime = require('react/jsx-dev-runtime');
|
||||
}
|
||||
@@ -86,7 +89,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn when owner and self are the same for string refs', () => {
|
||||
it('should warn when owner and self are the same for string refs', async () => {
|
||||
class RefComponent extends React.Component {
|
||||
render() {
|
||||
return null;
|
||||
@@ -102,7 +105,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
}).toErrorDev([
|
||||
'Component "Component" contains the string ref "refComponent". Support for string refs will be removed in a future major release.',
|
||||
]);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
it('should warn when owner and self are different for string refs', () => {
|
||||
|
||||
@@ -17,6 +17,9 @@ let Scheduler;
|
||||
let ReactTestRenderer;
|
||||
let act;
|
||||
let AdvanceTime;
|
||||
let assertLog;
|
||||
let waitFor;
|
||||
let waitForAll;
|
||||
|
||||
function loadModules({
|
||||
enableProfilerTimer = true,
|
||||
@@ -49,6 +52,11 @@ function loadModules({
|
||||
ReactTestRenderer = require('react-test-renderer');
|
||||
}
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
|
||||
AdvanceTime = class extends React.Component {
|
||||
static defaultProps = {
|
||||
byAmount: 10,
|
||||
@@ -188,7 +196,7 @@ describe(`onRender`, () => {
|
||||
expect(callback).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('is not invoked until the commit phase', () => {
|
||||
it('is not invoked until the commit phase', async () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
const Yield = ({value}) => {
|
||||
@@ -209,9 +217,9 @@ describe(`onRender`, () => {
|
||||
});
|
||||
|
||||
// Times are logged until a render is committed.
|
||||
expect(Scheduler).toFlushAndYieldThrough(['first']);
|
||||
await waitFor(['first']);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
expect(Scheduler).toFlushAndYield(['last']);
|
||||
await waitForAll(['last']);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -248,7 +256,7 @@ describe(`onRender`, () => {
|
||||
|
||||
// TODO: unstable_now is called by more places than just the profiler.
|
||||
// Rewrite this test so it's less fragile.
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'read current time',
|
||||
'read current time',
|
||||
'read current time',
|
||||
@@ -669,7 +677,7 @@ describe(`onRender`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['false:false', 'true:false', 'true:true']);
|
||||
assertLog(['false:false', 'true:false', 'true:true']);
|
||||
|
||||
expect(onRender).toHaveBeenCalledTimes(3);
|
||||
expect(onRender.mock.calls[0][1]).toBe('mount');
|
||||
@@ -711,7 +719,7 @@ describe(`onRender`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([false, true]);
|
||||
assertLog([false, true]);
|
||||
|
||||
// Verify that the nested update inside of the sync work is appropriately tagged.
|
||||
expect(onRender).toHaveBeenCalledTimes(2);
|
||||
@@ -720,7 +728,7 @@ describe(`onRender`, () => {
|
||||
});
|
||||
|
||||
describe('with regard to interruptions', () => {
|
||||
it('should accumulate actual time after a scheduling interruptions', () => {
|
||||
it('should accumulate actual time after a scheduling interruptions', async () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
const Yield = ({renderTime}) => {
|
||||
@@ -741,11 +749,11 @@ describe(`onRender`, () => {
|
||||
{unstable_isConcurrent: true},
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Yield:2']);
|
||||
await waitFor(['Yield:2']);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Resume render for remaining children.
|
||||
expect(Scheduler).toFlushAndYield(['Yield:3']);
|
||||
await waitForAll(['Yield:3']);
|
||||
|
||||
// Verify that logged times include both durations above.
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
@@ -756,7 +764,7 @@ describe(`onRender`, () => {
|
||||
expect(call[5]).toBe(10); // commit time
|
||||
});
|
||||
|
||||
it('should not include time between frames', () => {
|
||||
it('should not include time between frames', async () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
const Yield = ({renderTime}) => {
|
||||
@@ -781,7 +789,7 @@ describe(`onRender`, () => {
|
||||
{unstable_isConcurrent: true},
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Yield:5']);
|
||||
await waitFor(['Yield:5']);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Simulate time moving forward while frame is paused.
|
||||
@@ -789,7 +797,7 @@ describe(`onRender`, () => {
|
||||
|
||||
// Flush the remaining work,
|
||||
// Which should take an additional 10ms of simulated time.
|
||||
expect(Scheduler).toFlushAndYield(['Yield:10', 'Yield:17']);
|
||||
await waitForAll(['Yield:10', 'Yield:17']);
|
||||
expect(callback).toHaveBeenCalledTimes(2);
|
||||
|
||||
const [innerCall, outerCall] = callback.mock.calls;
|
||||
@@ -808,7 +816,7 @@ describe(`onRender`, () => {
|
||||
expect(outerCall[5]).toBe(87); // commit time
|
||||
});
|
||||
|
||||
it('should report the expected times when a high-pri update replaces a mount in-progress', () => {
|
||||
it('should report the expected times when a high-pri update replaces a mount in-progress', async () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
const Yield = ({renderTime}) => {
|
||||
@@ -831,7 +839,7 @@ describe(`onRender`, () => {
|
||||
{unstable_isConcurrent: true},
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Yield:10']);
|
||||
await waitFor(['Yield:10']);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Simulate time moving forward while frame is paused.
|
||||
@@ -846,7 +854,7 @@ describe(`onRender`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yield:5']);
|
||||
assertLog(['Yield:5']);
|
||||
|
||||
// The initial work was thrown away in this case,
|
||||
// So the actual and base times should only include the final rendered tree times.
|
||||
@@ -860,11 +868,11 @@ describe(`onRender`, () => {
|
||||
callback.mockReset();
|
||||
|
||||
// Verify no more unexpected callbacks from low priority work
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should report the expected times when a high-priority update replaces a low-priority update', () => {
|
||||
it('should report the expected times when a high-priority update replaces a low-priority update', async () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
const Yield = ({renderTime}) => {
|
||||
@@ -885,7 +893,7 @@ describe(`onRender`, () => {
|
||||
|
||||
// Render everything initially.
|
||||
// This should take 21 seconds of actual and base time.
|
||||
expect(Scheduler).toFlushAndYield(['Yield:6', 'Yield:15']);
|
||||
await waitForAll(['Yield:6', 'Yield:15']);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
let call = callback.mock.calls[0];
|
||||
expect(call[2]).toBe(21); // actual time
|
||||
@@ -908,14 +916,14 @@ describe(`onRender`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Yield:3']);
|
||||
await waitFor(['Yield:3']);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Simulate time moving forward while frame is paused.
|
||||
Scheduler.unstable_advanceTime(100); // 59 -> 159
|
||||
|
||||
// Render another 5ms of simulated time.
|
||||
expect(Scheduler).toFlushAndYieldThrough(['Yield:5']);
|
||||
await waitFor(['Yield:5']);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Simulate time moving forward while frame is paused.
|
||||
@@ -930,7 +938,7 @@ describe(`onRender`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Yield:11']);
|
||||
assertLog(['Yield:11']);
|
||||
|
||||
// The actual time should include only the most recent render,
|
||||
// Because this lets us avoid a lot of commit phase reset complexity.
|
||||
@@ -943,11 +951,11 @@ describe(`onRender`, () => {
|
||||
expect(call[5]).toBe(275); // commit time
|
||||
|
||||
// Verify no more unexpected callbacks from low priority work
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should report the expected times when a high-priority update interrupts a low-priority update', () => {
|
||||
it('should report the expected times when a high-priority update interrupts a low-priority update', async () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
const Yield = ({renderTime}) => {
|
||||
@@ -994,7 +1002,7 @@ describe(`onRender`, () => {
|
||||
// Render everything initially.
|
||||
// This simulates a total of 14ms of actual render time.
|
||||
// The base render time is also 14ms for the initial render.
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'FirstComponent:1',
|
||||
'Yield:4',
|
||||
'SecondComponent:2',
|
||||
@@ -1016,7 +1024,7 @@ describe(`onRender`, () => {
|
||||
React.startTransition(() => {
|
||||
first.setState({renderTime: 10});
|
||||
});
|
||||
expect(Scheduler).toFlushAndYieldThrough(['FirstComponent:10']);
|
||||
await waitFor(['FirstComponent:10']);
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Simulate time moving forward while frame is paused.
|
||||
@@ -1025,7 +1033,7 @@ describe(`onRender`, () => {
|
||||
// Interrupt with higher priority work.
|
||||
// This simulates a total of 37ms of actual render time.
|
||||
renderer.unstable_flushSync(() => second.setState({renderTime: 30}));
|
||||
expect(Scheduler).toHaveYielded(['SecondComponent:30', 'Yield:7']);
|
||||
assertLog(['SecondComponent:30', 'Yield:7']);
|
||||
|
||||
// The actual time should include only the most recent render (37ms),
|
||||
// Because this greatly simplifies the commit phase logic.
|
||||
@@ -1049,7 +1057,7 @@ describe(`onRender`, () => {
|
||||
// The tree contains 42ms of base render time at this point,
|
||||
// Reflecting the most recent (longer) render durations.
|
||||
// TODO: This actual time should decrease by 10ms once the scheduler supports resuming.
|
||||
expect(Scheduler).toFlushAndYield(['FirstComponent:10', 'Yield:4']);
|
||||
await waitForAll(['FirstComponent:10', 'Yield:4']);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
call = callback.mock.calls[0];
|
||||
expect(call[2]).toBe(14); // actual time
|
||||
@@ -1207,7 +1215,7 @@ describe(`onRender`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should reset the fiber stack correct after a "complete" phase error', () => {
|
||||
it('should reset the fiber stack correct after a "complete" phase error', async () => {
|
||||
jest.resetModules();
|
||||
|
||||
loadModules({
|
||||
@@ -1242,7 +1250,7 @@ describe(`onRender`, () => {
|
||||
<span>hi</span>
|
||||
</React.Profiler>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2381,12 +2389,12 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
|
||||
assertLog(['Component:false', 'Component:true']);
|
||||
expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
|
||||
expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
|
||||
});
|
||||
|
||||
it('is called when a function component schedules a batched update during a layout effect', () => {
|
||||
it('is called when a function component schedules a batched update during a layout effect', async () => {
|
||||
function Component() {
|
||||
const [didMount, setDidMount] = React.useState(false);
|
||||
React.useLayoutEffect(() => {
|
||||
@@ -2409,7 +2417,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
<Component />
|
||||
</React.Profiler>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndYield(['Component:false', 'Component:true']);
|
||||
await waitForAll(['Component:false', 'Component:true']);
|
||||
|
||||
expect(onRender).toHaveBeenCalledTimes(2);
|
||||
expect(onRender.mock.calls[0][1]).toBe('mount');
|
||||
@@ -2452,7 +2460,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
|
||||
assertLog(['Component:false', 'Component:true']);
|
||||
expect(onNestedUpdateScheduledOne).toHaveBeenCalledTimes(1);
|
||||
expect(onNestedUpdateScheduledOne.mock.calls[0][0]).toBe('one');
|
||||
expect(onNestedUpdateScheduledTwo).toHaveBeenCalledTimes(1);
|
||||
@@ -2500,7 +2508,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'ComponentRootOne:false',
|
||||
'ComponentRootTwo',
|
||||
'ComponentRootOne:true',
|
||||
@@ -2530,7 +2538,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
|
||||
assertLog(['Component:false', 'Component:true']);
|
||||
expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -2555,12 +2563,12 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Component:false']);
|
||||
assertLog(['Component:false']);
|
||||
|
||||
act(() => {
|
||||
updateFnRef.current();
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Component:true']);
|
||||
assertLog(['Component:true']);
|
||||
expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -2586,7 +2594,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
|
||||
assertLog(['Component:false', 'Component:true']);
|
||||
expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -2617,10 +2625,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Component:false:false',
|
||||
'Component:true:false',
|
||||
]);
|
||||
assertLog(['Component:false:false', 'Component:true:false']);
|
||||
expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
|
||||
expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
|
||||
|
||||
@@ -2634,10 +2639,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Component:true:false',
|
||||
'Component:true:true',
|
||||
]);
|
||||
assertLog(['Component:true:false', 'Component:true:true']);
|
||||
expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(2);
|
||||
expect(onNestedUpdateScheduled.mock.calls[1][0]).toBe('test');
|
||||
});
|
||||
@@ -2669,7 +2671,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Component:false', 'Component:true']);
|
||||
assertLog(['Component:false', 'Component:true']);
|
||||
expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
|
||||
expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
|
||||
});
|
||||
@@ -2708,7 +2710,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Component:false:false']);
|
||||
assertLog(['Component:false:false']);
|
||||
expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
|
||||
|
||||
act(() => {
|
||||
@@ -2721,10 +2723,7 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Component:true:false',
|
||||
'Component:true:true',
|
||||
]);
|
||||
assertLog(['Component:true:false', 'Component:true:true']);
|
||||
expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
|
||||
expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
|
||||
});
|
||||
@@ -2755,12 +2754,12 @@ describe(`onNestedUpdateScheduled`, () => {
|
||||
</React.Profiler>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Component:false']);
|
||||
assertLog(['Component:false']);
|
||||
|
||||
act(() => {
|
||||
updateFnRef.current();
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Component:true']);
|
||||
assertLog(['Component:true']);
|
||||
expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
let Scheduler;
|
||||
let AdvanceTime;
|
||||
let hook;
|
||||
let waitForAll;
|
||||
let waitFor;
|
||||
|
||||
beforeEach(() => {
|
||||
global.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = {
|
||||
@@ -34,6 +36,10 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
React = require('react');
|
||||
ReactTestRenderer = require('react-test-renderer');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
|
||||
AdvanceTime = class extends React.Component {
|
||||
static defaultProps = {
|
||||
byAmount: 10,
|
||||
@@ -138,7 +144,7 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
).toBe(7);
|
||||
});
|
||||
|
||||
it('regression test: #17159', () => {
|
||||
it('regression test: #17159', async () => {
|
||||
function Text({text}) {
|
||||
Scheduler.unstable_yieldValue(text);
|
||||
return text;
|
||||
@@ -148,7 +154,7 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
|
||||
// Commit something
|
||||
root.update(<Text text="A" />);
|
||||
expect(Scheduler).toFlushAndYield(['A']);
|
||||
await waitForAll(['A']);
|
||||
expect(root).toMatchRenderedOutput('A');
|
||||
|
||||
// Advance time by many seconds, larger than the default expiration time
|
||||
@@ -160,9 +166,9 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
});
|
||||
|
||||
// Update B should not instantly expire.
|
||||
expect(Scheduler).toFlushAndYieldThrough([]);
|
||||
await waitFor([]);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['B']);
|
||||
await waitForAll(['B']);
|
||||
expect(root).toMatchRenderedOutput('B');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ describe('forwardRef', () => {
|
||||
let ReactFeatureFlags;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let waitForAll;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
@@ -23,9 +24,12 @@ describe('forwardRef', () => {
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
});
|
||||
|
||||
it('should work without a ref to be forwarded', () => {
|
||||
it('should work without a ref to be forwarded', async () => {
|
||||
class Child extends React.Component {
|
||||
render() {
|
||||
Scheduler.unstable_yieldValue(this.props.value);
|
||||
@@ -42,10 +46,10 @@ describe('forwardRef', () => {
|
||||
));
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent value={123} />);
|
||||
expect(Scheduler).toFlushAndYield([123]);
|
||||
await waitForAll([123]);
|
||||
});
|
||||
|
||||
it('should forward a ref for a single child', () => {
|
||||
it('should forward a ref for a single child', async () => {
|
||||
class Child extends React.Component {
|
||||
render() {
|
||||
Scheduler.unstable_yieldValue(this.props.value);
|
||||
@@ -64,11 +68,11 @@ describe('forwardRef', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} value={123} />);
|
||||
expect(Scheduler).toFlushAndYield([123]);
|
||||
await waitForAll([123]);
|
||||
expect(ref.current instanceof Child).toBe(true);
|
||||
});
|
||||
|
||||
it('should forward a ref for multiple children', () => {
|
||||
it('should forward a ref for multiple children', async () => {
|
||||
class Child extends React.Component {
|
||||
render() {
|
||||
Scheduler.unstable_yieldValue(this.props.value);
|
||||
@@ -93,11 +97,11 @@ describe('forwardRef', () => {
|
||||
<div />
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndYield([123]);
|
||||
await waitForAll([123]);
|
||||
expect(ref.current instanceof Child).toBe(true);
|
||||
});
|
||||
|
||||
it('should maintain child instance and ref through updates', () => {
|
||||
it('should maintain child instance and ref through updates', async () => {
|
||||
class Child extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -125,16 +129,16 @@ describe('forwardRef', () => {
|
||||
};
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={setRef} value={123} />);
|
||||
expect(Scheduler).toFlushAndYield([123]);
|
||||
await waitForAll([123]);
|
||||
expect(ref instanceof Child).toBe(true);
|
||||
expect(setRefCount).toBe(1);
|
||||
ReactNoop.render(<RefForwardingComponent ref={setRef} value={456} />);
|
||||
expect(Scheduler).toFlushAndYield([456]);
|
||||
await waitForAll([456]);
|
||||
expect(ref instanceof Child).toBe(true);
|
||||
expect(setRefCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should not break lifecycle error handling', () => {
|
||||
it('should not break lifecycle error handling', async () => {
|
||||
class ErrorBoundary extends React.Component {
|
||||
state = {error: null};
|
||||
componentDidCatch(error) {
|
||||
@@ -175,7 +179,7 @@ describe('forwardRef', () => {
|
||||
<RefForwardingComponent ref={ref} />
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'ErrorBoundary.render: try',
|
||||
'Wrapper',
|
||||
'BadRender throw',
|
||||
@@ -192,7 +196,7 @@ describe('forwardRef', () => {
|
||||
expect(ref.current).toBe(null);
|
||||
});
|
||||
|
||||
it('should not re-run the render callback on a deep setState', () => {
|
||||
it('should not re-run the render callback on a deep setState', async () => {
|
||||
let inst;
|
||||
|
||||
class Inner extends React.Component {
|
||||
@@ -219,9 +223,9 @@ describe('forwardRef', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<App />);
|
||||
expect(Scheduler).toFlushAndYield(['App', 'Forward', 'Middle', 'Inner']);
|
||||
await waitForAll(['App', 'Forward', 'Middle', 'Inner']);
|
||||
|
||||
inst.setState({});
|
||||
expect(Scheduler).toFlushAndYield(['Inner']);
|
||||
await waitForAll(['Inner']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,17 +13,19 @@ describe('forwardRef', () => {
|
||||
let PropTypes;
|
||||
let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let waitForAll;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
PropTypes = require('prop-types');
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
});
|
||||
|
||||
it('should update refs when switching between children', () => {
|
||||
it('should update refs when switching between children', async () => {
|
||||
function FunctionComponent({forwardedRef, setRefOnDiv}) {
|
||||
return (
|
||||
<section>
|
||||
@@ -40,25 +42,25 @@ describe('forwardRef', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} setRefOnDiv={true} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ref.current.type).toBe('div');
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} setRefOnDiv={false} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ref.current.type).toBe('span');
|
||||
});
|
||||
|
||||
it('should support rendering null', () => {
|
||||
it('should support rendering null', async () => {
|
||||
const RefForwardingComponent = React.forwardRef((props, ref) => null);
|
||||
|
||||
const ref = React.createRef();
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ref.current).toBe(null);
|
||||
});
|
||||
|
||||
it('should support rendering null for multiple children', () => {
|
||||
it('should support rendering null for multiple children', async () => {
|
||||
const RefForwardingComponent = React.forwardRef((props, ref) => null);
|
||||
|
||||
const ref = React.createRef();
|
||||
@@ -70,11 +72,11 @@ describe('forwardRef', () => {
|
||||
<div />
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ref.current).toBe(null);
|
||||
});
|
||||
|
||||
it('should support propTypes and defaultProps', () => {
|
||||
it('should support propTypes and defaultProps', async () => {
|
||||
function FunctionComponent({forwardedRef, optional, required}) {
|
||||
return (
|
||||
<div ref={forwardedRef}>
|
||||
@@ -103,14 +105,14 @@ describe('forwardRef', () => {
|
||||
ReactNoop.render(
|
||||
<RefForwardingComponent ref={ref} optional="foo" required="bar" />,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ref.current.children).toEqual([
|
||||
{text: 'foo', hidden: false},
|
||||
{text: 'bar', hidden: false},
|
||||
]);
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} required="foo" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ref.current.children).toEqual([
|
||||
{text: 'default', hidden: false},
|
||||
{text: 'foo', hidden: false},
|
||||
@@ -344,7 +346,7 @@ describe('forwardRef', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should not bailout if forwardRef is not wrapped in memo', () => {
|
||||
it('should not bailout if forwardRef is not wrapped in memo', async () => {
|
||||
const Component = props => <div {...props} />;
|
||||
|
||||
let renderCount = 0;
|
||||
@@ -357,15 +359,15 @@ describe('forwardRef', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(1);
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(2);
|
||||
});
|
||||
|
||||
it('should bailout if forwardRef is wrapped in memo', () => {
|
||||
it('should bailout if forwardRef is wrapped in memo', async () => {
|
||||
const Component = props => <div ref={props.forwardedRef} />;
|
||||
|
||||
let renderCount = 0;
|
||||
@@ -380,13 +382,13 @@ describe('forwardRef', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(1);
|
||||
|
||||
expect(ref.current.type).toBe('div');
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(1);
|
||||
|
||||
const differentRef = React.createRef();
|
||||
@@ -394,18 +396,18 @@ describe('forwardRef', () => {
|
||||
ReactNoop.render(
|
||||
<RefForwardingComponent ref={differentRef} optional="foo" />,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(2);
|
||||
|
||||
expect(ref.current).toBe(null);
|
||||
expect(differentRef.current.type).toBe('div');
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} optional="bar" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(3);
|
||||
});
|
||||
|
||||
it('should custom memo comparisons to compose', () => {
|
||||
it('should custom memo comparisons to compose', async () => {
|
||||
const Component = props => <div ref={props.forwardedRef} />;
|
||||
|
||||
let renderCount = 0;
|
||||
@@ -421,19 +423,19 @@ describe('forwardRef', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="0" c="1" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(1);
|
||||
|
||||
expect(ref.current.type).toBe('div');
|
||||
|
||||
// Changing either a or b rerenders
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="1" c="1" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(2);
|
||||
|
||||
// Changing c doesn't rerender
|
||||
ReactNoop.render(<RefForwardingComponent ref={ref} a="0" b="1" c="2" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(2);
|
||||
|
||||
const ComposedMemo = React.memo(
|
||||
@@ -442,29 +444,29 @@ describe('forwardRef', () => {
|
||||
);
|
||||
|
||||
ReactNoop.render(<ComposedMemo ref={ref} a="0" b="0" c="0" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(3);
|
||||
|
||||
// Changing just b no longer updates
|
||||
ReactNoop.render(<ComposedMemo ref={ref} a="0" b="1" c="0" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(3);
|
||||
|
||||
// Changing just a and c updates
|
||||
ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="2" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(4);
|
||||
|
||||
// Changing just c does not update
|
||||
ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="3" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(4);
|
||||
|
||||
// Changing ref still rerenders
|
||||
const differentRef = React.createRef();
|
||||
|
||||
ReactNoop.render(<ComposedMemo ref={differentRef} a="2" b="2" c="3" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(renderCount).toBe(5);
|
||||
|
||||
expect(ref.current).toBe(null);
|
||||
|
||||
@@ -17,6 +17,12 @@ const packages = readdirSync(packagesRoot).filter(dir => {
|
||||
if (dir.includes('react-devtools')) {
|
||||
return false;
|
||||
}
|
||||
if (dir === 'internal-test-utils') {
|
||||
// This is an internal package used only for testing. It's OK to read
|
||||
// from source.
|
||||
// TODO: Maybe let's have some convention for this?
|
||||
return false;
|
||||
}
|
||||
const packagePath = join(packagesRoot, dir, 'package.json');
|
||||
let stat;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user