@samitouri / QOS-React-1 / commits / 29a6ca33a5

Update gate pragma to detect global error events (#28591)

If a global error event is dispatched during a test, Jest reports that test as a failure. Our `@gate` pragma feature should account for this — if the gate condition is false, and the global error event is dispatched, then the test should be reported as a success. The solution is to install an error event handler right before invoking the test function. Because we install our own handler, Jest will not report the test as a failure if a global error event is dispatched; it's conceptually as if we wrapped the whole test event in a try-catch.

Andrew Clark committed Mar 19, 2024 at 21:08 UTC 29a6ca33a548ba372942dd5f0ae1c777e405610b
2 files changed +40 -5
scripts/babel/__tests__/transform-test-gate-pragma-test.js
+9
@@ -203,6 +203,15 @@ describe('transform test-gate-pragma: actual runtime', () => {
203 console.error('Stop that!');
204 throw Error('I told you to stop!');
205 });
206 +
207 + // @gate false
208 + test('a global error event is treated as a test failure', () => {
209 + dispatchEvent(
210 + new ErrorEvent('error', {
211 + error: new Error('Oops!'),
212 + })
213 + );
214 + });
215 });
216
217 describe('dynamic gate method', () => {
scripts/jest/setupTests.js
+31 -5
@@ -241,13 +241,30 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
241 global.Error = ErrorProxy;
242 }
243
244 - const expectTestToFail = async (callback, error) => {
244 + const expectTestToFail = async (callback, errorToThrowIfTestSucceeds) => {
245 if (callback.length > 0) {
246 throw Error(
247 'Gated test helpers do not support the `done` callback. Return a ' +
248 'promise instead.'
249 );
250 }
251 +
252 + // Install a global error event handler. We treat global error events as
253 + // test failures, same as Jest's default behavior.
254 + //
255 + // Becaused we installed our own error event handler, Jest will not report a
256 + // test failure. Conceptually it's as if we wrapped the entire test event in
257 + // a try-catch.
258 + let didError = false;
259 + const errorEventHandler = () => {
260 + didError = true;
261 + };
262 + // eslint-disable-next-line no-restricted-globals
263 + if (typeof addEventListener === 'function') {
264 + // eslint-disable-next-line no-restricted-globals
265 + addEventListener('error', errorEventHandler);
266 + }
267 +
268 try {
269 const maybePromise = callback();
270 if (
@@ -262,11 +279,20 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
279 // throws, we won't have captured it.
280 flushAllUnexpectedConsoleCalls();
281 } catch (testError) {
265 - // Failed as expected
266 - resetAllUnexpectedConsoleCalls();
267 - return;
282 + didError = true;
283 + }
284 + resetAllUnexpectedConsoleCalls();
285 + // eslint-disable-next-line no-restricted-globals
286 + if (typeof removeEventListener === 'function') {
287 + // eslint-disable-next-line no-restricted-globals
288 + removeEventListener('error', errorEventHandler);
289 + }
290 +
291 + if (!didError) {
292 + // The test did not error like we expected it to. Report this to Jest as
293 + // a failure.
294 + throw errorToThrowIfTestSucceeds;
295 }
269 - throw error;
296 };
297
298 const gatedErrorMessage = 'Gated test was expected to fail, but it passed.';