mirror of
https://github.com/facebook/react.git
synced 2026-02-21 19:31:52 +00:00
[tests] Remove to*Dev matchers (#31989)
Based off: https://github.com/facebook/react/pull/31988 <img width="741" alt="Screenshot 2025-01-06 at 12 52 08 AM" src="https://github.com/user-attachments/assets/29b159ca-66d4-441f-8817-dd2db66d1edb" /> it is done
This commit is contained in:
@@ -303,7 +303,6 @@ module.exports = {
|
|||||||
ERROR,
|
ERROR,
|
||||||
{isProductionUserAppCode: true},
|
{isProductionUserAppCode: true},
|
||||||
],
|
],
|
||||||
'react-internal/no-to-warn-dev-within-to-throw': ERROR,
|
|
||||||
'react-internal/warning-args': ERROR,
|
'react-internal/warning-args': ERROR,
|
||||||
'react-internal/no-production-logging': ERROR,
|
'react-internal/no-production-logging': ERROR,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const stripAnsi = require('strip-ansi');
|
const stripAnsi = require('strip-ansi');
|
||||||
const {startTransition, useDeferredValue} = React;
|
const {startTransition, useDeferredValue} = React;
|
||||||
const chalk = require('chalk');
|
|
||||||
const ReactNoop = require('react-noop-renderer');
|
const ReactNoop = require('react-noop-renderer');
|
||||||
const {
|
const {
|
||||||
waitFor,
|
waitFor,
|
||||||
@@ -25,7 +24,7 @@ const {
|
|||||||
const act = require('internal-test-utils').act;
|
const act = require('internal-test-utils').act;
|
||||||
const Scheduler = require('scheduler/unstable_mock');
|
const Scheduler = require('scheduler/unstable_mock');
|
||||||
const {
|
const {
|
||||||
flushAllUnexpectedConsoleCalls,
|
assertConsoleLogsCleared,
|
||||||
resetAllUnexpectedConsoleCalls,
|
resetAllUnexpectedConsoleCalls,
|
||||||
patchConsoleMethods,
|
patchConsoleMethods,
|
||||||
} = require('../consoleMock');
|
} = require('../consoleMock');
|
||||||
@@ -205,16 +204,17 @@ describe('ReactInternalTestUtils console mocks', () => {
|
|||||||
it('should fail if not asserted', () => {
|
it('should fail if not asserted', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.log('hit');
|
console.log('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).toThrow(`Expected test not to call ${chalk.bold('console.log()')}.`);
|
}).toThrow(`console.log was called without assertConsoleLogDev`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('should not fail if mocked with spyOnDev', () => {
|
it('should not fail if mocked with spyOnDev', () => {
|
||||||
spyOnDev(console, 'log').mockImplementation(() => {});
|
spyOnDev(console, 'log').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
if (__DEV__) {
|
||||||
console.log('hit');
|
console.log('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
}
|
||||||
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ describe('ReactInternalTestUtils console mocks', () => {
|
|||||||
spyOnProd(console, 'log').mockImplementation(() => {});
|
spyOnProd(console, 'log').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.log('hit');
|
console.log('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -231,33 +231,26 @@ describe('ReactInternalTestUtils console mocks', () => {
|
|||||||
spyOnDevAndProd(console, 'log').mockImplementation(() => {});
|
spyOnDevAndProd(console, 'log').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.log('hit');
|
console.log('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('should not fail with toLogDev', () => {
|
|
||||||
expect(() => {
|
|
||||||
console.log('hit');
|
|
||||||
flushAllUnexpectedConsoleCalls();
|
|
||||||
}).toLogDev(['hit']);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('console.warn', () => {
|
describe('console.warn', () => {
|
||||||
it('should fail if not asserted', () => {
|
it('should fail if not asserted', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.warn('hit');
|
console.warn('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).toThrow(`Expected test not to call ${chalk.bold('console.warn()')}.`);
|
}).toThrow('console.warn was called without assertConsoleWarnDev');
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('should not fail if mocked with spyOnDev', () => {
|
it('should not fail if mocked with spyOnDev', () => {
|
||||||
spyOnDev(console, 'warn').mockImplementation(() => {});
|
spyOnDev(console, 'warn').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
if (__DEV__) {
|
||||||
console.warn('hit');
|
console.warn('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
}
|
||||||
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -266,7 +259,7 @@ describe('ReactInternalTestUtils console mocks', () => {
|
|||||||
spyOnProd(console, 'warn').mockImplementation(() => {});
|
spyOnProd(console, 'warn').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.warn('hit');
|
console.warn('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -274,33 +267,26 @@ describe('ReactInternalTestUtils console mocks', () => {
|
|||||||
spyOnDevAndProd(console, 'warn').mockImplementation(() => {});
|
spyOnDevAndProd(console, 'warn').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.warn('hit');
|
console.warn('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('should not fail with toWarnDev', () => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('hit');
|
|
||||||
flushAllUnexpectedConsoleCalls();
|
|
||||||
}).toWarnDev(['hit'], {withoutStack: true});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('console.error', () => {
|
describe('console.error', () => {
|
||||||
it('should fail if console.error is not asserted', () => {
|
it('should fail if console.error is not asserted', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.error('hit');
|
console.error('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).toThrow(`Expected test not to call ${chalk.bold('console.error()')}.`);
|
}).toThrow('console.error was called without assertConsoleErrorDev');
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('should not fail if mocked with spyOnDev', () => {
|
it('should not fail if mocked with spyOnDev', () => {
|
||||||
spyOnDev(console, 'error').mockImplementation(() => {});
|
spyOnDev(console, 'error').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
if (__DEV__) {
|
||||||
console.error('hit');
|
console.error('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
}
|
||||||
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -309,7 +295,7 @@ describe('ReactInternalTestUtils console mocks', () => {
|
|||||||
spyOnProd(console, 'error').mockImplementation(() => {});
|
spyOnProd(console, 'error').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.error('hit');
|
console.error('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -317,17 +303,9 @@ describe('ReactInternalTestUtils console mocks', () => {
|
|||||||
spyOnDevAndProd(console, 'error').mockImplementation(() => {});
|
spyOnDevAndProd(console, 'error').mockImplementation(() => {});
|
||||||
expect(() => {
|
expect(() => {
|
||||||
console.error('hit');
|
console.error('hit');
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('should not fail with toErrorDev', () => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('hit');
|
|
||||||
flushAllUnexpectedConsoleCalls();
|
|
||||||
}).toErrorDev(['hit'], {withoutStack: true});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -361,17 +339,19 @@ describe('ReactInternalTestUtils console assertions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('assertConsoleLogDev', () => {
|
describe('assertConsoleLogDev', () => {
|
||||||
// @gate __DEV__
|
|
||||||
it('passes for a single log', () => {
|
it('passes for a single log', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.log('Hello');
|
console.log('Hello');
|
||||||
|
}
|
||||||
assertConsoleLogDev(['Hello']);
|
assertConsoleLogDev(['Hello']);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('passes for multiple logs', () => {
|
it('passes for multiple logs', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.log('Hello');
|
console.log('Hello');
|
||||||
console.log('Good day');
|
console.log('Good day');
|
||||||
console.log('Bye');
|
console.log('Bye');
|
||||||
|
}
|
||||||
assertConsoleLogDev(['Hello', 'Good day', 'Bye']);
|
assertConsoleLogDev(['Hello', 'Good day', 'Bye']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -906,17 +886,19 @@ describe('ReactInternalTestUtils console assertions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('assertConsoleWarnDev', () => {
|
describe('assertConsoleWarnDev', () => {
|
||||||
// @gate __DEV__
|
|
||||||
it('passes if an warning contains a stack', () => {
|
it('passes if an warning contains a stack', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.warn('Hello\n in div');
|
console.warn('Hello\n in div');
|
||||||
|
}
|
||||||
assertConsoleWarnDev(['Hello']);
|
assertConsoleWarnDev(['Hello']);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('passes if all warnings contain a stack', () => {
|
it('passes if all warnings contain a stack', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.warn('Hello\n in div');
|
console.warn('Hello\n in div');
|
||||||
console.warn('Good day\n in div');
|
console.warn('Good day\n in div');
|
||||||
console.warn('Bye\n in div');
|
console.warn('Bye\n in div');
|
||||||
|
}
|
||||||
assertConsoleWarnDev(['Hello', 'Good day', 'Bye']);
|
assertConsoleWarnDev(['Hello', 'Good day', 'Bye']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1353,14 +1335,17 @@ describe('ReactInternalTestUtils console assertions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('global withoutStack', () => {
|
describe('global withoutStack', () => {
|
||||||
// @gate __DEV__
|
|
||||||
it('passes if warnings without stack explicitly opt out', () => {
|
it('passes if warnings without stack explicitly opt out', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.warn('Hello');
|
console.warn('Hello');
|
||||||
|
}
|
||||||
assertConsoleWarnDev(['Hello'], {withoutStack: true});
|
assertConsoleWarnDev(['Hello'], {withoutStack: true});
|
||||||
|
|
||||||
|
if (__DEV__) {
|
||||||
console.warn('Hello');
|
console.warn('Hello');
|
||||||
console.warn('Good day');
|
console.warn('Good day');
|
||||||
console.warn('Bye');
|
console.warn('Bye');
|
||||||
|
}
|
||||||
|
|
||||||
assertConsoleWarnDev(['Hello', 'Good day', 'Bye'], {
|
assertConsoleWarnDev(['Hello', 'Good day', 'Bye'], {
|
||||||
withoutStack: true,
|
withoutStack: true,
|
||||||
@@ -1460,11 +1445,12 @@ describe('ReactInternalTestUtils console assertions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('local withoutStack', () => {
|
describe('local withoutStack', () => {
|
||||||
// @gate __DEV__
|
|
||||||
it('passes when expected withoutStack logs matches the actual logs', () => {
|
it('passes when expected withoutStack logs matches the actual logs', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.warn('Hello\n in div');
|
console.warn('Hello\n in div');
|
||||||
console.warn('Good day');
|
console.warn('Good day');
|
||||||
console.warn('Bye\n in div');
|
console.warn('Bye\n in div');
|
||||||
|
}
|
||||||
assertConsoleWarnDev([
|
assertConsoleWarnDev([
|
||||||
'Hello',
|
'Hello',
|
||||||
['Good day', {withoutStack: true}],
|
['Good day', {withoutStack: true}],
|
||||||
@@ -1981,17 +1967,19 @@ describe('ReactInternalTestUtils console assertions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('assertConsoleErrorDev', () => {
|
describe('assertConsoleErrorDev', () => {
|
||||||
// @gate __DEV__
|
|
||||||
it('passes if an error contains a stack', () => {
|
it('passes if an error contains a stack', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.error('Hello\n in div');
|
console.error('Hello\n in div');
|
||||||
|
}
|
||||||
assertConsoleErrorDev(['Hello']);
|
assertConsoleErrorDev(['Hello']);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @gate __DEV__
|
|
||||||
it('passes if all errors contain a stack', () => {
|
it('passes if all errors contain a stack', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.error('Hello\n in div');
|
console.error('Hello\n in div');
|
||||||
console.error('Good day\n in div');
|
console.error('Good day\n in div');
|
||||||
console.error('Bye\n in div');
|
console.error('Bye\n in div');
|
||||||
|
}
|
||||||
assertConsoleErrorDev(['Hello', 'Good day', 'Bye']);
|
assertConsoleErrorDev(['Hello', 'Good day', 'Bye']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2446,14 +2434,17 @@ describe('ReactInternalTestUtils console assertions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('global withoutStack', () => {
|
describe('global withoutStack', () => {
|
||||||
// @gate __DEV__
|
|
||||||
it('passes if errors without stack explicitly opt out', () => {
|
it('passes if errors without stack explicitly opt out', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.error('Hello');
|
console.error('Hello');
|
||||||
|
}
|
||||||
assertConsoleErrorDev(['Hello'], {withoutStack: true});
|
assertConsoleErrorDev(['Hello'], {withoutStack: true});
|
||||||
|
|
||||||
|
if (__DEV__) {
|
||||||
console.error('Hello');
|
console.error('Hello');
|
||||||
console.error('Good day');
|
console.error('Good day');
|
||||||
console.error('Bye');
|
console.error('Bye');
|
||||||
|
}
|
||||||
|
|
||||||
assertConsoleErrorDev(['Hello', 'Good day', 'Bye'], {
|
assertConsoleErrorDev(['Hello', 'Good day', 'Bye'], {
|
||||||
withoutStack: true,
|
withoutStack: true,
|
||||||
@@ -2553,11 +2544,12 @@ describe('ReactInternalTestUtils console assertions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('local withoutStack', () => {
|
describe('local withoutStack', () => {
|
||||||
// @gate __DEV__
|
|
||||||
it('passes when expected withoutStack logs matches the actual logs', () => {
|
it('passes when expected withoutStack logs matches the actual logs', () => {
|
||||||
|
if (__DEV__) {
|
||||||
console.error('Hello\n in div');
|
console.error('Hello\n in div');
|
||||||
console.error('Good day');
|
console.error('Good day');
|
||||||
console.error('Bye\n in div');
|
console.error('Bye\n in div');
|
||||||
|
}
|
||||||
assertConsoleErrorDev([
|
assertConsoleErrorDev([
|
||||||
'Hello',
|
'Hello',
|
||||||
['Good day', {withoutStack: true}],
|
['Good day', {withoutStack: true}],
|
||||||
|
|||||||
@@ -19,19 +19,7 @@ const loggedErrors = (global.__loggedErrors = global.__loggedErrors || []);
|
|||||||
const loggedWarns = (global.__loggedWarns = global.__loggedWarns || []);
|
const loggedWarns = (global.__loggedWarns = global.__loggedWarns || []);
|
||||||
const loggedLogs = (global.__loggedLogs = global.__loggedLogs || []);
|
const loggedLogs = (global.__loggedLogs = global.__loggedLogs || []);
|
||||||
|
|
||||||
// TODO: delete these after code modding away from toWarnDev.
|
const patchConsoleMethod = (methodName, logged) => {
|
||||||
const unexpectedErrorCallStacks = (global.__unexpectedErrorCallStacks =
|
|
||||||
global.__unexpectedErrorCallStacks || []);
|
|
||||||
const unexpectedWarnCallStacks = (global.__unexpectedWarnCallStacks =
|
|
||||||
global.__unexpectedWarnCallStacks || []);
|
|
||||||
const unexpectedLogCallStacks = (global.__unexpectedLogCallStacks =
|
|
||||||
global.__unexpectedLogCallStacks || []);
|
|
||||||
|
|
||||||
const patchConsoleMethod = (
|
|
||||||
methodName,
|
|
||||||
unexpectedConsoleCallStacks,
|
|
||||||
logged,
|
|
||||||
) => {
|
|
||||||
const newMethod = function (format, ...args) {
|
const newMethod = function (format, ...args) {
|
||||||
// Ignore uncaught errors reported by jsdom
|
// Ignore uncaught errors reported by jsdom
|
||||||
// and React addendums because they're too noisy.
|
// and React addendums because they're too noisy.
|
||||||
@@ -72,14 +60,6 @@ const patchConsoleMethod = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture the call stack now so we can warn about it later.
|
|
||||||
// The call stack has helpful information for the test author.
|
|
||||||
// Don't throw yet though b'c it might be accidentally caught and suppressed.
|
|
||||||
const stack = new Error().stack;
|
|
||||||
unexpectedConsoleCallStacks.push([
|
|
||||||
stack.slice(stack.indexOf('\n') + 1),
|
|
||||||
util.format(format, ...args),
|
|
||||||
]);
|
|
||||||
logged.push([format, ...args]);
|
logged.push([format, ...args]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,123 +68,40 @@ const patchConsoleMethod = (
|
|||||||
return newMethod;
|
return newMethod;
|
||||||
};
|
};
|
||||||
|
|
||||||
const flushUnexpectedConsoleCalls = (
|
|
||||||
mockMethod,
|
|
||||||
methodName,
|
|
||||||
expectedMatcher,
|
|
||||||
unexpectedConsoleCallStacks,
|
|
||||||
) => {
|
|
||||||
if (
|
|
||||||
console[methodName] !== mockMethod &&
|
|
||||||
!jest.isMockFunction(console[methodName])
|
|
||||||
) {
|
|
||||||
// throw new Error(
|
|
||||||
// `Test did not tear down console.${methodName} mock properly.`
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
if (unexpectedConsoleCallStacks.length > 0) {
|
|
||||||
const messages = unexpectedConsoleCallStacks.map(
|
|
||||||
([stack, message]) =>
|
|
||||||
`${chalk.red(message)}\n` +
|
|
||||||
`${stack
|
|
||||||
.split('\n')
|
|
||||||
.map(line => chalk.gray(line))
|
|
||||||
.join('\n')}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const type = methodName === 'log' ? 'log' : 'warning';
|
|
||||||
const message =
|
|
||||||
`Expected test not to call ${chalk.bold(
|
|
||||||
`console.${methodName}()`,
|
|
||||||
)}.\n\n` +
|
|
||||||
`If the ${type} is expected, test for it explicitly by:\n` +
|
|
||||||
`1. Using ${chalk.bold(expectedMatcher + '()')} or...\n` +
|
|
||||||
`2. Mock it out using ${chalk.bold(
|
|
||||||
'spyOnDev',
|
|
||||||
)}(console, '${methodName}') or ${chalk.bold(
|
|
||||||
'spyOnProd',
|
|
||||||
)}(console, '${methodName}'), and test that the ${type} occurs.`;
|
|
||||||
|
|
||||||
throw new Error(`${message}\n\n${messages.join('\n\n')}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let errorMethod;
|
|
||||||
let warnMethod;
|
|
||||||
let logMethod;
|
let logMethod;
|
||||||
export function patchConsoleMethods({includeLog} = {includeLog: false}) {
|
export function patchConsoleMethods({includeLog} = {includeLog: false}) {
|
||||||
errorMethod = patchConsoleMethod(
|
patchConsoleMethod('error', loggedErrors);
|
||||||
'error',
|
patchConsoleMethod('warn', loggedWarns);
|
||||||
unexpectedErrorCallStacks,
|
|
||||||
loggedErrors,
|
|
||||||
);
|
|
||||||
warnMethod = patchConsoleMethod(
|
|
||||||
'warn',
|
|
||||||
unexpectedWarnCallStacks,
|
|
||||||
loggedWarns,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Only assert console.log isn't called in CI so you can debug tests in DEV.
|
// Only assert console.log isn't called in CI so you can debug tests in DEV.
|
||||||
// The matchers will still work in DEV, so you can assert locally.
|
// The matchers will still work in DEV, so you can assert locally.
|
||||||
if (includeLog) {
|
if (includeLog) {
|
||||||
logMethod = patchConsoleMethod('log', unexpectedLogCallStacks, loggedLogs);
|
logMethod = patchConsoleMethod('log', loggedLogs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flushAllUnexpectedConsoleCalls() {
|
|
||||||
flushUnexpectedConsoleCalls(
|
|
||||||
errorMethod,
|
|
||||||
'error',
|
|
||||||
'assertConsoleErrorDev',
|
|
||||||
unexpectedErrorCallStacks,
|
|
||||||
);
|
|
||||||
flushUnexpectedConsoleCalls(
|
|
||||||
warnMethod,
|
|
||||||
'warn',
|
|
||||||
'assertConsoleWarnDev',
|
|
||||||
unexpectedWarnCallStacks,
|
|
||||||
);
|
|
||||||
if (logMethod) {
|
|
||||||
flushUnexpectedConsoleCalls(
|
|
||||||
logMethod,
|
|
||||||
'log',
|
|
||||||
'assertConsoleLogDev',
|
|
||||||
unexpectedLogCallStacks,
|
|
||||||
);
|
|
||||||
unexpectedLogCallStacks.length = 0;
|
|
||||||
}
|
|
||||||
unexpectedErrorCallStacks.length = 0;
|
|
||||||
unexpectedWarnCallStacks.length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetAllUnexpectedConsoleCalls() {
|
export function resetAllUnexpectedConsoleCalls() {
|
||||||
loggedErrors.length = 0;
|
loggedErrors.length = 0;
|
||||||
loggedWarns.length = 0;
|
loggedWarns.length = 0;
|
||||||
unexpectedErrorCallStacks.length = 0;
|
|
||||||
unexpectedWarnCallStacks.length = 0;
|
|
||||||
if (logMethod) {
|
if (logMethod) {
|
||||||
loggedLogs.length = 0;
|
loggedLogs.length = 0;
|
||||||
unexpectedLogCallStacks.length = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearLogs() {
|
export function clearLogs() {
|
||||||
const logs = Array.from(loggedLogs);
|
const logs = Array.from(loggedLogs);
|
||||||
unexpectedLogCallStacks.length = 0;
|
|
||||||
loggedLogs.length = 0;
|
loggedLogs.length = 0;
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearWarnings() {
|
export function clearWarnings() {
|
||||||
const warnings = Array.from(loggedWarns);
|
const warnings = Array.from(loggedWarns);
|
||||||
unexpectedWarnCallStacks.length = 0;
|
|
||||||
loggedWarns.length = 0;
|
loggedWarns.length = 0;
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearErrors() {
|
export function clearErrors() {
|
||||||
const errors = Array.from(loggedErrors);
|
const errors = Array.from(loggedErrors);
|
||||||
unexpectedErrorCallStacks.length = 0;
|
|
||||||
loggedErrors.length = 0;
|
loggedErrors.length = 0;
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @emails react-core
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const rule = require('../no-to-warn-dev-within-to-throw');
|
|
||||||
const {RuleTester} = require('eslint');
|
|
||||||
const ruleTester = new RuleTester();
|
|
||||||
|
|
||||||
ruleTester.run('eslint-rules/no-to-warn-dev-within-to-throw', rule, {
|
|
||||||
valid: [
|
|
||||||
'expect(callback).toWarnDev("warning");',
|
|
||||||
'expect(function() { expect(callback).toThrow("error") }).toWarnDev("warning");',
|
|
||||||
],
|
|
||||||
invalid: [
|
|
||||||
{
|
|
||||||
code: 'expect(function() { expect(callback).toWarnDev("warning") }).toThrow("error");',
|
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
message: 'toWarnDev() matcher should not be nested',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
rules: {
|
rules: {
|
||||||
'no-primitive-constructors': require('./no-primitive-constructors'),
|
'no-primitive-constructors': require('./no-primitive-constructors'),
|
||||||
'no-to-warn-dev-within-to-throw': require('./no-to-warn-dev-within-to-throw'),
|
|
||||||
'warning-args': require('./warning-args'),
|
'warning-args': require('./warning-args'),
|
||||||
'prod-error-codes': require('./prod-error-codes'),
|
'prod-error-codes': require('./prod-error-codes'),
|
||||||
'no-production-logging': require('./no-production-logging'),
|
'no-production-logging': require('./no-production-logging'),
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @emails react-core
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
meta: {
|
|
||||||
schema: [],
|
|
||||||
},
|
|
||||||
create(context) {
|
|
||||||
return {
|
|
||||||
Identifier(node) {
|
|
||||||
if (node.name === 'toWarnDev' || node.name === 'toErrorDev') {
|
|
||||||
let current = node;
|
|
||||||
while (current.parent) {
|
|
||||||
if (current.type === 'CallExpression') {
|
|
||||||
if (
|
|
||||||
current &&
|
|
||||||
current.callee &&
|
|
||||||
current.callee.property &&
|
|
||||||
current.callee.property.name === 'toThrow'
|
|
||||||
) {
|
|
||||||
context.report(
|
|
||||||
node,
|
|
||||||
node.name + '() matcher should not be nested'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current = current.parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,435 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @emails react-core
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
describe('toErrorDev', () => {
|
|
||||||
it('does not fail if a warning contains a stack', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
}
|
|
||||||
}).toErrorDev('Hello');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail if all warnings contain a stack', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
console.error('Good day\n in div');
|
|
||||||
console.error('Bye\n in div');
|
|
||||||
}
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail if warnings without stack explicitly opt out', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.error('Hello');
|
|
||||||
}
|
|
||||||
}).toErrorDev('Hello', {withoutStack: true});
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.error('Hello');
|
|
||||||
console.error('Good day');
|
|
||||||
console.error('Bye');
|
|
||||||
}
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: true});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail when expected stack-less warning number matches the actual one', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
console.error('Good day');
|
|
||||||
console.error('Bye\n in div');
|
|
||||||
}
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: 1});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (__DEV__) {
|
|
||||||
// Helper methods avoids invalid toWarn().toThrow() nesting
|
|
||||||
// See no-to-warn-dev-within-to-throw
|
|
||||||
const expectToWarnAndToThrow = (expectBlock, expectedErrorMessage) => {
|
|
||||||
let caughtError;
|
|
||||||
try {
|
|
||||||
expectBlock();
|
|
||||||
} catch (error) {
|
|
||||||
caughtError = error;
|
|
||||||
}
|
|
||||||
expect(caughtError).toBeDefined();
|
|
||||||
expect(caughtError.message).toContain(expectedErrorMessage);
|
|
||||||
};
|
|
||||||
|
|
||||||
it('fails if a warning does not contain a stack', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello');
|
|
||||||
}).toErrorDev('Hello');
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if some warnings do not contain a stack', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
console.error('Good day\n in div');
|
|
||||||
console.error('Bye');
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello');
|
|
||||||
console.error('Good day\n in div');
|
|
||||||
console.error('Bye\n in div');
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
console.error('Good day');
|
|
||||||
console.error('Bye\n in div');
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello');
|
|
||||||
console.error('Good day');
|
|
||||||
console.error('Bye');
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if warning is expected to not have a stack, but does', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
}).toErrorDev('Hello', {withoutStack: true});
|
|
||||||
}, 'Received warning unexpectedly includes a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
console.error('Good day');
|
|
||||||
console.error('Bye\n in div');
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: true});
|
|
||||||
}, 'Received warning unexpectedly includes a component stack');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if expected stack-less warning number does not match the actual one', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hello\n in div');
|
|
||||||
console.error('Good day');
|
|
||||||
console.error('Bye\n in div');
|
|
||||||
}).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: 4});
|
|
||||||
}, 'Expected 4 warnings without a component stack but received 1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if withoutStack is invalid', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi');
|
|
||||||
}).toErrorDev('Hi', {withoutStack: null});
|
|
||||||
}, 'Instead received object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi');
|
|
||||||
}).toErrorDev('Hi', {withoutStack: {}});
|
|
||||||
}, 'Instead received object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi');
|
|
||||||
}).toErrorDev('Hi', {withoutStack: 'haha'});
|
|
||||||
}, 'Instead received string');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if the argument number does not match', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi %s', 'Sara', 'extra');
|
|
||||||
}).toErrorDev('Hi', {withoutStack: true});
|
|
||||||
}, 'Received 2 arguments for a message with 1 placeholders');
|
|
||||||
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi %s');
|
|
||||||
}).toErrorDev('Hi', {withoutStack: true});
|
|
||||||
}, 'Received 0 arguments for a message with 1 placeholders');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if stack is passed twice', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi %s%s', '\n in div', '\n in div');
|
|
||||||
}).toErrorDev('Hi');
|
|
||||||
}, 'Received more than one component stack for a warning');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if multiple strings are passed without an array wrapper', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi \n in div');
|
|
||||||
}).toErrorDev('Hi', 'Bye');
|
|
||||||
}, 'toErrorDev() second argument, when present, should be an object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi \n in div');
|
|
||||||
console.error('Bye \n in div');
|
|
||||||
}).toErrorDev('Hi', 'Bye');
|
|
||||||
}, 'toErrorDev() second argument, when present, should be an object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi \n in div');
|
|
||||||
console.error('Wow \n in div');
|
|
||||||
console.error('Bye \n in div');
|
|
||||||
}).toErrorDev('Hi', 'Bye');
|
|
||||||
}, 'toErrorDev() second argument, when present, should be an object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi \n in div');
|
|
||||||
console.error('Wow \n in div');
|
|
||||||
console.error('Bye \n in div');
|
|
||||||
}).toErrorDev('Hi', 'Wow', 'Bye');
|
|
||||||
}, 'toErrorDev() second argument, when present, should be an object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails on more than two arguments', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.error('Hi \n in div');
|
|
||||||
console.error('Wow \n in div');
|
|
||||||
console.error('Bye \n in div');
|
|
||||||
}).toErrorDev('Hi', undefined, 'Bye');
|
|
||||||
}, 'toErrorDev() received more than two arguments.');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('toWarnDev', () => {
|
|
||||||
it('does not fail if a warning contains a stack', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
}
|
|
||||||
}).toWarnDev('Hello');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail if all warnings contain a stack', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
console.warn('Good day\n in div');
|
|
||||||
console.warn('Bye\n in div');
|
|
||||||
}
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail if warnings without stack explicitly opt out', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.warn('Hello');
|
|
||||||
}
|
|
||||||
}).toWarnDev('Hello', {withoutStack: true});
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.warn('Hello');
|
|
||||||
console.warn('Good day');
|
|
||||||
console.warn('Bye');
|
|
||||||
}
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye'], {withoutStack: true});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail when expected stack-less warning number matches the actual one', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
console.warn('Good day');
|
|
||||||
console.warn('Bye\n in div');
|
|
||||||
}
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye'], {withoutStack: 1});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (__DEV__) {
|
|
||||||
// Helper methods avoids invalid toWarn().toThrow() nesting
|
|
||||||
// See no-to-warn-dev-within-to-throw
|
|
||||||
const expectToWarnAndToThrow = (expectBlock, expectedErrorMessage) => {
|
|
||||||
let caughtError;
|
|
||||||
try {
|
|
||||||
expectBlock();
|
|
||||||
} catch (error) {
|
|
||||||
caughtError = error;
|
|
||||||
}
|
|
||||||
expect(caughtError).toBeDefined();
|
|
||||||
expect(caughtError.message).toContain(expectedErrorMessage);
|
|
||||||
};
|
|
||||||
|
|
||||||
it('fails if a warning does not contain a stack', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello');
|
|
||||||
}).toWarnDev('Hello');
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if some warnings do not contain a stack', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
console.warn('Good day\n in div');
|
|
||||||
console.warn('Bye');
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello');
|
|
||||||
console.warn('Good day\n in div');
|
|
||||||
console.warn('Bye\n in div');
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
console.warn('Good day');
|
|
||||||
console.warn('Bye\n in div');
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello');
|
|
||||||
console.warn('Good day');
|
|
||||||
console.warn('Bye');
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
}, 'Received warning unexpectedly does not include a component stack');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if warning is expected to not have a stack, but does', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
}).toWarnDev('Hello', {withoutStack: true});
|
|
||||||
}, 'Received warning unexpectedly includes a component stack');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
console.warn('Good day');
|
|
||||||
console.warn('Bye\n in div');
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye'], {
|
|
||||||
withoutStack: true,
|
|
||||||
});
|
|
||||||
}, 'Received warning unexpectedly includes a component stack');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if expected stack-less warning number does not match the actual one', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hello\n in div');
|
|
||||||
console.warn('Good day');
|
|
||||||
console.warn('Bye\n in div');
|
|
||||||
}).toWarnDev(['Hello', 'Good day', 'Bye'], {
|
|
||||||
withoutStack: 4,
|
|
||||||
});
|
|
||||||
}, 'Expected 4 warnings without a component stack but received 1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if withoutStack is invalid', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi');
|
|
||||||
}).toWarnDev('Hi', {withoutStack: null});
|
|
||||||
}, 'Instead received object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi');
|
|
||||||
}).toWarnDev('Hi', {withoutStack: {}});
|
|
||||||
}, 'Instead received object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi');
|
|
||||||
}).toWarnDev('Hi', {withoutStack: 'haha'});
|
|
||||||
}, 'Instead received string');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if the argument number does not match', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi %s', 'Sara', 'extra');
|
|
||||||
}).toWarnDev('Hi', {withoutStack: true});
|
|
||||||
}, 'Received 2 arguments for a message with 1 placeholders');
|
|
||||||
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi %s');
|
|
||||||
}).toWarnDev('Hi', {withoutStack: true});
|
|
||||||
}, 'Received 0 arguments for a message with 1 placeholders');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if stack is passed twice', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi %s%s', '\n in div', '\n in div');
|
|
||||||
}).toWarnDev('Hi');
|
|
||||||
}, 'Received more than one component stack for a warning');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if multiple strings are passed without an array wrapper', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi \n in div');
|
|
||||||
}).toWarnDev('Hi', 'Bye');
|
|
||||||
}, 'toWarnDev() second argument, when present, should be an object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi \n in div');
|
|
||||||
console.warn('Bye \n in div');
|
|
||||||
}).toWarnDev('Hi', 'Bye');
|
|
||||||
}, 'toWarnDev() second argument, when present, should be an object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi \n in div');
|
|
||||||
console.warn('Wow \n in div');
|
|
||||||
console.warn('Bye \n in div');
|
|
||||||
}).toWarnDev('Hi', 'Bye');
|
|
||||||
}, 'toWarnDev() second argument, when present, should be an object');
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi \n in div');
|
|
||||||
console.warn('Wow \n in div');
|
|
||||||
console.warn('Bye \n in div');
|
|
||||||
}).toWarnDev('Hi', 'Wow', 'Bye');
|
|
||||||
}, 'toWarnDev() second argument, when present, should be an object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails on more than two arguments', () => {
|
|
||||||
expectToWarnAndToThrow(() => {
|
|
||||||
expect(() => {
|
|
||||||
console.warn('Hi \n in div');
|
|
||||||
console.warn('Wow \n in div');
|
|
||||||
console.warn('Bye \n in div');
|
|
||||||
}).toWarnDev('Hi', undefined, 'Bye');
|
|
||||||
}, 'toWarnDev() received more than two arguments.');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('toLogDev', () => {
|
|
||||||
it('does not fail if warnings do not include a stack', () => {
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.log('Hello');
|
|
||||||
}
|
|
||||||
}).toLogDev('Hello');
|
|
||||||
expect(() => {
|
|
||||||
if (__DEV__) {
|
|
||||||
console.log('Hello');
|
|
||||||
console.log('Good day');
|
|
||||||
console.log('Bye');
|
|
||||||
}
|
|
||||||
}).toLogDev(['Hello', 'Good day', 'Bye']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,348 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const {diff: jestDiff} = require('jest-diff');
|
|
||||||
const util = require('util');
|
|
||||||
const shouldIgnoreConsoleError = require('internal-test-utils/shouldIgnoreConsoleError');
|
|
||||||
|
|
||||||
function normalizeCodeLocInfo(str) {
|
|
||||||
if (typeof str !== 'string') {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
// This special case exists only for the special source location in
|
|
||||||
// ReactElementValidator. That will go away if we remove source locations.
|
|
||||||
str = str.replace(/Check your code at .+?:\d+/g, 'Check your code at **');
|
|
||||||
// V8 format:
|
|
||||||
// at Component (/path/filename.js:123:45)
|
|
||||||
// React format:
|
|
||||||
// in Component (at filename.js:123)
|
|
||||||
return str.replace(/\n +(?:at|in) ([\S]+)[^\n]*/g, function (m, name) {
|
|
||||||
if (name.endsWith('.render')) {
|
|
||||||
// Class components will have the `render` method as part of their stack trace.
|
|
||||||
// We strip that out in our normalization to make it look more like component stacks.
|
|
||||||
name = name.slice(0, name.length - 7);
|
|
||||||
}
|
|
||||||
return '\n in ' + name + ' (at **)';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const createMatcherFor = (consoleMethod, matcherName) =>
|
|
||||||
function matcher(callback, expectedMessages, options = {}) {
|
|
||||||
if (__DEV__) {
|
|
||||||
// Warn about incorrect usage of matcher.
|
|
||||||
if (typeof expectedMessages === 'string') {
|
|
||||||
expectedMessages = [expectedMessages];
|
|
||||||
} else if (!Array.isArray(expectedMessages)) {
|
|
||||||
throw Error(
|
|
||||||
`${matcherName}() requires a parameter of type string or an array of strings ` +
|
|
||||||
`but was given ${typeof expectedMessages}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
options != null &&
|
|
||||||
(typeof options !== 'object' || Array.isArray(options))
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`${matcherName}() second argument, when present, should be an object. ` +
|
|
||||||
'Did you forget to wrap the messages into an array?'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (arguments.length > 3) {
|
|
||||||
// `matcher` comes from Jest, so it's more than 2 in practice
|
|
||||||
throw new Error(
|
|
||||||
`${matcherName}() received more than two arguments. ` +
|
|
||||||
'Did you forget to wrap the messages into an array?'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const withoutStack = options.withoutStack;
|
|
||||||
const logAllErrors = options.logAllErrors;
|
|
||||||
const warningsWithoutComponentStack = [];
|
|
||||||
const warningsWithComponentStack = [];
|
|
||||||
const unexpectedWarnings = [];
|
|
||||||
|
|
||||||
let lastWarningWithMismatchingFormat = null;
|
|
||||||
let lastWarningWithExtraComponentStack = null;
|
|
||||||
|
|
||||||
// Catch errors thrown by the callback,
|
|
||||||
// But only rethrow them if all test expectations have been satisfied.
|
|
||||||
// Otherwise an Error in the callback can mask a failed expectation,
|
|
||||||
// and result in a test that passes when it shouldn't.
|
|
||||||
let caughtError;
|
|
||||||
|
|
||||||
const isLikelyAComponentStack = message =>
|
|
||||||
typeof message === 'string' &&
|
|
||||||
(message.includes('\n in ') || message.includes('\n at '));
|
|
||||||
|
|
||||||
const consoleSpy = (format, ...args) => {
|
|
||||||
// Ignore uncaught errors reported by jsdom
|
|
||||||
// and React addendums because they're too noisy.
|
|
||||||
if (!logAllErrors && shouldIgnoreConsoleError(format, args)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append Component Stacks. Simulates a framework or DevTools appending them.
|
|
||||||
if (
|
|
||||||
typeof format === 'string' &&
|
|
||||||
(consoleMethod === 'error' || consoleMethod === 'warn')
|
|
||||||
) {
|
|
||||||
const React = require('react');
|
|
||||||
if (React.captureOwnerStack) {
|
|
||||||
// enableOwnerStacks enabled. When it's always on, we can assume this case.
|
|
||||||
const stack = React.captureOwnerStack();
|
|
||||||
if (stack) {
|
|
||||||
format += '%s';
|
|
||||||
args.push(stack);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Otherwise we have to use internals to emulate parent stacks.
|
|
||||||
const ReactSharedInternals =
|
|
||||||
React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ||
|
|
||||||
React.__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
||||||
if (ReactSharedInternals && ReactSharedInternals.getCurrentStack) {
|
|
||||||
const stack = ReactSharedInternals.getCurrentStack();
|
|
||||||
if (stack !== '') {
|
|
||||||
format += '%s';
|
|
||||||
args.push(stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = util.format(format, ...args);
|
|
||||||
const normalizedMessage = normalizeCodeLocInfo(message);
|
|
||||||
|
|
||||||
// Remember if the number of %s interpolations
|
|
||||||
// doesn't match the number of arguments.
|
|
||||||
// We'll fail the test if it happens.
|
|
||||||
let argIndex = 0;
|
|
||||||
// console.* could have been called with a non-string e.g. `console.error(new Error())`
|
|
||||||
String(format).replace(/%s/g, () => argIndex++);
|
|
||||||
if (argIndex !== args.length) {
|
|
||||||
lastWarningWithMismatchingFormat = {
|
|
||||||
format,
|
|
||||||
args,
|
|
||||||
expectedArgCount: argIndex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Protect against accidentally passing a component stack
|
|
||||||
// to warning() which already injects the component stack.
|
|
||||||
if (
|
|
||||||
args.length >= 2 &&
|
|
||||||
isLikelyAComponentStack(args[args.length - 1]) &&
|
|
||||||
isLikelyAComponentStack(args[args.length - 2])
|
|
||||||
) {
|
|
||||||
lastWarningWithExtraComponentStack = {
|
|
||||||
format,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let index = 0; index < expectedMessages.length; index++) {
|
|
||||||
const expectedMessage = expectedMessages[index];
|
|
||||||
if (
|
|
||||||
normalizedMessage === expectedMessage ||
|
|
||||||
normalizedMessage.includes(expectedMessage)
|
|
||||||
) {
|
|
||||||
if (isLikelyAComponentStack(normalizedMessage)) {
|
|
||||||
warningsWithComponentStack.push(normalizedMessage);
|
|
||||||
} else {
|
|
||||||
warningsWithoutComponentStack.push(normalizedMessage);
|
|
||||||
}
|
|
||||||
expectedMessages.splice(index, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let errorMessage;
|
|
||||||
if (expectedMessages.length === 0) {
|
|
||||||
errorMessage =
|
|
||||||
'Unexpected warning recorded: ' +
|
|
||||||
this.utils.printReceived(normalizedMessage);
|
|
||||||
} else if (expectedMessages.length === 1) {
|
|
||||||
errorMessage =
|
|
||||||
'Unexpected warning recorded: ' +
|
|
||||||
jestDiff(expectedMessages[0], normalizedMessage);
|
|
||||||
} else {
|
|
||||||
errorMessage =
|
|
||||||
'Unexpected warning recorded: ' +
|
|
||||||
jestDiff(expectedMessages, [normalizedMessage]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the call stack for unexpected warnings.
|
|
||||||
// We don't throw an Error here though,
|
|
||||||
// Because it might be suppressed by ReactFiberScheduler.
|
|
||||||
unexpectedWarnings.push(new Error(errorMessage));
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO Decide whether we need to support nested toWarn* expectations.
|
|
||||||
// If we don't need it, add a check here to see if this is already our spy,
|
|
||||||
// And throw an error.
|
|
||||||
const originalMethod = console[consoleMethod];
|
|
||||||
|
|
||||||
// Avoid using Jest's built-in spy since it can't be removed.
|
|
||||||
console[consoleMethod] = consoleSpy;
|
|
||||||
|
|
||||||
const onFinally = () => {
|
|
||||||
// Restore the unspied method so that unexpected errors fail tests.
|
|
||||||
console[consoleMethod] = originalMethod;
|
|
||||||
|
|
||||||
// Any unexpected Errors thrown by the callback should fail the test.
|
|
||||||
// This should take precedence since unexpected errors could block warnings.
|
|
||||||
if (caughtError) {
|
|
||||||
throw caughtError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any unexpected warnings should be treated as a failure.
|
|
||||||
if (unexpectedWarnings.length > 0) {
|
|
||||||
return {
|
|
||||||
message: () => unexpectedWarnings[0].stack,
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any remaining messages indicate a failed expectations.
|
|
||||||
if (expectedMessages.length > 0) {
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`Expected warning was not recorded:\n ${this.utils.printReceived(
|
|
||||||
expectedMessages[0]
|
|
||||||
)}`,
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (consoleMethod === 'log') {
|
|
||||||
// We don't expect any console.log calls to have a stack.
|
|
||||||
} else if (typeof withoutStack === 'number') {
|
|
||||||
// We're expecting a particular number of warnings without stacks.
|
|
||||||
if (withoutStack !== warningsWithoutComponentStack.length) {
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`Expected ${withoutStack} warnings without a component stack but received ${warningsWithoutComponentStack.length}:\n` +
|
|
||||||
warningsWithoutComponentStack.map(warning =>
|
|
||||||
this.utils.printReceived(warning)
|
|
||||||
),
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (withoutStack === true) {
|
|
||||||
// We're expecting that all warnings won't have the stack.
|
|
||||||
// If some warnings have it, it's an error.
|
|
||||||
if (warningsWithComponentStack.length > 0) {
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`Received warning unexpectedly includes a component stack:\n ${this.utils.printReceived(
|
|
||||||
warningsWithComponentStack[0]
|
|
||||||
)}\nIf this warning intentionally includes the component stack, remove ` +
|
|
||||||
`{withoutStack: true} from the ${matcherName}() call. If you have a mix of ` +
|
|
||||||
`warnings with and without stack in one ${matcherName}() call, pass ` +
|
|
||||||
`{withoutStack: N} where N is the number of warnings without stacks.`,
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (withoutStack === false || withoutStack === undefined) {
|
|
||||||
// We're expecting that all warnings *do* have the stack (default).
|
|
||||||
// If some warnings don't have it, it's an error.
|
|
||||||
if (warningsWithoutComponentStack.length > 0) {
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`Received warning unexpectedly does not include a component stack:\n ${this.utils.printReceived(
|
|
||||||
warningsWithoutComponentStack[0]
|
|
||||||
)}\nIf this warning intentionally omits the component stack, add ` +
|
|
||||||
`{withoutStack: true} to the ${matcherName} call.`,
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw Error(
|
|
||||||
`The second argument for ${matcherName}(), when specified, must be an object. It may have a ` +
|
|
||||||
`property called "withoutStack" whose value may be undefined, boolean, or a number. ` +
|
|
||||||
`Instead received ${typeof withoutStack}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastWarningWithMismatchingFormat !== null) {
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`Received ${
|
|
||||||
lastWarningWithMismatchingFormat.args.length
|
|
||||||
} arguments for a message with ${
|
|
||||||
lastWarningWithMismatchingFormat.expectedArgCount
|
|
||||||
} placeholders:\n ${this.utils.printReceived(
|
|
||||||
lastWarningWithMismatchingFormat.format
|
|
||||||
)}`,
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastWarningWithExtraComponentStack !== null) {
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`Received more than one component stack for a warning:\n ${this.utils.printReceived(
|
|
||||||
lastWarningWithExtraComponentStack.format
|
|
||||||
)}\nDid you accidentally pass a stack to warning() as the last argument? ` +
|
|
||||||
`Don't forget warning() already injects the component stack automatically.`,
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {pass: true};
|
|
||||||
};
|
|
||||||
|
|
||||||
let returnPromise = null;
|
|
||||||
try {
|
|
||||||
const result = callback();
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof result === 'object' &&
|
|
||||||
result !== null &&
|
|
||||||
typeof result.then === 'function'
|
|
||||||
) {
|
|
||||||
// `act` returns a thenable that can't be chained.
|
|
||||||
// Once `act(async () => {}).then(() => {}).then(() => {})` works
|
|
||||||
// we can just return `result.then(onFinally, error => ...)`
|
|
||||||
returnPromise = new Promise((resolve, reject) => {
|
|
||||||
result
|
|
||||||
.then(
|
|
||||||
() => {
|
|
||||||
resolve(onFinally());
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
caughtError = error;
|
|
||||||
return resolve(onFinally());
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// In case onFinally throws we need to reject from this matcher
|
|
||||||
.catch(error => {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
caughtError = error;
|
|
||||||
} finally {
|
|
||||||
return returnPromise === null ? onFinally() : returnPromise;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Any uncaught errors or warnings should fail tests in production mode.
|
|
||||||
const result = callback();
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof result === 'object' &&
|
|
||||||
result !== null &&
|
|
||||||
typeof result.then === 'function'
|
|
||||||
) {
|
|
||||||
return result.then(() => {
|
|
||||||
return {pass: true};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return {pass: true};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
toWarnDev: createMatcherFor('warn', 'toWarnDev'),
|
|
||||||
toErrorDev: createMatcherFor('error', 'toErrorDev'),
|
|
||||||
toLogDev: createMatcherFor('log', 'toLogDev'),
|
|
||||||
};
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const {getTestFlags} = require('./TestFlags');
|
const {getTestFlags} = require('./TestFlags');
|
||||||
const {
|
const {
|
||||||
flushAllUnexpectedConsoleCalls,
|
assertConsoleLogsCleared,
|
||||||
resetAllUnexpectedConsoleCalls,
|
resetAllUnexpectedConsoleCalls,
|
||||||
patchConsoleMethods,
|
patchConsoleMethods,
|
||||||
} = require('internal-test-utils/consoleMock');
|
} = require('internal-test-utils/consoleMock');
|
||||||
@@ -44,7 +44,6 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
|
|||||||
expect.extend({
|
expect.extend({
|
||||||
...require('./matchers/reactTestMatchers'),
|
...require('./matchers/reactTestMatchers'),
|
||||||
...require('./matchers/toThrow'),
|
...require('./matchers/toThrow'),
|
||||||
...require('./matchers/toWarnDev'),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// We have a Babel transform that inserts guards against infinite loops.
|
// We have a Babel transform that inserts guards against infinite loops.
|
||||||
@@ -66,7 +65,19 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
|
|||||||
// Patch the console to assert that all console error/warn/log calls assert.
|
// Patch the console to assert that all console error/warn/log calls assert.
|
||||||
patchConsoleMethods({includeLog: !!process.env.CI});
|
patchConsoleMethods({includeLog: !!process.env.CI});
|
||||||
beforeEach(resetAllUnexpectedConsoleCalls);
|
beforeEach(resetAllUnexpectedConsoleCalls);
|
||||||
afterEach(flushAllUnexpectedConsoleCalls);
|
afterEach(assertConsoleLogsCleared);
|
||||||
|
|
||||||
|
// TODO: enable this check so we don't forget to reset spyOnX mocks.
|
||||||
|
// afterEach(() => {
|
||||||
|
// if (
|
||||||
|
// console[methodName] !== mockMethod &&
|
||||||
|
// !jest.isMockFunction(console[methodName])
|
||||||
|
// ) {
|
||||||
|
// throw new Error(
|
||||||
|
// `Test did not tear down console.${methodName} mock properly.`
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
// In production, we strip error messages and turn them into codes.
|
// In production, we strip error messages and turn them into codes.
|
||||||
@@ -187,7 +198,7 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
|
|||||||
// Flush unexpected console calls inside the test itself, instead of in
|
// Flush unexpected console calls inside the test itself, instead of in
|
||||||
// `afterEach` like we normally do. `afterEach` is too late because if it
|
// `afterEach` like we normally do. `afterEach` is too late because if it
|
||||||
// throws, we won't have captured it.
|
// throws, we won't have captured it.
|
||||||
flushAllUnexpectedConsoleCalls();
|
assertConsoleLogsCleared();
|
||||||
} catch (testError) {
|
} catch (testError) {
|
||||||
didError = true;
|
didError = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
const {
|
const {
|
||||||
patchConsoleMethods,
|
patchConsoleMethods,
|
||||||
resetAllUnexpectedConsoleCalls,
|
resetAllUnexpectedConsoleCalls,
|
||||||
flushAllUnexpectedConsoleCalls,
|
assertConsoleLogsCleared,
|
||||||
} = require('internal-test-utils/consoleMock');
|
} = require('internal-test-utils/consoleMock');
|
||||||
const spyOn = jest.spyOn;
|
const spyOn = jest.spyOn;
|
||||||
|
|
||||||
@@ -44,10 +44,21 @@ global.spyOnProd = function (...args) {
|
|||||||
// Patch the console to assert that all console error/warn/log calls assert.
|
// Patch the console to assert that all console error/warn/log calls assert.
|
||||||
patchConsoleMethods({includeLog: !!process.env.CI});
|
patchConsoleMethods({includeLog: !!process.env.CI});
|
||||||
beforeEach(resetAllUnexpectedConsoleCalls);
|
beforeEach(resetAllUnexpectedConsoleCalls);
|
||||||
afterEach(flushAllUnexpectedConsoleCalls);
|
afterEach(assertConsoleLogsCleared);
|
||||||
|
|
||||||
|
// TODO: enable this check so we don't forget to reset spyOnX mocks.
|
||||||
|
// afterEach(() => {
|
||||||
|
// if (
|
||||||
|
// console[methodName] !== mockMethod &&
|
||||||
|
// !jest.isMockFunction(console[methodName])
|
||||||
|
// ) {
|
||||||
|
// throw new Error(
|
||||||
|
// `Test did not tear down console.${methodName} mock properly.`
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
expect.extend({
|
expect.extend({
|
||||||
...require('../matchers/reactTestMatchers'),
|
...require('../matchers/reactTestMatchers'),
|
||||||
...require('../matchers/toThrow'),
|
...require('../matchers/toThrow'),
|
||||||
...require('../matchers/toWarnDev'),
|
|
||||||
});
|
});
|
||||||
|
|||||||
84
scripts/jest/typescript/jest.d.ts
vendored
84
scripts/jest/typescript/jest.d.ts
vendored
@@ -8,7 +8,7 @@ declare function describe(name: string, fn: any): void;
|
|||||||
declare const it: {
|
declare const it: {
|
||||||
(name: string, fn: any): void;
|
(name: string, fn: any): void;
|
||||||
only: (name: string, fn: any) => void;
|
only: (name: string, fn: any) => void;
|
||||||
}
|
};
|
||||||
declare function expect(val: any): Expect;
|
declare function expect(val: any): Expect;
|
||||||
declare const jest: Jest;
|
declare const jest: Jest;
|
||||||
declare function pit(name: string, fn: any): void;
|
declare function pit(name: string, fn: any): void;
|
||||||
@@ -19,55 +19,53 @@ declare function xdescribe(name: string, fn: any): void;
|
|||||||
declare function xit(name: string, fn: any): void;
|
declare function xit(name: string, fn: any): void;
|
||||||
|
|
||||||
interface Expect {
|
interface Expect {
|
||||||
not: Expect
|
not: Expect;
|
||||||
toThrow(message?: string): void
|
toThrow(message?: string): void;
|
||||||
toThrowError(message?: string): void
|
toThrowError(message?: string): void;
|
||||||
toErrorDev(message?: string | Array<string>, options?: any): void
|
toBe(value: any): void;
|
||||||
toWarnDev(message?: string | Array<string>, options?: any): void
|
toEqual(value: any): void;
|
||||||
toBe(value: any): void
|
toBeFalsy(): void;
|
||||||
toEqual(value: any): void
|
toBeTruthy(): void;
|
||||||
toBeFalsy(): void
|
toBeNull(): void;
|
||||||
toBeTruthy(): void
|
toBeUndefined(): void;
|
||||||
toBeNull(): void
|
toBeDefined(): void;
|
||||||
toBeUndefined(): void
|
toMatch(regexp: RegExp): void;
|
||||||
toBeDefined(): void
|
toContain(string: string): void;
|
||||||
toMatch(regexp: RegExp): void
|
toBeCloseTo(number: number, delta: number): void;
|
||||||
toContain(string: string): void
|
toBeGreaterThan(number: number): void;
|
||||||
toBeCloseTo(number: number, delta: number): void
|
toBeLessThan(number: number): void;
|
||||||
toBeGreaterThan(number: number): void
|
toBeCalled(): void;
|
||||||
toBeLessThan(number: number): void
|
toBeCalledWith(...arguments): void;
|
||||||
toBeCalled(): void
|
lastCalledWith(...arguments): void;
|
||||||
toBeCalledWith(...arguments): void
|
|
||||||
lastCalledWith(...arguments): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Jest {
|
interface Jest {
|
||||||
autoMockOff(): void
|
autoMockOff(): void;
|
||||||
autoMockOn(): void
|
autoMockOn(): void;
|
||||||
clearAllTimers(): void
|
clearAllTimers(): void;
|
||||||
dontMock(moduleName: string): void
|
dontMock(moduleName: string): void;
|
||||||
genMockFromModule(moduleObj: Object): Object
|
genMockFromModule(moduleObj: Object): Object;
|
||||||
genMockFunction(): MockFunction
|
genMockFunction(): MockFunction;
|
||||||
genMockFn(): MockFunction
|
genMockFn(): MockFunction;
|
||||||
mock(moduleName: string): void
|
mock(moduleName: string): void;
|
||||||
runAllTicks(): void
|
runAllTicks(): void;
|
||||||
runAllTimers(): void
|
runAllTimers(): void;
|
||||||
runOnlyPendingTimers(): void
|
runOnlyPendingTimers(): void;
|
||||||
setMock(moduleName: string, moduleExports: Object): void
|
setMock(moduleName: string, moduleExports: Object): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MockFunction {
|
interface MockFunction {
|
||||||
(...arguments): any
|
(...arguments): any;
|
||||||
mock: {
|
mock: {
|
||||||
calls: Array<Array<any>>
|
calls: Array<Array<any>>;
|
||||||
instances: Array<Object>
|
instances: Array<Object>;
|
||||||
}
|
};
|
||||||
mockClear(): void
|
mockClear(): void;
|
||||||
mockImplementation(fn: Function): MockFunction
|
mockImplementation(fn: Function): MockFunction;
|
||||||
mockImpl(fn: Function): MockFunction
|
mockImpl(fn: Function): MockFunction;
|
||||||
mockReturnThis(): MockFunction
|
mockReturnThis(): MockFunction;
|
||||||
mockReturnValue(value: any): MockFunction
|
mockReturnValue(value: any): MockFunction;
|
||||||
mockReturnValueOnce(value: any): MockFunction
|
mockReturnValueOnce(value: any): MockFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const check: any;
|
declare const check: any;
|
||||||
|
|||||||
Reference in New Issue
Block a user