Codemod tests to waitFor pattern (7/?) (#26307)
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:
parent
e98695db91
commit
3cb5afb82e
|
@ -15,6 +15,8 @@ let ReactDOMClient;
|
|||
let Scheduler;
|
||||
let act;
|
||||
let container;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
|
||||
describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -26,6 +28,10 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
Scheduler = require('scheduler');
|
||||
act = require('jest-react').act;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
});
|
||||
|
@ -139,23 +145,23 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
act(() => {
|
||||
root.render(<Parent swap={false} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...']);
|
||||
assertLog(['Loading...']);
|
||||
|
||||
await LazyChildA;
|
||||
expect(Scheduler).toFlushAndYield(['A', 'Ref mount: A']);
|
||||
await waitForAll(['A', 'Ref mount: A']);
|
||||
expect(container.innerHTML).toBe('<span>A</span>');
|
||||
|
||||
// Swap the position of A and B
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<Parent swap={true} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...', 'Ref unmount: A']);
|
||||
assertLog(['Loading...', 'Ref unmount: A']);
|
||||
expect(container.innerHTML).toBe(
|
||||
'<span style="display: none;">A</span>Loading...',
|
||||
);
|
||||
|
||||
await LazyChildB;
|
||||
expect(Scheduler).toFlushAndYield(['B', 'Ref mount: B']);
|
||||
await waitForAll(['B', 'Ref mount: B']);
|
||||
expect(container.innerHTML).toBe('<span>B</span>');
|
||||
});
|
||||
|
||||
|
@ -199,21 +205,21 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
act(() => {
|
||||
root.render(<Parent swap={false} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...']);
|
||||
assertLog(['Loading...']);
|
||||
|
||||
await LazyChildA;
|
||||
expect(Scheduler).toFlushAndYield(['A', 'Did mount: A']);
|
||||
await waitForAll(['A', 'Did mount: A']);
|
||||
expect(container.innerHTML).toBe('A');
|
||||
|
||||
// Swap the position of A and B
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<Parent swap={true} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...', 'Will unmount: A']);
|
||||
assertLog(['Loading...', 'Will unmount: A']);
|
||||
expect(container.innerHTML).toBe('Loading...');
|
||||
|
||||
await LazyChildB;
|
||||
expect(Scheduler).toFlushAndYield(['B', 'Did mount: B']);
|
||||
await waitForAll(['B', 'Did mount: B']);
|
||||
expect(container.innerHTML).toBe('B');
|
||||
});
|
||||
|
||||
|
@ -251,24 +257,24 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
act(() => {
|
||||
root.render(<Parent swap={false} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...']);
|
||||
assertLog(['Loading...']);
|
||||
|
||||
await LazyChildA;
|
||||
expect(Scheduler).toFlushAndYield(['A', 'Did mount: A']);
|
||||
await waitForAll(['A', 'Did mount: A']);
|
||||
expect(container.innerHTML).toBe('A');
|
||||
|
||||
// Swap the position of A and B
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<Parent swap={true} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...', 'Will unmount: A']);
|
||||
assertLog(['Loading...', 'Will unmount: A']);
|
||||
expect(container.innerHTML).toBe('Loading...');
|
||||
|
||||
// Destroy the whole tree, including the hidden A
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<h1>Hello</h1>);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(container.innerHTML).toBe('<h1>Hello</h1>');
|
||||
});
|
||||
|
||||
|
@ -318,17 +324,17 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
act(() => {
|
||||
root.render(<Parent swap={false} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...']);
|
||||
assertLog(['Loading...']);
|
||||
|
||||
await LazyChildA;
|
||||
expect(Scheduler).toFlushAndYield(['A', 'Ref mount: A']);
|
||||
await waitForAll(['A', 'Ref mount: A']);
|
||||
expect(container.innerHTML).toBe('<span>A</span>');
|
||||
|
||||
// Swap the position of A and B
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<Parent swap={true} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...', 'Ref unmount: A']);
|
||||
assertLog(['Loading...', 'Ref unmount: A']);
|
||||
expect(container.innerHTML).toBe(
|
||||
'<span style="display: none;">A</span>Loading...',
|
||||
);
|
||||
|
@ -337,7 +343,7 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
ReactDOM.flushSync(() => {
|
||||
root.render(<h1>Hello</h1>);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(container.innerHTML).toBe('<h1>Hello</h1>');
|
||||
});
|
||||
|
||||
|
@ -381,24 +387,24 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
act(() => {
|
||||
root.render(<Parent swap={false} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...']);
|
||||
assertLog(['Loading...']);
|
||||
|
||||
await LazyChildA;
|
||||
expect(Scheduler).toFlushAndYield(['A', 'Did mount: A']);
|
||||
await waitForAll(['A', 'Did mount: A']);
|
||||
expect(container.innerHTML).toBe('A');
|
||||
|
||||
// Swap the position of A and B
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<Parent swap={true} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Loading...', 'Will unmount: A']);
|
||||
assertLog(['Loading...', 'Will unmount: A']);
|
||||
expect(container.innerHTML).toBe('Loading...');
|
||||
|
||||
// Destroy the whole tree, including the hidden A
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<h1>Hello</h1>);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(container.innerHTML).toBe('<h1>Hello</h1>');
|
||||
});
|
||||
|
||||
|
@ -432,12 +438,12 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
|
||||
// Initial render
|
||||
ReactDOM.render(<App showMore={false} />, container);
|
||||
expect(Scheduler).toHaveYielded(['Child', 'Mount']);
|
||||
assertLog(['Child', 'Mount']);
|
||||
|
||||
// Update that suspends, causing the existing tree to switches it to
|
||||
// a fallback.
|
||||
ReactDOM.render(<App showMore={true} />, container);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Child',
|
||||
'Loading...',
|
||||
|
||||
|
@ -448,6 +454,6 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
|
|||
|
||||
// Delete the tree and unmount the effect
|
||||
ReactDOM.render(null, container);
|
||||
expect(Scheduler).toHaveYielded(['Unmount']);
|
||||
assertLog(['Unmount']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ let Suspense;
|
|||
let getCacheForType;
|
||||
let caches;
|
||||
let seededCache;
|
||||
let waitForAll;
|
||||
|
||||
describe('ReactSuspenseFallback', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -25,6 +26,9 @@ describe('ReactSuspenseFallback', () => {
|
|||
getCacheForType = React.unstable_getCacheForType;
|
||||
caches = [];
|
||||
seededCache = null;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
});
|
||||
|
||||
function createTextCache() {
|
||||
|
@ -128,26 +132,26 @@ describe('ReactSuspenseFallback', () => {
|
|||
}
|
||||
|
||||
// @gate enableLegacyCache
|
||||
it('suspends and shows fallback', () => {
|
||||
it('suspends and shows fallback', async () => {
|
||||
ReactNoop.render(
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
<AsyncText text="A" ms={100} />
|
||||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
|
||||
await waitForAll(['Suspend! [A]', 'Loading...']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
|
||||
});
|
||||
|
||||
// @gate enableLegacyCache
|
||||
it('suspends and shows null fallback', () => {
|
||||
it('suspends and shows null fallback', async () => {
|
||||
ReactNoop.render(
|
||||
<Suspense fallback={null}>
|
||||
<AsyncText text="A" ms={100} />
|
||||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend! [A]',
|
||||
// null
|
||||
]);
|
||||
|
@ -155,14 +159,14 @@ describe('ReactSuspenseFallback', () => {
|
|||
});
|
||||
|
||||
// @gate enableLegacyCache
|
||||
it('suspends and shows undefined fallback', () => {
|
||||
it('suspends and shows undefined fallback', async () => {
|
||||
ReactNoop.render(
|
||||
<Suspense>
|
||||
<AsyncText text="A" ms={100} />
|
||||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend! [A]',
|
||||
// null
|
||||
]);
|
||||
|
@ -170,7 +174,7 @@ describe('ReactSuspenseFallback', () => {
|
|||
});
|
||||
|
||||
// @gate enableLegacyCache
|
||||
it('suspends and shows inner fallback', () => {
|
||||
it('suspends and shows inner fallback', async () => {
|
||||
ReactNoop.render(
|
||||
<Suspense fallback={<Text text="Should not show..." />}>
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
|
@ -179,12 +183,12 @@ describe('ReactSuspenseFallback', () => {
|
|||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
|
||||
await waitForAll(['Suspend! [A]', 'Loading...']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span prop="Loading..." />);
|
||||
});
|
||||
|
||||
// @gate enableLegacyCache
|
||||
it('suspends and shows inner undefined fallback', () => {
|
||||
it('suspends and shows inner undefined fallback', async () => {
|
||||
ReactNoop.render(
|
||||
<Suspense fallback={<Text text="Should not show..." />}>
|
||||
<Suspense>
|
||||
|
@ -193,7 +197,7 @@ describe('ReactSuspenseFallback', () => {
|
|||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend! [A]',
|
||||
// null
|
||||
]);
|
||||
|
@ -201,7 +205,7 @@ describe('ReactSuspenseFallback', () => {
|
|||
});
|
||||
|
||||
// @gate enableLegacyCache
|
||||
it('suspends and shows inner null fallback', () => {
|
||||
it('suspends and shows inner null fallback', async () => {
|
||||
ReactNoop.render(
|
||||
<Suspense fallback={<Text text="Should not show..." />}>
|
||||
<Suspense fallback={null}>
|
||||
|
@ -210,7 +214,7 @@ describe('ReactSuspenseFallback', () => {
|
|||
</Suspense>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend! [A]',
|
||||
// null
|
||||
]);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,6 +17,8 @@ let ReactCache;
|
|||
let Suspense;
|
||||
let TextResource;
|
||||
let textResourceShouldFail;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
|
||||
describe('ReactSuspensePlaceholder', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -34,6 +36,10 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
Profiler = React.Profiler;
|
||||
Suspense = React.Suspense;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
TextResource = ReactCache.unstable_createResource(
|
||||
([text, ms = 0]) => {
|
||||
let listeners = null;
|
||||
|
@ -106,7 +112,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
}
|
||||
}
|
||||
|
||||
it('times out children that are already hidden', () => {
|
||||
it('times out children that are already hidden', async () => {
|
||||
class HiddenText extends React.PureComponent {
|
||||
render() {
|
||||
const text = this.props.text;
|
||||
|
@ -132,13 +138,13 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
// Initial mount
|
||||
ReactNoop.render(<App middleText="B" />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'C', 'Loading...']);
|
||||
await waitForAll(['A', 'Suspend! [B]', 'C', 'Loading...']);
|
||||
expect(ReactNoop).toMatchRenderedOutput('Loading...');
|
||||
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [B]']);
|
||||
assertLog(['Promise resolved [B]']);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
|
||||
await waitForAll(['A', 'B', 'C']);
|
||||
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
|
@ -150,11 +156,11 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
|
||||
// Update
|
||||
ReactNoop.render(<App middleText="B2" />);
|
||||
expect(Scheduler).toFlushAndYield(['Suspend! [B2]', 'C', 'Loading...']);
|
||||
await waitForAll(['Suspend! [B2]', 'C', 'Loading...']);
|
||||
|
||||
// Time out the update
|
||||
jest.advanceTimersByTime(750);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span hidden={true}>A</span>
|
||||
|
@ -166,8 +172,8 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
|
||||
// Resolve the promise
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [B2]']);
|
||||
expect(Scheduler).toFlushAndYield(['B2', 'C']);
|
||||
assertLog(['Promise resolved [B2]']);
|
||||
await waitForAll(['B2', 'C']);
|
||||
|
||||
// Render the final update. A should still be hidden, because it was
|
||||
// given a `hidden` prop.
|
||||
|
@ -194,39 +200,34 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
// Initial mount
|
||||
ReactNoop.render(<App middleText="B" />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['A', 'Suspend! [B]', 'C', 'Loading...']);
|
||||
await waitForAll(['A', 'Suspend! [B]', 'C', 'Loading...']);
|
||||
|
||||
expect(ReactNoop).not.toMatchRenderedOutput('ABC');
|
||||
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [B]']);
|
||||
expect(Scheduler).toFlushAndYield(['A', 'B', 'C']);
|
||||
assertLog(['Promise resolved [B]']);
|
||||
await waitForAll(['A', 'B', 'C']);
|
||||
expect(ReactNoop).toMatchRenderedOutput('ABC');
|
||||
|
||||
// Update
|
||||
ReactNoop.render(<App middleText="B2" />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'A',
|
||||
'Suspend! [B2]',
|
||||
'C',
|
||||
'Loading...',
|
||||
]);
|
||||
await waitForAll(['A', 'Suspend! [B2]', 'C', 'Loading...']);
|
||||
// Time out the update
|
||||
jest.advanceTimersByTime(750);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(ReactNoop).toMatchRenderedOutput('Loading...');
|
||||
|
||||
// Resolve the promise
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [B2]']);
|
||||
expect(Scheduler).toFlushAndYield(['A', 'B2', 'C']);
|
||||
assertLog(['Promise resolved [B2]']);
|
||||
await waitForAll(['A', 'B2', 'C']);
|
||||
|
||||
// Render the final update. A should still be hidden, because it was
|
||||
// given a `hidden` prop.
|
||||
expect(ReactNoop).toMatchRenderedOutput('AB2C');
|
||||
});
|
||||
|
||||
it('preserves host context for text nodes', () => {
|
||||
it('preserves host context for text nodes', async () => {
|
||||
function App(props) {
|
||||
return (
|
||||
// uppercase is a special type that causes React Noop to render child
|
||||
|
@ -244,32 +245,27 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
// Initial mount
|
||||
ReactNoop.render(<App middleText="b" />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['a', 'Suspend! [b]', 'c', 'Loading...']);
|
||||
await waitForAll(['a', 'Suspend! [b]', 'c', 'Loading...']);
|
||||
|
||||
expect(ReactNoop).toMatchRenderedOutput(<uppercase>LOADING...</uppercase>);
|
||||
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [b]']);
|
||||
expect(Scheduler).toFlushAndYield(['a', 'b', 'c']);
|
||||
assertLog(['Promise resolved [b]']);
|
||||
await waitForAll(['a', 'b', 'c']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(<uppercase>ABC</uppercase>);
|
||||
|
||||
// Update
|
||||
ReactNoop.render(<App middleText="b2" />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'a',
|
||||
'Suspend! [b2]',
|
||||
'c',
|
||||
'Loading...',
|
||||
]);
|
||||
await waitForAll(['a', 'Suspend! [b2]', 'c', 'Loading...']);
|
||||
// Time out the update
|
||||
jest.advanceTimersByTime(750);
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
expect(ReactNoop).toMatchRenderedOutput(<uppercase>LOADING...</uppercase>);
|
||||
|
||||
// Resolve the promise
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [b2]']);
|
||||
expect(Scheduler).toFlushAndYield(['a', 'b2', 'c']);
|
||||
assertLog(['Promise resolved [b2]']);
|
||||
await waitForAll(['a', 'b2', 'c']);
|
||||
|
||||
// Render the final update. A should still be hidden, because it was
|
||||
// given a `hidden` prop.
|
||||
|
@ -312,7 +308,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
describe('when suspending during mount', () => {
|
||||
it('properly accounts for base durations when a suspended times out in a legacy tree', async () => {
|
||||
ReactNoop.renderLegacySyncRoot(<App shouldSuspend={true} />);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App',
|
||||
'Suspending',
|
||||
'Suspend! [Loaded]',
|
||||
|
@ -330,11 +326,11 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
|
||||
jest.advanceTimersByTime(1000);
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [Loaded]']);
|
||||
assertLog(['Promise resolved [Loaded]']);
|
||||
|
||||
ReactNoop.flushSync();
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Loaded']);
|
||||
assertLog(['Loaded']);
|
||||
expect(ReactNoop).toMatchRenderedOutput('LoadedText');
|
||||
expect(onRender).toHaveBeenCalledTimes(2);
|
||||
|
||||
|
@ -345,10 +341,10 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
expect(onRender.mock.calls[1][3]).toBe(8);
|
||||
});
|
||||
|
||||
it('properly accounts for base durations when a suspended times out in a concurrent tree', () => {
|
||||
it('properly accounts for base durations when a suspended times out in a concurrent tree', async () => {
|
||||
ReactNoop.render(<App shouldSuspend={true} />);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'App',
|
||||
'Suspending',
|
||||
'Suspend! [Loaded]',
|
||||
|
@ -368,8 +364,8 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
|
||||
// Resolve the pending promise.
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [Loaded]']);
|
||||
expect(Scheduler).toFlushAndYield(['Suspending', 'Loaded', 'Text']);
|
||||
assertLog(['Promise resolved [Loaded]']);
|
||||
await waitForAll(['Suspending', 'Loaded', 'Text']);
|
||||
expect(ReactNoop).toMatchRenderedOutput('LoadedText');
|
||||
expect(onRender).toHaveBeenCalledTimes(2);
|
||||
|
||||
|
@ -385,7 +381,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
ReactNoop.renderLegacySyncRoot(
|
||||
<App shouldSuspend={false} textRenderDuration={5} />,
|
||||
);
|
||||
expect(Scheduler).toHaveYielded(['App', 'Text']);
|
||||
assertLog(['App', 'Text']);
|
||||
expect(ReactNoop).toMatchRenderedOutput('Text');
|
||||
expect(onRender).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
@ -395,7 +391,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
expect(onRender.mock.calls[0][3]).toBe(5);
|
||||
|
||||
ReactNoop.render(<App shouldSuspend={true} textRenderDuration={5} />);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App',
|
||||
'Suspending',
|
||||
'Suspend! [Loaded]',
|
||||
|
@ -415,7 +411,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
ReactNoop.renderLegacySyncRoot(
|
||||
<App shouldSuspend={true} text="New" textRenderDuration={6} />,
|
||||
);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App',
|
||||
'Suspending',
|
||||
'Suspend! [Loaded]',
|
||||
|
@ -429,11 +425,11 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
expect(onRender.mock.calls[1][3]).toBe(10);
|
||||
jest.advanceTimersByTime(1000);
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [Loaded]']);
|
||||
assertLog(['Promise resolved [Loaded]']);
|
||||
|
||||
ReactNoop.flushSync();
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Loaded']);
|
||||
assertLog(['Loaded']);
|
||||
expect(ReactNoop).toMatchRenderedOutput('LoadedNew');
|
||||
expect(onRender).toHaveBeenCalledTimes(4);
|
||||
|
||||
|
@ -444,7 +440,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
expect(onRender.mock.calls[3][3]).toBe(9);
|
||||
});
|
||||
|
||||
it('properly accounts for base durations when a suspended times out in a concurrent tree', () => {
|
||||
it('properly accounts for base durations when a suspended times out in a concurrent tree', async () => {
|
||||
ReactNoop.render(
|
||||
<>
|
||||
<App shouldSuspend={false} textRenderDuration={5} />
|
||||
|
@ -452,7 +448,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
</>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['App', 'Text']);
|
||||
await waitForAll(['App', 'Text']);
|
||||
expect(ReactNoop).toMatchRenderedOutput('Text');
|
||||
expect(onRender).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
@ -467,7 +463,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
<Suspense fallback={null} />
|
||||
</>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'App',
|
||||
'Suspending',
|
||||
'Suspend! [Loaded]',
|
||||
|
@ -507,7 +503,7 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
// from timers.
|
||||
Scheduler.unstable_advanceTime(100);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'App',
|
||||
'Suspending',
|
||||
'Suspend! [Loaded]',
|
||||
|
@ -520,17 +516,8 @@ describe('ReactSuspensePlaceholder', () => {
|
|||
|
||||
// Resolve the pending promise.
|
||||
jest.advanceTimersByTime(100);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Promise resolved [Loaded]',
|
||||
'Promise resolved [Sibling]',
|
||||
]);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'App',
|
||||
'Suspending',
|
||||
'Loaded',
|
||||
'New',
|
||||
'Sibling',
|
||||
]);
|
||||
assertLog(['Promise resolved [Loaded]', 'Promise resolved [Sibling]']);
|
||||
await waitForAll(['App', 'Suspending', 'Loaded', 'New', 'Sibling']);
|
||||
expect(onRender).toHaveBeenCalledTimes(3);
|
||||
|
||||
// When the suspending data is resolved and our final UI is rendered,
|
||||
|
|
|
@ -12,6 +12,10 @@ let Suspense;
|
|||
let startTransition;
|
||||
let cache;
|
||||
let pendingTextRequests;
|
||||
let waitFor;
|
||||
let waitForPaint;
|
||||
let assertLog;
|
||||
let waitForAll;
|
||||
|
||||
describe('ReactThenable', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -29,6 +33,12 @@ describe('ReactThenable', () => {
|
|||
startTransition = React.startTransition;
|
||||
cache = React.cache;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
waitForPaint = InternalTestUtils.waitForPaint;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
|
||||
pendingTextRequests = new Map();
|
||||
});
|
||||
|
||||
|
@ -94,7 +104,7 @@ describe('ReactThenable', () => {
|
|||
});
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// React will yield when the async component suspends.
|
||||
'Suspend!',
|
||||
'Resolve in microtask',
|
||||
|
@ -128,11 +138,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Suspend!',
|
||||
'Resolve in microtask',
|
||||
'Async',
|
||||
]);
|
||||
assertLog(['Suspend!', 'Resolve in microtask', 'Async']);
|
||||
expect(root).toMatchRenderedOutput('Async');
|
||||
});
|
||||
|
||||
|
@ -172,7 +178,7 @@ describe('ReactThenable', () => {
|
|||
await act(async () => {
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Suspend!', 'Loading...']);
|
||||
assertLog(['Suspend!', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput('Loading...');
|
||||
});
|
||||
|
||||
|
@ -201,7 +207,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['ABC']);
|
||||
assertLog(['ABC']);
|
||||
expect(root).toMatchRenderedOutput('ABC');
|
||||
});
|
||||
|
||||
|
@ -229,7 +235,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['ABC']);
|
||||
assertLog(['ABC']);
|
||||
expect(root).toMatchRenderedOutput('ABC');
|
||||
});
|
||||
|
||||
|
@ -275,7 +281,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Oops!', 'Oops!']);
|
||||
assertLog(['Oops!', 'Oops!']);
|
||||
});
|
||||
|
||||
// @gate enableUseHook
|
||||
|
@ -308,7 +314,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['ABCD']);
|
||||
assertLog(['ABCD']);
|
||||
expect(root).toMatchRenderedOutput('ABCD');
|
||||
});
|
||||
|
||||
|
@ -344,7 +350,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['CD', 'Loading...']);
|
||||
assertLog(['CD', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput('Loading...');
|
||||
});
|
||||
|
||||
|
@ -397,7 +403,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// First attempt. The uncached promise suspends.
|
||||
'Suspend! [Async]',
|
||||
// Because the promise already fulfilled, we're able to unwrap the value
|
||||
|
@ -427,7 +433,7 @@ describe('ReactThenable', () => {
|
|||
});
|
||||
|
||||
// @gate enableUseHook
|
||||
test('basic use(context)', () => {
|
||||
test('basic use(context)', async () => {
|
||||
const ContextA = React.createContext('');
|
||||
const ContextB = React.createContext('B');
|
||||
|
||||
|
@ -446,7 +452,7 @@ describe('ReactThenable', () => {
|
|||
|
||||
const root = ReactNoop.createRoot();
|
||||
root.render(<App />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(root).toMatchRenderedOutput('AB');
|
||||
});
|
||||
|
||||
|
@ -482,7 +488,7 @@ describe('ReactThenable', () => {
|
|||
startTransition(() => {
|
||||
root.render(<App text="world" />);
|
||||
});
|
||||
expect(Scheduler).toFlushUntilNextPaint([]);
|
||||
await waitForPaint([]);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
await resolve({default: <Text key="hi" text="Hello " />});
|
||||
|
@ -492,7 +498,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App text="world!" />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Hello ', 'world!']);
|
||||
assertLog(['Hello ', 'world!']);
|
||||
|
||||
expect(root).toMatchRenderedOutput(<div>Hello world!</div>);
|
||||
});
|
||||
|
@ -547,7 +553,7 @@ describe('ReactThenable', () => {
|
|||
</Suspense>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['(empty)']);
|
||||
assertLog(['(empty)']);
|
||||
expect(root).toMatchRenderedOutput('(empty)');
|
||||
|
||||
await act(async () => {
|
||||
|
@ -559,13 +565,13 @@ describe('ReactThenable', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [Async]']);
|
||||
assertLog(['Async text requested [Async]']);
|
||||
expect(root).toMatchRenderedOutput('(empty)');
|
||||
|
||||
await act(async () => {
|
||||
resolveTextRequests('Async');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [Async]', 'Async']);
|
||||
assertLog(['Async text requested [Async]', 'Async']);
|
||||
expect(root).toMatchRenderedOutput('Async');
|
||||
});
|
||||
|
||||
|
@ -586,10 +592,7 @@ describe('ReactThenable', () => {
|
|||
});
|
||||
});
|
||||
// Even though the initial render was a transition, it shows a fallback.
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [Async]',
|
||||
'Loading...',
|
||||
]);
|
||||
assertLog(['Async text requested [Async]', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput('Loading...');
|
||||
|
||||
// Resolve the original data
|
||||
|
@ -603,7 +606,7 @@ describe('ReactThenable', () => {
|
|||
// this test, how would the developer be able to imperatively flush it if it
|
||||
// wasn't initiated until the current `act` call? Can't think of a better
|
||||
// strategy at the moment.
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [Async]']);
|
||||
assertLog(['Async text requested [Async]']);
|
||||
expect(root).toMatchRenderedOutput('Loading...');
|
||||
|
||||
// Flush the second request.
|
||||
|
@ -611,7 +614,7 @@ describe('ReactThenable', () => {
|
|||
resolveTextRequests('Async');
|
||||
});
|
||||
// This time it finishes because it was during a retry.
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [Async]', 'Async']);
|
||||
assertLog(['Async text requested [Async]', 'Async']);
|
||||
expect(root).toMatchRenderedOutput('Async');
|
||||
});
|
||||
|
||||
|
@ -635,9 +638,7 @@ describe('ReactThenable', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [Will never resolve]',
|
||||
]);
|
||||
assertLog(['Async text requested [Will never resolve]']);
|
||||
|
||||
await act(async () => {
|
||||
root.render(
|
||||
|
@ -646,7 +647,7 @@ describe('ReactThenable', () => {
|
|||
</Suspense>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Something different']);
|
||||
assertLog(['Something different']);
|
||||
});
|
||||
|
||||
// @gate enableUseHook
|
||||
|
@ -669,9 +670,7 @@ describe('ReactThenable', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [Will never resolve]',
|
||||
]);
|
||||
assertLog(['Async text requested [Will never resolve]']);
|
||||
|
||||
// Calling a hook should error because we're oustide of a component.
|
||||
expect(useState).toThrow(
|
||||
|
@ -704,7 +703,7 @@ describe('ReactThenable', () => {
|
|||
ReactNoop.flushSync(() => {
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Hi']);
|
||||
assertLog(['Hi']);
|
||||
expect(root).toMatchRenderedOutput('Hi');
|
||||
});
|
||||
|
||||
|
@ -745,26 +744,21 @@ describe('ReactThenable', () => {
|
|||
await act(() => {
|
||||
root.render(<Parent />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'childShouldSuspend: false, showChild: true',
|
||||
'Child',
|
||||
]);
|
||||
assertLog(['childShouldSuspend: false, showChild: true', 'Child']);
|
||||
expect(root).toMatchRenderedOutput('Child');
|
||||
|
||||
await act(() => {
|
||||
await act(async () => {
|
||||
// Perform an update that causes the app to suspend
|
||||
startTransition(() => {
|
||||
setChildShouldSuspend(true);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
'childShouldSuspend: true, showChild: true',
|
||||
]);
|
||||
await waitFor(['childShouldSuspend: true, showChild: true']);
|
||||
// While the update is in progress, schedule another update.
|
||||
startTransition(() => {
|
||||
setShowChild(false);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Because the interleaved update is not higher priority than what we were
|
||||
// already working on, it won't interrupt. The first update will continue,
|
||||
// and will suspend.
|
||||
|
@ -827,17 +821,14 @@ describe('ReactThenable', () => {
|
|||
});
|
||||
});
|
||||
// Suspends while we wait for the async service to respond.
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Compute uppercase: Hello',
|
||||
'Async text requested [HELLO!]',
|
||||
]);
|
||||
assertLog(['Compute uppercase: Hello', 'Async text requested [HELLO!]']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
// The data is received.
|
||||
await act(async () => {
|
||||
resolveTextRequests('HELLO!');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// We shouldn't run the uppercase computation again, because we can reuse
|
||||
// the computation from the previous attempt.
|
||||
// 'Compute uppercase: Hello',
|
||||
|
@ -867,15 +858,12 @@ describe('ReactThenable', () => {
|
|||
root.render(<Kitchen />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [apple]']);
|
||||
assertLog(['Async text requested [apple]']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
await act(async () => {
|
||||
resolveTextRequests('apple');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [apple]',
|
||||
'apple carrot',
|
||||
]);
|
||||
assertLog(['Async text requested [apple]', 'apple carrot']);
|
||||
expect(root).toMatchRenderedOutput('apple carrot');
|
||||
|
||||
// Update the state variable after the use().
|
||||
|
@ -884,15 +872,12 @@ describe('ReactThenable', () => {
|
|||
_setVegetable('dill');
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [apple]']);
|
||||
assertLog(['Async text requested [apple]']);
|
||||
expect(root).toMatchRenderedOutput('apple carrot');
|
||||
await act(async () => {
|
||||
resolveTextRequests('apple');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [apple]',
|
||||
'apple dill',
|
||||
]);
|
||||
assertLog(['Async text requested [apple]', 'apple dill']);
|
||||
expect(root).toMatchRenderedOutput('apple dill');
|
||||
|
||||
// Update the state variable before the use(). The second state is maintained.
|
||||
|
@ -901,15 +886,12 @@ describe('ReactThenable', () => {
|
|||
_setFruit('banana');
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [banana]']);
|
||||
assertLog(['Async text requested [banana]']);
|
||||
expect(root).toMatchRenderedOutput('apple dill');
|
||||
await act(async () => {
|
||||
resolveTextRequests('banana');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [banana]',
|
||||
'banana dill',
|
||||
]);
|
||||
assertLog(['Async text requested [banana]', 'banana dill']);
|
||||
expect(root).toMatchRenderedOutput('banana dill');
|
||||
});
|
||||
|
||||
|
@ -931,15 +913,12 @@ describe('ReactThenable', () => {
|
|||
root.render(<Lexicon />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [aguacate]']);
|
||||
assertLog(['Async text requested [aguacate]']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
await act(async () => {
|
||||
resolveTextRequests('aguacate');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [aguacate]',
|
||||
'aguacate abogado',
|
||||
]);
|
||||
assertLog(['Async text requested [aguacate]', 'aguacate abogado']);
|
||||
expect(root).toMatchRenderedOutput('aguacate abogado');
|
||||
|
||||
// Now update the state.
|
||||
|
@ -948,15 +927,12 @@ describe('ReactThenable', () => {
|
|||
_setLawyer('avocat');
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [aguacate]']);
|
||||
assertLog(['Async text requested [aguacate]']);
|
||||
expect(root).toMatchRenderedOutput('aguacate abogado');
|
||||
await act(async () => {
|
||||
resolveTextRequests('aguacate');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Async text requested [aguacate]',
|
||||
'aguacate avocat',
|
||||
]);
|
||||
assertLog(['Async text requested [aguacate]', 'aguacate avocat']);
|
||||
expect(root).toMatchRenderedOutput('aguacate avocat');
|
||||
});
|
||||
|
||||
|
@ -977,13 +953,13 @@ describe('ReactThenable', () => {
|
|||
root.render(<App text="Hello" />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [Hello]']);
|
||||
assertLog(['Async text requested [Hello]']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
await act(async () => {
|
||||
resolveTextRequests('Hello');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// We shouldn't request async text again, because the async function
|
||||
// was memoized
|
||||
// 'Async text requested [Hello]'
|
||||
|
@ -1015,7 +991,7 @@ describe('ReactThenable', () => {
|
|||
</Suspense>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Async text requested [A]',
|
||||
'Async text requested [B]',
|
||||
'Async text requested [C]',
|
||||
|
@ -1028,19 +1004,19 @@ describe('ReactThenable', () => {
|
|||
await act(async () => {
|
||||
resolveTextRequests('A');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A', '(Loading C...)', '(Loading B...)']);
|
||||
assertLog(['A', '(Loading C...)', '(Loading B...)']);
|
||||
expect(root).toMatchRenderedOutput('A(Loading B...)');
|
||||
|
||||
await act(async () => {
|
||||
resolveTextRequests('B');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['B', '(Loading C...)']);
|
||||
assertLog(['B', '(Loading C...)']);
|
||||
expect(root).toMatchRenderedOutput('AB(Loading C...)');
|
||||
|
||||
await act(async () => {
|
||||
resolveTextRequests('C');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['C']);
|
||||
assertLog(['C']);
|
||||
expect(root).toMatchRenderedOutput('ABC');
|
||||
});
|
||||
|
||||
|
@ -1068,7 +1044,7 @@ describe('ReactThenable', () => {
|
|||
</Suspense>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Async text requested [A]',
|
||||
'Async text requested [B]',
|
||||
'Async text requested [C]',
|
||||
|
@ -1081,13 +1057,13 @@ describe('ReactThenable', () => {
|
|||
await act(async () => {
|
||||
resolveTextRequests('A');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [A]']);
|
||||
assertLog(['Async text requested [A]']);
|
||||
expect(root).toMatchRenderedOutput('(Loading A...)');
|
||||
|
||||
await act(async () => {
|
||||
resolveTextRequests('A');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// React suspends until A finishes loading.
|
||||
'Async text requested [A]',
|
||||
'A',
|
||||
|
@ -1106,13 +1082,13 @@ describe('ReactThenable', () => {
|
|||
await act(async () => {
|
||||
resolveTextRequests('B');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [B]']);
|
||||
assertLog(['Async text requested [B]']);
|
||||
expect(root).toMatchRenderedOutput('A(Loading B...)');
|
||||
|
||||
await act(async () => {
|
||||
resolveTextRequests('B');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// React suspends until B finishes loading.
|
||||
'Async text requested [B]',
|
||||
'B',
|
||||
|
@ -1126,13 +1102,13 @@ describe('ReactThenable', () => {
|
|||
await act(async () => {
|
||||
resolveTextRequests('C');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [C]']);
|
||||
assertLog(['Async text requested [C]']);
|
||||
expect(root).toMatchRenderedOutput('AB(Loading C...)');
|
||||
|
||||
await act(async () => {
|
||||
resolveTextRequests('C');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async text requested [C]', 'C']);
|
||||
assertLog(['Async text requested [C]', 'C']);
|
||||
expect(root).toMatchRenderedOutput('ABC');
|
||||
});
|
||||
|
||||
|
@ -1162,7 +1138,7 @@ describe('ReactThenable', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A1']);
|
||||
assertLog(['A1']);
|
||||
expect(root).toMatchRenderedOutput('A1');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let waitForAll;
|
||||
|
||||
// This is a new feature in Fiber so I put it in its own test file. It could
|
||||
// probably move to one of the other test files once it is official.
|
||||
|
@ -21,18 +21,20 @@ describe('ReactTopLevelFragment', function () {
|
|||
jest.resetModules();
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
});
|
||||
|
||||
it('should render a simple fragment at the top of a component', function () {
|
||||
it('should render a simple fragment at the top of a component', async function () {
|
||||
function Fragment() {
|
||||
return [<div key="a">Hello</div>, <div key="b">World</div>];
|
||||
}
|
||||
ReactNoop.render(<Fragment />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
it('should preserve state when switching from a single child', function () {
|
||||
it('should preserve state when switching from a single child', async function () {
|
||||
let instance = null;
|
||||
|
||||
class Stateful extends React.Component {
|
||||
|
@ -50,21 +52,21 @@ describe('ReactTopLevelFragment', function () {
|
|||
);
|
||||
}
|
||||
ReactNoop.render(<Fragment />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceA = instance;
|
||||
|
||||
expect(instanceA).not.toBe(null);
|
||||
|
||||
ReactNoop.render(<Fragment condition={true} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceB = instance;
|
||||
|
||||
expect(instanceB).toBe(instanceA);
|
||||
});
|
||||
|
||||
it('should not preserve state when switching to a nested array', function () {
|
||||
it('should not preserve state when switching to a nested array', async function () {
|
||||
let instance = null;
|
||||
|
||||
class Stateful extends React.Component {
|
||||
|
@ -82,21 +84,21 @@ describe('ReactTopLevelFragment', function () {
|
|||
);
|
||||
}
|
||||
ReactNoop.render(<Fragment />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceA = instance;
|
||||
|
||||
expect(instanceA).not.toBe(null);
|
||||
|
||||
ReactNoop.render(<Fragment condition={true} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceB = instance;
|
||||
|
||||
expect(instanceB).not.toBe(instanceA);
|
||||
});
|
||||
|
||||
it('preserves state if an implicit key slot switches from/to null', function () {
|
||||
it('preserves state if an implicit key slot switches from/to null', async function () {
|
||||
let instance = null;
|
||||
|
||||
class Stateful extends React.Component {
|
||||
|
@ -112,28 +114,28 @@ describe('ReactTopLevelFragment', function () {
|
|||
: [<div key="b">Hello</div>, <Stateful key="a" />];
|
||||
}
|
||||
ReactNoop.render(<Fragment />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceA = instance;
|
||||
|
||||
expect(instanceA).not.toBe(null);
|
||||
|
||||
ReactNoop.render(<Fragment condition={true} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceB = instance;
|
||||
|
||||
expect(instanceB).toBe(instanceA);
|
||||
|
||||
ReactNoop.render(<Fragment condition={false} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceC = instance;
|
||||
|
||||
expect(instanceC === instanceA).toBe(true);
|
||||
});
|
||||
|
||||
it('should preserve state in a reorder', function () {
|
||||
it('should preserve state in a reorder', async function () {
|
||||
let instance = null;
|
||||
|
||||
class Stateful extends React.Component {
|
||||
|
@ -149,14 +151,14 @@ describe('ReactTopLevelFragment', function () {
|
|||
: [[<Stateful key="a" />, <div key="b">World</div>], <div key="c" />];
|
||||
}
|
||||
ReactNoop.render(<Fragment />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceA = instance;
|
||||
|
||||
expect(instanceA).not.toBe(null);
|
||||
|
||||
ReactNoop.render(<Fragment condition={true} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
const instanceB = instance;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let waitForAll;
|
||||
|
||||
// This is a new feature in Fiber so I put it in its own test file. It could
|
||||
// probably move to one of the other test files once it is official.
|
||||
|
@ -21,20 +21,22 @@ describe('ReactTopLevelText', () => {
|
|||
jest.resetModules();
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
});
|
||||
|
||||
it('should render a component returning strings directly from render', () => {
|
||||
it('should render a component returning strings directly from render', async () => {
|
||||
const Text = ({value}) => value;
|
||||
ReactNoop.render(<Text value="foo" />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ReactNoop).toMatchRenderedOutput('foo');
|
||||
});
|
||||
|
||||
it('should render a component returning numbers directly from render', () => {
|
||||
it('should render a component returning numbers directly from render', async () => {
|
||||
const Text = ({value}) => value;
|
||||
ReactNoop.render(<Text value={10} />);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(ReactNoop).toMatchRenderedOutput('10');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,6 +20,10 @@ let useTransition;
|
|||
let startTransition;
|
||||
let act;
|
||||
let getCacheForType;
|
||||
let waitForAll;
|
||||
let waitFor;
|
||||
let waitForPaint;
|
||||
let assertLog;
|
||||
|
||||
let caches;
|
||||
let seededCache;
|
||||
|
@ -38,6 +42,12 @@ describe('ReactTransition', () => {
|
|||
getCacheForType = React.unstable_getCacheForType;
|
||||
act = require('jest-react').act;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForPaint = InternalTestUtils.waitForPaint;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
caches = [];
|
||||
seededCache = null;
|
||||
});
|
||||
|
@ -178,13 +188,13 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['(empty)']);
|
||||
assertLog(['(empty)']);
|
||||
expect(root).toMatchRenderedOutput('(empty)');
|
||||
|
||||
await act(async () => {
|
||||
start();
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Pending...',
|
||||
'(empty)',
|
||||
'Suspend! [Async]',
|
||||
|
@ -195,7 +205,7 @@ describe('ReactTransition', () => {
|
|||
|
||||
await resolveText('Async');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Async']);
|
||||
assertLog(['Async']);
|
||||
expect(root).toMatchRenderedOutput('Async');
|
||||
});
|
||||
|
||||
|
@ -239,7 +249,7 @@ describe('ReactTransition', () => {
|
|||
seedNextTextCache('A content');
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A label', 'A content']);
|
||||
assertLog(['A label', 'A content']);
|
||||
expect(root).toMatchRenderedOutput(
|
||||
<>
|
||||
A label<div>A content</div>
|
||||
|
@ -250,7 +260,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
update('B');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Commit pending state
|
||||
'B label (loading...)',
|
||||
'A content',
|
||||
|
@ -271,7 +281,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
update('C');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Commit pending state
|
||||
'C label (loading...)',
|
||||
'A content',
|
||||
|
@ -292,7 +302,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
resolveText('B content');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Attempt to render C, but it suspends
|
||||
'C label',
|
||||
'Suspend! [C content]',
|
||||
|
@ -308,7 +318,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
resolveText('C content');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['C label', 'C content']);
|
||||
assertLog(['C label', 'C content']);
|
||||
expect(root).toMatchRenderedOutput(
|
||||
<>
|
||||
C label<div>C content</div>
|
||||
|
@ -364,7 +374,7 @@ describe('ReactTransition', () => {
|
|||
seedNextTextCache('A content');
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A label', 'A content']);
|
||||
assertLog(['A label', 'A content']);
|
||||
expect(root).toMatchRenderedOutput(
|
||||
<>
|
||||
A label<div>A content</div>
|
||||
|
@ -375,7 +385,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
update('B');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Commit pending state
|
||||
'B label (loading...)',
|
||||
'A content',
|
||||
|
@ -396,7 +406,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
update('C');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Commit pending state
|
||||
'C label (loading...)',
|
||||
'A content',
|
||||
|
@ -417,7 +427,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
resolveText('B content');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Attempt to render C, but it suspends
|
||||
'C label',
|
||||
'Suspend! [C content]',
|
||||
|
@ -433,7 +443,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
resolveText('C content');
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['C label', 'C content']);
|
||||
assertLog(['C label', 'C content']);
|
||||
expect(root).toMatchRenderedOutput(
|
||||
<>
|
||||
C label<div>C content</div>
|
||||
|
@ -481,7 +491,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
assertLog([]);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
// Switch to A.
|
||||
|
@ -490,7 +500,7 @@ describe('ReactTransition', () => {
|
|||
setShowA(true);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Suspend! [A]', 'Loading...']);
|
||||
assertLog(['Suspend! [A]', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
// Before A loads, switch to B. This should entangle A with B.
|
||||
|
@ -500,7 +510,7 @@ describe('ReactTransition', () => {
|
|||
setShowB(true);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...']);
|
||||
assertLog(['Suspend! [B]', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
// Before A or B loads, switch to C. This should entangle C with B, and
|
||||
|
@ -511,7 +521,7 @@ describe('ReactTransition', () => {
|
|||
setShowC(true);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
|
||||
assertLog(['Suspend! [C]', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
// Now the data starts resolving out of order.
|
||||
|
@ -523,7 +533,7 @@ describe('ReactTransition', () => {
|
|||
resolveText('B');
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
|
||||
assertLog(['Suspend! [C]', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
// Now resolve A. Again, this will attempt to render C, since everything
|
||||
|
@ -533,7 +543,7 @@ describe('ReactTransition', () => {
|
|||
resolveText('A');
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']);
|
||||
assertLog(['Suspend! [C]', 'Loading...']);
|
||||
expect(root).toMatchRenderedOutput(null);
|
||||
|
||||
// Finally, resolve C. This time we can finish.
|
||||
|
@ -542,7 +552,7 @@ describe('ReactTransition', () => {
|
|||
resolveText('C');
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['C']);
|
||||
assertLog(['C']);
|
||||
expect(root).toMatchRenderedOutput('C');
|
||||
},
|
||||
);
|
||||
|
@ -559,7 +569,7 @@ describe('ReactTransition', () => {
|
|||
</>,
|
||||
);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Initial']);
|
||||
assertLog(['Initial']);
|
||||
expect(root).toMatchRenderedOutput('Initial');
|
||||
|
||||
await act(async () => {
|
||||
|
@ -577,7 +587,7 @@ describe('ReactTransition', () => {
|
|||
});
|
||||
|
||||
// Partially render it.
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
await waitFor([
|
||||
// Once we the update suspends, we know it's a refresh transition,
|
||||
// because the Suspense boundary has already mounted.
|
||||
'Suspend! [Async]',
|
||||
|
@ -598,7 +608,7 @@ describe('ReactTransition', () => {
|
|||
|
||||
// Because the first one is going to suspend regardless, we should
|
||||
// immediately switch to rendering the new transition.
|
||||
expect(Scheduler).toHaveYielded(['Updated']);
|
||||
assertLog(['Updated']);
|
||||
expect(root).toMatchRenderedOutput('Updated');
|
||||
});
|
||||
|
||||
|
@ -643,12 +653,7 @@ describe('ReactTransition', () => {
|
|||
|
||||
await act(async () => {
|
||||
root.render(<App />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'A',
|
||||
'shouldHideInParent: false',
|
||||
'B',
|
||||
'C',
|
||||
]);
|
||||
await waitForAll(['A', 'shouldHideInParent: false', 'B', 'C']);
|
||||
expect(root).toMatchRenderedOutput('ABC');
|
||||
|
||||
// Schedule an update
|
||||
|
@ -660,14 +665,14 @@ describe('ReactTransition', () => {
|
|||
// lane from the first one. At the time this was written, all transitions are worked on
|
||||
// simultaneously, unless a transition was already in progress when a
|
||||
// new one was scheduled. So, partially render the first transition.
|
||||
expect(Scheduler).toFlushAndYieldThrough(['A']);
|
||||
await waitFor(['A']);
|
||||
|
||||
// Now schedule a second transition. We won't interrupt the first one.
|
||||
React.startTransition(() => {
|
||||
setShouldHideInParent(true);
|
||||
});
|
||||
// Continue rendering the first transition.
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
await waitFor([
|
||||
'shouldHideInParent: false',
|
||||
'Suspend! [Async]',
|
||||
'Loading...',
|
||||
|
@ -683,16 +688,13 @@ describe('ReactTransition', () => {
|
|||
// time we re-enter the work loop (we don't interrupt immediately, we
|
||||
// just wait for the next time slice), we should throw out the
|
||||
// suspended first transition and try the second one.
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
'shouldHideInParent: true',
|
||||
'(empty)',
|
||||
]);
|
||||
await waitForPaint(['shouldHideInParent: true', '(empty)']);
|
||||
expect(root).toMatchRenderedOutput('A(empty)BC');
|
||||
|
||||
// Since the two transitions are not entangled, we then later go back
|
||||
// and finish retry the first transition. Not really relevant to this
|
||||
// test but I'll assert the result anyway.
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'A',
|
||||
'shouldHideInParent: true',
|
||||
'(empty)',
|
||||
|
@ -732,7 +734,7 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
root.render(<App shouldSuspend={false} step={0} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A0', 'B0', 'C0']);
|
||||
assertLog(['A0', 'B0', 'C0']);
|
||||
expect(root).toMatchRenderedOutput('A0B0C0');
|
||||
|
||||
await act(async () => {
|
||||
|
@ -741,14 +743,14 @@ describe('ReactTransition', () => {
|
|||
root.render(<App shouldSuspend={true} step={1} />);
|
||||
});
|
||||
// Flush past the root, but stop before the async component.
|
||||
expect(Scheduler).toFlushAndYieldThrough(['A1']);
|
||||
await waitFor(['A1']);
|
||||
|
||||
// Schedule another transition on the root, which already completed.
|
||||
startTransition(() => {
|
||||
root.render(<App shouldSuspend={false} step={2} />);
|
||||
});
|
||||
// We'll keep working on the first update.
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
await waitFor([
|
||||
// Now the async component suspends
|
||||
'Suspend! [Async]',
|
||||
'Loading...',
|
||||
|
@ -762,7 +764,7 @@ describe('ReactTransition', () => {
|
|||
// TODO: This should work even if React does not yield to the main
|
||||
// thread. Should use same mechanism as selective hydration to interrupt
|
||||
// the render before the end of the current slice of work.
|
||||
expect(Scheduler).toFlushAndYield(['A2', 'B2', 'C2']);
|
||||
await waitForAll(['A2', 'B2', 'C2']);
|
||||
|
||||
expect(root).toMatchRenderedOutput('A2B2C2');
|
||||
});
|
||||
|
@ -798,11 +800,7 @@ describe('ReactTransition', () => {
|
|||
});
|
||||
|
||||
// Initial render.
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Transition pri: 0',
|
||||
'Normal pri: 0',
|
||||
'Commit',
|
||||
]);
|
||||
assertLog(['Transition pri: 0', 'Normal pri: 0', 'Commit']);
|
||||
expect(root).toMatchRenderedOutput('Transition pri: 0, Normal pri: 0');
|
||||
|
||||
await act(async () => {
|
||||
|
@ -810,7 +808,7 @@ describe('ReactTransition', () => {
|
|||
updateNormalPri();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Normal update first.
|
||||
'Transition pri: 0',
|
||||
'Normal pri: 1',
|
||||
|
@ -854,14 +852,14 @@ describe('ReactTransition', () => {
|
|||
});
|
||||
|
||||
// Initial render.
|
||||
expect(Scheduler).toHaveYielded(['(empty)', 'Normal pri: 0', 'Commit']);
|
||||
assertLog(['(empty)', 'Normal pri: 0', 'Commit']);
|
||||
expect(root).toMatchRenderedOutput('(empty), Normal pri: 0');
|
||||
|
||||
await act(async () => {
|
||||
updateTransitionPri();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Suspend.
|
||||
'Suspend! [Async]',
|
||||
'Normal pri: 0',
|
||||
|
@ -874,7 +872,7 @@ describe('ReactTransition', () => {
|
|||
updateNormalPri();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Normal pri update.
|
||||
'(empty)',
|
||||
'Normal pri: 1',
|
||||
|
@ -914,17 +912,13 @@ describe('ReactTransition', () => {
|
|||
await act(async () => {
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Transition pri: 0',
|
||||
'Normal pri: 0',
|
||||
'Commit',
|
||||
]);
|
||||
assertLog(['Transition pri: 0', 'Normal pri: 0', 'Commit']);
|
||||
expect(root).toMatchRenderedOutput('Transition pri: 0, Normal pri: 0');
|
||||
|
||||
await act(async () => {
|
||||
updateTransitionPri();
|
||||
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
await waitFor([
|
||||
// Start transition update.
|
||||
'Transition pri: 1',
|
||||
]);
|
||||
|
@ -935,7 +929,7 @@ describe('ReactTransition', () => {
|
|||
});
|
||||
|
||||
if (gate(flags => flags.enableUnifiedSyncLane)) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Normal pri: 0',
|
||||
'Commit',
|
||||
|
||||
|
@ -945,7 +939,7 @@ describe('ReactTransition', () => {
|
|||
'Commit',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Finish transition update.
|
||||
'Normal pri: 0',
|
||||
'Commit',
|
||||
|
|
|
@ -12,6 +12,8 @@ let React;
|
|||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let act;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
|
||||
let getCacheForType;
|
||||
let useState;
|
||||
|
@ -43,6 +45,10 @@ describe('ReactInteractionTracing', () => {
|
|||
|
||||
act = require('jest-react').act;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
useState = React.useState;
|
||||
startTransition = React.startTransition;
|
||||
Suspense = React.Suspense;
|
||||
|
@ -233,7 +239,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
|
||||
await act(async () => {
|
||||
startTransition(() => root.render(<App navigate={true} />));
|
||||
|
@ -242,12 +248,12 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
|
||||
// Doesn't call transition or marker code
|
||||
expect(Scheduler).toFlushAndYield(['Page Two']);
|
||||
await waitForAll(['Page Two']);
|
||||
|
||||
startTransition(() => root.render(<App navigate={false} />), {
|
||||
name: 'transition',
|
||||
});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page One',
|
||||
'onTransitionStart(transition, 2000)',
|
||||
'onTransitionComplete(transition, 2000, 2000)',
|
||||
|
@ -299,7 +305,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
|
||||
await act(async () => {
|
||||
startTransition(() => navigateToPageTwo(), {name: 'page transition'});
|
||||
|
@ -307,7 +313,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'onTransitionStart(page transition, 1000)',
|
||||
'onTransitionComplete(page transition, 1000, 2000)',
|
||||
|
@ -358,7 +364,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One: hide']);
|
||||
await waitForAll(['Page One: hide']);
|
||||
|
||||
await act(async () => {
|
||||
startTransition(
|
||||
|
@ -372,7 +378,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two: show',
|
||||
'onTransitionStart(page transition, 1000)',
|
||||
'onTransitionComplete(page transition, 1000, 2000)',
|
||||
|
@ -431,7 +437,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
@ -440,7 +446,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'onTransitionStart(page transition, 1000)',
|
||||
|
@ -451,7 +457,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
await resolveText('Page Two');
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'onTransitionProgress(page transition, 1000, 3000, [])',
|
||||
'onTransitionComplete(page transition, 1000, 3000)',
|
||||
|
@ -526,13 +532,13 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
startTransition(() => navigateToPageTwo(), {name: 'page transition'});
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'onTransitionStart(page transition, 1000)',
|
||||
|
@ -542,14 +548,14 @@ describe('ReactInteractionTracing', () => {
|
|||
await resolveText('Page Two');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'onTransitionProgress(page transition, 1000, 2000, [])',
|
||||
'onTransitionComplete(page transition, 1000, 2000)',
|
||||
]);
|
||||
|
||||
startTransition(() => showTextFn(), {name: 'text transition'});
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Show Text]',
|
||||
'Show Text Loading...',
|
||||
'Page Two',
|
||||
|
@ -560,7 +566,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await resolveText('Show Text');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Show Text',
|
||||
'onTransitionProgress(text transition, 2000, 3000, [])',
|
||||
'onTransitionComplete(text transition, 2000, 3000)',
|
||||
|
@ -633,7 +639,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
@ -641,7 +647,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'onTransitionStart(page transition, 1000)',
|
||||
|
@ -652,7 +658,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await act(async () => {
|
||||
startTransition(() => showTextFn(), {name: 'show text'});
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Show Text]',
|
||||
'Show Text Loading...',
|
||||
'Suspend [Page Two]',
|
||||
|
@ -667,7 +673,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'onTransitionProgress(page transition, 1000, 3000, [])',
|
||||
'onTransitionComplete(page transition, 1000, 3000)',
|
||||
|
@ -677,7 +683,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Show Text',
|
||||
'onTransitionProgress(show text, 2000, 4000, [])',
|
||||
'onTransitionComplete(show text, 2000, 4000)',
|
||||
|
@ -750,7 +756,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
@ -758,7 +764,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Suspend [Show Text One]',
|
||||
'Show Text One Loading...',
|
||||
|
@ -773,7 +779,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'Suspend [Show Text One]',
|
||||
'Show Text One Loading...',
|
||||
|
@ -786,7 +792,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Show Text One',
|
||||
'onTransitionProgress(page transition, 1000, 4000, [show text two])',
|
||||
]);
|
||||
|
@ -795,7 +801,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Show Text Two',
|
||||
'onTransitionProgress(page transition, 1000, 5000, [])',
|
||||
'onTransitionComplete(page transition, 1000, 5000)',
|
||||
|
@ -881,7 +887,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
@ -890,7 +896,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Suspend [Show Text One]',
|
||||
'Show Text One Loading...',
|
||||
|
@ -906,7 +912,7 @@ describe('ReactInteractionTracing', () => {
|
|||
resolveText('Page Two');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'Suspend [Show Text One]',
|
||||
'Show Text One Loading...',
|
||||
|
@ -920,7 +926,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'Suspend [Show Text One]',
|
||||
'Show Text One Loading...',
|
||||
|
@ -938,7 +944,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Show Text',
|
||||
'onTransitionProgress(navigate, 1000, 5000, [show text one])',
|
||||
'onTransitionProgress(show text one, 1000, 5000, [show text one])',
|
||||
|
@ -948,7 +954,7 @@ describe('ReactInteractionTracing', () => {
|
|||
resolveText('Show Text Two');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Show Text Two',
|
||||
'onTransitionProgress(show text two, 3000, 6000, [])',
|
||||
'onTransitionComplete(show text two, 3000, 6000)',
|
||||
|
@ -959,7 +965,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Show Text One',
|
||||
'onTransitionProgress(navigate, 1000, 7000, [])',
|
||||
'onTransitionProgress(show text one, 1000, 7000, [])',
|
||||
|
@ -1037,7 +1043,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
|
||||
await act(async () => {
|
||||
startTransition(() => navigateToPageTwo(), {name: 'page transition'});
|
||||
|
@ -1045,7 +1051,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'onTransitionStart(page transition, 1000)',
|
||||
'onMarkerComplete(page transition, marker two, 1000, 2000)',
|
||||
|
@ -1124,7 +1130,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
@ -1133,7 +1139,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Suspend [Marker Text]',
|
||||
'Loading...',
|
||||
|
@ -1145,7 +1151,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
await resolveText('Page Two');
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'Suspend [Marker Text]',
|
||||
'Loading...',
|
||||
|
@ -1157,7 +1163,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
await resolveText('Marker Text');
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Marker Text',
|
||||
'onMarkerProgress(page transition, async marker, 1000, 4000, [])',
|
||||
'onMarkerComplete(page transition, async marker, 1000, 4000)',
|
||||
|
@ -1244,7 +1250,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
@ -1253,7 +1259,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Outer Text]',
|
||||
'Suspend [Inner Text One]',
|
||||
'Inner One...',
|
||||
|
@ -1267,12 +1273,12 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
await resolveText('Inner Text Two');
|
||||
expect(Scheduler).toFlushAndYield([]);
|
||||
await waitForAll([]);
|
||||
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
await resolveText('Outer Text');
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Outer Text',
|
||||
'Suspend [Inner Text One]',
|
||||
'Inner One...',
|
||||
|
@ -1284,7 +1290,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
await resolveText('Inner Text One');
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Inner Text One',
|
||||
'onMarkerProgress(page transition, outer marker, 1000, 5000, [])',
|
||||
'onMarkerComplete(page transition, marker one, 1000, 5000)',
|
||||
|
@ -1367,7 +1373,7 @@ describe('ReactInteractionTracing', () => {
|
|||
root.render(<App navigate={false} markerName="marker one" />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
|
||||
startTransition(
|
||||
() => root.render(<App navigate={true} markerName="marker one" />),
|
||||
|
@ -1378,7 +1384,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'onTransitionStart(transition one, 1000)',
|
||||
|
@ -1400,7 +1406,7 @@ describe('ReactInteractionTracing', () => {
|
|||
resolveText('Page Two');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'onMarkerProgress(transition one, marker one, 1000, 4000, [])',
|
||||
'onTransitionProgress(transition one, 1000, 4000, [])',
|
||||
|
@ -1501,7 +1507,7 @@ describe('ReactInteractionTracing', () => {
|
|||
root.render(<App navigate={false} showMarker={true} />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
|
||||
startTransition(
|
||||
() => root.render(<App navigate={true} showMarker={true} />),
|
||||
|
@ -1511,7 +1517,7 @@ describe('ReactInteractionTracing', () => {
|
|||
);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'Suspend [Sibling Text]',
|
||||
|
@ -1526,7 +1532,7 @@ describe('ReactInteractionTracing', () => {
|
|||
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'Suspend [Sibling Text]',
|
||||
|
@ -1539,7 +1545,7 @@ describe('ReactInteractionTracing', () => {
|
|||
root.render(<App navigate={true} showMarker={true} />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'Suspend [Sibling Text]',
|
||||
|
@ -1550,12 +1556,12 @@ describe('ReactInteractionTracing', () => {
|
|||
resolveText('Page Two');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield(['Page Two']);
|
||||
await waitForAll(['Page Two']);
|
||||
|
||||
resolveText('Sibling Text');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Sibling Text',
|
||||
'onMarkerProgress(transition one, parent, 1000, 6000, [])',
|
||||
'onMarkerProgress(transition one, sibling, 1000, 6000, [])',
|
||||
|
@ -1652,7 +1658,7 @@ describe('ReactInteractionTracing', () => {
|
|||
root.render(<App navigate={false} deleteOne={false} />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
|
||||
startTransition(
|
||||
() => root.render(<App navigate={true} deleteOne={false} />),
|
||||
|
@ -1662,7 +1668,7 @@ describe('ReactInteractionTracing', () => {
|
|||
);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page One]',
|
||||
'Loading One...',
|
||||
'Suspend [Page Two]',
|
||||
|
@ -1677,7 +1683,7 @@ describe('ReactInteractionTracing', () => {
|
|||
root.render(<App navigate={true} deleteOne={true} />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading Two...',
|
||||
'onMarkerProgress(transition, parent, 1000, 3000, [suspense two])',
|
||||
|
@ -1688,7 +1694,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await resolveText('Page Two');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
// Marker progress will still get called after incomplete but not marker complete
|
||||
'onMarkerProgress(transition, parent, 1000, 4000, [])',
|
||||
|
@ -1793,7 +1799,7 @@ describe('ReactInteractionTracing', () => {
|
|||
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield(['Page One']);
|
||||
await waitForAll(['Page One']);
|
||||
|
||||
startTransition(
|
||||
() => root.render(<App navigate={true} deleteOne={false} />),
|
||||
|
@ -1803,7 +1809,7 @@ describe('ReactInteractionTracing', () => {
|
|||
);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page One]',
|
||||
'Suspend [Child]',
|
||||
'Loading Child...',
|
||||
|
@ -1820,7 +1826,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await resolveText('Page One');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page One',
|
||||
'Suspend [Child]',
|
||||
'Loading Child...',
|
||||
|
@ -1833,7 +1839,7 @@ describe('ReactInteractionTracing', () => {
|
|||
root.render(<App navigate={true} deleteOne={true} />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading Two...',
|
||||
// "suspense one" has unsuspended so shouldn't be included
|
||||
|
@ -1848,7 +1854,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await resolveText('Page Two');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Page Two',
|
||||
'onMarkerProgress(transition, parent, 1000, 5000, [])',
|
||||
'onMarkerProgress(transition, two, 1000, 5000, [])',
|
||||
|
@ -1933,7 +1939,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Suspend [Child]',
|
||||
'onTransitionStart(transition, 0)',
|
||||
'onMarkerProgress(transition, parent, 0, 1000, [child])',
|
||||
|
@ -1945,23 +1951,20 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
// This appended child isn't part of the transition so we
|
||||
// don't call any callback
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'Suspend [Appended child]',
|
||||
'Suspend [Child]',
|
||||
]);
|
||||
await waitForAll(['Suspend [Appended child]', 'Suspend [Child]']);
|
||||
|
||||
// This deleted child isn't part of the transition so we
|
||||
// don't call any callbacks
|
||||
root.render(<App show={false} />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield(['Suspend [Child]']);
|
||||
await waitForAll(['Suspend [Child]']);
|
||||
|
||||
await resolveText('Child');
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Child',
|
||||
'onMarkerProgress(transition, parent, 0, 4000, [])',
|
||||
'onMarkerComplete(transition, parent, 0, 4000)',
|
||||
|
@ -2056,7 +2059,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Suspend [Child]',
|
||||
'onTransitionStart(transition one, 0)',
|
||||
'onMarkerProgress(transition one, parent, 0, 1000, [child])',
|
||||
|
@ -2075,7 +2078,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Suspend [Appended child]',
|
||||
'Suspend [Child]',
|
||||
'onTransitionStart(transition two, 1000)',
|
||||
|
@ -2089,7 +2092,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Suspend [Child]',
|
||||
'onMarkerProgress(transition two, appended child, 1000, 3000, [])',
|
||||
'onMarkerIncomplete(transition two, appended child, 1000, [{endTime: 3000, name: appended child, type: suspense}])',
|
||||
|
@ -2101,7 +2104,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Child',
|
||||
'onMarkerProgress(transition one, parent, 0, 4000, [])',
|
||||
'onMarkerComplete(transition one, parent, 0, 4000)',
|
||||
|
@ -2161,7 +2164,7 @@ describe('ReactInteractionTracing', () => {
|
|||
);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'one',
|
||||
'onTransitionStart(transition one, 0)',
|
||||
'onMarkerComplete(transition one, one, 0, 1000)',
|
||||
|
@ -2175,10 +2178,10 @@ describe('ReactInteractionTracing', () => {
|
|||
);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(() => {
|
||||
await expect(async () => {
|
||||
// onMarkerComplete shouldn't be called for transitions with
|
||||
// new keys
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'two',
|
||||
'onTransitionStart(transition two, 1000)',
|
||||
'onTransitionComplete(transition two, 1000, 2000)',
|
||||
|
@ -2195,7 +2198,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
// This should not warn and onMarkerComplete should be called
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'three',
|
||||
'onTransitionStart(transition three, 2000)',
|
||||
'onMarkerComplete(transition three, three, 2000, 3000)',
|
||||
|
@ -2247,7 +2250,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
advanceTimers(1000);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Suspend [Text]',
|
||||
'Loading...',
|
||||
'Suspend [Hidden Text]',
|
||||
|
@ -2260,7 +2263,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
advanceTimers(1000);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Text',
|
||||
'onMarkerComplete(transition, marker, 0, 2000)',
|
||||
'onTransitionComplete(transition, 0, 2000)',
|
||||
|
@ -2271,7 +2274,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
advanceTimers(1000);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Hidden Text']);
|
||||
assertLog(['Hidden Text']);
|
||||
});
|
||||
|
||||
// @gate enableTransitionTracing
|
||||
|
@ -2317,7 +2320,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'onTransitionStart(page transition, 0)',
|
||||
|
@ -2329,7 +2332,7 @@ describe('ReactInteractionTracing', () => {
|
|||
await advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Page Two',
|
||||
'onTransitionProgress(page transition, 0, 2000, [])',
|
||||
'onTransitionComplete(page transition, 0, 2000)',
|
||||
|
@ -2387,7 +2390,7 @@ describe('ReactInteractionTracing', () => {
|
|||
advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Suspend [Text]',
|
||||
'Loading...',
|
||||
'Suspend [Text Two]',
|
||||
|
@ -2404,7 +2407,7 @@ describe('ReactInteractionTracing', () => {
|
|||
ReactNoop.expire(1000);
|
||||
advanceTimers(1000);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Text Two',
|
||||
'onTransitionProgress(transition, 0, 2000, [])',
|
||||
'onTransitionComplete(transition, 0, 2000)',
|
||||
|
@ -2465,7 +2468,7 @@ describe('ReactInteractionTracing', () => {
|
|||
advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Suspend [Text one]',
|
||||
'Loading one...',
|
||||
'Suspend [Text two]',
|
||||
|
@ -2482,7 +2485,7 @@ describe('ReactInteractionTracing', () => {
|
|||
advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Text one',
|
||||
'onTransitionProgress(transition one, 0, 2000, []) /root one/',
|
||||
'onTransitionComplete(transition one, 0, 2000) /root one/',
|
||||
|
@ -2494,7 +2497,7 @@ describe('ReactInteractionTracing', () => {
|
|||
advanceTimers(1000);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Text two',
|
||||
'onTransitionProgress(transition two, 0, 3000, []) /root two/',
|
||||
'onTransitionComplete(transition two, 0, 3000) /root two/',
|
||||
|
|
|
@ -6,6 +6,9 @@ let startTransition;
|
|||
let useState;
|
||||
let useEffect;
|
||||
let act;
|
||||
let waitFor;
|
||||
let waitForPaint;
|
||||
let assertLog;
|
||||
|
||||
describe('ReactUpdatePriority', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -20,6 +23,11 @@ describe('ReactUpdatePriority', () => {
|
|||
startTransition = React.startTransition;
|
||||
useState = React.useState;
|
||||
useEffect = React.useEffect;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForPaint = InternalTestUtils.waitForPaint;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
});
|
||||
|
||||
function Text({text}) {
|
||||
|
@ -43,9 +51,9 @@ describe('ReactUpdatePriority', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
// Should not have flushed the effect update yet
|
||||
expect(Scheduler).toHaveYielded([1]);
|
||||
assertLog([1]);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([2]);
|
||||
assertLog([2]);
|
||||
});
|
||||
|
||||
test('setState inside passive effect triggered by idle update should have idle priority', async () => {
|
||||
|
@ -68,13 +76,13 @@ describe('ReactUpdatePriority', () => {
|
|||
root.render(<App />);
|
||||
});
|
||||
// Should not have flushed the effect update yet
|
||||
expect(Scheduler).toFlushUntilNextPaint(['Idle: 1, Default: 1']);
|
||||
await waitForPaint(['Idle: 1, Default: 1']);
|
||||
|
||||
// Schedule another update at default priority
|
||||
setDefaultState(2);
|
||||
|
||||
// The default update flushes first, because
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
await waitForPaint([
|
||||
// Idle update is scheduled
|
||||
'Idle update',
|
||||
|
||||
|
@ -83,7 +91,7 @@ describe('ReactUpdatePriority', () => {
|
|||
]);
|
||||
});
|
||||
// Now the idle update has flushed
|
||||
expect(Scheduler).toHaveYielded(['Idle: 2, Default: 2']);
|
||||
assertLog(['Idle: 2, Default: 2']);
|
||||
});
|
||||
|
||||
test('continuous updates should interrupt transitions', async () => {
|
||||
|
@ -111,19 +119,19 @@ describe('ReactUpdatePriority', () => {
|
|||
await act(async () => {
|
||||
root.render(<App />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['A1', 'B1', 'C1']);
|
||||
assertLog(['A1', 'B1', 'C1']);
|
||||
expect(root).toMatchRenderedOutput('A1B1C1');
|
||||
|
||||
await act(async () => {
|
||||
startTransition(() => {
|
||||
setCounter(2);
|
||||
});
|
||||
expect(Scheduler).toFlushAndYieldThrough(['A2']);
|
||||
await waitFor(['A2']);
|
||||
ReactNoop.unstable_runWithPriority(ContinuousEventPriority, () => {
|
||||
setIsHidden(true);
|
||||
});
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
// Because the hide update has continuous priority, it should interrupt the
|
||||
// in-progress transition
|
||||
'(hidden)',
|
||||
|
|
|
@ -19,6 +19,9 @@ let allSchedulerTags;
|
|||
let allSchedulerTypes;
|
||||
let onCommitRootShouldYield;
|
||||
let act;
|
||||
let waitFor;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
|
||||
describe('updaters', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -91,6 +94,11 @@ describe('updaters', () => {
|
|||
Scheduler = require('scheduler');
|
||||
|
||||
act = require('jest-react').act;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
});
|
||||
|
||||
it('should report the (host) root as the scheduler for root-level render', async () => {
|
||||
|
@ -210,10 +218,7 @@ describe('updaters', () => {
|
|||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await act(async () => {
|
||||
root.render(<Parent />);
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
'CascadingChild 0',
|
||||
'onCommitRoot',
|
||||
]);
|
||||
await waitFor(['CascadingChild 0', 'onCommitRoot']);
|
||||
});
|
||||
expect(triggerActiveCascade).not.toBeNull();
|
||||
expect(triggerPassiveCascade).not.toBeNull();
|
||||
|
@ -221,7 +226,7 @@ describe('updaters', () => {
|
|||
|
||||
await act(async () => {
|
||||
triggerActiveCascade();
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
await waitFor([
|
||||
'CascadingChild 0',
|
||||
'onCommitRoot',
|
||||
'CascadingChild 1',
|
||||
|
@ -236,7 +241,7 @@ describe('updaters', () => {
|
|||
|
||||
await act(async () => {
|
||||
triggerPassiveCascade();
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
await waitFor([
|
||||
'CascadingChild 1',
|
||||
'onCommitRoot',
|
||||
'CascadingChild 2',
|
||||
|
@ -252,7 +257,7 @@ describe('updaters', () => {
|
|||
]);
|
||||
|
||||
// Verify no outstanding flushes
|
||||
Scheduler.unstable_flushAll();
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
it('should cover suspense pings', async () => {
|
||||
|
@ -291,7 +296,7 @@ describe('updaters', () => {
|
|||
|
||||
await act(async () => {
|
||||
ReactDOM.render(<Parent />, document.createElement('div'));
|
||||
expect(Scheduler).toHaveYielded(['onCommitRoot']);
|
||||
assertLog(['onCommitRoot']);
|
||||
});
|
||||
expect(setShouldSuspend).not.toBeNull();
|
||||
expect(allSchedulerTypes).toEqual([[null]]);
|
||||
|
@ -299,7 +304,7 @@ describe('updaters', () => {
|
|||
await act(async () => {
|
||||
setShouldSuspend(true);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['onCommitRoot']);
|
||||
assertLog(['onCommitRoot']);
|
||||
expect(allSchedulerTypes).toEqual([[null], [Suspender]]);
|
||||
|
||||
expect(resolver).not.toBeNull();
|
||||
|
@ -307,11 +312,11 @@ describe('updaters', () => {
|
|||
resolver('abc');
|
||||
return promise;
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['onCommitRoot']);
|
||||
assertLog(['onCommitRoot']);
|
||||
expect(allSchedulerTypes).toEqual([[null], [Suspender], [Suspender]]);
|
||||
|
||||
// Verify no outstanding flushes
|
||||
Scheduler.unstable_flushAll();
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
it('should cover error handling', async () => {
|
||||
|
@ -354,7 +359,7 @@ describe('updaters', () => {
|
|||
await act(async () => {
|
||||
root.render(<Parent shouldError={false} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['initial', 'onCommitRoot']);
|
||||
assertLog(['initial', 'onCommitRoot']);
|
||||
expect(triggerError).not.toBeNull();
|
||||
|
||||
allSchedulerTypes.splice(0);
|
||||
|
@ -363,11 +368,11 @@ describe('updaters', () => {
|
|||
await act(async () => {
|
||||
triggerError();
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['onCommitRoot', 'error', 'onCommitRoot']);
|
||||
assertLog(['onCommitRoot', 'error', 'onCommitRoot']);
|
||||
expect(allSchedulerTypes).toEqual([[Parent], [ErrorBoundary]]);
|
||||
|
||||
// Verify no outstanding flushes
|
||||
Scheduler.unstable_flushAll();
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
it('should distinguish between updaters in the case of interleaved work', async () => {
|
||||
|
@ -409,7 +414,7 @@ describe('updaters', () => {
|
|||
);
|
||||
|
||||
// Render everything initially.
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'SyncPriorityUpdater 0',
|
||||
'Yield HighPriority 0',
|
||||
'LowPriorityUpdater 0',
|
||||
|
@ -421,14 +426,14 @@ describe('updaters', () => {
|
|||
expect(allSchedulerTags).toEqual([[HostRoot]]);
|
||||
|
||||
// Render a partial update, but don't finish.
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
triggerLowPriorityUpdate();
|
||||
expect(Scheduler).toFlushAndYieldThrough(['LowPriorityUpdater 1']);
|
||||
await waitFor(['LowPriorityUpdater 1']);
|
||||
expect(allSchedulerTags).toEqual([[HostRoot]]);
|
||||
|
||||
// Interrupt with higher priority work.
|
||||
ReactDOM.flushSync(triggerSyncPriorityUpdate);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'SyncPriorityUpdater 1',
|
||||
'Yield HighPriority 1',
|
||||
'onCommitRoot',
|
||||
|
@ -437,7 +442,7 @@ describe('updaters', () => {
|
|||
|
||||
// Finish the initial partial update
|
||||
triggerLowPriorityUpdate();
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'LowPriorityUpdater 2',
|
||||
'Yield LowPriority 2',
|
||||
'onCommitRoot',
|
||||
|
@ -455,6 +460,6 @@ describe('updaters', () => {
|
|||
]);
|
||||
|
||||
// Verify no outstanding flushes
|
||||
Scheduler.unstable_flushAll();
|
||||
await waitForAll([]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ let React;
|
|||
let ReactTestRenderer;
|
||||
let Scheduler;
|
||||
let act;
|
||||
let assertLog;
|
||||
|
||||
describe('StrictEffectsMode', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -21,6 +22,9 @@ describe('StrictEffectsMode', () => {
|
|||
ReactTestRenderer = require('react-test-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
act = require('jest-react').act;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
});
|
||||
|
||||
function supportsDoubleInvokeEffects() {
|
||||
|
@ -51,10 +55,7 @@ describe('StrictEffectsMode', () => {
|
|||
ReactTestRenderer.create(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect mount', 'useEffect mount']);
|
||||
});
|
||||
|
||||
it('double invoking for effects works properly', () => {
|
||||
|
@ -80,7 +81,7 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
'useLayoutEffect unmount',
|
||||
|
@ -89,17 +90,14 @@ describe('StrictEffectsMode', () => {
|
|||
'useEffect mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect mount', 'useEffect mount']);
|
||||
}
|
||||
|
||||
act(() => {
|
||||
renderer.update(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect unmount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect unmount',
|
||||
|
@ -110,10 +108,7 @@ describe('StrictEffectsMode', () => {
|
|||
renderer.unmount();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect unmount',
|
||||
'useEffect unmount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect unmount', 'useEffect unmount']);
|
||||
});
|
||||
|
||||
it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
|
||||
|
@ -139,7 +134,7 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useEffect One mount',
|
||||
'useEffect Two mount',
|
||||
'useEffect One unmount',
|
||||
|
@ -148,17 +143,14 @@ describe('StrictEffectsMode', () => {
|
|||
'useEffect Two mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useEffect One mount',
|
||||
'useEffect Two mount',
|
||||
]);
|
||||
assertLog(['useEffect One mount', 'useEffect Two mount']);
|
||||
}
|
||||
|
||||
act(() => {
|
||||
renderer.update(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useEffect One unmount',
|
||||
'useEffect Two unmount',
|
||||
'useEffect One mount',
|
||||
|
@ -169,10 +161,7 @@ describe('StrictEffectsMode', () => {
|
|||
renderer.unmount(null);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useEffect One unmount',
|
||||
'useEffect Two unmount',
|
||||
]);
|
||||
assertLog(['useEffect One unmount', 'useEffect Two unmount']);
|
||||
});
|
||||
|
||||
it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
|
||||
|
@ -200,7 +189,7 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect One mount',
|
||||
'useLayoutEffect Two mount',
|
||||
'useLayoutEffect One unmount',
|
||||
|
@ -209,17 +198,14 @@ describe('StrictEffectsMode', () => {
|
|||
'useLayoutEffect Two mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect One mount',
|
||||
'useLayoutEffect Two mount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect One mount', 'useLayoutEffect Two mount']);
|
||||
}
|
||||
|
||||
act(() => {
|
||||
renderer.update(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect One unmount',
|
||||
'useLayoutEffect Two unmount',
|
||||
'useLayoutEffect One mount',
|
||||
|
@ -230,10 +216,7 @@ describe('StrictEffectsMode', () => {
|
|||
renderer.unmount();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect One unmount',
|
||||
'useLayoutEffect Two unmount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect One unmount', 'useLayoutEffect Two unmount']);
|
||||
});
|
||||
|
||||
it('useEffect and useLayoutEffect is called twice when there is no unmount', () => {
|
||||
|
@ -257,33 +240,27 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect mount', 'useEffect mount']);
|
||||
}
|
||||
|
||||
act(() => {
|
||||
renderer.update(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect mount', 'useEffect mount']);
|
||||
|
||||
act(() => {
|
||||
renderer.unmount();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
assertLog([]);
|
||||
});
|
||||
|
||||
it('passes the right context to class component lifecycles', () => {
|
||||
|
@ -315,13 +292,13 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentDidMount',
|
||||
'componentWillUnmount',
|
||||
'componentDidMount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded(['componentDidMount']);
|
||||
assertLog(['componentDidMount']);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -352,26 +329,26 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentDidMount',
|
||||
'componentWillUnmount',
|
||||
'componentDidMount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded(['componentDidMount']);
|
||||
assertLog(['componentDidMount']);
|
||||
}
|
||||
|
||||
act(() => {
|
||||
renderer.update(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['componentDidUpdate']);
|
||||
assertLog(['componentDidUpdate']);
|
||||
|
||||
act(() => {
|
||||
renderer.unmount();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['componentWillUnmount']);
|
||||
assertLog(['componentWillUnmount']);
|
||||
});
|
||||
|
||||
it('should not double invoke class lifecycles in legacy mode', () => {
|
||||
|
@ -397,7 +374,7 @@ describe('StrictEffectsMode', () => {
|
|||
ReactTestRenderer.create(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['componentDidMount']);
|
||||
assertLog(['componentDidMount']);
|
||||
});
|
||||
|
||||
it('double flushing passive effects only results in one double invoke', () => {
|
||||
|
@ -427,7 +404,7 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'mount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
|
@ -442,7 +419,7 @@ describe('StrictEffectsMode', () => {
|
|||
'useEffect mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'mount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
|
@ -492,7 +469,7 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App useLayoutEffect mount',
|
||||
'App useEffect mount',
|
||||
'App useLayoutEffect unmount',
|
||||
|
@ -501,10 +478,7 @@ describe('StrictEffectsMode', () => {
|
|||
'App useEffect mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'App useLayoutEffect mount',
|
||||
'App useEffect mount',
|
||||
]);
|
||||
assertLog(['App useLayoutEffect mount', 'App useEffect mount']);
|
||||
}
|
||||
|
||||
act(() => {
|
||||
|
@ -512,7 +486,7 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App useLayoutEffect unmount',
|
||||
'Child useLayoutEffect mount',
|
||||
'App useLayoutEffect mount',
|
||||
|
@ -525,7 +499,7 @@ describe('StrictEffectsMode', () => {
|
|||
'Child useEffect mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App useLayoutEffect unmount',
|
||||
'Child useLayoutEffect mount',
|
||||
'App useLayoutEffect mount',
|
||||
|
@ -580,7 +554,7 @@ describe('StrictEffectsMode', () => {
|
|||
});
|
||||
|
||||
if (supportsDoubleInvokeEffects()) {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentDidMount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
|
@ -592,7 +566,7 @@ describe('StrictEffectsMode', () => {
|
|||
'useEffect mount',
|
||||
]);
|
||||
} else {
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentDidMount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
|
@ -603,7 +577,7 @@ describe('StrictEffectsMode', () => {
|
|||
renderer.update(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect unmount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect unmount',
|
||||
|
@ -614,7 +588,7 @@ describe('StrictEffectsMode', () => {
|
|||
renderer.unmount();
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentWillUnmount',
|
||||
'useLayoutEffect unmount',
|
||||
'useEffect unmount',
|
||||
|
|
|
@ -13,6 +13,10 @@ let React;
|
|||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let act;
|
||||
let assertLog;
|
||||
let waitFor;
|
||||
let waitForAll;
|
||||
let waitForPaint;
|
||||
|
||||
describe('StrictEffectsMode defaults', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -23,6 +27,12 @@ describe('StrictEffectsMode defaults', () => {
|
|||
Scheduler = require('scheduler');
|
||||
act = require('jest-react').act;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitForPaint = InternalTestUtils.waitForPaint;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
|
||||
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.createRootStrictEffectsByDefault = __DEV__;
|
||||
});
|
||||
|
@ -46,10 +56,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.renderLegacySyncRoot(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect mount', 'useEffect mount']);
|
||||
});
|
||||
|
||||
it('should not double invoke class lifecycles in legacy mode', () => {
|
||||
|
@ -75,11 +82,11 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.renderLegacySyncRoot(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['componentDidMount']);
|
||||
assertLog(['componentDidMount']);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
it('should flush double-invoked effects within the same frame as layout effects if there are no passive effects', () => {
|
||||
it('should flush double-invoked effects within the same frame as layout effects if there are no passive effects', async () => {
|
||||
function ComponentWithEffects({label}) {
|
||||
React.useLayoutEffect(() => {
|
||||
Scheduler.unstable_yieldValue(`useLayoutEffect mount "${label}"`);
|
||||
|
@ -90,21 +97,21 @@ describe('StrictEffectsMode defaults', () => {
|
|||
return label;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
ReactNoop.render(
|
||||
<>
|
||||
<ComponentWithEffects label={'one'} />
|
||||
</>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
await waitForPaint([
|
||||
'useLayoutEffect mount "one"',
|
||||
'useLayoutEffect unmount "one"',
|
||||
'useLayoutEffect mount "one"',
|
||||
]);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
ReactNoop.render(
|
||||
<>
|
||||
<ComponentWithEffects label={'one'} />
|
||||
|
@ -112,8 +119,8 @@ describe('StrictEffectsMode defaults', () => {
|
|||
</>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
expect(Scheduler).toFlushUntilNextPaint([
|
||||
assertLog([]);
|
||||
await waitForPaint([
|
||||
// Cleanup and re-run "one" (and "two") since there is no dependencies array.
|
||||
'useLayoutEffect unmount "one"',
|
||||
'useLayoutEffect mount "one"',
|
||||
|
@ -128,7 +135,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
|
||||
// This test also verifies that double-invoked effects flush synchronously
|
||||
// within the same frame as passive effects.
|
||||
it('should double invoke effects only for newly mounted components', () => {
|
||||
it('should double invoke effects only for newly mounted components', async () => {
|
||||
function ComponentWithEffects({label}) {
|
||||
React.useEffect(() => {
|
||||
Scheduler.unstable_yieldValue(`useEffect mount "${label}"`);
|
||||
|
@ -145,14 +152,14 @@ describe('StrictEffectsMode defaults', () => {
|
|||
return label;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
ReactNoop.render(
|
||||
<>
|
||||
<ComponentWithEffects label={'one'} />
|
||||
</>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'useLayoutEffect mount "one"',
|
||||
'useEffect mount "one"',
|
||||
'useLayoutEffect unmount "one"',
|
||||
|
@ -162,7 +169,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
ReactNoop.render(
|
||||
<>
|
||||
<ComponentWithEffects label={'one'} />
|
||||
|
@ -170,13 +177,13 @@ describe('StrictEffectsMode defaults', () => {
|
|||
</>,
|
||||
);
|
||||
|
||||
expect(Scheduler).toFlushAndYieldThrough([
|
||||
await waitFor([
|
||||
// Cleanup and re-run "one" (and "two") since there is no dependencies array.
|
||||
'useLayoutEffect unmount "one"',
|
||||
'useLayoutEffect mount "one"',
|
||||
'useLayoutEffect mount "two"',
|
||||
]);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'useEffect unmount "one"',
|
||||
'useEffect mount "one"',
|
||||
'useEffect mount "two"',
|
||||
|
@ -208,7 +215,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
'useLayoutEffect unmount',
|
||||
|
@ -221,7 +228,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect unmount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect unmount',
|
||||
|
@ -232,10 +239,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(null);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect unmount',
|
||||
'useEffect unmount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect unmount', 'useEffect unmount']);
|
||||
});
|
||||
|
||||
it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
|
||||
|
@ -257,7 +261,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useEffect One mount',
|
||||
'useEffect Two mount',
|
||||
'useEffect One unmount',
|
||||
|
@ -270,7 +274,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useEffect One unmount',
|
||||
'useEffect Two unmount',
|
||||
'useEffect One mount',
|
||||
|
@ -281,10 +285,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(null);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useEffect One unmount',
|
||||
'useEffect Two unmount',
|
||||
]);
|
||||
assertLog(['useEffect One unmount', 'useEffect Two unmount']);
|
||||
});
|
||||
|
||||
it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', () => {
|
||||
|
@ -308,7 +309,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect One mount',
|
||||
'useLayoutEffect Two mount',
|
||||
'useLayoutEffect One unmount',
|
||||
|
@ -321,7 +322,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect One unmount',
|
||||
'useLayoutEffect Two unmount',
|
||||
'useLayoutEffect One mount',
|
||||
|
@ -332,10 +333,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(null);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect One unmount',
|
||||
'useLayoutEffect Two unmount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect One unmount', 'useLayoutEffect Two unmount']);
|
||||
});
|
||||
|
||||
it('useEffect and useLayoutEffect is called twice when there is no unmount', () => {
|
||||
|
@ -355,7 +353,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
'useLayoutEffect mount',
|
||||
|
@ -366,16 +364,13 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
]);
|
||||
assertLog(['useLayoutEffect mount', 'useEffect mount']);
|
||||
|
||||
act(() => {
|
||||
ReactNoop.render(null);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
assertLog([]);
|
||||
});
|
||||
|
||||
//@gate useModernStrictMode
|
||||
|
@ -430,7 +425,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentDidMount',
|
||||
'componentWillUnmount',
|
||||
'componentDidMount',
|
||||
|
@ -460,7 +455,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentDidMount',
|
||||
'componentWillUnmount',
|
||||
'componentDidMount',
|
||||
|
@ -470,13 +465,13 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'update'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['componentDidUpdate']);
|
||||
assertLog(['componentDidUpdate']);
|
||||
|
||||
act(() => {
|
||||
ReactNoop.render(null);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded(['componentWillUnmount']);
|
||||
assertLog(['componentWillUnmount']);
|
||||
});
|
||||
|
||||
it('double flushing passive effects only results in one double invoke', () => {
|
||||
|
@ -503,7 +498,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'mount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
|
@ -555,7 +550,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App useLayoutEffect mount',
|
||||
'App useEffect mount',
|
||||
'App useLayoutEffect unmount',
|
||||
|
@ -568,7 +563,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
_setShowChild(true);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'App useLayoutEffect unmount',
|
||||
'Child useLayoutEffect mount',
|
||||
'App useLayoutEffect mount',
|
||||
|
@ -622,7 +617,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentDidMount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect mount',
|
||||
|
@ -638,7 +633,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(<App text={'mount'} />);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'useLayoutEffect unmount',
|
||||
'useLayoutEffect mount',
|
||||
'useEffect unmount',
|
||||
|
@ -649,7 +644,7 @@ describe('StrictEffectsMode defaults', () => {
|
|||
ReactNoop.render(null);
|
||||
});
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'componentWillUnmount',
|
||||
'useLayoutEffect unmount',
|
||||
'useEffect unmount',
|
||||
|
|
|
@ -26,6 +26,8 @@ describe('useEffectEvent', () => {
|
|||
let useEffect;
|
||||
let useLayoutEffect;
|
||||
let useMemo;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
|
@ -40,6 +42,10 @@ describe('useEffectEvent', () => {
|
|||
useEffect = React.useEffect;
|
||||
useLayoutEffect = React.useLayoutEffect;
|
||||
useMemo = React.useMemo;
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
});
|
||||
|
||||
function Text(props) {
|
||||
|
@ -48,7 +54,7 @@ describe('useEffectEvent', () => {
|
|||
}
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it('memoizes basic case correctly', () => {
|
||||
it('memoizes basic case correctly', async () => {
|
||||
class IncrementButton extends React.PureComponent {
|
||||
increment = () => {
|
||||
this.props.onClick();
|
||||
|
@ -72,7 +78,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
const button = React.createRef(null);
|
||||
ReactNoop.render(<Counter incrementBy={1} />);
|
||||
expect(Scheduler).toFlushAndYield(['Increment', 'Count: 0']);
|
||||
await waitForAll(['Increment', 'Count: 0']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -81,7 +87,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded(['Increment', 'Count: 1']);
|
||||
assertLog(['Increment', 'Count: 1']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -90,7 +96,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Increment',
|
||||
// Event should use the updated callback function closed over the new value.
|
||||
'Count: 2',
|
||||
|
@ -104,7 +110,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Increase the increment prop amount
|
||||
ReactNoop.render(<Counter incrementBy={10} />);
|
||||
expect(Scheduler).toFlushAndYield(['Increment', 'Count: 2']);
|
||||
await waitForAll(['Increment', 'Count: 2']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -114,7 +120,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Event uses the new prop
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded(['Increment', 'Count: 12']);
|
||||
assertLog(['Increment', 'Count: 12']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -124,7 +130,7 @@ describe('useEffectEvent', () => {
|
|||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it('can be defined more than once', () => {
|
||||
it('can be defined more than once', async () => {
|
||||
class IncrementButton extends React.PureComponent {
|
||||
increment = () => {
|
||||
this.props.onClick();
|
||||
|
@ -158,7 +164,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
const button = React.createRef(null);
|
||||
ReactNoop.render(<Counter incrementBy={5} />);
|
||||
expect(Scheduler).toFlushAndYield(['Increment', 'Count: 0']);
|
||||
await waitForAll(['Increment', 'Count: 0']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -167,7 +173,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded(['Increment', 'Count: 5']);
|
||||
assertLog(['Increment', 'Count: 5']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -176,7 +182,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.multiply);
|
||||
expect(Scheduler).toHaveYielded(['Increment', 'Count: 25']);
|
||||
assertLog(['Increment', 'Count: 25']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -186,7 +192,7 @@ describe('useEffectEvent', () => {
|
|||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it('does not preserve `this` in event functions', () => {
|
||||
it('does not preserve `this` in event functions', async () => {
|
||||
class GreetButton extends React.PureComponent {
|
||||
greet = () => {
|
||||
this.props.onClick();
|
||||
|
@ -217,7 +223,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
const button = React.createRef(null);
|
||||
ReactNoop.render(<Greeter hello={'hej'} />);
|
||||
expect(Scheduler).toFlushAndYield(['Say hej', 'Greeting: Seb says hej']);
|
||||
await waitForAll(['Say hej', 'Greeting: Seb says hej']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Say hej" />
|
||||
|
@ -226,10 +232,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.greet);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Say hej',
|
||||
'Greeting: undefined says hej',
|
||||
]);
|
||||
assertLog(['Say hej', 'Greeting: undefined says hej']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Say hej" />
|
||||
|
@ -272,11 +275,11 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// If something throws, we try one more time synchronously in case the error was
|
||||
// caused by a data race. See recoverFromConcurrentError
|
||||
expect(Scheduler).toHaveYielded(['Count: 0', 'Count: 0']);
|
||||
assertLog(['Count: 0', 'Count: 0']);
|
||||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it("useLayoutEffect shouldn't re-fire when event handlers change", () => {
|
||||
it("useLayoutEffect shouldn't re-fire when event handlers change", async () => {
|
||||
class IncrementButton extends React.PureComponent {
|
||||
increment = () => {
|
||||
this.props.onClick();
|
||||
|
@ -307,8 +310,8 @@ describe('useEffectEvent', () => {
|
|||
|
||||
const button = React.createRef(null);
|
||||
ReactNoop.render(<Counter incrementBy={1} />);
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
assertLog([]);
|
||||
await waitForAll([
|
||||
'Increment',
|
||||
'Count: 0',
|
||||
'Effect: by 2',
|
||||
|
@ -323,7 +326,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Increment',
|
||||
// Effect should not re-run because the dependency hasn't changed.
|
||||
'Count: 3',
|
||||
|
@ -336,7 +339,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Increment',
|
||||
// Event should use the updated callback function closed over the new value.
|
||||
'Count: 4',
|
||||
|
@ -350,7 +353,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Increase the increment prop amount
|
||||
ReactNoop.render(<Counter incrementBy={10} />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Increment',
|
||||
'Count: 4',
|
||||
'Effect: by 20',
|
||||
|
@ -366,7 +369,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Event uses the new prop
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded(['Increment', 'Count: 34']);
|
||||
assertLog(['Increment', 'Count: 34']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -376,7 +379,7 @@ describe('useEffectEvent', () => {
|
|||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it("useEffect shouldn't re-fire when event handlers change", () => {
|
||||
it("useEffect shouldn't re-fire when event handlers change", async () => {
|
||||
class IncrementButton extends React.PureComponent {
|
||||
increment = () => {
|
||||
this.props.onClick();
|
||||
|
@ -407,7 +410,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
const button = React.createRef(null);
|
||||
ReactNoop.render(<Counter incrementBy={1} />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Increment',
|
||||
'Count: 0',
|
||||
'Effect: by 2',
|
||||
|
@ -422,7 +425,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Increment',
|
||||
// Effect should not re-run because the dependency hasn't changed.
|
||||
'Count: 3',
|
||||
|
@ -435,7 +438,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Increment',
|
||||
// Event should use the updated callback function closed over the new value.
|
||||
'Count: 4',
|
||||
|
@ -449,7 +452,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Increase the increment prop amount
|
||||
ReactNoop.render(<Counter incrementBy={10} />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Increment',
|
||||
'Count: 4',
|
||||
'Effect: by 20',
|
||||
|
@ -465,7 +468,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Event uses the new prop
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded(['Increment', 'Count: 34']);
|
||||
assertLog(['Increment', 'Count: 34']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -475,7 +478,7 @@ describe('useEffectEvent', () => {
|
|||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it('is stable in a custom hook', () => {
|
||||
it('is stable in a custom hook', async () => {
|
||||
class IncrementButton extends React.PureComponent {
|
||||
increment = () => {
|
||||
this.props.onClick();
|
||||
|
@ -512,7 +515,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
const button = React.createRef(null);
|
||||
ReactNoop.render(<Counter incrementBy={1} />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Increment',
|
||||
'Count: 0',
|
||||
'Effect: by 2',
|
||||
|
@ -527,7 +530,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Increment',
|
||||
// Effect should not re-run because the dependency hasn't changed.
|
||||
'Count: 3',
|
||||
|
@ -540,7 +543,7 @@ describe('useEffectEvent', () => {
|
|||
);
|
||||
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
assertLog([
|
||||
'Increment',
|
||||
// Event should use the updated callback function closed over the new value.
|
||||
'Count: 4',
|
||||
|
@ -554,7 +557,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Increase the increment prop amount
|
||||
ReactNoop.render(<Counter incrementBy={10} />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'Increment',
|
||||
'Count: 4',
|
||||
'Effect: by 20',
|
||||
|
@ -570,7 +573,7 @@ describe('useEffectEvent', () => {
|
|||
|
||||
// Event uses the new prop
|
||||
act(button.current.increment);
|
||||
expect(Scheduler).toHaveYielded(['Increment', 'Count: 34']);
|
||||
assertLog(['Increment', 'Count: 34']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<span prop="Increment" />
|
||||
|
@ -580,7 +583,7 @@ describe('useEffectEvent', () => {
|
|||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it('is mutated before all other effects', () => {
|
||||
it('is mutated before all other effects', async () => {
|
||||
function Counter({value}) {
|
||||
useInsertionEffect(() => {
|
||||
Scheduler.unstable_yieldValue('Effect value: ' + value);
|
||||
|
@ -597,14 +600,14 @@ describe('useEffectEvent', () => {
|
|||
}
|
||||
|
||||
ReactNoop.render(<Counter value={1} />);
|
||||
expect(Scheduler).toFlushAndYield(['Effect value: 1', 'Event value: 1']);
|
||||
await waitForAll(['Effect value: 1', 'Event value: 1']);
|
||||
|
||||
act(() => ReactNoop.render(<Counter value={2} />));
|
||||
expect(Scheduler).toHaveYielded(['Effect value: 2', 'Event value: 2']);
|
||||
assertLog(['Effect value: 2', 'Event value: 2']);
|
||||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it("doesn't provide a stable identity", () => {
|
||||
it("doesn't provide a stable identity", async () => {
|
||||
function Counter({shouldRender, value}) {
|
||||
const onClick = useEffectEvent(() => {
|
||||
Scheduler.unstable_yieldValue(
|
||||
|
@ -627,16 +630,16 @@ describe('useEffectEvent', () => {
|
|||
}
|
||||
|
||||
ReactNoop.render(<Counter shouldRender={true} value={0} />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'onClick, shouldRender=true, value=0',
|
||||
'onClick, shouldRender=true, value=0',
|
||||
]);
|
||||
|
||||
ReactNoop.render(<Counter shouldRender={true} value={1} />);
|
||||
expect(Scheduler).toFlushAndYield(['onClick, shouldRender=true, value=1']);
|
||||
await waitForAll(['onClick, shouldRender=true, value=1']);
|
||||
|
||||
ReactNoop.render(<Counter shouldRender={false} value={2} />);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
await waitForAll([
|
||||
'onClick, shouldRender=false, value=2',
|
||||
'onClick, shouldRender=false, value=2',
|
||||
]);
|
||||
|
@ -676,7 +679,7 @@ describe('useEffectEvent', () => {
|
|||
await act(async () => {
|
||||
root.render(<App value={1} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded(['Commit new event handler']);
|
||||
assertLog(['Commit new event handler']);
|
||||
expect(root).toMatchRenderedOutput('Latest rendered value 1');
|
||||
expect(committedEventHandler()).toBe('Value seen by useEffectEvent: 1');
|
||||
|
||||
|
@ -686,14 +689,14 @@ describe('useEffectEvent', () => {
|
|||
});
|
||||
// No new event handler should be committed, because it was omitted from
|
||||
// the dependency array.
|
||||
expect(Scheduler).toHaveYielded([]);
|
||||
assertLog([]);
|
||||
// But the event handler should still be able to see the latest value.
|
||||
expect(root).toMatchRenderedOutput('Latest rendered value 2');
|
||||
expect(committedEventHandler()).toBe('Value seen by useEffectEvent: 2');
|
||||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it('integration: implements docs chat room example', () => {
|
||||
it('integration: implements docs chat room example', async () => {
|
||||
function createConnection() {
|
||||
let connectedCallback;
|
||||
let timeout;
|
||||
|
@ -738,47 +741,47 @@ describe('useEffectEvent', () => {
|
|||
}
|
||||
|
||||
act(() => ReactNoop.render(<ChatRoom roomId="general" theme="light" />));
|
||||
expect(Scheduler).toHaveYielded(['Welcome to the general room!']);
|
||||
assertLog(['Welcome to the general room!']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<span prop="Welcome to the general room!" />,
|
||||
);
|
||||
|
||||
jest.advanceTimersByTime(100);
|
||||
Scheduler.unstable_advanceTime(100);
|
||||
expect(Scheduler).toHaveYielded(['Connected! theme: light']);
|
||||
assertLog(['Connected! theme: light']);
|
||||
|
||||
// change roomId only
|
||||
act(() => ReactNoop.render(<ChatRoom roomId="music" theme="light" />));
|
||||
expect(Scheduler).toHaveYielded(['Welcome to the music room!']);
|
||||
assertLog(['Welcome to the music room!']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<span prop="Welcome to the music room!" />,
|
||||
);
|
||||
jest.advanceTimersByTime(100);
|
||||
Scheduler.unstable_advanceTime(100);
|
||||
// should trigger a reconnect
|
||||
expect(Scheduler).toHaveYielded(['Connected! theme: light']);
|
||||
assertLog(['Connected! theme: light']);
|
||||
|
||||
// change theme only
|
||||
act(() => ReactNoop.render(<ChatRoom roomId="music" theme="dark" />));
|
||||
expect(Scheduler).toHaveYielded(['Welcome to the music room!']);
|
||||
assertLog(['Welcome to the music room!']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<span prop="Welcome to the music room!" />,
|
||||
);
|
||||
jest.advanceTimersByTime(100);
|
||||
Scheduler.unstable_advanceTime(100);
|
||||
// should not trigger a reconnect
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
|
||||
// change roomId only
|
||||
act(() => ReactNoop.render(<ChatRoom roomId="travel" theme="dark" />));
|
||||
expect(Scheduler).toHaveYielded(['Welcome to the travel room!']);
|
||||
assertLog(['Welcome to the travel room!']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<span prop="Welcome to the travel room!" />,
|
||||
);
|
||||
jest.advanceTimersByTime(100);
|
||||
Scheduler.unstable_advanceTime(100);
|
||||
// should trigger a reconnect
|
||||
expect(Scheduler).toHaveYielded(['Connected! theme: dark']);
|
||||
assertLog(['Connected! theme: dark']);
|
||||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
|
@ -837,12 +840,9 @@ describe('useEffectEvent', () => {
|
|||
</AppShell>,
|
||||
),
|
||||
);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Add to cart',
|
||||
'url: /shop/1, numberOfItems: 0',
|
||||
]);
|
||||
assertLog(['Add to cart', 'url: /shop/1, numberOfItems: 0']);
|
||||
act(button.current.addToCart);
|
||||
expect(Scheduler).toHaveYielded(['Add to cart']);
|
||||
assertLog(['Add to cart']);
|
||||
|
||||
act(() =>
|
||||
ReactNoop.render(
|
||||
|
@ -851,9 +851,6 @@ describe('useEffectEvent', () => {
|
|||
</AppShell>,
|
||||
),
|
||||
);
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Add to cart',
|
||||
'url: /shop/2, numberOfItems: 1',
|
||||
]);
|
||||
assertLog(['Add to cart', 'url: /shop/2, numberOfItems: 1']);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue