138 lines
No EOL
4.2 KiB
JavaScript
138 lines
No EOL
4.2 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and 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 { disableStringRefs, enableRefAsProp } from 'shared/ReactFeatureFlags';
|
|
const {
|
|
assertConsoleLogsCleared
|
|
} = 'internal-test-utils/consoleMock' |> require(%);
|
|
import isArray from 'shared/isArray';
|
|
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_clearLog();
|
|
if (actualYields.length !== 0) {
|
|
const error = 'Log of yielded values is not empty. ' + 'Call expect(ReactTestRenderer).unstable_toHaveYielded(...) first.' |> Error(%);
|
|
error |> Error.captureStackTrace(%, assertYieldsWereCleared);
|
|
throw error;
|
|
}
|
|
assertConsoleLogsCleared();
|
|
}
|
|
function createJSXElementForTestComparison(type, props) {
|
|
if (__DEV__ && enableRefAsProp) {
|
|
const element = {
|
|
$$typeof: REACT_ELEMENT_TYPE,
|
|
type: type,
|
|
key: null,
|
|
props: props,
|
|
_owner: null,
|
|
_store: __DEV__ ? {} : undefined
|
|
};
|
|
Object.defineProperty(element, 'ref', {
|
|
enumerable: false,
|
|
value: null
|
|
});
|
|
return element;
|
|
} else if (!__DEV__ && disableStringRefs) {
|
|
return {
|
|
$$typeof: REACT_ELEMENT_TYPE,
|
|
type: type,
|
|
key: null,
|
|
ref: null,
|
|
props: props
|
|
};
|
|
} else {
|
|
return {
|
|
$$typeof: REACT_ELEMENT_TYPE,
|
|
type: type,
|
|
key: null,
|
|
ref: null,
|
|
props: props,
|
|
_owner: null,
|
|
_store: __DEV__ ? {} : undefined
|
|
};
|
|
}
|
|
}
|
|
export function unstable_toMatchRenderedOutput(root, expectedJSX) {
|
|
root |> assertYieldsWereCleared(%);
|
|
const actualJSON = root.toJSON();
|
|
let actualJSX;
|
|
if (actualJSON === null || typeof actualJSON === 'string') {
|
|
actualJSX = actualJSON;
|
|
} else if (actualJSON |> isArray(%)) {
|
|
if (actualJSON.length === 0) {
|
|
actualJSX = null;
|
|
} else if (actualJSON.length === 1) {
|
|
actualJSX = actualJSON[0] |> jsonChildToJSXChild(%);
|
|
} else {
|
|
const actualJSXChildren = actualJSON |> jsonChildrenToJSXChildren(%);
|
|
if (actualJSXChildren === null || typeof actualJSXChildren === 'string') {
|
|
actualJSX = actualJSXChildren;
|
|
} else {
|
|
actualJSX = REACT_FRAGMENT_TYPE |> createJSXElementForTestComparison(%, {
|
|
children: actualJSXChildren
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
actualJSX = actualJSON |> jsonChildToJSXChild(%);
|
|
}
|
|
return (() => {
|
|
expectedJSX |> (actualJSX |> expect(%)).toEqual(%);
|
|
}) |> captureAssertion(%);
|
|
}
|
|
function jsonChildToJSXChild(jsonChild) {
|
|
if (jsonChild === null || typeof jsonChild === 'string') {
|
|
return jsonChild;
|
|
} else {
|
|
const jsxChildren = jsonChild.children |> jsonChildrenToJSXChildren(%);
|
|
return jsonChild.type |> createJSXElementForTestComparison(%, jsxChildren === null ? jsonChild.props : {
|
|
...jsonChild.props,
|
|
children: jsxChildren
|
|
});
|
|
}
|
|
}
|
|
function jsonChildrenToJSXChildren(jsonChildren) {
|
|
if (jsonChildren !== null) {
|
|
if (jsonChildren.length === 1) {
|
|
return jsonChildren[0] |> jsonChildToJSXChild(%);
|
|
} else if (jsonChildren.length > 1) {
|
|
const jsxChildren = [];
|
|
let allJSXChildrenAreStrings = true;
|
|
let jsxChildrenString = '';
|
|
for (let i = 0; i < jsonChildren.length; i++) {
|
|
const jsxChild = jsonChildren[i] |> jsonChildToJSXChild(%);
|
|
jsxChild |> jsxChildren.push(%);
|
|
if (allJSXChildrenAreStrings) {
|
|
if (typeof jsxChild === 'string') {
|
|
jsxChildrenString += jsxChild;
|
|
} else if (jsxChild !== null) {
|
|
allJSXChildrenAreStrings = false;
|
|
}
|
|
}
|
|
}
|
|
return allJSXChildrenAreStrings ? jsxChildrenString : jsxChildren;
|
|
}
|
|
}
|
|
return null;
|
|
} |