[tests] remove withoutStack from assertConsole helpers (#35498)

Stacked on https://github.com/facebook/react/pull/35497

-----

Now that the assert helpers require a component stack, we don't need the
`{withoutStack: true}` option.
This commit is contained in:
Ricky
2026-01-27 22:34:03 -05:00
committed by GitHub
parent bed6200ba1
commit 28715701c7
43 changed files with 872 additions and 2053 deletions
@@ -568,36 +568,6 @@ describe('ReactInternalTestUtils console assertions', () => {
`);
});
// @gate __DEV__
it('fails if local withoutStack passed to assertConsoleLogDev', () => {
const message = expectToThrowFailure(() => {
console.log('Hello');
assertConsoleLogDev([['Hello', {withoutStack: true}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleLogDev(expected)
Do not pass withoutStack to assertConsoleLogDev logs, console.log does not have component stacks."
`);
});
// @gate __DEV__
it('fails if global withoutStack passed to assertConsoleLogDev', () => {
const message = expectToThrowFailure(() => {
console.log('Hello');
assertConsoleLogDev(['Hello'], {withoutStack: true});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleLogDev(expected)
Do not pass withoutStack to assertConsoleLogDev, console.log does not have component stacks."
`);
assertConsoleLogDev(['Hello']);
});
// @gate __DEV__
it('fails if the args is greater than %s argument number', () => {
const message = expectToThrowFailure(() => {
@@ -1173,23 +1143,6 @@ describe('ReactInternalTestUtils console assertions', () => {
`);
});
// @gate __DEV__
it('fails if only warning does not contain a stack', () => {
const message = expectToThrowFailure(() => {
console.warn('Hello');
assertConsoleWarnDev(['Hello']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Missing component stack for:
"Hello"
If this warning should omit a component stack, pass [log, {withoutStack: true}].
If all warnings should omit the component stack, add {withoutStack: true} to the assertConsoleWarnDev call."
`);
});
// @gate __DEV__
it('fails if first warning does not contain a stack', () => {
const message = expectToThrowFailure(() => {
@@ -1277,287 +1230,11 @@ describe('ReactInternalTestUtils console assertions', () => {
`);
});
describe('global withoutStack', () => {
it('passes if warnings without stack explicitly opt out', () => {
if (__DEV__) {
console.warn('Hello');
}
assertConsoleWarnDev(['Hello'], {withoutStack: true});
if (__DEV__) {
console.warn('Hello');
console.warn('Good day');
console.warn('Bye');
}
assertConsoleWarnDev(['Hello', 'Good day', 'Bye'], {
withoutStack: true,
});
});
// @gate __DEV__
it('fails if withoutStack is invalid null value', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi');
assertConsoleWarnDev(['Hi'], {withoutStack: null});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
The second argument must be {withoutStack: true}.
Instead received {"withoutStack":null}."
`);
assertConsoleWarnDev(['Hi'], {withoutStack: true});
});
// @gate __DEV__
it('fails if withoutStack is invalid {} value', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi');
assertConsoleWarnDev(['Hi'], {withoutStack: {}});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
The second argument must be {withoutStack: true}.
Instead received {"withoutStack":{}}."
`);
assertConsoleWarnDev(['Hi'], {withoutStack: true});
});
// @gate __DEV__
it('fails if withoutStack is invalid string value', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi');
assertConsoleWarnDev(['Hi'], {withoutStack: 'haha'});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
The second argument must be {withoutStack: true}.
Instead received {"withoutStack":"haha"}."
`);
assertConsoleWarnDev(['Hi'], {withoutStack: true});
});
// @gate __DEV__
it('fails if only warning is not expected to have a stack, but does', () => {
const message = expectToThrowFailure(() => {
console.warn('Hello\n in div');
assertConsoleWarnDev(['Hello'], {withoutStack: true});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Unexpected warning(s) recorded.
- Expected warnings
+ Received warnings
- Hello
+ Hello in div (at **)"
`);
});
// @gate __DEV__
it('fails if warnings are not expected to have a stack, but some do', () => {
const message = expectToThrowFailure(() => {
console.warn('Hello\n in div');
console.warn('Good day');
console.warn('Bye\n in div');
assertConsoleWarnDev(['Hello', 'Good day', 'Bye'], {
withoutStack: true,
});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Unexpected warning(s) recorded.
- Expected warnings
+ Received warnings
- Hello
+ Hello in div (at **)
Good day
- Bye
+ Bye in div (at **)"
`);
});
});
describe('local withoutStack', () => {
it('passes when expected withoutStack logs matches the actual logs', () => {
if (__DEV__) {
console.warn('Hello\n in div');
console.warn('Good day');
console.warn('Bye\n in div');
}
assertConsoleWarnDev([
'Hello\n in div',
['Good day', {withoutStack: true}],
'Bye\n in div',
]);
});
// @gate __DEV__
it('fails if withoutStack is invalid null value', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi');
assertConsoleWarnDev([['Hi', {withoutStack: null}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":null}]."
`);
});
// @gate __DEV__
it('fails if withoutStack is invalid {} value', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi');
assertConsoleWarnDev([['Hi', {withoutStack: {}}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":{}}]."
`);
});
// @gate __DEV__
it('fails if withoutStack is invalid string value', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi');
assertConsoleWarnDev([['Hi', {withoutStack: 'haha'}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":"haha"}]."
`);
});
// @gate __DEV__
it('fails if withoutStack is invalid number value', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi');
assertConsoleWarnDev([['Hi', {withoutStack: 4}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":4}]."
`);
});
// @gate __DEV__
it('fails if you forget to wrap local withoutStack in array', () => {
const message = expectToThrowFailure(() => {
console.warn('Hello\n in div');
console.warn('Bye\n in div');
assertConsoleWarnDev(['Hello', {withoutStack: true}, 'Bye']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Did you forget to wrap a log with withoutStack in an array?
The expected message for assertConsoleWarnDev() must be a string or an array of length 2.
Instead received {"withoutStack":true}."
`);
});
// @gate __DEV__
it('fails if you wrap in an array unnecessarily', () => {
const message = expectToThrowFailure(() => {
console.warn('Hello');
assertConsoleWarnDev([['Hello']]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Did you forget to remove the array around the log?
The expected message for assertConsoleWarnDev() must be a string or an array of length 2, but there's only one item in the array. If this is intentional, remove the extra array."
`);
});
// @gate __DEV__
it('fails if only warning is not expected to have a stack, but does', () => {
const message = expectToThrowFailure(() => {
console.warn('Hello\n in div');
assertConsoleWarnDev([['Hello', {withoutStack: true}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Unexpected warning(s) recorded.
- Expected warnings
+ Received warnings
- Hello
+ Hello in div (at **)"
`);
});
// @gate __DEV__
it('fails if warnings are not expected to have a stack, but some do', () => {
const message = expectToThrowFailure(() => {
console.warn('Hello\n in div');
console.warn('Good day');
console.warn('Bye\n in div');
assertConsoleWarnDev([
[
'Hello',
{
withoutStack: true,
},
],
'Good day',
[
'Bye',
{
withoutStack: true,
},
],
]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
Unexpected warning(s) recorded.
- Expected warnings
+ Received warnings
- Hello
+ Hello in div (at **)
Good day
- Bye
+ Bye in div (at **)"
`);
});
});
// @gate __DEV__
it('fails if the args is greater than %s argument number', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi %s', 'Sara', 'extra');
assertConsoleWarnDev(['Hi'], {withoutStack: true});
assertConsoleWarnDev(['Hi']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
@@ -1572,7 +1249,7 @@ describe('ReactInternalTestUtils console assertions', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi %s', 'Sara', 'extra');
console.warn('Bye %s', 'Sara', 'extra');
assertConsoleWarnDev(['Hi', 'Bye'], {withoutStack: true});
assertConsoleWarnDev(['Hi', 'Bye']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
@@ -1589,7 +1266,7 @@ describe('ReactInternalTestUtils console assertions', () => {
it('fails if the %s argument number is greater than args', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi %s');
assertConsoleWarnDev(['Hi'], {withoutStack: true});
assertConsoleWarnDev(['Hi']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
@@ -1604,7 +1281,7 @@ describe('ReactInternalTestUtils console assertions', () => {
const message = expectToThrowFailure(() => {
console.warn('Hi %s');
console.warn('Bye %s');
assertConsoleWarnDev(['Hi', 'Bye'], {withoutStack: true});
assertConsoleWarnDev(['Hi', 'Bye']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleWarnDev(expected)
@@ -2217,7 +1894,7 @@ describe('ReactInternalTestUtils console assertions', () => {
"TypeError: Cannot read properties of undefined (reading 'stack')\n" +
' in Foo (at **)'
);
assertConsoleErrorDev([['Hi', {withoutStack: true}]]);
assertConsoleErrorDev(['Hi']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
@@ -2254,313 +1931,11 @@ describe('ReactInternalTestUtils console assertions', () => {
`);
});
describe('global withoutStack', () => {
it('passes if errors without stack explicitly opt out', () => {
if (__DEV__) {
console.error('Hello');
}
assertConsoleErrorDev(['Hello'], {withoutStack: true});
if (__DEV__) {
console.error('Hello');
console.error('Good day');
console.error('Bye');
}
assertConsoleErrorDev(['Hello', 'Good day', 'Bye'], {
withoutStack: true,
});
});
// @gate __DEV__
it('fails if withoutStack is invalid null value', () => {
const message = expectToThrowFailure(() => {
console.error('Hi');
assertConsoleErrorDev(['Hi'], {withoutStack: null});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
The second argument must be {withoutStack: true}.
Instead received {"withoutStack":null}."
`);
assertConsoleErrorDev(['Hi'], {withoutStack: true});
});
// @gate __DEV__
it('fails if withoutStack is invalid {} value', () => {
const message = expectToThrowFailure(() => {
console.error('Hi');
assertConsoleErrorDev(['Hi'], {withoutStack: {}});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
The second argument must be {withoutStack: true}.
Instead received {"withoutStack":{}}."
`);
assertConsoleErrorDev(['Hi'], {withoutStack: true});
});
// @gate __DEV__
it('fails if withoutStack is invalid string value', () => {
const message = expectToThrowFailure(() => {
console.error('Hi');
assertConsoleErrorDev(['Hi'], {withoutStack: 'haha'});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
The second argument must be {withoutStack: true}.
Instead received {"withoutStack":"haha"}."
`);
assertConsoleErrorDev(['Hi'], {withoutStack: true});
});
// @gate __DEV__
it('fails if only error is not expected to have a stack, but does', () => {
const message = expectToThrowFailure(() => {
console.error('Hello\n in div');
assertConsoleErrorDev(['Hello'], {withoutStack: true});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Unexpected error(s) recorded.
- Expected errors
+ Received errors
- Hello
+ Hello in div (at **)"
`);
});
// @gate __DEV__
it('fails if errors are not expected to have a stack, but some do', () => {
const message = expectToThrowFailure(() => {
console.error('Hello\n in div');
console.error('Good day');
console.error('Bye\n in div');
assertConsoleErrorDev(['Hello', 'Good day', 'Bye'], {
withoutStack: true,
});
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Unexpected error(s) recorded.
- Expected errors
+ Received errors
- Hello
+ Hello in div (at **)
Good day
- Bye
+ Bye in div (at **)"
`);
});
});
describe('local withoutStack', () => {
it('passes when expected withoutStack logs matches the actual logs', () => {
if (__DEV__) {
console.error('Hello\n in div');
console.error('Good day');
console.error('Bye\n in div');
}
assertConsoleErrorDev([
'Hello\n in div',
['Good day', {withoutStack: true}],
'Bye\n in div',
]);
});
// @gate __DEV__
it('fails if withoutStack is invalid null value', () => {
const message = expectToThrowFailure(() => {
console.error('Hi');
assertConsoleErrorDev([['Hi', {withoutStack: null}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":null}]."
`);
});
// @gate __DEV__
it('fails if withoutStack is invalid {} value', () => {
const message = expectToThrowFailure(() => {
console.error('Hi');
assertConsoleErrorDev([['Hi', {withoutStack: {}}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":{}}]."
`);
});
// @gate __DEV__
it('fails if withoutStack is invalid string value', () => {
const message = expectToThrowFailure(() => {
console.error('Hi');
assertConsoleErrorDev([['Hi', {withoutStack: 'haha'}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":"haha"}]."
`);
});
// @gate __DEV__
it('fails if withoutStack is invalid number value', () => {
const message = expectToThrowFailure(() => {
console.error('Hi');
assertConsoleErrorDev([['Hi', {withoutStack: 4}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Log entries that are arrays must be of the form [string, {withoutStack: true}]
Instead received [string, {"withoutStack":4}]."
`);
});
// @gate __DEV__
it('fails if you forget to wrap local withoutStack in array', () => {
const message = expectToThrowFailure(() => {
console.error('Hello\n in div');
console.error('Bye\n in div');
assertConsoleErrorDev(['Hello', {withoutStack: true}, 'Bye']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Did you forget to wrap a log with withoutStack in an array?
The expected message for assertConsoleErrorDev() must be a string or an array of length 2.
Instead received {"withoutStack":true}."
`);
});
// @gate __DEV__
it('fails if you wrap in an array unnecessarily', () => {
const message = expectToThrowFailure(() => {
console.error('Hello');
assertConsoleErrorDev([['Hello']]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Did you forget to remove the array around the log?
The expected message for assertConsoleErrorDev() must be a string or an array of length 2, but there's only one item in the array. If this is intentional, remove the extra array."
`);
});
// @gate __DEV__
it('fails if only error is not expected to have a stack, but does', () => {
const message = expectToThrowFailure(() => {
console.error('Hello\n in div');
assertConsoleErrorDev([['Hello', {withoutStack: true}]]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Unexpected error(s) recorded.
- Expected errors
+ Received errors
- Hello
+ Hello in div (at **)"
`);
});
// @gate __DEV__
it('fails if errors are not expected to have a stack, but some do', () => {
const message = expectToThrowFailure(() => {
console.error('Hello\n in div');
console.error('Good day');
console.error('Bye\n in div');
assertConsoleErrorDev([
[
'Hello',
{
withoutStack: true,
},
],
'Good day',
[
'Bye',
{
withoutStack: true,
},
],
]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Unexpected error(s) recorded.
- Expected errors
+ Received errors
- Hello
+ Hello in div (at **)
Good day
- Bye
+ Bye in div (at **)"
`);
});
// @gate __DEV__
it('fails with a helpful error message if the expected error message mismatches', () => {
const message = expectToThrowFailure(() => {
console.error('Bye\n in div');
assertConsoleErrorDev([
[
'Hello',
{
withoutStack: true,
},
],
]);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
Unexpected error(s) recorded.
- Expected errors
+ Received errors
- Hello
+ Bye in div (at **)"
`);
});
});
// @gate __DEV__
it('fails if the args is greater than %s argument number', () => {
const message = expectToThrowFailure(() => {
console.error('Hi %s', 'Sara', 'extra');
assertConsoleErrorDev(['Hi'], {withoutStack: true});
assertConsoleErrorDev(['Hi']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
@@ -2575,7 +1950,7 @@ describe('ReactInternalTestUtils console assertions', () => {
const message = expectToThrowFailure(() => {
console.error('Hi %s', 'Sara', 'extra');
console.error('Bye %s', 'Sara', 'extra');
assertConsoleErrorDev(['Hi', 'Bye'], {withoutStack: true});
assertConsoleErrorDev(['Hi', 'Bye']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
@@ -2592,7 +1967,7 @@ describe('ReactInternalTestUtils console assertions', () => {
it('fails if the %s argument number is greater than args', () => {
const message = expectToThrowFailure(() => {
console.error('Hi %s');
assertConsoleErrorDev(['Hi'], {withoutStack: true});
assertConsoleErrorDev(['Hi']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
@@ -2607,7 +1982,7 @@ describe('ReactInternalTestUtils console assertions', () => {
const message = expectToThrowFailure(() => {
console.error('Hi %s');
console.error('Bye %s');
assertConsoleErrorDev(['Hi', 'Bye'], {withoutStack: true});
assertConsoleErrorDev(['Hi', 'Bye']);
});
expect(message).toMatchInlineSnapshot(`
"assertConsoleErrorDev(expected)
@@ -2812,27 +2187,21 @@ describe('ReactInternalTestUtils console assertions', () => {
it('expands [Server] to ANSI escape sequence for server badge', () => {
const badge = '\u001b[0m\u001b[7m Server \u001b[0m';
console.error(badge + 'Error: something went wrong');
assertConsoleErrorDev([
['[Server] Error: something went wrong', {withoutStack: true}],
]);
assertConsoleErrorDev(['[Server] Error: something went wrong']);
});
// @gate __DEV__
it('expands [Prerender] to ANSI escape sequence for server badge', () => {
const badge = '\u001b[0m\u001b[7m Prerender \u001b[0m';
console.error(badge + 'Error: something went wrong');
assertConsoleErrorDev([
['[Prerender] Error: something went wrong', {withoutStack: true}],
]);
assertConsoleErrorDev(['[Prerender] Error: something went wrong']);
});
// @gate __DEV__
it('expands [Cache] to ANSI escape sequence for server badge', () => {
const badge = '\u001b[0m\u001b[7m Cache \u001b[0m';
console.error(badge + 'Error: something went wrong');
assertConsoleErrorDev([
['[Cache] Error: something went wrong', {withoutStack: true}],
]);
assertConsoleErrorDev(['[Cache] Error: something went wrong']);
});
});
+3 -125
View File
@@ -290,26 +290,11 @@ export function createLogAssertion(
}
}
const withoutStack = options.withoutStack;
if (consoleMethod === 'log' && withoutStack !== undefined) {
throwFormattedError(
`Do not pass withoutStack to assertConsoleLogDev, console.log does not have component stacks.`,
);
} else if (withoutStack !== undefined && withoutStack !== true) {
throwFormattedError(
`The second argument must be {withoutStack: true}.` +
`\n\nInstead received ${JSON.stringify(options)}.`,
);
}
const observedLogs = clearObservedErrors();
const receivedLogs = [];
const missingExpectedLogs = Array.from(expectedMessages);
const unexpectedLogs = [];
const unexpectedMissingComponentStack = [];
const unexpectedIncludingComponentStack = [];
const unexpectedMissingErrorStack = [];
const unexpectedIncludingErrorStack = [];
const logsMismatchingFormat = [];
@@ -334,72 +319,12 @@ export function createLogAssertion(
}
let expectedMessage;
let expectedWithoutStack;
const expectedMessageOrArray = expectedMessages[index];
if (
expectedMessageOrArray != null &&
Array.isArray(expectedMessageOrArray)
) {
// Should be in the local form assert([['log', {withoutStack: true}]])
// Some validations for common mistakes.
if (expectedMessageOrArray.length === 1) {
throwFormattedError(
`Did you forget to remove the array around the log?` +
`\n\nThe expected message for ${matcherName}() must be a string or an array of length 2, but there's only one item in the array. If this is intentional, remove the extra array.`,
);
} else if (expectedMessageOrArray.length !== 2) {
throwFormattedError(
`The expected message for ${matcherName}() must be a string or an array of length 2. ` +
`Instead received ${expectedMessageOrArray}.`,
);
} else if (consoleMethod === 'log') {
// We don't expect any console.log calls to have a stack.
throwFormattedError(
`Do not pass withoutStack to assertConsoleLogDev logs, console.log does not have component stacks.`,
);
}
// Format is correct, check the values.
const currentExpectedMessage = expectedMessageOrArray[0];
const currentExpectedOptions = expectedMessageOrArray[1];
if (
typeof currentExpectedMessage !== 'string' ||
typeof currentExpectedOptions !== 'object' ||
currentExpectedOptions.withoutStack !== true
) {
throwFormattedError(
`Log entries that are arrays must be of the form [string, {withoutStack: true}]` +
`\n\nInstead received [${typeof currentExpectedMessage}, ${JSON.stringify(
currentExpectedOptions,
)}].`,
);
}
expectedMessage = normalizeExpectedMessage(currentExpectedMessage);
expectedWithoutStack = expectedMessageOrArray[1].withoutStack;
} else if (typeof expectedMessageOrArray === 'string') {
if (typeof expectedMessageOrArray === 'string') {
expectedMessage = normalizeExpectedMessage(expectedMessageOrArray);
// withoutStack: inherit from global option - simplify when withoutStack is removed.
if (consoleMethod === 'log') {
expectedWithoutStack = true;
} else {
expectedWithoutStack = withoutStack;
}
} else if (
typeof expectedMessageOrArray === 'object' &&
expectedMessageOrArray != null &&
expectedMessageOrArray.withoutStack != null
) {
// Special case for common case of a wrong withoutStack value.
throwFormattedError(
`Did you forget to wrap a log with withoutStack in an array?` +
`\n\nThe expected message for ${matcherName}() must be a string or an array of length 2.` +
`\n\nInstead received ${JSON.stringify(expectedMessageOrArray)}.`,
);
} else if (expectedMessageOrArray != null) {
throwFormattedError(
`The expected message for ${matcherName}() must be a string or an array of length 2. ` +
`The expected message for ${matcherName}() must be a string. ` +
`Instead received ${JSON.stringify(expectedMessageOrArray)}.`,
);
}
@@ -499,18 +424,6 @@ export function createLogAssertion(
}
if (matchesExpectedMessage) {
// withoutStack: Check for unexpected/missing component stacks.
// These checks can be simplified when withoutStack is removed.
if (isLikelyAComponentStack(normalizedMessage)) {
if (expectedWithoutStack === true && !hasErrorStack) {
// Only report unexpected component stack if it's not an error stack
// (error stacks look like component stacks after normalization)
unexpectedIncludingComponentStack.push(normalizedMessage);
}
} else if (expectedWithoutStack !== true && !expectsErrorStack) {
unexpectedMissingComponentStack.push(normalizedMessage);
}
// Check for unexpected/missing error stacks
if (hasErrorStack && !expectsErrorStack) {
// Error stack is present but \n in <stack> was not in the expected message
@@ -538,12 +451,7 @@ export function createLogAssertion(
function printDiff() {
return `${diff(
expectedMessages
.map(messageOrTuple => {
const message = Array.isArray(messageOrTuple)
? messageOrTuple[0]
: messageOrTuple;
return message.replace('\n', ' ');
})
.map(message => message.replace('\n', ' '))
.join('\n'),
receivedLogs.map(message => message.replace('\n', ' ')).join('\n'),
{
@@ -582,36 +490,6 @@ export function createLogAssertion(
);
}
// Any logs that include a component stack but shouldn't.
if (unexpectedIncludingComponentStack.length > 0) {
throwFormattedError(
`${unexpectedIncludingComponentStack
.map(
stack =>
`Unexpected component stack for:\n ${printReceived(stack)}`,
)
.join(
'\n\n',
)}\n\nIf this ${logName()} should include a component stack, remove {withoutStack: true} from this ${logName()}.` +
`\nIf all ${logName()}s should include the component stack, you may need to remove {withoutStack: true} from the ${matcherName} call.`,
);
}
// Any logs that are missing a component stack without withoutStack.
if (unexpectedMissingComponentStack.length > 0) {
throwFormattedError(
`${unexpectedMissingComponentStack
.map(
stack =>
`Missing component stack for:\n ${printReceived(stack)}`,
)
.join(
'\n\n',
)}\n\nIf this ${logName()} should omit a component stack, pass [log, {withoutStack: true}].` +
`\nIf all ${logName()}s should omit the component stack, add {withoutStack: true} to the ${matcherName} call.`,
);
}
// Any logs that include an error stack trace but \n in <stack> wasn't expected.
if (unexpectedIncludingErrorStack.length > 0) {
throwFormattedError(
+58 -88
View File
@@ -1514,16 +1514,13 @@ describe('ReactFlight', () => {
},
};
const transport = ReactNoopFlightServer.render(<input value={obj} />);
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
]);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
@@ -1545,14 +1542,11 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render(
<div>Womp womp: {new MyError('spaghetti')}</div>,
);
assertConsoleErrorDev(
[
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
]);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
@@ -1565,15 +1559,12 @@ describe('ReactFlight', () => {
it('should warn in DEV if a special object is passed to a host component', () => {
const transport = ReactNoopFlightServer.render(<input value={Math} />);
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
]);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
@@ -1589,15 +1580,12 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render(
<input value={{[Symbol.iterator]: {}}} />,
);
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
]);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
@@ -1620,16 +1608,13 @@ describe('ReactFlight', () => {
}
const Client = clientReference(ClientImpl);
const transport = ReactNoopFlightServer.render(<Client value={obj} />);
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
]);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
@@ -1655,16 +1640,13 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render(
<Client>Current date: {obj}</Client>,
);
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
]);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
@@ -1683,15 +1665,12 @@ describe('ReactFlight', () => {
}
const Client = clientReference(ClientImpl);
const transport = ReactNoopFlightServer.render(<Client value={Math} />);
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
]);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
@@ -1712,15 +1691,12 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />,
);
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
]);
ReactNoopFlightClient.read(transport);
@@ -1744,13 +1720,10 @@ describe('ReactFlight', () => {
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
@@ -1769,13 +1742,10 @@ describe('ReactFlight', () => {
);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
+157 -193
View File
@@ -642,35 +642,32 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in Component (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
]);
});
it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', async () => {
@@ -708,35 +705,32 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in Component (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: Component',
]);
await act(() => {
root.render(<Component value={2} />);
@@ -810,25 +804,22 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in AllLegacyLifecycles (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
]);
class WillMount extends React.Component {
state = {};
@@ -877,18 +868,15 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in WillMountAndUpdate (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillMountAndUpdate',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillMountAndUpdate',
]);
class WillReceiveProps extends React.Component {
state = {};
@@ -912,23 +900,18 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in WillReceiveProps (at **)',
]);
assertConsoleWarnDev(
[
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillReceiveProps',
],
{
withoutStack: true,
},
);
assertConsoleWarnDev([
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillReceiveProps',
]);
});
it('should warn about deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', async () => {
@@ -958,25 +941,22 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in AllLegacyLifecycles (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: AllLegacyLifecycles',
]);
class WillMount extends React.Component {
state = {};
@@ -1023,20 +1003,15 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in WillMountAndUpdate (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillMountAndUpdate',
],
{
withoutStack: true,
},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillMountAndUpdate',
]);
class WillReceiveProps extends React.Component {
state = {};
@@ -1059,23 +1034,18 @@ describe('ReactComponentLifeCycle', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in WillReceiveProps (at **)',
]);
assertConsoleWarnDev(
[
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillReceiveProps',
],
{
withoutStack: true,
},
);
assertConsoleWarnDev([
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: WillReceiveProps',
]);
});
it('should warn if getDerivedStateFromProps returns undefined', async () => {
@@ -1162,35 +1132,32 @@ describe('ReactComponentLifeCycle', () => {
await act(() => {
root.render(<MyComponent foo="bar" />);
});
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: MyComponent',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: MyComponent',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: MyComponent',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: MyComponent',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your code to use " +
'memoization techniques or move it to static getDerivedStateFromProps. ' +
'Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: MyComponent',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' +
'Please update the following components: MyComponent',
]);
expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
log.length = 0;
@@ -1488,30 +1455,27 @@ describe('ReactComponentLifeCycle', () => {
await act(() => {
root.render(<MyComponent x={1} />);
});
assertConsoleWarnDev(
[
`componentWillMount has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
assertConsoleWarnDev([
`componentWillMount has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move code with side effects to componentDidMount, and set initial state in the constructor.
* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
Please update the following components: MyComponent`,
`componentWillReceiveProps has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
`componentWillReceiveProps has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state
* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
Please update the following components: MyComponent`,
`componentWillUpdate has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
`componentWillUpdate has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
Please update the following components: MyComponent`,
],
{withoutStack: true},
);
]);
// Dedupe check (update and instantiate new)
await act(() => {
+24 -42
View File
@@ -195,13 +195,10 @@ describe('ReactDOM', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be a function. Instead received: no.',
'Expected the last optional `callback` argument to be a function. Instead received: no.',
],
{withoutStack: 2},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be a function. Instead received: no.',
'Expected the last optional `callback` argument to be a function. Instead received: no.',
]);
await expect(async () => {
await act(() => {
@@ -211,13 +208,10 @@ describe('ReactDOM', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }",
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.",
],
{withoutStack: 2},
);
assertConsoleErrorDev([
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }",
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.",
]);
await expect(async () => {
await act(() => {
@@ -227,13 +221,10 @@ describe('ReactDOM', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
],
{withoutStack: 2},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
]);
});
// @gate !disableLegacyMode
@@ -261,13 +252,10 @@ describe('ReactDOM', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be a function. Instead received: no.',
'Expected the last optional `callback` argument to be a function. Instead received: no.',
],
{withoutStack: 2},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be a function. Instead received: no.',
'Expected the last optional `callback` argument to be a function. Instead received: no.',
]);
ReactDOM.render(<A />, myDiv); // Re-mount
await expect(async () => {
@@ -278,13 +266,10 @@ describe('ReactDOM', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.",
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.",
],
{withoutStack: 2},
);
assertConsoleErrorDev([
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.",
"Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.",
]);
ReactDOM.render(<A />, myDiv); // Re-mount
await expect(async () => {
@@ -295,13 +280,10 @@ describe('ReactDOM', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
],
{withoutStack: 2},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.',
]);
});
it('preserves focus', async () => {
+9 -24
View File
@@ -3590,14 +3590,11 @@ describe('ReactDOMFizzServer', () => {
onRecoverableError(error, errorInfo) {
expect(error.digest).toBe('a digest');
expect(errorInfo.digest).toBe(undefined);
assertConsoleErrorDev(
[
'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' +
' This property is no longer provided as part of errorInfo but can be accessed as a property' +
' of the Error instance itself.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' +
' This property is no longer provided as part of errorInfo but can be accessed as a property' +
' of the Error instance itself.',
]);
},
},
);
@@ -7770,10 +7767,7 @@ describe('ReactDOMFizzServer', () => {
</html>,
);
assertConsoleErrorDev([
[
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
{withoutStack: true},
],
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' +
'\n' +
'\n <App>' +
@@ -7788,10 +7782,7 @@ describe('ReactDOMFizzServer', () => {
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'\n in html (at **)' +
'\n in App (at **)',
[
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
{withoutStack: true},
],
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
]);
await root.unmount();
@@ -7886,10 +7877,7 @@ describe('ReactDOMFizzServer', () => {
</html>,
);
assertConsoleErrorDev([
[
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
{withoutStack: true},
],
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' +
'\n' +
'\n <App>' +
@@ -7904,10 +7892,7 @@ describe('ReactDOMFizzServer', () => {
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'\n in html (at **)' +
'\n in App (at **)',
[
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
{withoutStack: true},
],
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
]);
await root.unmount();
+8 -17
View File
@@ -520,10 +520,7 @@ describe('ReactDOMFloat', () => {
);
await waitForAll([]);
assertConsoleErrorDev([
[
'Cannot render <noscript> outside the main document. Try moving it into the root <head> tag.',
{withoutStack: true},
],
'Cannot render <noscript> outside the main document. Try moving it into the root <head> tag.',
]);
root.render(
@@ -580,11 +577,8 @@ describe('ReactDOMFloat', () => {
);
await waitForAll([]);
assertConsoleErrorDev([
[
'Cannot render a <link rel="stylesheet" /> outside the main document without knowing its precedence. ' +
'Consider adding precedence="default" or moving it into the root <head> tag.',
{withoutStack: true},
],
'Cannot render a <link rel="stylesheet" /> outside the main document without knowing its precedence. ' +
'Consider adding precedence="default" or moving it into the root <head> tag.',
]);
root.render(
@@ -633,14 +627,11 @@ describe('ReactDOMFloat', () => {
</>,
);
await waitForAll([]);
assertConsoleErrorDev(
[
'Cannot render a <link> with onLoad or onError listeners outside the main document. ' +
'Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or ' +
'somewhere in the <body>.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Cannot render a <link> with onLoad or onError listeners outside the main document. ' +
'Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or ' +
'somewhere in the <body>.',
]);
return;
});
+8 -16
View File
@@ -1505,13 +1505,10 @@ describe('ReactDOMForm', () => {
// Dispatch outside of a transition.
await act(() => dispatch());
assertConsoleErrorDev([
[
'An async function with useActionState was called outside of a transition. ' +
'This is likely not what you intended (for example, isPending will not update ' +
'correctly). Either call the returned function inside startTransition, or pass it ' +
'to an `action` or `formAction` prop.',
{withoutStack: true},
],
'An async function with useActionState was called outside of a transition. ' +
'This is likely not what you intended (for example, isPending will not update ' +
'correctly). Either call the returned function inside startTransition, or pass it ' +
'to an `action` or `formAction` prop.',
]);
assertLog([
'Suspend! [Count: 1]',
@@ -1967,15 +1964,10 @@ describe('ReactDOMForm', () => {
// This triggers a synchronous requestFormReset, and a warning
await act(() => resolveText('Wait 1'));
assertConsoleErrorDev(
[
'requestFormReset was called outside a transition or action. ' +
'To fix, move to an action, or wrap with startTransition.',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'requestFormReset was called outside a transition or action. ' +
'To fix, move to an action, or wrap with startTransition.',
]);
assertLog(['Request form reset']);
// The form was reset even though the action didn't finish.
@@ -1073,24 +1073,18 @@ describe('FragmentRefs', () => {
// Warning when there is no attached observer
fragmentRef.current.unobserveUsing(observer);
assertConsoleErrorDev(
[
'You are calling unobserveUsing() with an observer that is not being observed with this fragment ' +
'instance. First attach the observer with observeUsing()',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'You are calling unobserveUsing() with an observer that is not being observed with this fragment ' +
'instance. First attach the observer with observeUsing()',
]);
// Warning when the attached observer does not match
fragmentRef.current.observeUsing(observer);
fragmentRef.current.unobserveUsing(observer2);
assertConsoleErrorDev(
[
'You are calling unobserveUsing() with an observer that is not being observed with this fragment ' +
'instance. First attach the observer with observeUsing()',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'You are calling unobserveUsing() with an observer that is not being observed with this fragment ' +
'instance. First attach the observer with observeUsing()',
]);
});
// @gate enableFragmentRefs && enableFragmentRefsInstanceHandles
@@ -35,15 +35,12 @@ describe('ReactDOMComponentTree', () => {
const component = <div />;
const node = ReactDOM.render(<div>{component}</div>, container);
ReactDOM.unmountComponentAtNode(node);
assertConsoleErrorDev(
[
"unmountComponentAtNode(): The node you're attempting to unmount " +
'was rendered by React and is not a top-level container. You may ' +
'have accidentally passed in a React root node instead of its ' +
'container.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
"unmountComponentAtNode(): The node you're attempting to unmount " +
'was rendered by React and is not a top-level container. You may ' +
'have accidentally passed in a React root node instead of its ' +
'container.',
]);
});
// @gate !disableLegacyMode
@@ -56,14 +53,11 @@ describe('ReactDOMComponentTree', () => {
const anotherComponent = <div />;
const instance = ReactDOM.render(component, container);
ReactDOM.render(anotherComponent, instance);
assertConsoleErrorDev(
[
'Replacing React-rendered children with a new root ' +
'component. If you intended to update the children of this node, ' +
'you should instead have the existing children update their state ' +
'and render the new components instead of calling ReactDOM.render.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Replacing React-rendered children with a new root ' +
'component. If you intended to update the children of this node, ' +
'you should instead have the existing children update their state ' +
'and render the new components instead of calling ReactDOM.render.',
]);
});
});
+21 -30
View File
@@ -1275,16 +1275,13 @@ describe('ReactDOMLegacyFiber', () => {
ReactDOM.render(<div key="2">baz</div>, container);
});
}).rejects.toThrow('The node to be removed is not a child of this node.');
assertConsoleErrorDev(
[
'' +
'It looks like the React-rendered content of this container was ' +
'removed without using React. This is not supported and will ' +
'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
'to empty a container.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'' +
'It looks like the React-rendered content of this container was ' +
'removed without using React. This is not supported and will ' +
'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
'to empty a container.',
]);
});
// @gate !disableLegacyMode
@@ -1296,16 +1293,13 @@ describe('ReactDOMLegacyFiber', () => {
// then we mess with the DOM before an update
container.innerHTML = '<div>MEOW.</div>';
ReactDOM.render(<div>baz</div>, container);
assertConsoleErrorDev(
[
'' +
'It looks like the React-rendered content of this container was ' +
'removed without using React. This is not supported and will ' +
'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
'to empty a container.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'' +
'It looks like the React-rendered content of this container was ' +
'removed without using React. This is not supported and will ' +
'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
'to empty a container.',
]);
});
// @gate !disableLegacyMode
@@ -1317,16 +1311,13 @@ describe('ReactDOMLegacyFiber', () => {
// then we mess with the DOM before an update
container.innerHTML = '';
ReactDOM.render(<div>baz</div>, container);
assertConsoleErrorDev(
[
'' +
'It looks like the React-rendered content of this container was ' +
'removed without using React. This is not supported and will ' +
'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
'to empty a container.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'' +
'It looks like the React-rendered content of this container was ' +
'removed without using React. This is not supported and will ' +
'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
'to empty a container.',
]);
});
// @gate !disableLegacyMode
+43 -76
View File
@@ -52,13 +52,10 @@ describe('ReactDOMRoot', () => {
const callback = jest.fn();
const root = ReactDOMClient.createRoot(container);
root.render(<div>Hi</div>, callback);
assertConsoleErrorDev(
[
'does not support the second callback argument. ' +
'To execute a side effect after rendering, declare it in a component body with useEffect().',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'does not support the second callback argument. ' +
'To execute a side effect after rendering, declare it in a component body with useEffect().',
]);
await waitForAll([]);
expect(callback).not.toHaveBeenCalled();
});
@@ -70,15 +67,10 @@ describe('ReactDOMRoot', () => {
const root = ReactDOMClient.createRoot(container);
root.render(<App />, {});
assertConsoleErrorDev(
[
'You passed a second argument to root.render(...) but it only accepts ' +
'one argument.',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'You passed a second argument to root.render(...) but it only accepts ' +
'one argument.',
]);
});
it('warn if a container is passed to root.render(...)', async () => {
@@ -88,16 +80,11 @@ describe('ReactDOMRoot', () => {
const root = ReactDOMClient.createRoot(container);
root.render(<App />, container);
assertConsoleErrorDev(
[
'You passed a container to the second argument of root.render(...). ' +
"You don't need to pass it again since you already passed it to create " +
'the root.',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'You passed a container to the second argument of root.render(...). ' +
"You don't need to pass it again since you already passed it to create " +
'the root.',
]);
});
it('warns if a callback parameter is provided to unmount', async () => {
@@ -105,13 +92,10 @@ describe('ReactDOMRoot', () => {
const root = ReactDOMClient.createRoot(container);
root.render(<div>Hi</div>);
root.unmount(callback);
assertConsoleErrorDev(
[
'does not support a callback argument. ' +
'To execute a side effect after rendering, declare it in a component body with useEffect().',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'does not support a callback argument. ' +
'To execute a side effect after rendering, declare it in a component body with useEffect().',
]);
await waitForAll([]);
expect(callback).not.toHaveBeenCalled();
});
@@ -216,14 +200,11 @@ describe('ReactDOMRoot', () => {
it('warns when creating two roots managing the same container', () => {
ReactDOMClient.createRoot(container);
ReactDOMClient.createRoot(container);
assertConsoleErrorDev(
[
'You are calling ReactDOMClient.createRoot() on a container that ' +
'has already been passed to createRoot() before. Instead, call ' +
'root.render() on the existing root instead if you want to update it.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'You are calling ReactDOMClient.createRoot() on a container that ' +
'has already been passed to createRoot() before. Instead, call ' +
'root.render() on the existing root instead if you want to update it.',
]);
});
it('does not warn when creating second root after first one is unmounted', async () => {
@@ -413,13 +394,10 @@ describe('ReactDOMRoot', () => {
it('warn if no children passed to hydrateRoot', async () => {
ReactDOMClient.hydrateRoot(container);
assertConsoleErrorDev(
[
'Must provide initial children as second argument to hydrateRoot. ' +
'Example usage: hydrateRoot(domContainer, <App />)',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Must provide initial children as second argument to hydrateRoot. ' +
'Example usage: hydrateRoot(domContainer, <App />)',
]);
});
it('warn if JSX passed to createRoot', async () => {
@@ -428,18 +406,13 @@ describe('ReactDOMRoot', () => {
}
ReactDOMClient.createRoot(container, <App />);
assertConsoleErrorDev(
[
'You passed a JSX element to createRoot. You probably meant to call root.render instead. ' +
'Example usage:\n' +
'\n' +
' let root = createRoot(domContainer);\n' +
' root.render(<App />);',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'You passed a JSX element to createRoot. You probably meant to call root.render instead. ' +
'Example usage:\n' +
'\n' +
' let root = createRoot(domContainer);\n' +
' root.render(<App />);',
]);
});
it('warns when given a function', () => {
@@ -452,15 +425,12 @@ describe('ReactDOMRoot', () => {
ReactDOM.flushSync(() => {
root.render(Component);
});
assertConsoleErrorDev(
[
'Functions are not valid as a React child. ' +
'This may happen if you return Component instead of <Component /> from render. ' +
'Or maybe you meant to call this function rather than return it.\n' +
' root.render(Component)',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Functions are not valid as a React child. ' +
'This may happen if you return Component instead of <Component /> from render. ' +
'Or maybe you meant to call this function rather than return it.\n' +
' root.render(Component)',
]);
});
it('warns when given a symbol', () => {
@@ -469,12 +439,9 @@ describe('ReactDOMRoot', () => {
ReactDOM.flushSync(() => {
root.render(Symbol('foo'));
});
assertConsoleErrorDev(
[
'Symbols are not valid as a React child.\n' +
' root.render(Symbol(foo))',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Symbols are not valid as a React child.\n' +
' root.render(Symbol(foo))',
]);
});
});
+4 -7
View File
@@ -323,12 +323,9 @@ describe('ReactIdentity', () => {
</div>,
);
}).toThrowError(new TypeError('prod message'));
assertConsoleErrorDev(
[
'The provided key is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'The provided key is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.',
]);
});
});
+49 -70
View File
@@ -67,15 +67,12 @@ describe('ReactMount', () => {
const container = document.createElement('div');
ReactDOM.render(Component, container);
assertConsoleErrorDev(
[
'Functions are not valid as a React child. ' +
'This may happen if you return Component instead of <Component /> from render. ' +
'Or maybe you meant to call this function rather than return it.\n' +
' root.render(Component)',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Functions are not valid as a React child. ' +
'This may happen if you return Component instead of <Component /> from render. ' +
'Or maybe you meant to call this function rather than return it.\n' +
' root.render(Component)',
]);
});
// @gate !disableLegacyMode
@@ -172,15 +169,12 @@ describe('ReactMount', () => {
const rootNode = container.firstChild;
ReactDOM.render(<span />, rootNode);
assertConsoleErrorDev(
[
'Replacing React-rendered children with a new ' +
'root component. If you intended to update the children of this node, ' +
'you should instead have the existing children update their state and ' +
'render the new components instead of calling ReactDOM.render.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Replacing React-rendered children with a new ' +
'root component. If you intended to update the children of this node, ' +
'you should instead have the existing children update their state and ' +
'render the new components instead of calling ReactDOM.render.',
]);
});
// @gate !disableLegacyMode
@@ -204,13 +198,10 @@ describe('ReactMount', () => {
expect(ReactDOM).not.toEqual(ReactDOMOther);
ReactDOMOther.unmountComponentAtNode(container);
assertConsoleErrorDev(
[
"unmountComponentAtNode(): The node you're attempting to unmount " +
'was rendered by another copy of React.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
"unmountComponentAtNode(): The node you're attempting to unmount " +
'was rendered by another copy of React.',
]);
// Don't throw a warning if the correct React copy unmounts the node
ReactDOM.unmountComponentAtNode(container);
@@ -361,20 +352,17 @@ describe('ReactMount', () => {
await waitForAll([]);
expect(container.textContent).toEqual('Hi');
ReactDOM.render(<div>Bye</div>, container);
assertConsoleErrorDev(
[
// We care about this warning:
'You are calling ReactDOM.render() on a container that was previously ' +
'passed to ReactDOMClient.createRoot(). This is not supported. ' +
'Did you mean to call root.render(element)?',
// This is more of a symptom but restructuring the code to avoid it isn't worth it:
'Replacing React-rendered children with a new root component. ' +
'If you intended to update the children of this node, ' +
'you should instead have the existing children update their state ' +
'and render the new components instead of calling ReactDOM.render.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
// We care about this warning:
'You are calling ReactDOM.render() on a container that was previously ' +
'passed to ReactDOMClient.createRoot(). This is not supported. ' +
'Did you mean to call root.render(element)?',
// This is more of a symptom but restructuring the code to avoid it isn't worth it:
'Replacing React-rendered children with a new root component. ' +
'If you intended to update the children of this node, ' +
'you should instead have the existing children update their state ' +
'and render the new components instead of calling ReactDOM.render.',
]);
await waitForAll([]);
// This works now but we could disallow it:
expect(container.textContent).toEqual('Bye');
@@ -388,18 +376,15 @@ describe('ReactMount', () => {
await waitForAll([]);
expect(container.textContent).toEqual('Hi');
const unmounted = ReactDOM.unmountComponentAtNode(container);
assertConsoleErrorDev(
[
// We care about this warning:
'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?',
// This is more of a symptom but restructuring the code to avoid it isn't worth it:
'unmountComponentAtNode(): ' +
"The node you're attempting to unmount was rendered by React and is not a top-level container. " +
'Instead, have the parent component update its state and rerender in order to remove this component.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
// We care about this warning:
'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?',
// This is more of a symptom but restructuring the code to avoid it isn't worth it:
'unmountComponentAtNode(): ' +
"The node you're attempting to unmount was rendered by React and is not a top-level container. " +
'Instead, have the parent component update its state and rerender in order to remove this component.',
]);
expect(unmounted).toBe(false);
await waitForAll([]);
expect(container.textContent).toEqual('Hi');
@@ -419,18 +404,15 @@ describe('ReactMount', () => {
await waitForAll([]);
expect(container.textContent).toEqual('Hi');
const unmounted = ReactDOM.unmountComponentAtNode(container);
assertConsoleErrorDev(
[
'You are calling ReactDOM.unmountComponentAtNode() on a container ' +
'that was previously passed to ReactDOMClient.createRoot(). ' +
'This is not supported. Did you mean to call root.unmount()?',
// This is more of a symptom but restructuring the code to avoid it isn't worth it:
'unmountComponentAtNode(): ' +
"The node you're attempting to unmount was rendered by React and is not a top-level container. " +
'Instead, have the parent component update its state and rerender in order to remove this component.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'You are calling ReactDOM.unmountComponentAtNode() on a container ' +
'that was previously passed to ReactDOMClient.createRoot(). ' +
'This is not supported. Did you mean to call root.unmount()?',
// This is more of a symptom but restructuring the code to avoid it isn't worth it:
'unmountComponentAtNode(): ' +
"The node you're attempting to unmount was rendered by React and is not a top-level container. " +
'Instead, have the parent component update its state and rerender in order to remove this component.',
]);
expect(unmounted).toBe(false);
await waitForAll([]);
expect(container.textContent).toEqual('Hi');
@@ -444,12 +426,9 @@ describe('ReactMount', () => {
const container = document.createElement('div');
ReactDOM.render(<div>Hi</div>, container);
ReactDOMClient.createRoot(container);
assertConsoleErrorDev(
[
'You are calling ReactDOMClient.createRoot() on a container that was previously ' +
'passed to ReactDOM.render(). This is not supported.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'You are calling ReactDOMClient.createRoot() on a container that was previously ' +
'passed to ReactDOM.render(). This is not supported.',
]);
});
});
+16 -28
View File
@@ -916,13 +916,10 @@ describe('ReactLegacyUpdates', () => {
'Invalid argument passed as callback. Expected a function. ' +
'Instead received: no',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.',
]);
container = document.createElement('div');
component = ReactDOM.render(<A />, container);
@@ -934,13 +931,10 @@ describe('ReactLegacyUpdates', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be a function. ' +
"Instead received: { foo: 'bar' }.",
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be a function. ' +
"Instead received: { foo: 'bar' }.",
]);
// Make sure the warning is deduplicated and doesn't fire again
container = document.createElement('div');
component = ReactDOM.render(<A />, container);
@@ -980,13 +974,10 @@ describe('ReactLegacyUpdates', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be a function. ' +
'Instead received: no.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be a function. ' +
'Instead received: no.',
]);
container = document.createElement('div');
component = ReactDOM.render(<A />, container);
await expect(async () => {
@@ -997,13 +988,10 @@ describe('ReactLegacyUpdates', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be a function. ' +
"Instead received: { foo: 'bar' }.",
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be a function. ' +
"Instead received: { foo: 'bar' }.",
]);
// Make sure the warning is deduplicated and doesn't fire again
container = document.createElement('div');
component = ReactDOM.render(<A />, container);
@@ -66,15 +66,12 @@ describe('ReactMount', () => {
// Test that unmounting at a root node gives a helpful warning
const rootDiv = mainContainerDiv.firstChild;
ReactDOM.unmountComponentAtNode(rootDiv);
assertConsoleErrorDev(
[
"unmountComponentAtNode(): The node you're attempting to " +
'unmount was rendered by React and is not a top-level container. You ' +
'may have accidentally passed in a React root node instead of its ' +
'container.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
"unmountComponentAtNode(): The node you're attempting to " +
'unmount was rendered by React and is not a top-level container. You ' +
'may have accidentally passed in a React root node instead of its ' +
'container.',
]);
});
// @gate !disableLegacyMode
@@ -94,14 +91,11 @@ describe('ReactMount', () => {
// Test that unmounting at a non-root node gives a different warning
const nonRootDiv = mainContainerDiv.firstChild.firstChild;
ReactDOM.unmountComponentAtNode(nonRootDiv);
assertConsoleErrorDev(
[
"unmountComponentAtNode(): The node you're attempting to " +
'unmount was rendered by React and is not a top-level container. ' +
'Instead, have the parent component update its state and rerender in ' +
'order to remove this component.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
"unmountComponentAtNode(): The node you're attempting to " +
'unmount was rendered by React and is not a top-level container. ' +
'Instead, have the parent component update its state and rerender in ' +
'order to remove this component.',
]);
});
});
+14 -20
View File
@@ -606,16 +606,13 @@ describe('ReactDOMServer', () => {
ReactDOMServer.renderToString(<Foo />);
jest.runOnlyPendingTimers();
assertConsoleErrorDev(
[
'Can only update a mounting component. ' +
'This usually means you called setState() outside componentWillMount() on the server. ' +
'This is a no-op.\n' +
'\n' +
'Please check the code for the Foo component.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Can only update a mounting component. ' +
'This usually means you called setState() outside componentWillMount() on the server. ' +
'This is a no-op.\n' +
'\n' +
'Please check the code for the Foo component.',
]);
const markup = ReactDOMServer.renderToStaticMarkup(<Foo />);
expect(markup).toBe('<div>hello</div>');
@@ -639,16 +636,13 @@ describe('ReactDOMServer', () => {
ReactDOMServer.renderToString(<Baz />);
jest.runOnlyPendingTimers();
assertConsoleErrorDev(
[
'Can only update a mounting component. ' +
'This usually means you called forceUpdate() outside componentWillMount() on the server. ' +
'This is a no-op.\n' +
'\n' +
'Please check the code for the Baz component.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Can only update a mounting component. ' +
'This usually means you called forceUpdate() outside componentWillMount() on the server. ' +
'This is a no-op.\n' +
'\n' +
'Please check the code for the Baz component.',
]);
const markup = ReactDOMServer.renderToStaticMarkup(<Baz />);
expect(markup).toBe('<div></div>');
});
@@ -377,23 +377,18 @@ describe('ReactDOMServerHydration', () => {
await act(() => {
ReactDOMClient.hydrateRoot(element, markup);
});
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n' +
'\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\n' +
'Please update the following components: ComponentWithWarning',
],
{
withoutStack: true,
},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n' +
'\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' +
'In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, ' +
'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\n' +
'Please update the following components: ComponentWithWarning',
]);
expect(element.textContent).toBe('Hi');
});
+16 -28
View File
@@ -1063,13 +1063,10 @@ describe('ReactUpdates', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.',
]);
container = document.createElement('div');
root = ReactDOMClient.createRoot(container);
await act(() => {
@@ -1084,13 +1081,10 @@ describe('ReactUpdates', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be ' +
"a function. Instead received: { foo: 'bar' }.",
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be ' +
"a function. Instead received: { foo: 'bar' }.",
]);
container = document.createElement('div');
root = ReactDOMClient.createRoot(container);
await act(() => {
@@ -1136,13 +1130,10 @@ describe('ReactUpdates', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: no',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be ' +
'a function. Instead received: no.',
]);
container = document.createElement('div');
root = ReactDOMClient.createRoot(container);
await act(() => {
@@ -1157,13 +1148,10 @@ describe('ReactUpdates', () => {
'Invalid argument passed as callback. Expected a function. Instead ' +
'received: [object Object]',
);
assertConsoleErrorDev(
[
'Expected the last optional `callback` argument to be ' +
"a function. Instead received: { foo: 'bar' }.",
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Expected the last optional `callback` argument to be ' +
"a function. Instead received: { foo: 'bar' }.",
]);
// Make sure the warning is deduplicated and doesn't fire again
container = document.createElement('div');
root = ReactDOMClient.createRoot(container);
@@ -15,7 +15,7 @@ const ReactDOMClient = require('react-dom/client');
const assertConsoleErrorDev =
require('internal-test-utils').assertConsoleErrorDev;
function expectWarnings(tags, warnings = [], withoutStack = 0) {
function expectWarnings(tags, warnings = []) {
tags = [...tags];
warnings = [...warnings];
@@ -61,10 +61,7 @@ function expectWarnings(tags, warnings = [], withoutStack = 0) {
root.render(element);
});
if (warnings.length) {
assertConsoleErrorDev(
warnings,
withoutStack > 0 ? {withoutStack} : undefined,
);
assertConsoleErrorDev(warnings);
}
root.unmount();
}
@@ -477,9 +477,7 @@ describe('ReactFabric', () => {
expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
ReactFabric.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
assertConsoleErrorDev([DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT], {
withoutStack: true,
});
assertConsoleErrorDev([DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT]);
expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
});
@@ -542,9 +540,7 @@ describe('ReactFabric', () => {
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
ReactFabric.sendAccessibilityEvent(viewRef, 'eventTypeName');
assertConsoleErrorDev([SEND_ACCESSIBILITY_EVENT_REQUIRES_HOST_COMPONENT], {
withoutStack: true,
});
assertConsoleErrorDev([SEND_ACCESSIBILITY_EVENT_REQUIRES_HOST_COMPONENT]);
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
});
@@ -219,10 +219,9 @@ describe('act warnings', () => {
act(() => {
setState(1);
});
assertConsoleErrorDev(
['The current testing environment is not configured to support act(...)'],
{withoutStack: true},
);
assertConsoleErrorDev([
'The current testing environment is not configured to support act(...)',
]);
assertLog([1]);
expect(root).toMatchRenderedOutput('1');
@@ -240,12 +239,9 @@ describe('act warnings', () => {
act(() => {
setState(1);
});
assertConsoleErrorDev(
[
'The current testing environment is not configured to support act(...)',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'The current testing environment is not configured to support act(...)',
]);
assertLog([1]);
expect(root).toMatchRenderedOutput('1');
});
@@ -255,24 +251,21 @@ describe('act warnings', () => {
await withActEnvironment(true, () => {
const root = ReactNoop.createRoot();
root.render('Hi');
assertConsoleErrorDev(
[
// TODO: Better error message that doesn't make it look like "Root" is
// the name of a custom component
'An update to Root inside a test was not wrapped in act(...).\n' +
'\n' +
'When testing, code that causes React state updates should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* fire events that update state */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
],
{withoutStack: true},
);
assertConsoleErrorDev([
// TODO: Better error message that doesn't make it look like "Root" is
// the name of a custom component
'An update to Root inside a test was not wrapped in act(...).\n' +
'\n' +
'When testing, code that causes React state updates should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* fire events that update state */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
]);
});
});
@@ -374,37 +367,33 @@ describe('act warnings', () => {
// This is a retry, not a ping, because we already showed a fallback.
resolveText('Async');
assertConsoleErrorDev(
[
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
assertConsoleErrorDev([
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
// pre-warming
// pre-warming
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
],
{withoutStack: true},
);
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
]);
});
});
@@ -437,22 +426,19 @@ describe('act warnings', () => {
// This is a ping, not a retry, because no fallback is showing.
resolveText('Async');
assertConsoleErrorDev(
[
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
'\n' +
'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
'\n' +
'act(() => {\n' +
' /* finish loading suspended data */\n' +
'});\n' +
'/* assert on the output */\n' +
'\n' +
"This ensures that you're testing the behavior the user would see in the browser. " +
'Learn more at https://react.dev/link/wrap-tests-with-act',
]);
});
});
});
@@ -1237,14 +1237,11 @@ describe('ReactAsyncActions', () => {
setLoadingProgress('25%');
startTransition(() => setText('B'));
});
assertConsoleErrorDev(
[
'An optimistic state update occurred outside a transition or ' +
'action. To fix, move the update to an action, or wrap ' +
'with startTransition.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'An optimistic state update occurred outside a transition or ' +
'action. To fix, move the update to an action, or wrap ' +
'with startTransition.',
]);
assertLog(['Loading... (25%)', 'A', 'B']);
expect(root).toMatchRenderedOutput(<div>B</div>);
});
@@ -244,15 +244,12 @@ describe('ReactHooks', () => {
throw new Error('Expected to ignore the callback.');
}),
);
assertConsoleErrorDev(
[
'State updates from the useState() and useReducer() Hooks ' +
"don't support the second callback argument. " +
'To execute a side effect after rendering, ' +
'declare it in the component body with useEffect().',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'State updates from the useState() and useReducer() Hooks ' +
"don't support the second callback argument. " +
'To execute a side effect after rendering, ' +
'declare it in the component body with useEffect().',
]);
assertLog(['Count: 1']);
expect(root).toMatchRenderedOutput('1');
});
@@ -279,15 +276,12 @@ describe('ReactHooks', () => {
throw new Error('Expected to ignore the callback.');
}),
);
assertConsoleErrorDev(
[
'State updates from the useState() and useReducer() Hooks ' +
"don't support the second callback argument. " +
'To execute a side effect after rendering, ' +
'declare it in the component body with useEffect().',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'State updates from the useState() and useReducer() Hooks ' +
"don't support the second callback argument. " +
'To execute a side effect after rendering, ' +
'declare it in the component body with useEffect().',
]);
assertLog(['Count: 1']);
expect(root).toMatchRenderedOutput('1');
});
@@ -236,17 +236,14 @@ describe('ReactHooksWithNoopRenderer', () => {
expect(() => useState(0)).toThrow(
"Cannot read property 'useState' of null",
);
assertConsoleErrorDev(
[
'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' +
'2. You might be breaking the Rules of Hooks\n' +
'3. You might have more than one copy of React in the same app\n' +
'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'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' +
'2. You might be breaking the Rules of Hooks\n' +
'3. You might have more than one copy of React in the same app\n' +
'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.',
]);
});
describe('useState', () => {
+8 -14
View File
@@ -375,24 +375,18 @@ describe('memo', () => {
it('warns if the first argument is undefined', () => {
memo();
assertConsoleErrorDev(
[
'memo: The first argument must be a component. Instead ' +
'received: undefined',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'memo: The first argument must be a component. Instead ' +
'received: undefined',
]);
});
it('warns if the first argument is null', () => {
memo(null);
assertConsoleErrorDev(
[
'memo: The first argument must be a component. Instead ' +
'received: null',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'memo: The first argument must be a component. Instead ' +
'received: null',
]);
});
it('does not drop lower priority state updates when bailing out at higher pri (simple)', async () => {
@@ -862,14 +862,9 @@ describe('ReactNewContext', () => {
);
await waitForAll([]);
assertConsoleErrorDev(
[
'The `value` prop is required for the `<Context.Provider>`. Did you misspell it or forget to pass it?',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'The `value` prop is required for the `<Context.Provider>`. Did you misspell it or forget to pass it?',
]);
});
it('warns if multiple renderers concurrently render the same context', async () => {
@@ -1120,20 +1120,14 @@ describe('ReactFlightDOMEdge', () => {
};
ServerModule.greet.bind({}, 'hi');
assertConsoleErrorDev(
[
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
]);
ServerModuleImportedOnClient.greet.bind({}, 'hi');
assertConsoleErrorDev(
[
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
]);
});
it('should supports ReadableStreams with typed arrays', async () => {
@@ -189,13 +189,10 @@ describe('ReactFlight', () => {
);
assertConsoleErrorDev([
[
'Attempted to render <span key="one"> without development properties. This is not supported. It can happen if:' +
'\n- The element is created with a production version of React but rendered in development.' +
'\n- The element was cloned with a custom function instead of `React.cloneElement`.\n' +
"The props of this element may help locate this element: { children: 'Free!', [key]: [Getter] }",
{withoutStack: true},
],
'Attempted to render <span key="one"> without development properties. This is not supported. It can happen if:' +
'\n- The element is created with a production version of React but rendered in development.' +
'\n- The element was cloned with a custom function instead of `React.cloneElement`.\n' +
"The props of this element may help locate this element: { children: 'Free!', [key]: [Getter] }",
"TypeError: Cannot read properties of undefined (reading 'stack')" +
'\n in <stack>',
]);
@@ -38,17 +38,12 @@ describe('ReactTestRenderer', () => {
await act(() => {
ReactTestRenderer.create(ReactDOM.createPortal('foo', container));
}).catch(e => (error = e));
assertConsoleErrorDev(
[
'An invalid container has been provided. ' +
'This may indicate that another renderer is being used in addition to the test renderer. ' +
'(For example, ReactDOM.createPortal inside of a ReactTestRenderer tree.) ' +
'This is not supported.',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'An invalid container has been provided. ' +
'This may indicate that another renderer is being used in addition to the test renderer. ' +
'(For example, ReactDOM.createPortal inside of a ReactTestRenderer tree.) ' +
'This is not supported.',
]);
// After the update throws, a subsequent render is scheduled to
// unmount the whole tree. This update also causes an error, so React
@@ -539,15 +539,11 @@ describe 'ReactCoffeeScriptClass', ->
expect(-> ref.current.replaceState {}).toThrow()
assertConsoleWarnDev([
'replaceState(...) is deprecated in plain JavaScript React classes.
Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236).'
], {withoutStack: true})
'replaceState(...) is deprecated in plain JavaScript React classes. Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236).'])
expect(-> ref.current.isMounted()).toThrow()
assertConsoleWarnDev([
'isMounted(...) is deprecated in plain JavaScript React classes.
Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks.',
], {withoutStack: true})
'isMounted(...) is deprecated in plain JavaScript React classes. Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks.'])
if !featureFlags.disableLegacyContext
it 'supports this.context passed via getChildContext', ->
@@ -84,15 +84,12 @@ describe('ReactCreateElement', () => {
it('should warn when `key` is being accessed on a host element', () => {
const element = React.createElement('div', {key: '3'});
void element.props.key;
assertConsoleErrorDev(
[
'div: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://react.dev/link/special-props)',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'div: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://react.dev/link/special-props)',
]);
});
it('allows a string to be passed as the type', () => {
@@ -151,16 +148,11 @@ describe('ReactCreateElement', () => {
});
expect(element.type).toBe(ComponentClass);
expect(element.ref).toBe(ref);
assertConsoleErrorDev(
[
'Accessing element.ref was removed in React 19. ref is now a ' +
'regular prop. It will be removed from the JSX Element ' +
'type in a future release.',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'Accessing element.ref was removed in React 19. ref is now a ' +
'regular prop. It will be removed from the JSX Element ' +
'type in a future release.',
]);
const expectation = {foo: '56', ref};
Object.freeze(expectation);
expect(element.props).toEqual(expectation);
@@ -429,16 +421,11 @@ describe('ReactCreateElement', () => {
it('warns if outdated JSX transform is detected', async () => {
// Warns if __self is detected, because that's only passed by a compiler
React.createElement('div', {className: 'foo', __self: this});
assertConsoleWarnDev(
[
'Your app (or one of its dependencies) is using an outdated JSX ' +
'transform. Update to the modern JSX transform for ' +
'faster performance: https://react.dev/link/new-jsx-transform',
],
{
withoutStack: true,
},
);
assertConsoleWarnDev([
'Your app (or one of its dependencies) is using an outdated JSX ' +
'transform. Update to the modern JSX transform for ' +
'faster performance: https://react.dev/link/new-jsx-transform',
]);
// Only warns the first time. Subsequent elements don't warn.
React.createElement('div', {className: 'foo', __self: this});
@@ -589,22 +589,16 @@ describe('ReactES6Class', () => {
runTest(<Inner name="foo" ref={ref} />, 'DIV', 'foo');
expect(() => ref.current.replaceState({})).toThrow();
assertConsoleWarnDev(
[
'replaceState(...) is deprecated in plain JavaScript React classes. ' +
'Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236).',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'replaceState(...) is deprecated in plain JavaScript React classes. ' +
'Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236).',
]);
expect(() => ref.current.isMounted()).toThrow();
assertConsoleWarnDev(
[
'isMounted(...) is deprecated in plain JavaScript React classes. ' +
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'isMounted(...) is deprecated in plain JavaScript React classes. ' +
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.',
]);
});
if (!require('shared/ReactFeatureFlags').disableLegacyContext) {
@@ -346,16 +346,11 @@ describe('ReactElementClone', () => {
expect(clone.key).toBe('12');
expect(clone.props.ref).toBe('34');
expect(clone.ref).toBe('34');
assertConsoleErrorDev(
[
'Accessing element.ref was removed in React 19. ref is now a ' +
'regular prop. It will be removed from the JSX Element ' +
'type in a future release.',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'Accessing element.ref was removed in React 19. ref is now a ' +
'regular prop. It will be removed from the JSX Element ' +
'type in a future release.',
]);
expect(clone.props).toEqual({foo: 'ef', ref: '34'});
if (__DEV__) {
expect(Object.isFrozen(element)).toBe(true);
@@ -225,28 +225,22 @@ describe('ReactJSXRuntime', () => {
await act(() => {
root.render(JSXRuntime.jsxs('div', {children: 'foo'}, null));
});
assertConsoleErrorDev(
[
'React.jsx: Static children should always be an array. ' +
'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
'Use the Babel transform instead.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'React.jsx: Static children should always be an array. ' +
'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
'Use the Babel transform instead.',
]);
});
it('should warn when `key` is being accessed on a host element', () => {
const element = JSXRuntime.jsxs('div', {}, '3');
void element.props.key;
assertConsoleErrorDev(
[
'div: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://react.dev/link/special-props)',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'div: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://react.dev/link/special-props)',
]);
});
it('should warn when unkeyed children are passed to jsx', async () => {
@@ -372,17 +366,14 @@ describe('ReactJSXRuntime', () => {
const elementWithSpreadKey = __DEV__
? JSXDEVRuntime.jsxDEV('div', configWithKey)
: JSXRuntime.jsx('div', configWithKey);
assertConsoleErrorDev(
[
'A props object containing a "key" prop is being spread into JSX:\n' +
' let props = {key: someKey, foo: ..., bar: ...};\n' +
' <div {...props} />\n' +
'React keys must be passed directly to JSX without using spread:\n' +
' let props = {foo: ..., bar: ...};\n' +
' <div key={someKey} {...props} />',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'A props object containing a "key" prop is being spread into JSX:\n' +
' let props = {key: someKey, foo: ..., bar: ...};\n' +
' <div {...props} />\n' +
'React keys must be passed directly to JSX without using spread:\n' +
' let props = {foo: ..., bar: ...};\n' +
' <div key={someKey} {...props} />',
]);
expect(elementWithSpreadKey.props).not.toBe(configWithKey);
});
});
@@ -114,14 +114,11 @@ describe('ReactJSXTransformIntegration', () => {
const element = <Component ref={ref} foo="56" />;
expect(element.type).toBe(Component);
expect(element.ref).toBe(ref);
assertConsoleErrorDev(
[
'Accessing element.ref was removed in React 19. ref is now a ' +
'regular prop. It will be removed from the JSX Element ' +
'type in a future release.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Accessing element.ref was removed in React 19. ref is now a ' +
'regular prop. It will be removed from the JSX Element ' +
'type in a future release.',
]);
const expectation = {foo: '56', ref};
Object.freeze(expectation);
expect(element.props).toEqual(expectation);
@@ -59,14 +59,9 @@ describe('Profiler', () => {
await act(() => {
root.render(<React.Profiler />);
});
assertConsoleErrorDev(
[
'Profiler must specify an "id" of type `string` as a prop. Received the type `undefined` instead.',
],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'Profiler must specify an "id" of type `string` as a prop. Received the type `undefined` instead.',
]);
});
}
@@ -61,14 +61,11 @@ describe('ReactStartTransition', () => {
});
});
});
assertConsoleWarnDev(
[
'Detected a large number of updates inside startTransition. ' +
'If this is due to a subscription please re-write it to use React provided hooks. ' +
'Otherwise concurrent mode guarantees are off the table.',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'Detected a large number of updates inside startTransition. ' +
'If this is due to a subscription please re-write it to use React provided hooks. ' +
'Otherwise concurrent mode guarantees are off the table.',
]);
await act(() => {
triggerHookTransition(() => {
@@ -77,13 +74,10 @@ describe('ReactStartTransition', () => {
});
});
});
assertConsoleWarnDev(
[
'Detected a large number of updates inside startTransition. ' +
'If this is due to a subscription please re-write it to use React provided hooks. ' +
'Otherwise concurrent mode guarantees are off the table.',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'Detected a large number of updates inside startTransition. ' +
'If this is due to a subscription please re-write it to use React provided hooks. ' +
'Otherwise concurrent mode guarantees are off the table.',
]);
});
});
@@ -624,27 +624,24 @@ describe('Concurrent Mode', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await act(() => root.render(<StrictRoot />));
assertConsoleErrorDev(
[
`Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
assertConsoleErrorDev([
`Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move code with side effects to componentDidMount, and set initial state in the constructor.
Please update the following components: App`,
`Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
`Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state
Please update the following components: Bar, Foo`,
`Using UNSAFE_componentWillUpdate in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
`Using UNSAFE_componentWillUpdate in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
Please update the following components: App`,
],
{withoutStack: true},
);
]);
// Dedupe
await act(() => root.render(<App />));
@@ -684,51 +681,45 @@ Please update the following components: App`,
const root = ReactDOMClient.createRoot(container);
await act(() => root.render(<StrictRoot />));
assertConsoleErrorDev(
[
`Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
assertConsoleErrorDev([
`Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move code with side effects to componentDidMount, and set initial state in the constructor.
Please update the following components: App`,
`Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
`Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state
Please update the following components: Child`,
`Using UNSAFE_componentWillUpdate in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
`Using UNSAFE_componentWillUpdate in strict mode is not recommended and may indicate bugs in your code. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
Please update the following components: App`,
],
{withoutStack: true},
);
assertConsoleWarnDev(
[
`componentWillMount has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
]);
assertConsoleWarnDev([
`componentWillMount has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move code with side effects to componentDidMount, and set initial state in the constructor.
* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
Please update the following components: Parent`,
`componentWillReceiveProps has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
`componentWillReceiveProps has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state
* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
Please update the following components: Parent`,
`componentWillUpdate has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
`componentWillUpdate has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run \`npx react-codemod rename-unsafe-lifecycles\` in your project source folder.
Please update the following components: Parent`,
],
{withoutStack: true},
);
]);
// Dedupe
await act(() => root.render(<StrictRoot />));
});
@@ -753,26 +744,20 @@ Please update the following components: Parent`,
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await act(() => root.render(<StrictRoot foo={true} />));
assertConsoleErrorDev(
[
'Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n\n' +
'Please update the following components: Foo',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n\n' +
'Please update the following components: Foo',
]);
await act(() => root.render(<StrictRoot foo={false} />));
assertConsoleErrorDev(
[
'Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n\n' +
'Please update the following components: Bar',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n\n' +
'Please update the following components: Bar',
]);
// Dedupe
await act(() => root.render(<StrictRoot foo={true} />));
@@ -821,19 +806,16 @@ Please update the following components: Parent`,
await act(() => {
root.render(<SyncRoot />);
});
assertConsoleErrorDev(
[
'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' +
'and may indicate bugs in your code. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, " +
'refactor your code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n\n' +
'Please update the following components: Bar, Foo',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' +
'and may indicate bugs in your code. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, " +
'refactor your code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n\n' +
'Please update the following components: Bar, Foo',
]);
// Dedupe
await act(() => {
@@ -694,22 +694,16 @@ describe('ReactTypeScriptClass', function () {
const ref = React.createRef();
test(React.createElement(Inner, {name: 'foo', ref: ref}), 'DIV', 'foo');
expect(() => ref.current.replaceState({})).toThrow();
assertConsoleWarnDev(
[
'replaceState(...) is deprecated in plain JavaScript React classes. ' +
'Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236).',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'replaceState(...) is deprecated in plain JavaScript React classes. ' +
'Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236).',
]);
expect(() => ref.current.isMounted()).toThrow();
assertConsoleWarnDev(
[
'isMounted(...) is deprecated in plain JavaScript React classes. ' +
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'isMounted(...) is deprecated in plain JavaScript React classes. ' +
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.',
]);
});
if (!ReactFeatureFlags.disableLegacyContext) {
@@ -67,13 +67,10 @@ describe('create-react-class-integration', () => {
return <span>{this.props.prop}</span>;
},
});
assertConsoleErrorDev(
[
'Warning: Component: prop type `prop` is invalid; ' +
'it must be a function, usually from React.PropTypes.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: Component: prop type `prop` is invalid; ' +
'it must be a function, usually from React.PropTypes.',
]);
});
it('should warn on invalid context types', () => {
@@ -86,13 +83,10 @@ describe('create-react-class-integration', () => {
return <span>{this.props.prop}</span>;
},
});
assertConsoleErrorDev(
[
'Warning: Component: context type `prop` is invalid; ' +
'it must be a function, usually from React.PropTypes.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: Component: context type `prop` is invalid; ' +
'it must be a function, usually from React.PropTypes.',
]);
});
it('should throw on invalid child context types', () => {
@@ -105,12 +99,9 @@ describe('create-react-class-integration', () => {
return <span>{this.props.prop}</span>;
},
});
assertConsoleErrorDev(
[
'Warning: Component: child context type `prop` is invalid; it must be a function, usually from React.PropTypes.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: Component: child context type `prop` is invalid; it must be a function, usually from React.PropTypes.',
]);
});
it('should warn when misspelling shouldComponentUpdate', () => {
@@ -122,14 +113,11 @@ describe('create-react-class-integration', () => {
return <div />;
},
});
assertConsoleErrorDev(
[
'Warning: A component has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: A component has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
]);
createReactClass({
displayName: 'NamedComponent',
@@ -140,14 +128,11 @@ describe('create-react-class-integration', () => {
return <div />;
},
});
assertConsoleErrorDev(
[
'Warning: NamedComponent has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: NamedComponent has a method called componentShouldUpdate(). Did you ' +
'mean shouldComponentUpdate()? The name is phrased as a question ' +
'because the function is expected to return a value.',
]);
});
it('should warn when misspelling componentWillReceiveProps', () => {
@@ -159,13 +144,10 @@ describe('create-react-class-integration', () => {
return <div />;
},
});
assertConsoleErrorDev(
[
'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
'mean componentWillReceiveProps()?',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
'mean componentWillReceiveProps()?',
]);
});
it('should warn when misspelling UNSAFE_componentWillReceiveProps', () => {
@@ -177,13 +159,10 @@ describe('create-react-class-integration', () => {
return <div />;
},
});
assertConsoleErrorDev(
[
'Warning: A component has a method called UNSAFE_componentWillRecieveProps(). ' +
'Did you mean UNSAFE_componentWillReceiveProps()?',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: A component has a method called UNSAFE_componentWillRecieveProps(). ' +
'Did you mean UNSAFE_componentWillReceiveProps()?',
]);
});
it('should throw if a reserved property is in statics', () => {
@@ -348,11 +327,8 @@ describe('create-react-class-integration', () => {
root.render(<Outer />);
});
assertConsoleErrorDev([
[
'Component uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)',
{withoutStack: true},
],
'Component uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)',
'Component uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)' +
'\n in ReactClassComponent (at **)',
@@ -409,13 +385,10 @@ describe('create-react-class-integration', () => {
});
expect(() => Component()).toThrow();
assertConsoleErrorDev(
[
'Warning: Something is calling a React component directly. Use a ' +
'factory or JSX instead. See: https://fb.me/react-legacyfactory',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'Warning: Something is calling a React component directly. Use a ' +
'factory or JSX instead. See: https://fb.me/react-legacyfactory',
]);
});
it('replaceState and callback works', async () => {
@@ -635,38 +608,35 @@ describe('create-react-class-integration', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in Component (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your " +
'code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your " +
'code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
]);
await act(() => {
root.render(<Component foo={1} />);
});
@@ -707,38 +677,35 @@ describe('create-react-class-integration', () => {
'https://react.dev/link/unsafe-component-lifecycles\n' +
' in Component (at **)',
]);
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your " +
'code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your " +
'code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
]);
await act(() => {
const root2 = ReactDOMClient.createRoot(document.createElement('div'));
root2.render(<Component foo={1} />);
@@ -781,38 +748,35 @@ describe('create-react-class-integration', () => {
await act(() => {
root.render(<Component foo="bar" />);
});
assertConsoleWarnDev(
[
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your " +
'code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
],
{withoutStack: true},
);
assertConsoleWarnDev([
'componentWillMount has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
'* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
"* If you're updating state whenever props change, refactor your " +
'code to use memoization techniques or move it to ' +
'static getDerivedStateFromProps. Learn more at: https://react.dev/link/derived-state\n' +
'* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
'componentWillUpdate has been renamed, and is not recommended for use. ' +
'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' +
'* Move data fetching code or side effects to componentDidUpdate.\n' +
'* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
'To rename all deprecated lifecycles to their new names, you can run ' +
'`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
'\nPlease update the following components: Component',
]);
expect(log).toEqual(['componentWillMount', 'UNSAFE_componentWillMount']);
log.length = 0;
+29 -47
View File
@@ -78,32 +78,26 @@ describe('forwardRef', () => {
it('should warn if not provided a callback during creation', () => {
React.forwardRef(undefined);
assertConsoleErrorDev(
['forwardRef requires a render function but was given undefined.'],
{withoutStack: true},
);
assertConsoleErrorDev([
'forwardRef requires a render function but was given undefined.',
]);
React.forwardRef(null);
assertConsoleErrorDev(
['forwardRef requires a render function but was given null.'],
{
withoutStack: true,
},
);
assertConsoleErrorDev([
'forwardRef requires a render function but was given null.',
]);
React.forwardRef('foo');
assertConsoleErrorDev(
['forwardRef requires a render function but was given string.'],
{withoutStack: true},
);
assertConsoleErrorDev([
'forwardRef requires a render function but was given string.',
]);
});
it('should warn if no render function is provided', () => {
React.forwardRef();
assertConsoleErrorDev(
['forwardRef requires a render function but was given undefined.'],
{withoutStack: true},
);
assertConsoleErrorDev([
'forwardRef requires a render function but was given undefined.',
]);
});
it('should warn if the render function provided has defaultProps attributes', () => {
@@ -113,13 +107,10 @@ describe('forwardRef', () => {
renderWithDefaultProps.defaultProps = {};
React.forwardRef(renderWithDefaultProps);
assertConsoleErrorDev(
[
'forwardRef render functions do not support defaultProps. ' +
'Did you accidentally pass a React component?',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'forwardRef render functions do not support defaultProps. ' +
'Did you accidentally pass a React component?',
]);
});
it('should not warn if the render function provided does not use any parameter', () => {
@@ -132,13 +123,10 @@ describe('forwardRef', () => {
const arityOfOne = props => <div {...props} />;
React.forwardRef(arityOfOne);
assertConsoleErrorDev(
[
'forwardRef render functions accept exactly two parameters: props and ref. ' +
'Did you forget to use the ref parameter?',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'forwardRef render functions accept exactly two parameters: props and ref. ' +
'Did you forget to use the ref parameter?',
]);
});
it('should not warn if the render function provided use exactly two parameters', () => {
@@ -150,13 +138,10 @@ describe('forwardRef', () => {
const arityOfThree = (props, ref, x) => <div {...props} ref={ref} x={x} />;
React.forwardRef(arityOfThree);
assertConsoleErrorDev(
[
'forwardRef render functions accept exactly two parameters: props and ref. ' +
'Any additional parameter will be undefined.',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'forwardRef render functions accept exactly two parameters: props and ref. ' +
'Any additional parameter will be undefined.',
]);
});
it('should skip forwardRef in the stack if neither displayName nor name are present', async () => {
@@ -394,13 +379,10 @@ describe('forwardRef', () => {
return null;
}),
);
assertConsoleErrorDev(
[
'forwardRef requires a render function but received a `memo` ' +
'component. Instead of forwardRef(memo(...)), use ' +
'memo(forwardRef(...)).',
],
{withoutStack: true},
);
assertConsoleErrorDev([
'forwardRef requires a render function but received a `memo` ' +
'component. Instead of forwardRef(memo(...)), use ' +
'memo(forwardRef(...)).',
]);
});
});
@@ -637,17 +637,11 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
assertConsoleErrorDev(
gate(flags => flags.enableUseSyncExternalStoreShim)
? [
[
'The result of getSnapshot should be cached to avoid an infinite loop',
{withoutStack: true},
],
[
'Error: Maximum update depth exceeded. ' +
'This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. ' +
'React limits the number of nested updates to prevent infinite loops.' +
'\n in <stack>',
{withoutStack: true},
],
'The result of getSnapshot should be cached to avoid an infinite loop',
'Error: Maximum update depth exceeded. ' +
'This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. ' +
'React limits the number of nested updates to prevent infinite loops.' +
'\n in <stack>',
'The above error occurred in the <App> component:\n\n' +
' in App (at **)\n\n' +
'Consider adding an error boundary to your tree to customize error handling behavior.\n' +