From 349cf5acc3cda0010fa464a3c959c83a78a24bd7 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Sat, 19 Oct 2019 16:08:08 -0700 Subject: [PATCH] Experimental test helper: `it.experimental` (#17149) Special version of Jest's `it` for experimental tests. Tests marked as experimental will run **both** stable and experimental modes. In experimental mode, they work the same as the normal Jest methods. In stable mode, they are **expected to fail**. This means we can detect when a test previously marked as experimental can be un-marked when the feature becomes stable. It also reduces the chances that we accidentally add experimental APIs to the stable builds before we intend. I added corresponding methods for the focus and skip APIs: - `fit` -> `fit.experimental` - `it.only` -> `it.only.experimental` or `it.experimental.only` - `xit` -> `xit.experimental` - `it.skip` -> `it.skip.experimental` or `it.experimental.skip` Since `it` is an alias of `test`, `test.experimental` works, too. --- .../src/__tests__/ReactUpdates-test.js | 9 ++-- scripts/jest/setupTests.js | 53 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index 04e69d591e17c..cb4d8214c1cbc 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -1292,8 +1292,9 @@ describe('ReactUpdates', () => { expect(ops).toEqual(['Foo', 'Bar', 'Baz']); }); - if (__EXPERIMENTAL__) { - it('delays sync updates inside hidden subtrees in Concurrent Mode', () => { + it.experimental( + 'delays sync updates inside hidden subtrees in Concurrent Mode', + () => { const container = document.createElement('div'); function Baz() { @@ -1368,8 +1369,8 @@ describe('ReactUpdates', () => { expect(Scheduler).toFlushAndYield(['Bar']); } expect(hiddenDiv.innerHTML).toBe('

bar 1

'); - }); - } + }, + ); it('can render ridiculously large number of roots without triggering infinite update loop error', () => { class Foo extends React.Component { diff --git a/scripts/jest/setupTests.js b/scripts/jest/setupTests.js index b2933bc5fba55..330cf65c0fc68 100644 --- a/scripts/jest/setupTests.js +++ b/scripts/jest/setupTests.js @@ -205,5 +205,58 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) { global.Error = ErrorProxy; } + const expectExperimentalToFail = async callback => { + if (callback.length > 0) { + throw Error( + 'Experimental test helpers do not support `done` callback. Return a ' + + 'promise instead.' + ); + } + try { + const maybePromise = callback(); + if ( + maybePromise !== undefined && + maybePromise !== null && + typeof maybePromise.then === 'function' + ) { + await maybePromise; + } + } catch (error) { + // Failed as expected + return; + } + throw Error( + 'Tests marked experimental are expected to fail, but this one passed.' + ); + }; + + const it = global.it; + const fit = global.fit; + const xit = global.xit; + if (__EXPERIMENTAL__) { + it.experimental = it; + fit.experimental = it.only.experimental = it.experimental.only = fit; + xit.experimental = it.skip.experimental = it.experimental.skip = xit; + } else { + it.experimental = (message, callback) => { + it(`[EXPERIMENTAL, SHOULD FAIL] ${message}`, () => + expectExperimentalToFail(callback)); + }; + fit.experimental = it.only.experimental = it.experimental.only = ( + message, + callback + ) => { + fit(`[EXPERIMENTAL, SHOULD FAIL] ${message}`, () => + expectExperimentalToFail(callback)); + }; + xit.experimental = it.skip.experimental = it.experimental.skip = ( + message, + callback + ) => { + xit(`[EXPERIMENTAL, SHOULD FAIL] ${message}`, () => + expectExperimentalToFail(callback)); + }; + } + require('jasmine-check').install(); }