mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Codemod tests to waitFor pattern (9/?) (#26309)
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:
@@ -20,6 +20,7 @@ let TextResource;
|
||||
let textResourceShouldFail;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
let waitForThrow;
|
||||
|
||||
describe('ReactCache', () => {
|
||||
beforeEach(() => {
|
||||
@@ -38,6 +39,7 @@ describe('ReactCache', () => {
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
|
||||
TextResource = createResource(
|
||||
([text, ms = 0]) => {
|
||||
@@ -150,12 +152,12 @@ describe('ReactCache', () => {
|
||||
jest.advanceTimersByTime(100);
|
||||
assertLog(['Promise rejected [Hi]']);
|
||||
|
||||
expect(Scheduler).toFlushAndThrow('Failed to load: Hi');
|
||||
await waitForThrow('Failed to load: Hi');
|
||||
assertLog(['Error! [Hi]', 'Error! [Hi]']);
|
||||
|
||||
// Should throw again on a subsequent read
|
||||
root.update(<App />);
|
||||
expect(Scheduler).toFlushAndThrow('Failed to load: Hi');
|
||||
await waitForThrow('Failed to load: Hi');
|
||||
assertLog(['Error! [Hi]', 'Error! [Hi]']);
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -4398,7 +4398,7 @@ background-color: green;
|
||||
</body>
|
||||
</html>,
|
||||
);
|
||||
expect(Scheduler).toFlushWithoutYielding();
|
||||
await waitForAll([]);
|
||||
expect(getMeaningfulChildren(document)).toEqual(
|
||||
<html>
|
||||
<head>
|
||||
|
||||
+25
-21
@@ -1092,8 +1092,8 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
const innerHTML = ReactDOMServer.renderToString(<InnerApp />);
|
||||
innerContainer.innerHTML = innerHTML;
|
||||
|
||||
expect(OuterScheduler).toHaveYielded(['Outer']);
|
||||
expect(InnerScheduler).toHaveYielded(['Inner']);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual(['Outer']);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual(['Inner']);
|
||||
|
||||
suspendOuter = true;
|
||||
suspendInner = true;
|
||||
@@ -1101,8 +1101,10 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
OuterReactDOMClient.hydrateRoot(outerContainer, <OuterApp />);
|
||||
InnerReactDOMClient.hydrateRoot(innerContainer, <InnerApp />);
|
||||
|
||||
expect(OuterScheduler).toFlushAndYield(['Suspend Outer']);
|
||||
expect(InnerScheduler).toFlushAndYield(['Suspend Inner']);
|
||||
OuterScheduler.unstable_flushAllWithoutAsserting();
|
||||
InnerScheduler.unstable_flushAllWithoutAsserting();
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual(['Suspend Outer']);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual(['Suspend Inner']);
|
||||
|
||||
innerDiv = document.querySelector('#inner');
|
||||
|
||||
@@ -1115,7 +1117,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
InnerScheduler.unstable_flushAllWithoutAsserting();
|
||||
});
|
||||
|
||||
expect(OuterScheduler).toHaveYielded(['Suspend Outer']);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual(['Suspend Outer']);
|
||||
if (
|
||||
gate(
|
||||
flags =>
|
||||
@@ -1124,10 +1126,12 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
) {
|
||||
// InnerApp doesn't see the event because OuterApp calls stopPropagation in
|
||||
// capture phase since the event is blocked on suspended component
|
||||
expect(InnerScheduler).toHaveYielded([]);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual([]);
|
||||
} else {
|
||||
// no stopPropagation
|
||||
expect(InnerScheduler).toHaveYielded(['Suspend Inner']);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual([
|
||||
'Suspend Inner',
|
||||
]);
|
||||
}
|
||||
|
||||
assertLog([]);
|
||||
@@ -1149,15 +1153,15 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
InnerScheduler.unstable_flushAllWithoutAsserting();
|
||||
});
|
||||
|
||||
expect(OuterScheduler).toHaveYielded(['Suspend Outer']);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual(['Suspend Outer']);
|
||||
// Inner App renders because it is unblocked
|
||||
expect(InnerScheduler).toHaveYielded(['Inner']);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual(['Inner']);
|
||||
// No event is replayed yet
|
||||
assertLog([]);
|
||||
|
||||
dispatchMouseHoverEvent(innerDiv);
|
||||
expect(OuterScheduler).toHaveYielded([]);
|
||||
expect(InnerScheduler).toHaveYielded([]);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual([]);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual([]);
|
||||
// No event is replayed yet
|
||||
assertLog([]);
|
||||
|
||||
@@ -1172,9 +1176,9 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
|
||||
// Nothing happens to inner app yet.
|
||||
// Its blocked on the outer app replaying the event
|
||||
expect(InnerScheduler).toHaveYielded([]);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual([]);
|
||||
// Outer hydrates and schedules Replay
|
||||
expect(OuterScheduler).toHaveYielded(['Outer']);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual(['Outer']);
|
||||
// No event is replayed yet
|
||||
assertLog([]);
|
||||
|
||||
@@ -1203,9 +1207,9 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
});
|
||||
|
||||
// Outer resolves and scheduled replay
|
||||
expect(OuterScheduler).toHaveYielded(['Outer']);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual(['Outer']);
|
||||
// Inner App is still blocked
|
||||
expect(InnerScheduler).toHaveYielded([]);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual([]);
|
||||
|
||||
// Replay outer event
|
||||
await act(async () => {
|
||||
@@ -1217,12 +1221,12 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
// Inner is still blocked so when Outer replays the event in capture phase
|
||||
// inner ends up caling stopPropagation
|
||||
assertLog([]);
|
||||
expect(OuterScheduler).toHaveYielded([]);
|
||||
expect(InnerScheduler).toHaveYielded(['Suspend Inner']);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual([]);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual(['Suspend Inner']);
|
||||
|
||||
dispatchMouseHoverEvent(innerDiv);
|
||||
expect(OuterScheduler).toHaveYielded([]);
|
||||
expect(InnerScheduler).toHaveYielded([]);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual([]);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual([]);
|
||||
assertLog([]);
|
||||
|
||||
await act(async () => {
|
||||
@@ -1234,9 +1238,9 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
||||
});
|
||||
|
||||
// Inner hydrates
|
||||
expect(InnerScheduler).toHaveYielded(['Inner']);
|
||||
expect(InnerScheduler.unstable_clearYields()).toEqual(['Inner']);
|
||||
// Outer was hydrated earlier
|
||||
expect(OuterScheduler).toHaveYielded([]);
|
||||
expect(OuterScheduler.unstable_clearYields()).toEqual([]);
|
||||
|
||||
await act(async () => {
|
||||
Scheduler.unstable_flushAllWithoutAsserting();
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let JSXDEVRuntime;
|
||||
let waitForAll;
|
||||
|
||||
@@ -20,7 +19,6 @@ describe('ReactDeprecationWarnings', () => {
|
||||
jest.resetModules();
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
if (__DEV__) {
|
||||
@@ -28,7 +26,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should warn when given defaultProps', () => {
|
||||
it('should warn when given defaultProps', async () => {
|
||||
function FunctionalComponent(props) {
|
||||
return null;
|
||||
}
|
||||
@@ -38,14 +36,14 @@ describe('ReactDeprecationWarnings', () => {
|
||||
};
|
||||
|
||||
ReactNoop.render(<FunctionalComponent />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Warning: FunctionalComponent: Support for defaultProps ' +
|
||||
'will be removed from function components in a future major ' +
|
||||
'release. Use JavaScript default parameters instead.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn when given defaultProps on a memoized function', () => {
|
||||
it('should warn when given defaultProps on a memoized function', async () => {
|
||||
const MemoComponent = React.memo(function FunctionalComponent(props) {
|
||||
return null;
|
||||
});
|
||||
@@ -59,14 +57,14 @@ describe('ReactDeprecationWarnings', () => {
|
||||
<MemoComponent />
|
||||
</div>,
|
||||
);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Warning: FunctionalComponent: Support for defaultProps ' +
|
||||
'will be removed from memo components in a future major ' +
|
||||
'release. Use JavaScript default parameters instead.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn when given string refs', () => {
|
||||
it('should warn when given string refs', async () => {
|
||||
class RefComponent extends React.Component {
|
||||
render() {
|
||||
return null;
|
||||
@@ -79,7 +77,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<Component />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Warning: Component "Component" contains the string ref "refComponent". ' +
|
||||
'Support for string refs will be removed in a future major release. ' +
|
||||
'We recommend using useRef() or createRef() instead. ' +
|
||||
@@ -108,7 +106,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
it('should warn when owner and self are different for string refs', () => {
|
||||
it('should warn when owner and self are different for string refs', async () => {
|
||||
class RefComponent extends React.Component {
|
||||
render() {
|
||||
return null;
|
||||
@@ -121,7 +119,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<Component />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([
|
||||
await expect(async () => await waitForAll([])).toErrorDev([
|
||||
'Warning: Component "Component" contains the string ref "refComponent". ' +
|
||||
'Support for string refs will be removed in a future major release. ' +
|
||||
'This case cannot be automatically converted to an arrow function. ' +
|
||||
@@ -132,7 +130,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
it('should warn when owner and self are different for string refs', () => {
|
||||
it('should warn when owner and self are different for string refs', async () => {
|
||||
class RefComponent extends React.Component {
|
||||
render() {
|
||||
return null;
|
||||
@@ -152,7 +150,7 @@ describe('ReactDeprecationWarnings', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<Component />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Warning: Component "Component" contains the string ref "refComponent". ' +
|
||||
'Support for string refs will be removed in a future major release. ' +
|
||||
'This case cannot be automatically converted to an arrow function. ' +
|
||||
|
||||
+4
-2
@@ -6,6 +6,7 @@ let Suspense;
|
||||
let scheduleCallback;
|
||||
let NormalPriority;
|
||||
let waitForAll;
|
||||
let waitFor;
|
||||
|
||||
describe('ReactSuspenseList', () => {
|
||||
beforeEach(() => {
|
||||
@@ -24,6 +25,7 @@ describe('ReactSuspenseList', () => {
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
});
|
||||
|
||||
function Text(props) {
|
||||
@@ -86,11 +88,11 @@ describe('ReactSuspenseList', () => {
|
||||
});
|
||||
|
||||
// This resolves A and schedules a task for React to retry.
|
||||
await expect(Scheduler).toFlushAndYieldThrough(['Resolve A']);
|
||||
await waitFor(['Resolve A']);
|
||||
|
||||
// The next task that flushes should be the one that resolves B. The render
|
||||
// task should not jump the queue ahead of B.
|
||||
await expect(Scheduler).toFlushAndYieldThrough(['Resolve B']);
|
||||
await waitFor(['Resolve B']);
|
||||
|
||||
await waitForAll(['A', 'B']);
|
||||
expect(root).toMatchRenderedOutput('AB');
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let waitForAll;
|
||||
|
||||
describe('ReactFragment', () => {
|
||||
@@ -20,7 +19,6 @@ describe('ReactFragment', () => {
|
||||
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
@@ -707,7 +705,7 @@ describe('ReactFragment', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should not preserve state when switching to a keyed fragment to an array', async function () {
|
||||
it('should not preserve state when switching to a keyed fragment to an array', async () => {
|
||||
const ops = [];
|
||||
|
||||
class Stateful extends React.Component {
|
||||
@@ -742,7 +740,7 @@ describe('ReactFragment', () => {
|
||||
await waitForAll([]);
|
||||
|
||||
ReactNoop.render(<Foo condition={false} />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Each child in a list should have a unique "key" prop.',
|
||||
);
|
||||
|
||||
@@ -939,7 +937,7 @@ describe('ReactFragment', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<Foo condition={true} />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Each child in a list should have a unique "key" prop.',
|
||||
);
|
||||
|
||||
|
||||
+44
-46
@@ -209,7 +209,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
||||
}
|
||||
ReactNoop.render(<BadCounter />);
|
||||
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
|
||||
' one of the following reasons:\n' +
|
||||
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
|
||||
@@ -227,19 +227,20 @@ describe('ReactHooksWithNoopRenderer', () => {
|
||||
await waitForAll([10]);
|
||||
});
|
||||
|
||||
if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
|
||||
it('throws inside module-style components', async () => {
|
||||
function Counter() {
|
||||
return {
|
||||
render() {
|
||||
const [count] = useState(0);
|
||||
return <Text text={this.props.label + ': ' + count} />;
|
||||
},
|
||||
};
|
||||
}
|
||||
ReactNoop.render(<Counter />);
|
||||
expect(() =>
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
// @gate !disableModulePatternComponents
|
||||
it('throws inside module-style components', async () => {
|
||||
function Counter() {
|
||||
return {
|
||||
render() {
|
||||
const [count] = useState(0);
|
||||
return <Text text={this.props.label + ': ' + count} />;
|
||||
},
|
||||
};
|
||||
}
|
||||
ReactNoop.render(<Counter />);
|
||||
await expect(
|
||||
async () =>
|
||||
await waitForThrow(
|
||||
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen ' +
|
||||
'for one of the following reasons:\n' +
|
||||
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
|
||||
@@ -247,23 +248,22 @@ describe('ReactHooksWithNoopRenderer', () => {
|
||||
'3. You might have more than one copy of React in the same app\n' +
|
||||
'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',
|
||||
),
|
||||
).toErrorDev(
|
||||
'Warning: The <Counter /> component appears to be a function component that returns a class instance. ' +
|
||||
'Change Counter to a class that extends React.Component instead. ' +
|
||||
"If you can't use a class try assigning the prototype on the function as a workaround. " +
|
||||
'`Counter.prototype = React.Component.prototype`. ' +
|
||||
"Don't use an arrow function since it cannot be called with `new` by React.",
|
||||
);
|
||||
).toErrorDev(
|
||||
'Warning: The <Counter /> component appears to be a function component that returns a class instance. ' +
|
||||
'Change Counter to a class that extends React.Component instead. ' +
|
||||
"If you can't use a class try assigning the prototype on the function as a workaround. " +
|
||||
'`Counter.prototype = React.Component.prototype`. ' +
|
||||
"Don't use an arrow function since it cannot be called with `new` by React.",
|
||||
);
|
||||
|
||||
// Confirm that a subsequent hook works properly.
|
||||
function GoodCounter(props) {
|
||||
const [count] = useState(props.initialCount);
|
||||
return <Text text={count} />;
|
||||
}
|
||||
ReactNoop.render(<GoodCounter initialCount={10} />);
|
||||
await waitForAll([10]);
|
||||
});
|
||||
}
|
||||
// Confirm that a subsequent hook works properly.
|
||||
function GoodCounter(props) {
|
||||
const [count] = useState(props.initialCount);
|
||||
return <Text text={count} />;
|
||||
}
|
||||
ReactNoop.render(<GoodCounter initialCount={10} />);
|
||||
await waitForAll([10]);
|
||||
});
|
||||
|
||||
it('throws when called outside the render phase', async () => {
|
||||
expect(() => {
|
||||
@@ -487,20 +487,18 @@ describe('ReactHooksWithNoopRenderer', () => {
|
||||
assertLog(['Foo [0]', 'Bar']);
|
||||
|
||||
// Bar will update Foo during its render phase. React should warn.
|
||||
await act(async () => {
|
||||
root.render(
|
||||
<>
|
||||
<Foo />
|
||||
<Bar triggerUpdate={true} />
|
||||
</>,
|
||||
);
|
||||
expect(() =>
|
||||
expect(Scheduler).toFlushAndYield(['Foo [0]', 'Bar', 'Foo [1]']),
|
||||
).toErrorDev([
|
||||
'Cannot update a component (`Foo`) while rendering a ' +
|
||||
'different component (`Bar`). To locate the bad setState() call inside `Bar`',
|
||||
]);
|
||||
});
|
||||
root.render(
|
||||
<>
|
||||
<Foo />
|
||||
<Bar triggerUpdate={true} />
|
||||
</>,
|
||||
);
|
||||
await expect(
|
||||
async () => await waitForAll(['Foo [0]', 'Bar', 'Foo [1]']),
|
||||
).toErrorDev([
|
||||
'Cannot update a component (`Foo`) while rendering a ' +
|
||||
'different component (`Bar`). To locate the bad setState() call inside `Bar`',
|
||||
]);
|
||||
|
||||
// It should not warn again (deduplication).
|
||||
await act(async () => {
|
||||
@@ -562,7 +560,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
||||
return <Text text={count} />;
|
||||
}
|
||||
ReactNoop.render(<Counter />);
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
'Too many re-renders. React limits the number of renders to prevent ' +
|
||||
'an infinite loop.',
|
||||
);
|
||||
@@ -3805,7 +3803,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
||||
assertLog(['A: 2, B: 3, C: 4']);
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span prop="A: 2, B: 3, C: 4" />);
|
||||
ReactNoop.render(<App loadC={false} />);
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
'Rendered fewer hooks than expected. This may be caused by an ' +
|
||||
'accidental early return statement.',
|
||||
);
|
||||
|
||||
@@ -1896,7 +1896,7 @@ describe('ReactIncremental', () => {
|
||||
});
|
||||
|
||||
if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
|
||||
it('does not leak own context into context provider (factory components)', () => {
|
||||
it('does not leak own context into context provider (factory components)', async () => {
|
||||
function Recurse(props, context) {
|
||||
return {
|
||||
getChildContext() {
|
||||
@@ -1919,13 +1919,14 @@ describe('ReactIncremental', () => {
|
||||
};
|
||||
|
||||
ReactNoop.render(<Recurse />);
|
||||
expect(() =>
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'Recurse {}',
|
||||
'Recurse {"n":2}',
|
||||
'Recurse {"n":1}',
|
||||
'Recurse {"n":0}',
|
||||
]),
|
||||
await expect(
|
||||
async () =>
|
||||
await waitForAll([
|
||||
'Recurse {}',
|
||||
'Recurse {"n":2}',
|
||||
'Recurse {"n":1}',
|
||||
'Recurse {"n":0}',
|
||||
]),
|
||||
).toErrorDev([
|
||||
'Warning: The <Recurse /> component appears to be a function component that returns a class instance. ' +
|
||||
'Change Recurse to a class that extends React.Component instead. ' +
|
||||
@@ -2281,7 +2282,7 @@ describe('ReactIncremental', () => {
|
||||
instance.setState({
|
||||
throwError: true,
|
||||
});
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Error boundaries should implement getDerivedStateFromError()',
|
||||
);
|
||||
});
|
||||
|
||||
+39
-40
@@ -1219,7 +1219,7 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span prop="a" />);
|
||||
});
|
||||
|
||||
it('catches reconciler errors in a boundary during mounting', () => {
|
||||
it('catches reconciler errors in a boundary during mounting', async () => {
|
||||
class ErrorBoundary extends React.Component {
|
||||
state = {error: null};
|
||||
componentDidCatch(error) {
|
||||
@@ -1242,7 +1242,7 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
<BrokenRender />
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([
|
||||
await expect(async () => await waitForAll([])).toErrorDev([
|
||||
'Warning: React.createElement: type is invalid -- expected a string',
|
||||
// React retries once on error
|
||||
'Warning: React.createElement: type is invalid -- expected a string',
|
||||
@@ -1293,7 +1293,7 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
<BrokenRender fail={true} />
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([
|
||||
await expect(async () => await waitForAll([])).toErrorDev([
|
||||
'Warning: React.createElement: type is invalid -- expected a string',
|
||||
// React retries once on error
|
||||
'Warning: React.createElement: type is invalid -- expected a string',
|
||||
@@ -1319,7 +1319,7 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
'Warning: React.createElement: type is invalid -- expected a string',
|
||||
{withoutStack: true},
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
'Element type is invalid: expected a string (for built-in components) or ' +
|
||||
'a class/function (for composite components) but got: undefined.' +
|
||||
(__DEV__
|
||||
@@ -1425,7 +1425,7 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
|
||||
// Unmount
|
||||
ReactNoop.render(<Foo hide={true} />);
|
||||
expect(Scheduler).toFlushAndThrow('Detach error');
|
||||
await waitForThrow('Detach error');
|
||||
assertLog([
|
||||
'barRef detach',
|
||||
// Bar should unmount even though its ref threw an error while detaching
|
||||
@@ -1435,16 +1435,16 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
expect(ReactNoop).toMatchRenderedOutput(null);
|
||||
});
|
||||
|
||||
it('handles error thrown by host config while working on failed root', () => {
|
||||
it('handles error thrown by host config while working on failed root', async () => {
|
||||
ReactNoop.render(<errorInBeginPhase />);
|
||||
expect(Scheduler).toFlushAndThrow('Error in host config.');
|
||||
await waitForThrow('Error in host config.');
|
||||
});
|
||||
|
||||
it('handles error thrown by top-level callback', () => {
|
||||
it('handles error thrown by top-level callback', async () => {
|
||||
ReactNoop.render(<div />, () => {
|
||||
throw new Error('Error!');
|
||||
});
|
||||
expect(Scheduler).toFlushAndThrow('Error!');
|
||||
await waitForThrow('Error!');
|
||||
});
|
||||
|
||||
it('error boundaries capture non-errors', async () => {
|
||||
@@ -1758,37 +1758,36 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
);
|
||||
});
|
||||
|
||||
if (!ReactFeatureFlags.disableModulePatternComponents) {
|
||||
it('handles error thrown inside getDerivedStateFromProps of a module-style context provider', () => {
|
||||
function Provider() {
|
||||
return {
|
||||
getChildContext() {
|
||||
return {foo: 'bar'};
|
||||
},
|
||||
render() {
|
||||
return 'Hi';
|
||||
},
|
||||
};
|
||||
}
|
||||
Provider.childContextTypes = {
|
||||
x: () => {},
|
||||
};
|
||||
Provider.getDerivedStateFromProps = () => {
|
||||
throw new Error('Oops!');
|
||||
// @gate !disableModulePatternComponents
|
||||
it('handles error thrown inside getDerivedStateFromProps of a module-style context provider', async () => {
|
||||
function Provider() {
|
||||
return {
|
||||
getChildContext() {
|
||||
return {foo: 'bar'};
|
||||
},
|
||||
render() {
|
||||
return 'Hi';
|
||||
},
|
||||
};
|
||||
}
|
||||
Provider.childContextTypes = {
|
||||
x: () => {},
|
||||
};
|
||||
Provider.getDerivedStateFromProps = () => {
|
||||
throw new Error('Oops!');
|
||||
};
|
||||
|
||||
ReactNoop.render(<Provider />);
|
||||
expect(() => {
|
||||
expect(Scheduler).toFlushAndThrow('Oops!');
|
||||
}).toErrorDev([
|
||||
'Warning: The <Provider /> component appears to be a function component that returns a class instance. ' +
|
||||
'Change Provider to a class that extends React.Component instead. ' +
|
||||
"If you can't use a class try assigning the prototype on the function as a workaround. " +
|
||||
'`Provider.prototype = React.Component.prototype`. ' +
|
||||
"Don't use an arrow function since it cannot be called with `new` by React.",
|
||||
]);
|
||||
});
|
||||
}
|
||||
ReactNoop.render(<Provider />);
|
||||
await expect(async () => {
|
||||
await waitForThrow('Oops!');
|
||||
}).toErrorDev([
|
||||
'Warning: The <Provider /> component appears to be a function component that returns a class instance. ' +
|
||||
'Change Provider to a class that extends React.Component instead. ' +
|
||||
"If you can't use a class try assigning the prototype on the function as a workaround. " +
|
||||
'`Provider.prototype = React.Component.prototype`. ' +
|
||||
"Don't use an arrow function since it cannot be called with `new` by React.",
|
||||
]);
|
||||
});
|
||||
|
||||
it('uncaught errors should be discarded if the render is aborted', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
@@ -1924,10 +1923,10 @@ describe('ReactIncrementalErrorHandling', () => {
|
||||
});
|
||||
|
||||
if (global.__PERSISTENT__) {
|
||||
it('regression test: should fatal if error is thrown at the root', () => {
|
||||
it('regression test: should fatal if error is thrown at the root', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
root.render('Error when completing root');
|
||||
expect(Scheduler).toFlushAndThrow('Error when completing root');
|
||||
await waitForThrow('Error when completing root');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
+8
-6
@@ -14,6 +14,7 @@ let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let waitForAll;
|
||||
let waitForThrow;
|
||||
|
||||
describe('ReactIncrementalErrorLogging', () => {
|
||||
beforeEach(() => {
|
||||
@@ -24,6 +25,7 @@ describe('ReactIncrementalErrorLogging', () => {
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
});
|
||||
|
||||
// Note: in this test file we won't be using toErrorDev() matchers
|
||||
@@ -39,7 +41,7 @@ describe('ReactIncrementalErrorLogging', () => {
|
||||
oldConsoleError = null;
|
||||
});
|
||||
|
||||
it('should log errors that occur during the begin phase', () => {
|
||||
it('should log errors that occur during the begin phase', async () => {
|
||||
class ErrorThrowingComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -56,7 +58,7 @@ describe('ReactIncrementalErrorLogging', () => {
|
||||
</span>
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow('constructor error');
|
||||
await waitForThrow('constructor error');
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
__DEV__
|
||||
@@ -76,7 +78,7 @@ describe('ReactIncrementalErrorLogging', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should log errors that occur during the commit phase', () => {
|
||||
it('should log errors that occur during the commit phase', async () => {
|
||||
class ErrorThrowingComponent extends React.Component {
|
||||
componentDidMount() {
|
||||
throw new Error('componentDidMount error');
|
||||
@@ -92,7 +94,7 @@ describe('ReactIncrementalErrorLogging', () => {
|
||||
</span>
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow('componentDidMount error');
|
||||
await waitForThrow('componentDidMount error');
|
||||
expect(console.error).toHaveBeenCalledTimes(1);
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
__DEV__
|
||||
@@ -112,7 +114,7 @@ describe('ReactIncrementalErrorLogging', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore errors thrown in log method to prevent cycle', () => {
|
||||
it('should ignore errors thrown in log method to prevent cycle', async () => {
|
||||
const logCapturedErrorCalls = [];
|
||||
console.error.mockImplementation(error => {
|
||||
// Test what happens when logging itself is buggy.
|
||||
@@ -131,7 +133,7 @@ describe('ReactIncrementalErrorLogging', () => {
|
||||
</span>
|
||||
</div>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow('render error');
|
||||
await waitForThrow('render error');
|
||||
expect(logCapturedErrorCalls.length).toBe(1);
|
||||
expect(logCapturedErrorCalls[0]).toEqual(
|
||||
__DEV__
|
||||
|
||||
+4
-4
@@ -12,23 +12,23 @@
|
||||
|
||||
let React;
|
||||
let ReactNoop;
|
||||
let Scheduler;
|
||||
let waitForAll;
|
||||
let waitForThrow;
|
||||
|
||||
describe('ReactIncrementalErrorReplay', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
React = require('react');
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
});
|
||||
|
||||
it('should fail gracefully on error in the host environment', () => {
|
||||
it('should fail gracefully on error in the host environment', async () => {
|
||||
ReactNoop.render(<errorInBeginPhase />);
|
||||
expect(Scheduler).toFlushAndThrow('Error in host config.');
|
||||
await waitForThrow('Error in host config.');
|
||||
});
|
||||
|
||||
it("should ignore error if it doesn't throw on retry", async () => {
|
||||
|
||||
+1
-1
@@ -1296,7 +1296,7 @@ describe('ReactIncrementalSideEffects', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<Foo show={true} />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Warning: Function components cannot be given refs. ' +
|
||||
'Attempts to access this ref will fail. ' +
|
||||
'Did you mean to use React.forwardRef()?\n\n' +
|
||||
|
||||
@@ -421,27 +421,28 @@ describe('ReactIncrementalUpdates', () => {
|
||||
return {a: 'a'};
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
expect(Scheduler).toFlushAndYield(
|
||||
gate(flags =>
|
||||
flags.deferRenderPhaseUpdateToNextBatch
|
||||
? [
|
||||
'setState updater',
|
||||
// In the new reconciler, updates inside the render phase are
|
||||
// treated as if they came from an event, so the update gets
|
||||
// shifted to a subsequent render.
|
||||
'render',
|
||||
'render',
|
||||
]
|
||||
: [
|
||||
'setState updater',
|
||||
// In the old reconciler, updates in the render phase receive
|
||||
// the currently rendering expiration time, so the update
|
||||
// flushes immediately in the same render.
|
||||
'render',
|
||||
],
|
||||
await expect(
|
||||
async () =>
|
||||
await waitForAll(
|
||||
gate(flags =>
|
||||
flags.deferRenderPhaseUpdateToNextBatch
|
||||
? [
|
||||
'setState updater',
|
||||
// In the new reconciler, updates inside the render phase are
|
||||
// treated as if they came from an event, so the update gets
|
||||
// shifted to a subsequent render.
|
||||
'render',
|
||||
'render',
|
||||
]
|
||||
: [
|
||||
'setState updater',
|
||||
// In the old reconciler, updates in the render phase receive
|
||||
// the currently rendering expiration time, so the update
|
||||
// flushes immediately in the same render.
|
||||
'render',
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
).toErrorDev(
|
||||
'An update (setState, replaceState, or forceUpdate) was scheduled ' +
|
||||
'from inside an update function. Update functions should be pure, ' +
|
||||
|
||||
@@ -314,7 +314,7 @@ describe('ReactLazy', () => {
|
||||
|
||||
await resolveFakeImport(T);
|
||||
|
||||
expect(() => expect(Scheduler).toFlushAndYield(['Hi'])).toErrorDev(
|
||||
await expect(async () => await waitForAll(['Hi'])).toErrorDev(
|
||||
'Warning: T: Support for defaultProps ' +
|
||||
'will be removed from function components in a future major ' +
|
||||
'release. Use JavaScript default parameters instead.',
|
||||
@@ -369,8 +369,8 @@ describe('ReactLazy', () => {
|
||||
|
||||
await resolveFakeImport(LazyImpl);
|
||||
|
||||
expect(() =>
|
||||
expect(Scheduler).toFlushAndYield(['Lazy', 'Sibling', 'A']),
|
||||
await expect(
|
||||
async () => await waitForAll(['Lazy', 'Sibling', 'A']),
|
||||
).toErrorDev(
|
||||
'Warning: LazyImpl: Support for defaultProps ' +
|
||||
'will be removed from function components in a future major ' +
|
||||
@@ -676,7 +676,7 @@ describe('ReactLazy', () => {
|
||||
expect(root).not.toMatchRenderedOutput('Hi Bye');
|
||||
|
||||
await resolveFakeImport(T);
|
||||
expect(() => expect(Scheduler).toFlushAndYield(['Hi Bye'])).toErrorDev(
|
||||
await expect(async () => await waitForAll(['Hi Bye'])).toErrorDev(
|
||||
'Warning: T: Support for defaultProps ' +
|
||||
'will be removed from function components in a future major ' +
|
||||
'release. Use JavaScript default parameters instead.',
|
||||
@@ -721,7 +721,7 @@ describe('ReactLazy', () => {
|
||||
<BadLazy />
|
||||
</Suspense>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
'Element type is invalid. Received a promise that resolves to: 42. ' +
|
||||
'Lazy element type must resolve to a class or function.',
|
||||
);
|
||||
@@ -749,7 +749,7 @@ describe('ReactLazy', () => {
|
||||
<Lazy2 text="Hello" />
|
||||
</Suspense>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
'Element type is invalid. Received a promise that resolves to: [object Object]. ' +
|
||||
'Lazy element type must resolve to a class or function.' +
|
||||
(__DEV__
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('memo', () => {
|
||||
return <App ref={() => {}} />;
|
||||
}
|
||||
ReactNoop.render(<Outer />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([
|
||||
await expect(async () => await waitForAll([])).toErrorDev([
|
||||
'Warning: Function components cannot be given refs. Attempts to access ' +
|
||||
'this ref will fail.',
|
||||
]);
|
||||
@@ -76,7 +76,7 @@ describe('memo', () => {
|
||||
return <App ref={() => {}} />;
|
||||
}
|
||||
ReactNoop.render(<Outer />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([
|
||||
await expect(async () => await waitForAll([])).toErrorDev([
|
||||
'App: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
|
||||
'Warning: Function components cannot be given refs. Attempts to access ' +
|
||||
'this ref will fail.',
|
||||
|
||||
+15
-13
@@ -16,6 +16,7 @@ let Scheduler;
|
||||
let gen;
|
||||
let waitForAll;
|
||||
let waitFor;
|
||||
let waitForThrow;
|
||||
|
||||
describe('ReactNewContext', () => {
|
||||
beforeEach(() => {
|
||||
@@ -30,6 +31,7 @@ describe('ReactNewContext', () => {
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -850,14 +852,14 @@ describe('ReactNewContext', () => {
|
||||
}
|
||||
|
||||
describe('Context.Provider', () => {
|
||||
it('warns if no value prop provided', () => {
|
||||
it('warns if no value prop provided', async () => {
|
||||
const Context = React.createContext();
|
||||
|
||||
ReactNoop.render(
|
||||
<Context.Provider anyPropNameOtherThanValue="value could be anything" />,
|
||||
);
|
||||
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'The `value` prop is required for the `<Context.Provider>`. Did you misspell it or forget to pass it?',
|
||||
{
|
||||
withoutStack: true,
|
||||
@@ -1050,11 +1052,11 @@ describe('ReactNewContext', () => {
|
||||
});
|
||||
|
||||
describe('Context.Consumer', () => {
|
||||
it('warns if child is not a function', () => {
|
||||
it('warns if child is not a function', async () => {
|
||||
spyOnDev(console, 'error').mockImplementation(() => {});
|
||||
const Context = React.createContext(0);
|
||||
ReactNoop.render(<Context.Consumer />);
|
||||
expect(Scheduler).toFlushAndThrow('is not a function');
|
||||
await waitForThrow('is not a function');
|
||||
if (__DEV__) {
|
||||
expect(console.error.mock.calls[0][0]).toContain(
|
||||
'A context consumer was rendered with multiple children, or a child ' +
|
||||
@@ -1298,7 +1300,7 @@ describe('ReactNewContext', () => {
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span prop="goodbye" />);
|
||||
});
|
||||
|
||||
it('warns when reading context inside render phase class setState updater', () => {
|
||||
it('warns when reading context inside render phase class setState updater', async () => {
|
||||
const ThemeContext = React.createContext('light');
|
||||
|
||||
class Cls extends React.Component {
|
||||
@@ -1312,7 +1314,7 @@ describe('ReactNewContext', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<Cls />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev([
|
||||
await expect(async () => await waitForAll([])).toErrorDev([
|
||||
'Context can only be read while React is rendering',
|
||||
'Cannot update during an existing state transition',
|
||||
]);
|
||||
@@ -1320,7 +1322,7 @@ describe('ReactNewContext', () => {
|
||||
});
|
||||
|
||||
describe('useContext', () => {
|
||||
it('throws when used in a class component', () => {
|
||||
it('throws when used in a class component', async () => {
|
||||
const Context = React.createContext(0);
|
||||
class Foo extends React.Component {
|
||||
render() {
|
||||
@@ -1328,7 +1330,7 @@ describe('ReactNewContext', () => {
|
||||
}
|
||||
}
|
||||
ReactNoop.render(<Foo />);
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen' +
|
||||
' for one of the following reasons:\n' +
|
||||
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
|
||||
@@ -1338,27 +1340,27 @@ describe('ReactNewContext', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('warns when passed a consumer', () => {
|
||||
it('warns when passed a consumer', async () => {
|
||||
const Context = React.createContext(0);
|
||||
function Foo() {
|
||||
return useContext(Context.Consumer);
|
||||
}
|
||||
ReactNoop.render(<Foo />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Calling useContext(Context.Consumer) is not supported, may cause bugs, ' +
|
||||
'and will be removed in a future major release. ' +
|
||||
'Did you mean to call useContext(Context) instead?',
|
||||
);
|
||||
});
|
||||
|
||||
it('warns when passed a provider', () => {
|
||||
it('warns when passed a provider', async () => {
|
||||
const Context = React.createContext(0);
|
||||
function Foo() {
|
||||
useContext(Context.Provider);
|
||||
return null;
|
||||
}
|
||||
ReactNoop.render(<Foo />);
|
||||
expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
|
||||
await expect(async () => await waitForAll([])).toErrorDev(
|
||||
'Calling useContext(Context.Provider) is not supported. ' +
|
||||
'Did you mean to call useContext(Context) instead?',
|
||||
);
|
||||
@@ -1420,7 +1422,7 @@ describe('ReactNewContext', () => {
|
||||
<Context.Provider value={null} />
|
||||
</errorInCompletePhase>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow('Error in host config.');
|
||||
await waitForThrow('Error in host config.');
|
||||
|
||||
ReactNoop.render(
|
||||
<Context.Provider value={10}>
|
||||
|
||||
@@ -1395,12 +1395,13 @@ describe('ReactInteractionTracing', () => {
|
||||
root.render(<App navigate={true} markerName="marker two" />);
|
||||
ReactNoop.expire(1000);
|
||||
await advanceTimers(1000);
|
||||
expect(() =>
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'onMarkerIncomplete(transition one, marker one, 1000, [{endTime: 3000, name: marker one, newName: marker two, type: marker}])',
|
||||
]),
|
||||
await expect(
|
||||
async () =>
|
||||
await waitForAll([
|
||||
'Suspend [Page Two]',
|
||||
'Loading...',
|
||||
'onMarkerIncomplete(transition one, marker one, 1000, [{endTime: 3000, name: marker one, newName: marker two, type: marker}])',
|
||||
]),
|
||||
).toErrorDev('');
|
||||
|
||||
resolveText('Page Two');
|
||||
|
||||
@@ -28,6 +28,7 @@ describe('useEffectEvent', () => {
|
||||
let useMemo;
|
||||
let waitForAll;
|
||||
let assertLog;
|
||||
let waitForThrow;
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
@@ -46,6 +47,7 @@ describe('useEffectEvent', () => {
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
});
|
||||
|
||||
function Text(props) {
|
||||
@@ -242,7 +244,7 @@ describe('useEffectEvent', () => {
|
||||
});
|
||||
|
||||
// @gate enableUseEffectEventHook
|
||||
it('throws when called in render', () => {
|
||||
it('throws when called in render', async () => {
|
||||
class IncrementButton extends React.PureComponent {
|
||||
increment = () => {
|
||||
this.props.onClick();
|
||||
@@ -269,7 +271,7 @@ describe('useEffectEvent', () => {
|
||||
}
|
||||
|
||||
ReactNoop.render(<Counter incrementBy={1} />);
|
||||
expect(Scheduler).toFlushAndThrow(
|
||||
await waitForThrow(
|
||||
"A function wrapped in useEffectEvent can't be called during rendering.",
|
||||
);
|
||||
|
||||
|
||||
@@ -1518,16 +1518,14 @@ describe('useMutableSource', () => {
|
||||
}
|
||||
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(async () => {
|
||||
root.render(
|
||||
<>
|
||||
<Read />
|
||||
</>,
|
||||
);
|
||||
expect(() => expect(Scheduler).toFlushAndYield(['a'])).toErrorDev(
|
||||
'Mutable source should not return a function as the snapshot value.',
|
||||
);
|
||||
});
|
||||
root.render(
|
||||
<>
|
||||
<Read />
|
||||
</>,
|
||||
);
|
||||
await expect(async () => await waitForAll(['a'])).toErrorDev(
|
||||
'Mutable source should not return a function as the snapshot value.',
|
||||
);
|
||||
expect(root).toMatchRenderedOutput('a');
|
||||
});
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ let AdvanceTime;
|
||||
let assertLog;
|
||||
let waitFor;
|
||||
let waitForAll;
|
||||
let waitForThrow;
|
||||
|
||||
function loadModules({
|
||||
enableProfilerTimer = true,
|
||||
@@ -56,6 +57,7 @@ function loadModules({
|
||||
assertLog = InternalTestUtils.assertLog;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
|
||||
AdvanceTime = class extends React.Component {
|
||||
static defaultProps = {
|
||||
@@ -1230,7 +1232,7 @@ describe(`onRender`, () => {
|
||||
<errorInCompletePhase>hi</errorInCompletePhase>
|
||||
</React.Profiler>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow('Error in host config.');
|
||||
await waitForThrow('Error in host config.');
|
||||
|
||||
// A similar case we've seen caused by an invariant in ReactDOM.
|
||||
// It didn't reproduce without a host component inside.
|
||||
@@ -1241,7 +1243,7 @@ describe(`onRender`, () => {
|
||||
</errorInCompletePhase>
|
||||
</React.Profiler>,
|
||||
);
|
||||
expect(Scheduler).toFlushAndThrow('Error in host config.');
|
||||
await waitForThrow('Error in host config.');
|
||||
|
||||
// So long as the profiler timer's fiber stack is reset correctly,
|
||||
// Subsequent renders should not error.
|
||||
|
||||
@@ -144,7 +144,8 @@ describe('Scheduler', () => {
|
||||
assertLog([]);
|
||||
|
||||
Scheduler.unstable_advanceTime(1);
|
||||
expect(Scheduler).toFlushExpired(['A']);
|
||||
Scheduler.unstable_flushExpired();
|
||||
assertLog(['A']);
|
||||
});
|
||||
|
||||
it('continues working on same task after yielding', async () => {
|
||||
@@ -221,7 +222,8 @@ describe('Scheduler', () => {
|
||||
|
||||
// Advance time by just a bit more. This should expire all the remaining work.
|
||||
Scheduler.unstable_advanceTime(1);
|
||||
expect(Scheduler).toFlushExpired(['C', 'D']);
|
||||
Scheduler.unstable_flushExpired();
|
||||
assertLog(['C', 'D']);
|
||||
});
|
||||
|
||||
it('continuations are interrupted by higher priority work', async () => {
|
||||
@@ -326,7 +328,8 @@ describe('Scheduler', () => {
|
||||
// Immediate callback hasn't fired, yet.
|
||||
assertLog([]);
|
||||
// They all flush immediately within the subsequent task.
|
||||
expect(Scheduler).toFlushExpired(['A', 'B', 'C', 'D']);
|
||||
Scheduler.unstable_flushExpired();
|
||||
assertLog(['A', 'B', 'C', 'D']);
|
||||
});
|
||||
|
||||
it('nested immediate callbacks are added to the queue of immediate callbacks', () => {
|
||||
@@ -345,7 +348,8 @@ describe('Scheduler', () => {
|
||||
);
|
||||
assertLog([]);
|
||||
// C should flush at the end
|
||||
expect(Scheduler).toFlushExpired(['A', 'B', 'D', 'C']);
|
||||
Scheduler.unstable_flushExpired();
|
||||
assertLog(['A', 'B', 'D', 'C']);
|
||||
});
|
||||
|
||||
it('wrapped callbacks have same signature as original callback', () => {
|
||||
@@ -410,12 +414,12 @@ describe('Scheduler', () => {
|
||||
throw new Error('Oops C');
|
||||
});
|
||||
|
||||
expect(() => expect(Scheduler).toFlushExpired()).toThrow('Oops A');
|
||||
expect(() => Scheduler.unstable_flushExpired()).toThrow('Oops A');
|
||||
assertLog(['A']);
|
||||
|
||||
// B and C flush in a subsequent event. That way, the second error is not
|
||||
// swallowed.
|
||||
expect(() => expect(Scheduler).toFlushExpired()).toThrow('Oops C');
|
||||
expect(() => Scheduler.unstable_flushExpired()).toThrow('Oops C');
|
||||
assertLog(['B', 'C']);
|
||||
});
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ let cancelCallback;
|
||||
// let shouldYield;
|
||||
let waitForAll;
|
||||
let waitFor;
|
||||
let waitForThrow;
|
||||
|
||||
function priorityLevelToString(priorityLevel) {
|
||||
switch (priorityLevel) {
|
||||
@@ -75,6 +76,7 @@ describe('Scheduler', () => {
|
||||
const InternalTestUtils = require('internal-test-utils');
|
||||
waitForAll = InternalTestUtils.waitForAll;
|
||||
waitFor = InternalTestUtils.waitFor;
|
||||
waitForThrow = InternalTestUtils.waitForThrow;
|
||||
});
|
||||
|
||||
const TaskStartEvent = 1;
|
||||
@@ -335,7 +337,7 @@ Task 1 [Normal] │██████░░🡐 canceled
|
||||
throw Error('Oops');
|
||||
});
|
||||
|
||||
expect(Scheduler).toFlushAndThrow('Oops');
|
||||
await waitForThrow('Oops');
|
||||
Scheduler.unstable_advanceTime(100);
|
||||
|
||||
Scheduler.unstable_advanceTime(1000);
|
||||
|
||||
Reference in New Issue
Block a user