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.';