mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
69060e1da6
* Swap expect(ReactNoop) for expect(Scheduler) In the previous commits, I upgraded our custom Jest matchers for the noop and test renderers to use Scheduler under the hood. Now that all these matchers are using Scheduler, we can drop support for passing ReactNoop and test roots and always pass Scheduler directly. * Externalize Scheduler in noop and test bundles I also noticed we don't need to regenerator runtime in noop anymore.
121 lines
3.4 KiB
JavaScript
121 lines
3.4 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';
|
|
|
|
import invariant from 'shared/invariant';
|
|
|
|
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 assertYieldsWereCleared(root) {
|
|
const Scheduler = root._Scheduler;
|
|
const actualYields = Scheduler.unstable_clearYields();
|
|
invariant(
|
|
actualYields.length === 0,
|
|
'Log of yielded values is not empty. ' +
|
|
'Call expect(ReactTestRenderer).unstable_toHaveYielded(...) first.',
|
|
);
|
|
}
|
|
|
|
export function unstable_toMatchRenderedOutput(root, expectedJSX) {
|
|
assertYieldsWereCleared(root);
|
|
const actualJSON = root.toJSON();
|
|
|
|
let actualJSX;
|
|
if (actualJSON === null || typeof actualJSON === 'string') {
|
|
actualJSX = actualJSON;
|
|
} else if (Array.isArray(actualJSON)) {
|
|
if (actualJSON.length === 0) {
|
|
actualJSX = null;
|
|
} else if (actualJSON.length === 1) {
|
|
actualJSX = jsonChildToJSXChild(actualJSON[0]);
|
|
} else {
|
|
const actualJSXChildren = jsonChildrenToJSXChildren(actualJSON);
|
|
if (actualJSXChildren === null || typeof actualJSXChildren === 'string') {
|
|
actualJSX = actualJSXChildren;
|
|
} else {
|
|
actualJSX = {
|
|
$$typeof: REACT_ELEMENT_TYPE,
|
|
type: REACT_FRAGMENT_TYPE,
|
|
key: null,
|
|
ref: null,
|
|
props: {
|
|
children: actualJSXChildren,
|
|
},
|
|
_owner: null,
|
|
_store: __DEV__ ? {} : undefined,
|
|
};
|
|
}
|
|
}
|
|
} else {
|
|
actualJSX = jsonChildToJSXChild(actualJSON);
|
|
}
|
|
|
|
return captureAssertion(() => {
|
|
expect(actualJSX).toEqual(expectedJSX);
|
|
});
|
|
}
|
|
|
|
function jsonChildToJSXChild(jsonChild) {
|
|
if (jsonChild === null || typeof jsonChild === 'string') {
|
|
return jsonChild;
|
|
} else {
|
|
const jsxChildren = jsonChildrenToJSXChildren(jsonChild.children);
|
|
return {
|
|
$$typeof: REACT_ELEMENT_TYPE,
|
|
type: jsonChild.type,
|
|
key: null,
|
|
ref: null,
|
|
props:
|
|
jsxChildren === null
|
|
? jsonChild.props
|
|
: {...jsonChild.props, children: jsxChildren},
|
|
_owner: null,
|
|
_store: __DEV__ ? {} : undefined,
|
|
};
|
|
}
|
|
}
|
|
|
|
function jsonChildrenToJSXChildren(jsonChildren) {
|
|
if (jsonChildren !== null) {
|
|
if (jsonChildren.length === 1) {
|
|
return jsonChildToJSXChild(jsonChildren[0]);
|
|
} else if (jsonChildren.length > 1) {
|
|
let jsxChildren = [];
|
|
let allJSXChildrenAreStrings = true;
|
|
let jsxChildrenString = '';
|
|
for (let i = 0; i < jsonChildren.length; i++) {
|
|
const jsxChild = jsonChildToJSXChild(jsonChildren[i]);
|
|
jsxChildren.push(jsxChild);
|
|
if (allJSXChildrenAreStrings) {
|
|
if (typeof jsxChild === 'string') {
|
|
jsxChildrenString += jsxChild;
|
|
} else if (jsxChild !== null) {
|
|
allJSXChildrenAreStrings = false;
|
|
}
|
|
}
|
|
}
|
|
return allJSXChildrenAreStrings ? jsxChildrenString : jsxChildren;
|
|
}
|
|
}
|
|
return null;
|
|
}
|