@samitouri / QOS-React / commits / 6e65010999

[tests] Disallow unasserted console.log (#28708)

Followup from https://github.com/facebook/react/pull/28693 and https://github.com/facebook/react/pull/28680. In CI, we fail the test for any unasserted console.log. In DEV, we don't fail, but you can still use the matchers and we'll assert on them.

Ricky committed Apr 1, 2024 at 17:45 UTC 6e650109999e5f483fcb910ff20fe8148a566cb2
3 files changed +44 -3
scripts/jest/matchers/__tests__/toWarnDev-test.js
+17
@@ -416,3 +416,20 @@ describe('toWarnDev', () => {
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
+4 -1
@@ -178,7 +178,9 @@ const createMatcherFor = (consoleMethod, matcherName) =>
178 };
179 }
180
181 - if (typeof withoutStack === 'number') {
181 + if (consoleMethod === 'log') {
182 + // We don't expect any console.log calls to have a stack.
183 + } else if (typeof withoutStack === 'number') {
184 // We're expecting a particular number of warnings without stacks.
185 if (withoutStack !== warningsWithoutComponentStack.length) {
186 return {
@@ -309,4 +311,5 @@ const createMatcherFor = (consoleMethod, matcherName) =>
311 module.exports = {
312 toWarnDev: createMatcherFor('warn', 'toWarnDev'),
313 toErrorDev: createMatcherFor('error', 'toErrorDev'),
314 + toLogDev: createMatcherFor('log', 'toLogDev'),
315 };
scripts/jest/setupTests.js
+23 -2
@@ -116,18 +116,19 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
116 .join('\n')}`
117 );
118
119 + const type = methodName === 'log' ? 'log' : 'warning';
120 const message =
121 `Expected test not to call ${chalk.bold(
122 `console.${methodName}()`
123 )}.\n\n` +
123 - 'If the warning is expected, test for it explicitly by:\n' +
124 + `If the ${type} is expected, test for it explicitly by:\n` +
125 `1. Using the ${chalk.bold('.' + expectedMatcher + '()')} ` +
126 `matcher, or...\n` +
127 `2. Mock it out using ${chalk.bold(
128 'spyOnDev'
129 )}(console, '${methodName}') or ${chalk.bold(
130 'spyOnProd'
130 - )}(console, '${methodName}'), and test that the warning occurs.`;
131 + )}(console, '${methodName}'), and test that the ${type} occurs.`;
132
133 throw new Error(`${message}\n\n${messages.join('\n\n')}`);
134 }
@@ -135,9 +136,17 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
136
137 const unexpectedErrorCallStacks = [];
138 const unexpectedWarnCallStacks = [];
139 + const unexpectedLogCallStacks = [];
140
141 const errorMethod = patchConsoleMethod('error', unexpectedErrorCallStacks);
142 const warnMethod = patchConsoleMethod('warn', unexpectedWarnCallStacks);
143 + let logMethod;
144 +
145 + // Only assert console.log isn't called in CI so you can debug tests in DEV.
146 + // The matchers will still work in DEV, so you can assert locally.
147 + if (process.env.CI) {
148 + logMethod = patchConsoleMethod('log', unexpectedLogCallStacks);
149 + }
150
151 const flushAllUnexpectedConsoleCalls = () => {
152 flushUnexpectedConsoleCalls(
@@ -152,6 +161,15 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
161 'toWarnDev',
162 unexpectedWarnCallStacks
163 );
164 + if (logMethod) {
165 + flushUnexpectedConsoleCalls(
166 + logMethod,
167 + 'log',
168 + 'toLogDev',
169 + unexpectedLogCallStacks
170 + );
171 + unexpectedLogCallStacks.length = 0;
172 + }
173 unexpectedErrorCallStacks.length = 0;
174 unexpectedWarnCallStacks.length = 0;
175 };
@@ -159,6 +177,9 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
177 const resetAllUnexpectedConsoleCalls = () => {
178 unexpectedErrorCallStacks.length = 0;
179 unexpectedWarnCallStacks.length = 0;
180 + if (logMethod) {
181 + unexpectedLogCallStacks.length = 0;
182 + }
183 };
184
185 beforeEach(resetAllUnexpectedConsoleCalls);