@samitouri / QOS-React-1 / commits / a160102f3a

[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

Ricky committed Jan 7, 2025 at 14:17 UTC a160102f3aedae0da2d692e7cf53b28a011b7bc9
11 files changed +149 -1097
.eslintrc.js
-1
@@ -303,7 +303,6 @@ module.exports = {
303 ERROR,
304 {isProductionUserAppCode: true},
305 ],
306 - 'react-internal/no-to-warn-dev-within-to-throw': ERROR,
306 'react-internal/warning-args': ERROR,
307 'react-internal/no-production-logging': ERROR,
308 },
packages/internal-test-utils/__tests__/ReactInternalTestUtils-test.js
+75 -83
@@ -13,7 +13,6 @@
13 const React = require('react');
14 const stripAnsi = require('strip-ansi');
15 const {startTransition, useDeferredValue} = React;
16 -const chalk = require('chalk');
16 const ReactNoop = require('react-noop-renderer');
17 const {
18 waitFor,
@@ -25,7 +24,7 @@ const {
24 const act = require('internal-test-utils').act;
25 const Scheduler = require('scheduler/unstable_mock');
26 const {
28 - flushAllUnexpectedConsoleCalls,
27 + assertConsoleLogsCleared,
28 resetAllUnexpectedConsoleCalls,
29 patchConsoleMethods,
30 } = require('../consoleMock');
@@ -205,16 +204,17 @@ describe('ReactInternalTestUtils console mocks', () => {
204 it('should fail if not asserted', () => {
205 expect(() => {
206 console.log('hit');
208 - flushAllUnexpectedConsoleCalls();
209 - }).toThrow(`Expected test not to call ${chalk.bold('console.log()')}.`);
207 + assertConsoleLogsCleared();
208 + }).toThrow(`console.log was called without assertConsoleLogDev`);
209 });
210
212 - // @gate __DEV__
211 it('should not fail if mocked with spyOnDev', () => {
212 spyOnDev(console, 'log').mockImplementation(() => {});
213 expect(() => {
216 - console.log('hit');
217 - flushAllUnexpectedConsoleCalls();
214 + if (__DEV__) {
215 + console.log('hit');
216 + }
217 + assertConsoleLogsCleared();
218 }).not.toThrow();
219 });
220
@@ -223,7 +223,7 @@ describe('ReactInternalTestUtils console mocks', () => {
223 spyOnProd(console, 'log').mockImplementation(() => {});
224 expect(() => {
225 console.log('hit');
226 - flushAllUnexpectedConsoleCalls();
226 + assertConsoleLogsCleared();
227 }).not.toThrow();
228 });
229
@@ -231,33 +231,26 @@ describe('ReactInternalTestUtils console mocks', () => {
231 spyOnDevAndProd(console, 'log').mockImplementation(() => {});
232 expect(() => {
233 console.log('hit');
234 - flushAllUnexpectedConsoleCalls();
234 + assertConsoleLogsCleared();
235 }).not.toThrow();
236 });
237 -
238 - // @gate __DEV__
239 - it('should not fail with toLogDev', () => {
240 - expect(() => {
241 - console.log('hit');
242 - flushAllUnexpectedConsoleCalls();
243 - }).toLogDev(['hit']);
244 - });
237 });
238
239 describe('console.warn', () => {
240 it('should fail if not asserted', () => {
241 expect(() => {
242 console.warn('hit');
251 - flushAllUnexpectedConsoleCalls();
252 - }).toThrow(`Expected test not to call ${chalk.bold('console.warn()')}.`);
243 + assertConsoleLogsCleared();
244 + }).toThrow('console.warn was called without assertConsoleWarnDev');
245 });
246
255 - // @gate __DEV__
247 it('should not fail if mocked with spyOnDev', () => {
248 spyOnDev(console, 'warn').mockImplementation(() => {});
249 expect(() => {
259 - console.warn('hit');
260 - flushAllUnexpectedConsoleCalls();
250 + if (__DEV__) {
251 + console.warn('hit');
252 + }
253 + assertConsoleLogsCleared();
254 }).not.toThrow();
255 });
256
@@ -266,7 +259,7 @@ describe('ReactInternalTestUtils console mocks', () => {
259 spyOnProd(console, 'warn').mockImplementation(() => {});
260 expect(() => {
261 console.warn('hit');
269 - flushAllUnexpectedConsoleCalls();
262 + assertConsoleLogsCleared();
263 }).not.toThrow();
264 });
265
@@ -274,33 +267,26 @@ describe('ReactInternalTestUtils console mocks', () => {
267 spyOnDevAndProd(console, 'warn').mockImplementation(() => {});
268 expect(() => {
269 console.warn('hit');
277 - flushAllUnexpectedConsoleCalls();
270 + assertConsoleLogsCleared();
271 }).not.toThrow();
272 });
280 -
281 - // @gate __DEV__
282 - it('should not fail with toWarnDev', () => {
283 - expect(() => {
284 - console.warn('hit');
285 - flushAllUnexpectedConsoleCalls();
286 - }).toWarnDev(['hit'], {withoutStack: true});
287 - });
273 });
274
275 describe('console.error', () => {
276 it('should fail if console.error is not asserted', () => {
277 expect(() => {
278 console.error('hit');
294 - flushAllUnexpectedConsoleCalls();
295 - }).toThrow(`Expected test not to call ${chalk.bold('console.error()')}.`);
279 + assertConsoleLogsCleared();
280 + }).toThrow('console.error was called without assertConsoleErrorDev');
281 });
282
298 - // @gate __DEV__
283 it('should not fail if mocked with spyOnDev', () => {
284 spyOnDev(console, 'error').mockImplementation(() => {});
285 expect(() => {
302 - console.error('hit');
303 - flushAllUnexpectedConsoleCalls();
286 + if (__DEV__) {
287 + console.error('hit');
288 + }
289 + assertConsoleLogsCleared();
290 }).not.toThrow();
291 });
292
@@ -309,7 +295,7 @@ describe('ReactInternalTestUtils console mocks', () => {
295 spyOnProd(console, 'error').mockImplementation(() => {});
296 expect(() => {
297 console.error('hit');
312 - flushAllUnexpectedConsoleCalls();
298 + assertConsoleLogsCleared();
299 }).not.toThrow();
300 });
301
@@ -317,17 +303,9 @@ describe('ReactInternalTestUtils console mocks', () => {
303 spyOnDevAndProd(console, 'error').mockImplementation(() => {});
304 expect(() => {
305 console.error('hit');
320 - flushAllUnexpectedConsoleCalls();
306 + assertConsoleLogsCleared();
307 }).not.toThrow();
308 });
323 -
324 - // @gate __DEV__
325 - it('should not fail with toErrorDev', () => {
326 - expect(() => {
327 - console.error('hit');
328 - flushAllUnexpectedConsoleCalls();
329 - }).toErrorDev(['hit'], {withoutStack: true});
330 - });
309 });
310 });
311
@@ -361,17 +339,19 @@ describe('ReactInternalTestUtils console assertions', () => {
339 });
340
341 describe('assertConsoleLogDev', () => {
364 - // @gate __DEV__
342 it('passes for a single log', () => {
366 - console.log('Hello');
343 + if (__DEV__) {
344 + console.log('Hello');
345 + }
346 assertConsoleLogDev(['Hello']);
347 });
348
370 - // @gate __DEV__
349 it('passes for multiple logs', () => {
372 - console.log('Hello');
373 - console.log('Good day');
374 - console.log('Bye');
350 + if (__DEV__) {
351 + console.log('Hello');
352 + console.log('Good day');
353 + console.log('Bye');
354 + }
355 assertConsoleLogDev(['Hello', 'Good day', 'Bye']);
356 });
357
@@ -906,17 +886,19 @@ describe('ReactInternalTestUtils console assertions', () => {
886 });
887
888 describe('assertConsoleWarnDev', () => {
909 - // @gate __DEV__
889 it('passes if an warning contains a stack', () => {
911 - console.warn('Hello\n in div');
890 + if (__DEV__) {
891 + console.warn('Hello\n in div');
892 + }
893 assertConsoleWarnDev(['Hello']);
894 });
895
915 - // @gate __DEV__
896 it('passes if all warnings contain a stack', () => {
917 - console.warn('Hello\n in div');
918 - console.warn('Good day\n in div');
919 - console.warn('Bye\n in div');
897 + if (__DEV__) {
898 + console.warn('Hello\n in div');
899 + console.warn('Good day\n in div');
900 + console.warn('Bye\n in div');
901 + }
902 assertConsoleWarnDev(['Hello', 'Good day', 'Bye']);
903 });
904
@@ -1353,14 +1335,17 @@ describe('ReactInternalTestUtils console assertions', () => {
1335 });
1336
1337 describe('global withoutStack', () => {
1356 - // @gate __DEV__
1338 it('passes if warnings without stack explicitly opt out', () => {
1358 - console.warn('Hello');
1339 + if (__DEV__) {
1340 + console.warn('Hello');
1341 + }
1342 assertConsoleWarnDev(['Hello'], {withoutStack: true});
1343
1361 - console.warn('Hello');
1362 - console.warn('Good day');
1363 - console.warn('Bye');
1344 + if (__DEV__) {
1345 + console.warn('Hello');
1346 + console.warn('Good day');
1347 + console.warn('Bye');
1348 + }
1349
1350 assertConsoleWarnDev(['Hello', 'Good day', 'Bye'], {
1351 withoutStack: true,
@@ -1460,11 +1445,12 @@ describe('ReactInternalTestUtils console assertions', () => {
1445 });
1446 });
1447 describe('local withoutStack', () => {
1463 - // @gate __DEV__
1448 it('passes when expected withoutStack logs matches the actual logs', () => {
1465 - console.warn('Hello\n in div');
1466 - console.warn('Good day');
1467 - console.warn('Bye\n in div');
1449 + if (__DEV__) {
1450 + console.warn('Hello\n in div');
1451 + console.warn('Good day');
1452 + console.warn('Bye\n in div');
1453 + }
1454 assertConsoleWarnDev([
1455 'Hello',
1456 ['Good day', {withoutStack: true}],
@@ -1981,17 +1967,19 @@ describe('ReactInternalTestUtils console assertions', () => {
1967 });
1968
1969 describe('assertConsoleErrorDev', () => {
1984 - // @gate __DEV__
1970 it('passes if an error contains a stack', () => {
1986 - console.error('Hello\n in div');
1971 + if (__DEV__) {
1972 + console.error('Hello\n in div');
1973 + }
1974 assertConsoleErrorDev(['Hello']);
1975 });
1976
1990 - // @gate __DEV__
1977 it('passes if all errors contain a stack', () => {
1992 - console.error('Hello\n in div');
1993 - console.error('Good day\n in div');
1994 - console.error('Bye\n in div');
1978 + if (__DEV__) {
1979 + console.error('Hello\n in div');
1980 + console.error('Good day\n in div');
1981 + console.error('Bye\n in div');
1982 + }
1983 assertConsoleErrorDev(['Hello', 'Good day', 'Bye']);
1984 });
1985
@@ -2446,14 +2434,17 @@ describe('ReactInternalTestUtils console assertions', () => {
2434 });
2435
2436 describe('global withoutStack', () => {
2449 - // @gate __DEV__
2437 it('passes if errors without stack explicitly opt out', () => {
2451 - console.error('Hello');
2438 + if (__DEV__) {
2439 + console.error('Hello');
2440 + }
2441 assertConsoleErrorDev(['Hello'], {withoutStack: true});
2442
2454 - console.error('Hello');
2455 - console.error('Good day');
2456 - console.error('Bye');
2443 + if (__DEV__) {
2444 + console.error('Hello');
2445 + console.error('Good day');
2446 + console.error('Bye');
2447 + }
2448
2449 assertConsoleErrorDev(['Hello', 'Good day', 'Bye'], {
2450 withoutStack: true,
@@ -2553,11 +2544,12 @@ describe('ReactInternalTestUtils console assertions', () => {
2544 });
2545 });
2546 describe('local withoutStack', () => {
2556 - // @gate __DEV__
2547 it('passes when expected withoutStack logs matches the actual logs', () => {
2558 - console.error('Hello\n in div');
2559 - console.error('Good day');
2560 - console.error('Bye\n in div');
2548 + if (__DEV__) {
2549 + console.error('Hello\n in div');
2550 + console.error('Good day');
2551 + console.error('Bye\n in div');
2552 + }
2553 assertConsoleErrorDev([
2554 'Hello',
2555 ['Good day', {withoutStack: true}],
packages/internal-test-utils/consoleMock.js
+4 -107
@@ -19,19 +19,7 @@ const loggedErrors = (global.__loggedErrors = global.__loggedErrors || []);
19 const loggedWarns = (global.__loggedWarns = global.__loggedWarns || []);
20 const loggedLogs = (global.__loggedLogs = global.__loggedLogs || []);
21
22 -// TODO: delete these after code modding away from toWarnDev.
23 -const unexpectedErrorCallStacks = (global.__unexpectedErrorCallStacks =
24 - global.__unexpectedErrorCallStacks || []);
25 -const unexpectedWarnCallStacks = (global.__unexpectedWarnCallStacks =
26 - global.__unexpectedWarnCallStacks || []);
27 -const unexpectedLogCallStacks = (global.__unexpectedLogCallStacks =
28 - global.__unexpectedLogCallStacks || []);
29 -
30 -const patchConsoleMethod = (
31 - methodName,
32 - unexpectedConsoleCallStacks,
33 - logged,
34 -) => {
22 +const patchConsoleMethod = (methodName, logged) => {
23 const newMethod = function (format, ...args) {
24 // Ignore uncaught errors reported by jsdom
25 // and React addendums because they're too noisy.
@@ -72,14 +60,6 @@ const patchConsoleMethod = (
60 }
61 }
62
75 - // Capture the call stack now so we can warn about it later.
76 - // The call stack has helpful information for the test author.
77 - // Don't throw yet though b'c it might be accidentally caught and suppressed.
78 - const stack = new Error().stack;
79 - unexpectedConsoleCallStacks.push([
80 - stack.slice(stack.indexOf('\n') + 1),
81 - util.format(format, ...args),
82 - ]);
63 logged.push([format, ...args]);
64 };
65
@@ -88,123 +68,40 @@ const patchConsoleMethod = (
68 return newMethod;
69 };
70
91 -const flushUnexpectedConsoleCalls = (
92 - mockMethod,
93 - methodName,
94 - expectedMatcher,
95 - unexpectedConsoleCallStacks,
96 -) => {
97 - if (
98 - console[methodName] !== mockMethod &&
99 - !jest.isMockFunction(console[methodName])
100 - ) {
101 - // throw new Error(
102 - // `Test did not tear down console.${methodName} mock properly.`
103 - // );
104 - }
105 - if (unexpectedConsoleCallStacks.length > 0) {
106 - const messages = unexpectedConsoleCallStacks.map(
107 - ([stack, message]) =>
108 - `${chalk.red(message)}\n` +
109 - `${stack
110 - .split('\n')
111 - .map(line => chalk.gray(line))
112 - .join('\n')}`,
113 - );
114 -
115 - const type = methodName === 'log' ? 'log' : 'warning';
116 - const message =
117 - `Expected test not to call ${chalk.bold(
118 - `console.${methodName}()`,
119 - )}.\n\n` +
120 - `If the ${type} is expected, test for it explicitly by:\n` +
121 - `1. Using ${chalk.bold(expectedMatcher + '()')} or...\n` +
122 - `2. Mock it out using ${chalk.bold(
123 - 'spyOnDev',
124 - )}(console, '${methodName}') or ${chalk.bold(
125 - 'spyOnProd',
126 - )}(console, '${methodName}'), and test that the ${type} occurs.`;
127 -
128 - throw new Error(`${message}\n\n${messages.join('\n\n')}`);
129 - }
130 -};
131 -
132 -let errorMethod;
133 -let warnMethod;
71 let logMethod;
72 export function patchConsoleMethods({includeLog} = {includeLog: false}) {
136 - errorMethod = patchConsoleMethod(
137 - 'error',
138 - unexpectedErrorCallStacks,
139 - loggedErrors,
140 - );
141 - warnMethod = patchConsoleMethod(
142 - 'warn',
143 - unexpectedWarnCallStacks,
144 - loggedWarns,
145 - );
73 + patchConsoleMethod('error', loggedErrors);
74 + patchConsoleMethod('warn', loggedWarns);
75
76 // Only assert console.log isn't called in CI so you can debug tests in DEV.
77 // The matchers will still work in DEV, so you can assert locally.
78 if (includeLog) {
150 - logMethod = patchConsoleMethod('log', unexpectedLogCallStacks, loggedLogs);
151 - }
152 -}
153 -
154 -export function flushAllUnexpectedConsoleCalls() {
155 - flushUnexpectedConsoleCalls(
156 - errorMethod,
157 - 'error',
158 - 'assertConsoleErrorDev',
159 - unexpectedErrorCallStacks,
160 - );
161 - flushUnexpectedConsoleCalls(
162 - warnMethod,
163 - 'warn',
164 - 'assertConsoleWarnDev',
165 - unexpectedWarnCallStacks,
166 - );
167 - if (logMethod) {
168 - flushUnexpectedConsoleCalls(
169 - logMethod,
170 - 'log',
171 - 'assertConsoleLogDev',
172 - unexpectedLogCallStacks,
173 - );
174 - unexpectedLogCallStacks.length = 0;
79 + logMethod = patchConsoleMethod('log', loggedLogs);
80 }
176 - unexpectedErrorCallStacks.length = 0;
177 - unexpectedWarnCallStacks.length = 0;
81 }
82
83 export function resetAllUnexpectedConsoleCalls() {
84 loggedErrors.length = 0;
85 loggedWarns.length = 0;
183 - unexpectedErrorCallStacks.length = 0;
184 - unexpectedWarnCallStacks.length = 0;
86 if (logMethod) {
87 loggedLogs.length = 0;
187 - unexpectedLogCallStacks.length = 0;
88 }
89 }
90
91 export function clearLogs() {
92 const logs = Array.from(loggedLogs);
193 - unexpectedLogCallStacks.length = 0;
93 loggedLogs.length = 0;
94 return logs;
95 }
96
97 export function clearWarnings() {
98 const warnings = Array.from(loggedWarns);
200 - unexpectedWarnCallStacks.length = 0;
99 loggedWarns.length = 0;
100 return warnings;
101 }
102
103 export function clearErrors() {
104 const errors = Array.from(loggedErrors);
207 - unexpectedErrorCallStacks.length = 0;
105 loggedErrors.length = 0;
106 return errors;
107 }
scripts/eslint-rules/__tests__/no-to-warn-dev-within-to-throw-test.internal.js deleted
-31
@@ -1,31 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -const rule = require('../no-to-warn-dev-within-to-throw');
13 -const {RuleTester} = require('eslint');
14 -const ruleTester = new RuleTester();
15 -
16 -ruleTester.run('eslint-rules/no-to-warn-dev-within-to-throw', rule, {
17 - valid: [
18 - 'expect(callback).toWarnDev("warning");',
19 - 'expect(function() { expect(callback).toThrow("error") }).toWarnDev("warning");',
20 - ],
21 - invalid: [
22 - {
23 - code: 'expect(function() { expect(callback).toWarnDev("warning") }).toThrow("error");',
24 - errors: [
25 - {
26 - message: 'toWarnDev() matcher should not be nested',
27 - },
28 - ],
29 - },
30 - ],
31 -});
scripts/eslint-rules/index.js
-1
@@ -3,7 +3,6 @@
3 module.exports = {
4 rules: {
5 'no-primitive-constructors': require('./no-primitive-constructors'),
6 - 'no-to-warn-dev-within-to-throw': require('./no-to-warn-dev-within-to-throw'),
6 'warning-args': require('./warning-args'),
7 'prod-error-codes': require('./prod-error-codes'),
8 'no-production-logging': require('./no-production-logging'),
scripts/eslint-rules/no-to-warn-dev-within-to-throw.js deleted
-41
@@ -1,41 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -module.exports = {
13 - meta: {
14 - schema: [],
15 - },
16 - create(context) {
17 - return {
18 - Identifier(node) {
19 - if (node.name === 'toWarnDev' || node.name === 'toErrorDev') {
20 - let current = node;
21 - while (current.parent) {
22 - if (current.type === 'CallExpression') {
23 - if (
24 - current &&
25 - current.callee &&
26 - current.callee.property &&
27 - current.callee.property.name === 'toThrow'
28 - ) {
29 - context.report(
30 - node,
31 - node.name + '() matcher should not be nested'
32 - );
33 - }
34 - }
35 - current = current.parent;
36 - }
37 - }
38 - },
39 - };
40 - },
41 -};
scripts/jest/matchers/__tests__/toWarnDev-test.js deleted
-435
@@ -1,435 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -describe('toErrorDev', () => {
13 - it('does not fail if a warning contains a stack', () => {
14 - expect(() => {
15 - if (__DEV__) {
16 - console.error('Hello\n in div');
17 - }
18 - }).toErrorDev('Hello');
19 - });
20 -
21 - it('does not fail if all warnings contain a stack', () => {
22 - expect(() => {
23 - if (__DEV__) {
24 - console.error('Hello\n in div');
25 - console.error('Good day\n in div');
26 - console.error('Bye\n in div');
27 - }
28 - }).toErrorDev(['Hello', 'Good day', 'Bye']);
29 - });
30 -
31 - it('does not fail if warnings without stack explicitly opt out', () => {
32 - expect(() => {
33 - if (__DEV__) {
34 - console.error('Hello');
35 - }
36 - }).toErrorDev('Hello', {withoutStack: true});
37 - expect(() => {
38 - if (__DEV__) {
39 - console.error('Hello');
40 - console.error('Good day');
41 - console.error('Bye');
42 - }
43 - }).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: true});
44 - });
45 -
46 - it('does not fail when expected stack-less warning number matches the actual one', () => {
47 - expect(() => {
48 - if (__DEV__) {
49 - console.error('Hello\n in div');
50 - console.error('Good day');
51 - console.error('Bye\n in div');
52 - }
53 - }).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: 1});
54 - });
55 -
56 - if (__DEV__) {
57 - // Helper methods avoids invalid toWarn().toThrow() nesting
58 - // See no-to-warn-dev-within-to-throw
59 - const expectToWarnAndToThrow = (expectBlock, expectedErrorMessage) => {
60 - let caughtError;
61 - try {
62 - expectBlock();
63 - } catch (error) {
64 - caughtError = error;
65 - }
66 - expect(caughtError).toBeDefined();
67 - expect(caughtError.message).toContain(expectedErrorMessage);
68 - };
69 -
70 - it('fails if a warning does not contain a stack', () => {
71 - expectToWarnAndToThrow(() => {
72 - expect(() => {
73 - console.error('Hello');
74 - }).toErrorDev('Hello');
75 - }, 'Received warning unexpectedly does not include a component stack');
76 - });
77 -
78 - it('fails if some warnings do not contain a stack', () => {
79 - expectToWarnAndToThrow(() => {
80 - expect(() => {
81 - console.error('Hello\n in div');
82 - console.error('Good day\n in div');
83 - console.error('Bye');
84 - }).toErrorDev(['Hello', 'Good day', 'Bye']);
85 - }, 'Received warning unexpectedly does not include a component stack');
86 - expectToWarnAndToThrow(() => {
87 - expect(() => {
88 - console.error('Hello');
89 - console.error('Good day\n in div');
90 - console.error('Bye\n in div');
91 - }).toErrorDev(['Hello', 'Good day', 'Bye']);
92 - }, 'Received warning unexpectedly does not include a component stack');
93 - expectToWarnAndToThrow(() => {
94 - expect(() => {
95 - console.error('Hello\n in div');
96 - console.error('Good day');
97 - console.error('Bye\n in div');
98 - }).toErrorDev(['Hello', 'Good day', 'Bye']);
99 - }, 'Received warning unexpectedly does not include a component stack');
100 - expectToWarnAndToThrow(() => {
101 - expect(() => {
102 - console.error('Hello');
103 - console.error('Good day');
104 - console.error('Bye');
105 - }).toErrorDev(['Hello', 'Good day', 'Bye']);
106 - }, 'Received warning unexpectedly does not include a component stack');
107 - });
108 -
109 - it('fails if warning is expected to not have a stack, but does', () => {
110 - expectToWarnAndToThrow(() => {
111 - expect(() => {
112 - console.error('Hello\n in div');
113 - }).toErrorDev('Hello', {withoutStack: true});
114 - }, 'Received warning unexpectedly includes a component stack');
115 - expectToWarnAndToThrow(() => {
116 - expect(() => {
117 - console.error('Hello\n in div');
118 - console.error('Good day');
119 - console.error('Bye\n in div');
120 - }).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: true});
121 - }, 'Received warning unexpectedly includes a component stack');
122 - });
123 -
124 - it('fails if expected stack-less warning number does not match the actual one', () => {
125 - expectToWarnAndToThrow(() => {
126 - expect(() => {
127 - console.error('Hello\n in div');
128 - console.error('Good day');
129 - console.error('Bye\n in div');
130 - }).toErrorDev(['Hello', 'Good day', 'Bye'], {withoutStack: 4});
131 - }, 'Expected 4 warnings without a component stack but received 1');
132 - });
133 -
134 - it('fails if withoutStack is invalid', () => {
135 - expectToWarnAndToThrow(() => {
136 - expect(() => {
137 - console.error('Hi');
138 - }).toErrorDev('Hi', {withoutStack: null});
139 - }, 'Instead received object');
140 - expectToWarnAndToThrow(() => {
141 - expect(() => {
142 - console.error('Hi');
143 - }).toErrorDev('Hi', {withoutStack: {}});
144 - }, 'Instead received object');
145 - expectToWarnAndToThrow(() => {
146 - expect(() => {
147 - console.error('Hi');
148 - }).toErrorDev('Hi', {withoutStack: 'haha'});
149 - }, 'Instead received string');
150 - });
151 -
152 - it('fails if the argument number does not match', () => {
153 - expectToWarnAndToThrow(() => {
154 - expect(() => {
155 - console.error('Hi %s', 'Sara', 'extra');
156 - }).toErrorDev('Hi', {withoutStack: true});
157 - }, 'Received 2 arguments for a message with 1 placeholders');
158 -
159 - expectToWarnAndToThrow(() => {
160 - expect(() => {
161 - console.error('Hi %s');
162 - }).toErrorDev('Hi', {withoutStack: true});
163 - }, 'Received 0 arguments for a message with 1 placeholders');
164 - });
165 -
166 - it('fails if stack is passed twice', () => {
167 - expectToWarnAndToThrow(() => {
168 - expect(() => {
169 - console.error('Hi %s%s', '\n in div', '\n in div');
170 - }).toErrorDev('Hi');
171 - }, 'Received more than one component stack for a warning');
172 - });
173 -
174 - it('fails if multiple strings are passed without an array wrapper', () => {
175 - expectToWarnAndToThrow(() => {
176 - expect(() => {
177 - console.error('Hi \n in div');
178 - }).toErrorDev('Hi', 'Bye');
179 - }, 'toErrorDev() second argument, when present, should be an object');
180 - expectToWarnAndToThrow(() => {
181 - expect(() => {
182 - console.error('Hi \n in div');
183 - console.error('Bye \n in div');
184 - }).toErrorDev('Hi', 'Bye');
185 - }, 'toErrorDev() second argument, when present, should be an object');
186 - expectToWarnAndToThrow(() => {
187 - expect(() => {
188 - console.error('Hi \n in div');
189 - console.error('Wow \n in div');
190 - console.error('Bye \n in div');
191 - }).toErrorDev('Hi', 'Bye');
192 - }, 'toErrorDev() second argument, when present, should be an object');
193 - expectToWarnAndToThrow(() => {
194 - expect(() => {
195 - console.error('Hi \n in div');
196 - console.error('Wow \n in div');
197 - console.error('Bye \n in div');
198 - }).toErrorDev('Hi', 'Wow', 'Bye');
199 - }, 'toErrorDev() second argument, when present, should be an object');
200 - });
201 -
202 - it('fails on more than two arguments', () => {
203 - expectToWarnAndToThrow(() => {
204 - expect(() => {
205 - console.error('Hi \n in div');
206 - console.error('Wow \n in div');
207 - console.error('Bye \n in div');
208 - }).toErrorDev('Hi', undefined, 'Bye');
209 - }, 'toErrorDev() received more than two arguments.');
210 - });
211 - }
212 -});
213 -
214 -describe('toWarnDev', () => {
215 - it('does not fail if a warning contains a stack', () => {
216 - expect(() => {
217 - if (__DEV__) {
218 - console.warn('Hello\n in div');
219 - }
220 - }).toWarnDev('Hello');
221 - });
222 -
223 - it('does not fail if all warnings contain a stack', () => {
224 - expect(() => {
225 - if (__DEV__) {
226 - console.warn('Hello\n in div');
227 - console.warn('Good day\n in div');
228 - console.warn('Bye\n in div');
229 - }
230 - }).toWarnDev(['Hello', 'Good day', 'Bye']);
231 - });
232 -
233 - it('does not fail if warnings without stack explicitly opt out', () => {
234 - expect(() => {
235 - if (__DEV__) {
236 - console.warn('Hello');
237 - }
238 - }).toWarnDev('Hello', {withoutStack: true});
239 - expect(() => {
240 - if (__DEV__) {
241 - console.warn('Hello');
242 - console.warn('Good day');
243 - console.warn('Bye');
244 - }
245 - }).toWarnDev(['Hello', 'Good day', 'Bye'], {withoutStack: true});
246 - });
247 -
248 - it('does not fail when expected stack-less warning number matches the actual one', () => {
249 - expect(() => {
250 - if (__DEV__) {
251 - console.warn('Hello\n in div');
252 - console.warn('Good day');
253 - console.warn('Bye\n in div');
254 - }
255 - }).toWarnDev(['Hello', 'Good day', 'Bye'], {withoutStack: 1});
256 - });
257 -
258 - if (__DEV__) {
259 - // Helper methods avoids invalid toWarn().toThrow() nesting
260 - // See no-to-warn-dev-within-to-throw
261 - const expectToWarnAndToThrow = (expectBlock, expectedErrorMessage) => {
262 - let caughtError;
263 - try {
264 - expectBlock();
265 - } catch (error) {
266 - caughtError = error;
267 - }
268 - expect(caughtError).toBeDefined();
269 - expect(caughtError.message).toContain(expectedErrorMessage);
270 - };
271 -
272 - it('fails if a warning does not contain a stack', () => {
273 - expectToWarnAndToThrow(() => {
274 - expect(() => {
275 - console.warn('Hello');
276 - }).toWarnDev('Hello');
277 - }, 'Received warning unexpectedly does not include a component stack');
278 - });
279 -
280 - it('fails if some warnings do not contain a stack', () => {
281 - expectToWarnAndToThrow(() => {
282 - expect(() => {
283 - console.warn('Hello\n in div');
284 - console.warn('Good day\n in div');
285 - console.warn('Bye');
286 - }).toWarnDev(['Hello', 'Good day', 'Bye']);
287 - }, 'Received warning unexpectedly does not include a component stack');
288 - expectToWarnAndToThrow(() => {
289 - expect(() => {
290 - console.warn('Hello');
291 - console.warn('Good day\n in div');
292 - console.warn('Bye\n in div');
293 - }).toWarnDev(['Hello', 'Good day', 'Bye']);
294 - }, 'Received warning unexpectedly does not include a component stack');
295 - expectToWarnAndToThrow(() => {
296 - expect(() => {
297 - console.warn('Hello\n in div');
298 - console.warn('Good day');
299 - console.warn('Bye\n in div');
300 - }).toWarnDev(['Hello', 'Good day', 'Bye']);
301 - }, 'Received warning unexpectedly does not include a component stack');
302 - expectToWarnAndToThrow(() => {
303 - expect(() => {
304 - console.warn('Hello');
305 - console.warn('Good day');
306 - console.warn('Bye');
307 - }).toWarnDev(['Hello', 'Good day', 'Bye']);
308 - }, 'Received warning unexpectedly does not include a component stack');
309 - });
310 -
311 - it('fails if warning is expected to not have a stack, but does', () => {
312 - expectToWarnAndToThrow(() => {
313 - expect(() => {
314 - console.warn('Hello\n in div');
315 - }).toWarnDev('Hello', {withoutStack: true});
316 - }, 'Received warning unexpectedly includes a component stack');
317 - expectToWarnAndToThrow(() => {
318 - expect(() => {
319 - console.warn('Hello\n in div');
320 - console.warn('Good day');
321 - console.warn('Bye\n in div');
322 - }).toWarnDev(['Hello', 'Good day', 'Bye'], {
323 - withoutStack: true,
324 - });
325 - }, 'Received warning unexpectedly includes a component stack');
326 - });
327 -
328 - it('fails if expected stack-less warning number does not match the actual one', () => {
329 - expectToWarnAndToThrow(() => {
330 - expect(() => {
331 - console.warn('Hello\n in div');
332 - console.warn('Good day');
333 - console.warn('Bye\n in div');
334 - }).toWarnDev(['Hello', 'Good day', 'Bye'], {
335 - withoutStack: 4,
336 - });
337 - }, 'Expected 4 warnings without a component stack but received 1');
338 - });
339 -
340 - it('fails if withoutStack is invalid', () => {
341 - expectToWarnAndToThrow(() => {
342 - expect(() => {
343 - console.warn('Hi');
344 - }).toWarnDev('Hi', {withoutStack: null});
345 - }, 'Instead received object');
346 - expectToWarnAndToThrow(() => {
347 - expect(() => {
348 - console.warn('Hi');
349 - }).toWarnDev('Hi', {withoutStack: {}});
350 - }, 'Instead received object');
351 - expectToWarnAndToThrow(() => {
352 - expect(() => {
353 - console.warn('Hi');
354 - }).toWarnDev('Hi', {withoutStack: 'haha'});
355 - }, 'Instead received string');
356 - });
357 -
358 - it('fails if the argument number does not match', () => {
359 - expectToWarnAndToThrow(() => {
360 - expect(() => {
361 - console.warn('Hi %s', 'Sara', 'extra');
362 - }).toWarnDev('Hi', {withoutStack: true});
363 - }, 'Received 2 arguments for a message with 1 placeholders');
364 -
365 - expectToWarnAndToThrow(() => {
366 - expect(() => {
367 - console.warn('Hi %s');
368 - }).toWarnDev('Hi', {withoutStack: true});
369 - }, 'Received 0 arguments for a message with 1 placeholders');
370 - });
371 -
372 - it('fails if stack is passed twice', () => {
373 - expectToWarnAndToThrow(() => {
374 - expect(() => {
375 - console.warn('Hi %s%s', '\n in div', '\n in div');
376 - }).toWarnDev('Hi');
377 - }, 'Received more than one component stack for a warning');
378 - });
379 -
380 - it('fails if multiple strings are passed without an array wrapper', () => {
381 - expectToWarnAndToThrow(() => {
382 - expect(() => {
383 - console.warn('Hi \n in div');
384 - }).toWarnDev('Hi', 'Bye');
385 - }, 'toWarnDev() second argument, when present, should be an object');
386 - expectToWarnAndToThrow(() => {
387 - expect(() => {
388 - console.warn('Hi \n in div');
389 - console.warn('Bye \n in div');
390 - }).toWarnDev('Hi', 'Bye');
391 - }, 'toWarnDev() second argument, when present, should be an object');
392 - expectToWarnAndToThrow(() => {
393 - expect(() => {
394 - console.warn('Hi \n in div');
395 - console.warn('Wow \n in div');
396 - console.warn('Bye \n in div');
397 - }).toWarnDev('Hi', 'Bye');
398 - }, 'toWarnDev() second argument, when present, should be an object');
399 - expectToWarnAndToThrow(() => {
400 - expect(() => {
401 - console.warn('Hi \n in div');
402 - console.warn('Wow \n in div');
403 - console.warn('Bye \n in div');
404 - }).toWarnDev('Hi', 'Wow', 'Bye');
405 - }, 'toWarnDev() second argument, when present, should be an object');
406 - });
407 -
408 - it('fails on more than two arguments', () => {
409 - expectToWarnAndToThrow(() => {
410 - expect(() => {
411 - console.warn('Hi \n in div');
412 - console.warn('Wow \n in div');
413 - console.warn('Bye \n in div');
414 - }).toWarnDev('Hi', undefined, 'Bye');
415 - }, 'toWarnDev() received more than two arguments.');
416 - });
417 - }
418 -});
419 -
420 -describe('toLogDev', () => {
421 - it('does not fail if warnings do not include a stack', () => {
422 - expect(() => {
423 - if (__DEV__) {
424 - console.log('Hello');
425 - }
426 - }).toLogDev('Hello');
427 - expect(() => {
428 - if (__DEV__) {
429 - console.log('Hello');
430 - console.log('Good day');
431 - console.log('Bye');
432 - }
433 - }).toLogDev(['Hello', 'Good day', 'Bye']);
434 - });
435 -});
scripts/jest/matchers/toWarnDev.js deleted
-348
@@ -1,348 +0,0 @@
1 -'use strict';
2 -
3 -const {diff: jestDiff} = require('jest-diff');
4 -const util = require('util');
5 -const shouldIgnoreConsoleError = require('internal-test-utils/shouldIgnoreConsoleError');
6 -
7 -function normalizeCodeLocInfo(str) {
8 - if (typeof str !== 'string') {
9 - return str;
10 - }
11 - // This special case exists only for the special source location in
12 - // ReactElementValidator. That will go away if we remove source locations.
13 - str = str.replace(/Check your code at .+?:\d+/g, 'Check your code at **');
14 - // V8 format:
15 - // at Component (/path/filename.js:123:45)
16 - // React format:
17 - // in Component (at filename.js:123)
18 - return str.replace(/\n +(?:at|in) ([\S]+)[^\n]*/g, function (m, name) {
19 - if (name.endsWith('.render')) {
20 - // Class components will have the `render` method as part of their stack trace.
21 - // We strip that out in our normalization to make it look more like component stacks.
22 - name = name.slice(0, name.length - 7);
23 - }
24 - return '\n in ' + name + ' (at **)';
25 - });
26 -}
27 -
28 -const createMatcherFor = (consoleMethod, matcherName) =>
29 - function matcher(callback, expectedMessages, options = {}) {
30 - if (__DEV__) {
31 - // Warn about incorrect usage of matcher.
32 - if (typeof expectedMessages === 'string') {
33 - expectedMessages = [expectedMessages];
34 - } else if (!Array.isArray(expectedMessages)) {
35 - throw Error(
36 - `${matcherName}() requires a parameter of type string or an array of strings ` +
37 - `but was given ${typeof expectedMessages}.`
38 - );
39 - }
40 - if (
41 - options != null &&
42 - (typeof options !== 'object' || Array.isArray(options))
43 - ) {
44 - throw new Error(
45 - `${matcherName}() second argument, when present, should be an object. ` +
46 - 'Did you forget to wrap the messages into an array?'
47 - );
48 - }
49 - if (arguments.length > 3) {
50 - // `matcher` comes from Jest, so it's more than 2 in practice
51 - throw new Error(
52 - `${matcherName}() received more than two arguments. ` +
53 - 'Did you forget to wrap the messages into an array?'
54 - );
55 - }
56 -
57 - const withoutStack = options.withoutStack;
58 - const logAllErrors = options.logAllErrors;
59 - const warningsWithoutComponentStack = [];
60 - const warningsWithComponentStack = [];
61 - const unexpectedWarnings = [];
62 -
63 - let lastWarningWithMismatchingFormat = null;
64 - let lastWarningWithExtraComponentStack = null;
65 -
66 - // Catch errors thrown by the callback,
67 - // But only rethrow them if all test expectations have been satisfied.
68 - // Otherwise an Error in the callback can mask a failed expectation,
69 - // and result in a test that passes when it shouldn't.
70 - let caughtError;
71 -
72 - const isLikelyAComponentStack = message =>
73 - typeof message === 'string' &&
74 - (message.includes('\n in ') || message.includes('\n at '));
75 -
76 - const consoleSpy = (format, ...args) => {
77 - // Ignore uncaught errors reported by jsdom
78 - // and React addendums because they're too noisy.
79 - if (!logAllErrors && shouldIgnoreConsoleError(format, args)) {
80 - return;
81 - }
82 -
83 - // Append Component Stacks. Simulates a framework or DevTools appending them.
84 - if (
85 - typeof format === 'string' &&
86 - (consoleMethod === 'error' || consoleMethod === 'warn')
87 - ) {
88 - const React = require('react');
89 - if (React.captureOwnerStack) {
90 - // enableOwnerStacks enabled. When it's always on, we can assume this case.
91 - const stack = React.captureOwnerStack();
92 - if (stack) {
93 - format += '%s';
94 - args.push(stack);
95 - }
96 - } else {
97 - // Otherwise we have to use internals to emulate parent stacks.
98 - const ReactSharedInternals =
99 - React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ||
100 - React.__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
101 - if (ReactSharedInternals && ReactSharedInternals.getCurrentStack) {
102 - const stack = ReactSharedInternals.getCurrentStack();
103 - if (stack !== '') {
104 - format += '%s';
105 - args.push(stack);
106 - }
107 - }
108 - }
109 - }
110 -
111 - const message = util.format(format, ...args);
112 - const normalizedMessage = normalizeCodeLocInfo(message);
113 -
114 - // Remember if the number of %s interpolations
115 - // doesn't match the number of arguments.
116 - // We'll fail the test if it happens.
117 - let argIndex = 0;
118 - // console.* could have been called with a non-string e.g. `console.error(new Error())`
119 - String(format).replace(/%s/g, () => argIndex++);
120 - if (argIndex !== args.length) {
121 - lastWarningWithMismatchingFormat = {
122 - format,
123 - args,
124 - expectedArgCount: argIndex,
125 - };
126 - }
127 -
128 - // Protect against accidentally passing a component stack
129 - // to warning() which already injects the component stack.
130 - if (
131 - args.length >= 2 &&
132 - isLikelyAComponentStack(args[args.length - 1]) &&
133 - isLikelyAComponentStack(args[args.length - 2])
134 - ) {
135 - lastWarningWithExtraComponentStack = {
136 - format,
137 - };
138 - }
139 -
140 - for (let index = 0; index < expectedMessages.length; index++) {
141 - const expectedMessage = expectedMessages[index];
142 - if (
143 - normalizedMessage === expectedMessage ||
144 - normalizedMessage.includes(expectedMessage)
145 - ) {
146 - if (isLikelyAComponentStack(normalizedMessage)) {
147 - warningsWithComponentStack.push(normalizedMessage);
148 - } else {
149 - warningsWithoutComponentStack.push(normalizedMessage);
150 - }
151 - expectedMessages.splice(index, 1);
152 - return;
153 - }
154 - }
155 -
156 - let errorMessage;
157 - if (expectedMessages.length === 0) {
158 - errorMessage =
159 - 'Unexpected warning recorded: ' +
160 - this.utils.printReceived(normalizedMessage);
161 - } else if (expectedMessages.length === 1) {
162 - errorMessage =
163 - 'Unexpected warning recorded: ' +
164 - jestDiff(expectedMessages[0], normalizedMessage);
165 - } else {
166 - errorMessage =
167 - 'Unexpected warning recorded: ' +
168 - jestDiff(expectedMessages, [normalizedMessage]);
169 - }
170 -
171 - // Record the call stack for unexpected warnings.
172 - // We don't throw an Error here though,
173 - // Because it might be suppressed by ReactFiberScheduler.
174 - unexpectedWarnings.push(new Error(errorMessage));
175 - };
176 -
177 - // TODO Decide whether we need to support nested toWarn* expectations.
178 - // If we don't need it, add a check here to see if this is already our spy,
179 - // And throw an error.
180 - const originalMethod = console[consoleMethod];
181 -
182 - // Avoid using Jest's built-in spy since it can't be removed.
183 - console[consoleMethod] = consoleSpy;
184 -
185 - const onFinally = () => {
186 - // Restore the unspied method so that unexpected errors fail tests.
187 - console[consoleMethod] = originalMethod;
188 -
189 - // Any unexpected Errors thrown by the callback should fail the test.
190 - // This should take precedence since unexpected errors could block warnings.
191 - if (caughtError) {
192 - throw caughtError;
193 - }
194 -
195 - // Any unexpected warnings should be treated as a failure.
196 - if (unexpectedWarnings.length > 0) {
197 - return {
198 - message: () => unexpectedWarnings[0].stack,
199 - pass: false,
200 - };
201 - }
202 -
203 - // Any remaining messages indicate a failed expectations.
204 - if (expectedMessages.length > 0) {
205 - return {
206 - message: () =>
207 - `Expected warning was not recorded:\n ${this.utils.printReceived(
208 - expectedMessages[0]
209 - )}`,
210 - pass: false,
211 - };
212 - }
213 -
214 - if (consoleMethod === 'log') {
215 - // We don't expect any console.log calls to have a stack.
216 - } else if (typeof withoutStack === 'number') {
217 - // We're expecting a particular number of warnings without stacks.
218 - if (withoutStack !== warningsWithoutComponentStack.length) {
219 - return {
220 - message: () =>
221 - `Expected ${withoutStack} warnings without a component stack but received ${warningsWithoutComponentStack.length}:\n` +
222 - warningsWithoutComponentStack.map(warning =>
223 - this.utils.printReceived(warning)
224 - ),
225 - pass: false,
226 - };
227 - }
228 - } else if (withoutStack === true) {
229 - // We're expecting that all warnings won't have the stack.
230 - // If some warnings have it, it's an error.
231 - if (warningsWithComponentStack.length > 0) {
232 - return {
233 - message: () =>
234 - `Received warning unexpectedly includes a component stack:\n ${this.utils.printReceived(
235 - warningsWithComponentStack[0]
236 - )}\nIf this warning intentionally includes the component stack, remove ` +
237 - `{withoutStack: true} from the ${matcherName}() call. If you have a mix of ` +
238 - `warnings with and without stack in one ${matcherName}() call, pass ` +
239 - `{withoutStack: N} where N is the number of warnings without stacks.`,
240 - pass: false,
241 - };
242 - }
243 - } else if (withoutStack === false || withoutStack === undefined) {
244 - // We're expecting that all warnings *do* have the stack (default).
245 - // If some warnings don't have it, it's an error.
246 - if (warningsWithoutComponentStack.length > 0) {
247 - return {
248 - message: () =>
249 - `Received warning unexpectedly does not include a component stack:\n ${this.utils.printReceived(
250 - warningsWithoutComponentStack[0]
251 - )}\nIf this warning intentionally omits the component stack, add ` +
252 - `{withoutStack: true} to the ${matcherName} call.`,
253 - pass: false,
254 - };
255 - }
256 - } else {
257 - throw Error(
258 - `The second argument for ${matcherName}(), when specified, must be an object. It may have a ` +
259 - `property called "withoutStack" whose value may be undefined, boolean, or a number. ` +
260 - `Instead received ${typeof withoutStack}.`
261 - );
262 - }
263 -
264 - if (lastWarningWithMismatchingFormat !== null) {
265 - return {
266 - message: () =>
267 - `Received ${
268 - lastWarningWithMismatchingFormat.args.length
269 - } arguments for a message with ${
270 - lastWarningWithMismatchingFormat.expectedArgCount
271 - } placeholders:\n ${this.utils.printReceived(
272 - lastWarningWithMismatchingFormat.format
273 - )}`,
274 - pass: false,
275 - };
276 - }
277 -
278 - if (lastWarningWithExtraComponentStack !== null) {
279 - return {
280 - message: () =>
281 - `Received more than one component stack for a warning:\n ${this.utils.printReceived(
282 - lastWarningWithExtraComponentStack.format
283 - )}\nDid you accidentally pass a stack to warning() as the last argument? ` +
284 - `Don't forget warning() already injects the component stack automatically.`,
285 - pass: false,
286 - };
287 - }
288 -
289 - return {pass: true};
290 - };
291 -
292 - let returnPromise = null;
293 - try {
294 - const result = callback();
295 -
296 - if (
297 - typeof result === 'object' &&
298 - result !== null &&
299 - typeof result.then === 'function'
300 - ) {
301 - // `act` returns a thenable that can't be chained.
302 - // Once `act(async () => {}).then(() => {}).then(() => {})` works
303 - // we can just return `result.then(onFinally, error => ...)`
304 - returnPromise = new Promise((resolve, reject) => {
305 - result
306 - .then(
307 - () => {
308 - resolve(onFinally());
309 - },
310 - error => {
311 - caughtError = error;
312 - return resolve(onFinally());
313 - }
314 - )
315 - // In case onFinally throws we need to reject from this matcher
316 - .catch(error => {
317 - reject(error);
318 - });
319 - });
320 - }
321 - } catch (error) {
322 - caughtError = error;
323 - } finally {
324 - return returnPromise === null ? onFinally() : returnPromise;
325 - }
326 - } else {
327 - // Any uncaught errors or warnings should fail tests in production mode.
328 - const result = callback();
329 -
330 - if (
331 - typeof result === 'object' &&
332 - result !== null &&
333 - typeof result.then === 'function'
334 - ) {
335 - return result.then(() => {
336 - return {pass: true};
337 - });
338 - } else {
339 - return {pass: true};
340 - }
341 - }
342 - };
343 -
344 -module.exports = {
345 - toWarnDev: createMatcherFor('warn', 'toWarnDev'),
346 - toErrorDev: createMatcherFor('error', 'toErrorDev'),
347 - toLogDev: createMatcherFor('log', 'toLogDev'),
348 -};
scripts/jest/setupTests.js
+15 -4
@@ -2,7 +2,7 @@
2
3 const {getTestFlags} = require('./TestFlags');
4 const {
5 - flushAllUnexpectedConsoleCalls,
5 + assertConsoleLogsCleared,
6 resetAllUnexpectedConsoleCalls,
7 patchConsoleMethods,
8 } = require('internal-test-utils/consoleMock');
@@ -44,7 +44,6 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
44 expect.extend({
45 ...require('./matchers/reactTestMatchers'),
46 ...require('./matchers/toThrow'),
47 - ...require('./matchers/toWarnDev'),
47 });
48
49 // We have a Babel transform that inserts guards against infinite loops.
@@ -66,7 +65,19 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
65 // Patch the console to assert that all console error/warn/log calls assert.
66 patchConsoleMethods({includeLog: !!process.env.CI});
67 beforeEach(resetAllUnexpectedConsoleCalls);
69 - afterEach(flushAllUnexpectedConsoleCalls);
68 + afterEach(assertConsoleLogsCleared);
69 +
70 + // TODO: enable this check so we don't forget to reset spyOnX mocks.
71 + // afterEach(() => {
72 + // if (
73 + // console[methodName] !== mockMethod &&
74 + // !jest.isMockFunction(console[methodName])
75 + // ) {
76 + // throw new Error(
77 + // `Test did not tear down console.${methodName} mock properly.`
78 + // );
79 + // }
80 + // });
81
82 if (process.env.NODE_ENV === 'production') {
83 // In production, we strip error messages and turn them into codes.
@@ -187,7 +198,7 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
198 // Flush unexpected console calls inside the test itself, instead of in
199 // `afterEach` like we normally do. `afterEach` is too late because if it
200 // throws, we won't have captured it.
190 - flushAllUnexpectedConsoleCalls();
201 + assertConsoleLogsCleared();
202 } catch (testError) {
203 didError = true;
204 }
scripts/jest/spec-equivalence-reporter/setupTests.js
+14 -3
@@ -10,7 +10,7 @@
10 const {
11 patchConsoleMethods,
12 resetAllUnexpectedConsoleCalls,
13 - flushAllUnexpectedConsoleCalls,
13 + assertConsoleLogsCleared,
14 } = require('internal-test-utils/consoleMock');
15 const spyOn = jest.spyOn;
16
@@ -44,10 +44,21 @@ global.spyOnProd = function (...args) {
44 // Patch the console to assert that all console error/warn/log calls assert.
45 patchConsoleMethods({includeLog: !!process.env.CI});
46 beforeEach(resetAllUnexpectedConsoleCalls);
47 -afterEach(flushAllUnexpectedConsoleCalls);
47 +afterEach(assertConsoleLogsCleared);
48 +
49 +// TODO: enable this check so we don't forget to reset spyOnX mocks.
50 +// afterEach(() => {
51 +// if (
52 +// console[methodName] !== mockMethod &&
53 +// !jest.isMockFunction(console[methodName])
54 +// ) {
55 +// throw new Error(
56 +// `Test did not tear down console.${methodName} mock properly.`
57 +// );
58 +// }
59 +// });
60
61 expect.extend({
62 ...require('../matchers/reactTestMatchers'),
63 ...require('../matchers/toThrow'),
52 - ...require('../matchers/toWarnDev'),
64 });
scripts/jest/typescript/jest.d.ts
+41 -43
@@ -8,7 +8,7 @@ declare function describe(name: string, fn: any): void;
8 declare const it: {
9 (name: string, fn: any): void;
10 only: (name: string, fn: any) => void;
11 -}
11 +};
12 declare function expect(val: any): Expect;
13 declare const jest: Jest;
14 declare function pit(name: string, fn: any): void;
@@ -19,55 +19,53 @@ declare function xdescribe(name: string, fn: any): void;
19 declare function xit(name: string, fn: any): void;
20
21 interface Expect {
22 - not: Expect
23 - toThrow(message?: string): void
24 - toThrowError(message?: string): void
25 - toErrorDev(message?: string | Array<string>, options?: any): void
26 - toWarnDev(message?: string | Array<string>, options?: any): void
27 - toBe(value: any): void
28 - toEqual(value: any): void
29 - toBeFalsy(): void
30 - toBeTruthy(): void
31 - toBeNull(): void
32 - toBeUndefined(): void
33 - toBeDefined(): void
34 - toMatch(regexp: RegExp): void
35 - toContain(string: string): void
36 - toBeCloseTo(number: number, delta: number): void
37 - toBeGreaterThan(number: number): void
38 - toBeLessThan(number: number): void
39 - toBeCalled(): void
40 - toBeCalledWith(...arguments): void
41 - lastCalledWith(...arguments): void
22 + not: Expect;
23 + toThrow(message?: string): void;
24 + toThrowError(message?: string): void;
25 + toBe(value: any): void;
26 + toEqual(value: any): void;
27 + toBeFalsy(): void;
28 + toBeTruthy(): void;
29 + toBeNull(): void;
30 + toBeUndefined(): void;
31 + toBeDefined(): void;
32 + toMatch(regexp: RegExp): void;
33 + toContain(string: string): void;
34 + toBeCloseTo(number: number, delta: number): void;
35 + toBeGreaterThan(number: number): void;
36 + toBeLessThan(number: number): void;
37 + toBeCalled(): void;
38 + toBeCalledWith(...arguments): void;
39 + lastCalledWith(...arguments): void;
40 }
41
42 interface Jest {
45 - autoMockOff(): void
46 - autoMockOn(): void
47 - clearAllTimers(): void
48 - dontMock(moduleName: string): void
49 - genMockFromModule(moduleObj: Object): Object
50 - genMockFunction(): MockFunction
51 - genMockFn(): MockFunction
52 - mock(moduleName: string): void
53 - runAllTicks(): void
54 - runAllTimers(): void
55 - runOnlyPendingTimers(): void
56 - setMock(moduleName: string, moduleExports: Object): void
43 + autoMockOff(): void;
44 + autoMockOn(): void;
45 + clearAllTimers(): void;
46 + dontMock(moduleName: string): void;
47 + genMockFromModule(moduleObj: Object): Object;
48 + genMockFunction(): MockFunction;
49 + genMockFn(): MockFunction;
50 + mock(moduleName: string): void;
51 + runAllTicks(): void;
52 + runAllTimers(): void;
53 + runOnlyPendingTimers(): void;
54 + setMock(moduleName: string, moduleExports: Object): void;
55 }
56
57 interface MockFunction {
60 - (...arguments): any
58 + (...arguments): any;
59 mock: {
62 - calls: Array<Array<any>>
63 - instances: Array<Object>
64 - }
65 - mockClear(): void
66 - mockImplementation(fn: Function): MockFunction
67 - mockImpl(fn: Function): MockFunction
68 - mockReturnThis(): MockFunction
69 - mockReturnValue(value: any): MockFunction
70 - mockReturnValueOnce(value: any): MockFunction
60 + calls: Array<Array<any>>;
61 + instances: Array<Object>;
62 + };
63 + mockClear(): void;
64 + mockImplementation(fn: Function): MockFunction;
65 + mockImpl(fn: Function): MockFunction;
66 + mockReturnThis(): MockFunction;
67 + mockReturnValue(value: any): MockFunction;
68 + mockReturnValueOnce(value: any): MockFunction;
69 }
70
71 declare const check: any;