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