mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
Jest + test renderer helpers for concurrent mode (#13751)
* Jest + test renderer helpers for concurrent mode Most of our concurrent React tests use the noop renderer. But most of those tests don't test the renderer API, and could instead be written with the test renderer. We should switch to using the test renderer whenever possible, because that's what we expect product devs and library authors to do. If test renderer is sufficient for writing most React core tests, it should be sufficient for others, too. (The converse isn't true but we should aim to dogfood test renderer as much as possible.) This PR adds a new package, jest-react (thanks @cpojer). I've moved our existing Jest matchers into that package and added some new ones. I'm not expecting to figure out the final API in this PR. My goal is to land something good enough that we can start dogfooding in www. TODO: Continue migrating Suspense tests, decide on better API names * Add additional invariants to prevent common errors - Errors if user attempts to flush when log of yields is not empty - Throws if argument passed to toClearYields is not ReactTestRenderer * Better method names - toFlushAll -> toFlushAndYield - toFlushAndYieldThrough -> - toClearYields -> toHaveYielded Also added toFlushWithoutYielding * Fix jest-react exports * Tweak README
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
function captureAssertion(fn) {
|
||||
// Trick to use a Jest matcher inside another Jest matcher. `fn` contains an
|
||||
// assertion; if it throws, we capture the error and return it, so the stack
|
||||
// trace presented to the user points to the original assertion in the
|
||||
// test file.
|
||||
try {
|
||||
fn();
|
||||
} catch (error) {
|
||||
return {
|
||||
pass: false,
|
||||
message: () => error.message,
|
||||
};
|
||||
}
|
||||
return {pass: true};
|
||||
}
|
||||
|
||||
function toFlushAll(renderer, expectedYields) {
|
||||
const actualYields = renderer.unstable_flushAll();
|
||||
return captureAssertion(() => expect(actualYields).toEqual(expectedYields));
|
||||
}
|
||||
|
||||
function toFlushThrough(renderer, expectedYields) {
|
||||
const actualYields = renderer.unstable_flushNumberOfYields(
|
||||
expectedYields.length
|
||||
);
|
||||
return captureAssertion(() => expect(actualYields).toEqual(expectedYields));
|
||||
}
|
||||
|
||||
function toClearYields(ReactTestRenderer, expectedYields) {
|
||||
const actualYields = ReactTestRenderer.unstable_clearYields();
|
||||
return captureAssertion(() => expect(actualYields).toEqual(expectedYields));
|
||||
}
|
||||
|
||||
function toFlushAndThrow(renderer, expectedYields, ...rest) {
|
||||
return captureAssertion(() => {
|
||||
try {
|
||||
expect(() => {
|
||||
renderer.unstable_flushAll();
|
||||
}).toThrow(...rest);
|
||||
} catch (error) {
|
||||
const actualYields = renderer.unstable_clearYields();
|
||||
expect(actualYields).toEqual(expectedYields);
|
||||
throw error;
|
||||
}
|
||||
const actualYields = renderer.unstable_clearYields();
|
||||
expect(actualYields).toEqual(expectedYields);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
toFlushAll,
|
||||
toFlushThrough,
|
||||
toFlushAndThrow,
|
||||
toClearYields,
|
||||
};
|
||||
@@ -43,10 +43,17 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
|
||||
global.spyOnDevAndProd = spyOn;
|
||||
}
|
||||
|
||||
const JestReact = require('jest-react');
|
||||
expect.extend({
|
||||
...require('./matchers/interactionTracing'),
|
||||
...require('./matchers/toWarnDev'),
|
||||
...require('./matchers/testRenderer'),
|
||||
|
||||
toFlushWithoutYielding: JestReact.toFlushWithoutYielding,
|
||||
toFlushAndYield: JestReact.toFlushAndYield,
|
||||
toFlushAndYieldThrough: JestReact.toFlushAndYieldThrough,
|
||||
toHaveYielded: JestReact.toHaveYielded,
|
||||
toFlushAndThrow: JestReact.toFlushAndThrow,
|
||||
toMatchRenderedOutput: JestReact.toMatchRenderedOutput,
|
||||
});
|
||||
|
||||
// We have a Babel transform that inserts guards against infinite loops.
|
||||
|
||||
@@ -45,10 +45,17 @@ global.spyOnProd = function(...args) {
|
||||
}
|
||||
};
|
||||
|
||||
const JestReact = require('jest-react');
|
||||
expect.extend({
|
||||
...require('../matchers/interactionTracing'),
|
||||
...require('../matchers/toWarnDev'),
|
||||
...require('../matchers/testRenderer'),
|
||||
|
||||
toFlushWithoutYielding: JestReact.toFlushWithoutYielding,
|
||||
toFlushAndYield: JestReact.toFlushAndYield,
|
||||
toFlushAndYieldThrough: JestReact.toFlushAndYieldThrough,
|
||||
toHaveYielded: JestReact.toHaveYielded,
|
||||
toFlushAndThrow: JestReact.toFlushAndThrow,
|
||||
toMatchRenderedOutput: JestReact.toMatchRenderedOutput,
|
||||
});
|
||||
|
||||
beforeEach(() => (numExpectations = 0));
|
||||
|
||||
@@ -400,6 +400,16 @@ const bundles = [
|
||||
externals: [],
|
||||
},
|
||||
|
||||
/******* Jest React (experimental) *******/
|
||||
{
|
||||
label: 'jest-react',
|
||||
bundleTypes: [NODE_DEV, NODE_PROD, FB_WWW_DEV, FB_WWW_PROD],
|
||||
moduleType: ISOMORPHIC,
|
||||
entry: 'jest-react',
|
||||
global: 'JestReact',
|
||||
externals: ['jest-diff'],
|
||||
},
|
||||
|
||||
{
|
||||
label: 'scheduler-tracing',
|
||||
bundleTypes: [
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# Don't validate noop renderer bundle.
|
||||
# Unlike others, it currently uses ES6 syntax (generators).
|
||||
# We also don't use or publish it.
|
||||
**/react-noop-renderer/**
|
||||
**/react-noop-renderer/**
|
||||
JestReact-prod.js
|
||||
JestReact-dev.js
|
||||
**/jest-react/**
|
||||
Reference in New Issue
Block a user