[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:
Ricky
2025-01-07 14:17:14 -05:00
committed by GitHub
parent f892dabd8c
commit a160102f3a
11 changed files with 149 additions and 1097 deletions

View File

@@ -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,
}, },

View File

@@ -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(() => {
console.log('hit'); if (__DEV__) {
flushAllUnexpectedConsoleCalls(); console.log('hit');
}
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(() => {
console.warn('hit'); if (__DEV__) {
flushAllUnexpectedConsoleCalls(); console.warn('hit');
}
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(() => {
console.error('hit'); if (__DEV__) {
flushAllUnexpectedConsoleCalls(); console.error('hit');
}
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', () => {
console.log('Hello'); if (__DEV__) {
console.log('Hello');
}
assertConsoleLogDev(['Hello']); assertConsoleLogDev(['Hello']);
}); });
// @gate __DEV__
it('passes for multiple logs', () => { it('passes for multiple logs', () => {
console.log('Hello'); if (__DEV__) {
console.log('Good day'); console.log('Hello');
console.log('Bye'); console.log('Good day');
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', () => {
console.warn('Hello\n in div'); if (__DEV__) {
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', () => {
console.warn('Hello\n in div'); if (__DEV__) {
console.warn('Good day\n in div'); console.warn('Hello\n in div');
console.warn('Bye\n in div'); console.warn('Good day\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', () => {
console.warn('Hello'); if (__DEV__) {
console.warn('Hello');
}
assertConsoleWarnDev(['Hello'], {withoutStack: true}); assertConsoleWarnDev(['Hello'], {withoutStack: true});
console.warn('Hello'); if (__DEV__) {
console.warn('Good day'); console.warn('Hello');
console.warn('Bye'); console.warn('Good day');
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', () => {
console.warn('Hello\n in div'); if (__DEV__) {
console.warn('Good day'); console.warn('Hello\n in div');
console.warn('Bye\n in div'); console.warn('Good day');
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', () => {
console.error('Hello\n in div'); if (__DEV__) {
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', () => {
console.error('Hello\n in div'); if (__DEV__) {
console.error('Good day\n in div'); console.error('Hello\n in div');
console.error('Bye\n in div'); console.error('Good day\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', () => {
console.error('Hello'); if (__DEV__) {
console.error('Hello');
}
assertConsoleErrorDev(['Hello'], {withoutStack: true}); assertConsoleErrorDev(['Hello'], {withoutStack: true});
console.error('Hello'); if (__DEV__) {
console.error('Good day'); console.error('Hello');
console.error('Bye'); console.error('Good day');
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', () => {
console.error('Hello\n in div'); if (__DEV__) {
console.error('Good day'); console.error('Hello\n in div');
console.error('Bye\n in div'); console.error('Good day');
console.error('Bye\n in div');
}
assertConsoleErrorDev([ assertConsoleErrorDev([
'Hello', 'Hello',
['Good day', {withoutStack: true}], ['Good day', {withoutStack: true}],

View File

@@ -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;
} }

View File

@@ -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',
},
],
},
],
});

View File

@@ -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'),

View File

@@ -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;
}
}
},
};
},
};

View File

@@ -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']);
});
});

View File

@@ -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'),
};

View File

@@ -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;
} }

View File

@@ -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'),
}); });

View File

@@ -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;