mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
d7dce572c7
* Move internal version of act to shared module No reason to have three different copies of this anymore. I've left the the renderer-specific `act` entry points because legacy mode tests need to also be wrapped in `batchedUpdates`. Next, I'll update the tests to use `batchedUpdates` manually when needed. * Migrates tests to use internal module directly Instead of the `unstable_concurrentAct` exports. Now we can drop those from the public builds. I put it in the jest-react package since that's where we put our other testing utilities (like `toFlushAndYield`). Not so much so it can be consumed publicly (nobody uses that package except us), but so it works with our build tests. * Remove unused internal fields These were used by the old act implementation. No longer needed.
124 lines
3.5 KiB
JavaScript
124 lines
3.5 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';
|
|
import isArray from 'shared/isArray';
|
|
|
|
export {act} from './internalAct';
|
|
|
|
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 (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) {
|
|
const 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;
|
|
}
|