@samitouri / QOS-React-2 / commits / 30ae0baed1

[devtools][tests] add support for @gate pragma (#28479)

Adds support for `// @gate` pragma in devtools tests Adds a couple gate test assertions to ensure they continue to work

Josh Story committed Mar 1, 2024 at 13:26 UTC 30ae0baed1cfe670dea41d7c7abdc375c9a4859a
3 files changed +96
.eslintrc.js
+7
@@ -381,6 +381,13 @@ module.exports = {
381 'jest/valid-expect-in-promise': ERROR,
382 },
383 },
384 + {
385 + // disable no focused tests for test setup helper files even if they are inside __tests__ directory
386 + files: ['**/setupTests.js'],
387 + rules: {
388 + 'jest/no-focused-tests': OFF,
389 + },
390 + },
391 {
392 files: [
393 '**/__tests__/**/*.js',
packages/react-devtools-shared/src/__tests__/gate-test.js new
+18
@@ -0,0 +1,18 @@
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 + * @flow
8 + */
9 +
10 +describe('gate', () => {
11 + //@gate false
12 + it('should expect an error for this test', () => {
13 + throw new Error('This test should fail');
14 + });
15 +
16 + //@gate true
17 + it('should not an error for this test', () => {});
18 +});
packages/react-devtools-shared/src/__tests__/setupTests.js
+71
@@ -13,6 +13,7 @@ import type {
13 BackendBridge,
14 FrontendBridge,
15 } from 'react-devtools-shared/src/bridge';
16 +const {getTestFlags} = require('../../../../scripts/jest/TestFlags');
17
18 // Argument is serialized when passed from jest-cli script through to setupTests.
19 const compactConsole = process.env.compactConsole === 'true';
@@ -32,6 +33,76 @@ if (compactConsole) {
33 global.console = new CustomConsole(process.stdout, process.stderr, formatter);
34 }
35
36 +const expectTestToFail = async (callback, error) => {
37 + if (callback.length > 0) {
38 + throw Error(
39 + 'Gated test helpers do not support the `done` callback. Return a ' +
40 + 'promise instead.',
41 + );
42 + }
43 + try {
44 + const maybePromise = callback();
45 + if (
46 + maybePromise !== undefined &&
47 + maybePromise !== null &&
48 + typeof maybePromise.then === 'function'
49 + ) {
50 + await maybePromise;
51 + }
52 + } catch (testError) {
53 + return;
54 + }
55 + throw error;
56 +};
57 +
58 +const gatedErrorMessage = 'Gated test was expected to fail, but it passed.';
59 +global._test_gate = (gateFn, testName, callback) => {
60 + let shouldPass;
61 + try {
62 + const flags = getTestFlags();
63 + shouldPass = gateFn(flags);
64 + } catch (e) {
65 + test(testName, () => {
66 + throw e;
67 + });
68 + return;
69 + }
70 + if (shouldPass) {
71 + test(testName, callback);
72 + } else {
73 + const error = new Error(gatedErrorMessage);
74 + Error.captureStackTrace(error, global._test_gate);
75 + test(`[GATED, SHOULD FAIL] ${testName}`, () =>
76 + expectTestToFail(callback, error));
77 + }
78 +};
79 +global._test_gate_focus = (gateFn, testName, callback) => {
80 + let shouldPass;
81 + try {
82 + const flags = getTestFlags();
83 + shouldPass = gateFn(flags);
84 + } catch (e) {
85 + test.only(testName, () => {
86 + throw e;
87 + });
88 + return;
89 + }
90 + if (shouldPass) {
91 + test.only(testName, callback);
92 + } else {
93 + const error = new Error(gatedErrorMessage);
94 + Error.captureStackTrace(error, global._test_gate_focus);
95 + test.only(`[GATED, SHOULD FAIL] ${testName}`, () =>
96 + expectTestToFail(callback, error));
97 + }
98 +};
99 +
100 +// Dynamic version of @gate pragma
101 +global.gate = fn => {
102 + const flags = getTestFlags();
103 + return fn(flags);
104 +};
105 +
106 beforeEach(() => {
107 global.mockClipboardCopy = jest.fn();
108