package.dist.pure.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of react Show documentation
Show all versions of react Show documentation
Simple and complete React DOM testing utilities that encourage good testing practices.
The newest version!
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
var _exportNames = {
render: true,
renderHook: true,
cleanup: true,
act: true,
fireEvent: true
};
Object.defineProperty(exports, "act", {
enumerable: true,
get: function () {
return _actCompat.default;
}
});
exports.cleanup = cleanup;
Object.defineProperty(exports, "fireEvent", {
enumerable: true,
get: function () {
return _fireEvent.fireEvent;
}
});
exports.render = render;
exports.renderHook = renderHook;
var React = _interopRequireWildcard(require("react"));
var _reactDom = _interopRequireDefault(require("react-dom"));
var ReactDOMClient = _interopRequireWildcard(require("react-dom/client"));
var _dom = require("@testing-library/dom");
Object.keys(_dom).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
if (key in exports && exports[key] === _dom[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _dom[key];
}
});
});
var _actCompat = _interopRequireWildcard(require("./act-compat"));
var _fireEvent = require("./fire-event");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
(0, _dom.configure)({
unstable_advanceTimersWrapper: cb => {
return (0, _actCompat.default)(cb);
},
// We just want to run `waitFor` without IS_REACT_ACT_ENVIRONMENT
// But that's not necessarily how `asyncWrapper` is used since it's a public method.
// Let's just hope nobody else is using it.
asyncWrapper: async cb => {
const previousActEnvironment = (0, _actCompat.getIsReactActEnvironment)();
(0, _actCompat.setReactActEnvironment)(false);
try {
return await cb();
} finally {
(0, _actCompat.setReactActEnvironment)(previousActEnvironment);
}
},
eventWrapper: cb => {
let result;
(0, _actCompat.default)(() => {
result = cb();
});
return result;
}
}); // Ideally we'd just use a WeakMap where containers are keys and roots are values.
// We use two variables so that we can bail out in constant time when we render with a new container (most common use case)
/**
* @type {Set}
*/
const mountedContainers = new Set();
/**
* @type Array<{container: import('react-dom').Container, root: ReturnType}>
*/
const mountedRootEntries = [];
function createConcurrentRoot(container, {
hydrate,
ui,
wrapper: WrapperComponent
}) {
let root;
if (hydrate) {
(0, _actCompat.default)(() => {
root = ReactDOMClient.hydrateRoot(container, WrapperComponent ? /*#__PURE__*/React.createElement(WrapperComponent, null, ui) : ui);
});
} else {
root = ReactDOMClient.createRoot(container);
}
return {
hydrate() {
/* istanbul ignore if */
if (!hydrate) {
throw new Error('Attempted to hydrate a non-hydrateable root. This is a bug in `@testing-library/react`.');
} // Nothing to do since hydration happens when creating the root object.
},
render(element) {
root.render(element);
},
unmount() {
root.unmount();
}
};
}
function createLegacyRoot(container) {
return {
hydrate(element) {
_reactDom.default.hydrate(element, container);
},
render(element) {
_reactDom.default.render(element, container);
},
unmount() {
_reactDom.default.unmountComponentAtNode(container);
}
};
}
function renderRoot(ui, {
baseElement,
container,
hydrate,
queries,
root,
wrapper: WrapperComponent
}) {
const wrapUiIfNeeded = innerElement => WrapperComponent ? /*#__PURE__*/React.createElement(WrapperComponent, null, innerElement) : innerElement;
(0, _actCompat.default)(() => {
if (hydrate) {
root.hydrate(wrapUiIfNeeded(ui), container);
} else {
root.render(wrapUiIfNeeded(ui), container);
}
});
return {
container,
baseElement,
debug: (el = baseElement, maxLength, options) => Array.isArray(el) ? // eslint-disable-next-line no-console
el.forEach(e => console.log((0, _dom.prettyDOM)(e, maxLength, options))) : // eslint-disable-next-line no-console,
console.log((0, _dom.prettyDOM)(el, maxLength, options)),
unmount: () => {
(0, _actCompat.default)(() => {
root.unmount();
});
},
rerender: rerenderUi => {
renderRoot(wrapUiIfNeeded(rerenderUi), {
container,
baseElement,
root
}); // Intentionally do not return anything to avoid unnecessarily complicating the API.
// folks can use all the same utilities we return in the first place that are bound to the container
},
asFragment: () => {
/* istanbul ignore else (old jsdom limitation) */
if (typeof document.createRange === 'function') {
return document.createRange().createContextualFragment(container.innerHTML);
} else {
const template = document.createElement('template');
template.innerHTML = container.innerHTML;
return template.content;
}
},
...(0, _dom.getQueriesForElement)(baseElement, queries)
};
}
function render(ui, {
container,
baseElement = container,
legacyRoot = false,
queries,
hydrate = false,
wrapper
} = {}) {
if (!baseElement) {
// default to document.body instead of documentElement to avoid output of potentially-large
// head elements (such as JSS style blocks) in debug output
baseElement = document.body;
}
if (!container) {
container = baseElement.appendChild(document.createElement('div'));
}
let root; // eslint-disable-next-line no-negated-condition -- we want to map the evolution of this over time. The root is created first. Only later is it re-used so we don't want to read the case that happens later first.
if (!mountedContainers.has(container)) {
const createRootImpl = legacyRoot ? createLegacyRoot : createConcurrentRoot;
root = createRootImpl(container, {
hydrate,
ui,
wrapper
});
mountedRootEntries.push({
container,
root
}); // we'll add it to the mounted containers regardless of whether it's actually
// added to document.body so the cleanup method works regardless of whether
// they're passing us a custom container or not.
mountedContainers.add(container);
} else {
mountedRootEntries.forEach(rootEntry => {
// Else is unreachable since `mountedContainers` has the `container`.
// Only reachable if one would accidentally add the container to `mountedContainers` but not the root to `mountedRootEntries`
/* istanbul ignore else */
if (rootEntry.container === container) {
root = rootEntry.root;
}
});
}
return renderRoot(ui, {
container,
baseElement,
queries,
hydrate,
wrapper,
root
});
}
function cleanup() {
mountedRootEntries.forEach(({
root,
container
}) => {
(0, _actCompat.default)(() => {
root.unmount();
});
if (container.parentNode === document.body) {
document.body.removeChild(container);
}
});
mountedRootEntries.length = 0;
mountedContainers.clear();
}
function renderHook(renderCallback, options = {}) {
const {
initialProps,
...renderOptions
} = options;
const result = /*#__PURE__*/React.createRef();
function TestComponent({
renderCallbackProps
}) {
const pendingResult = renderCallback(renderCallbackProps);
React.useEffect(() => {
result.current = pendingResult;
});
return null;
}
const {
rerender: baseRerender,
unmount
} = render( /*#__PURE__*/React.createElement(TestComponent, {
renderCallbackProps: initialProps
}), renderOptions);
function rerender(rerenderCallbackProps) {
return baseRerender( /*#__PURE__*/React.createElement(TestComponent, {
renderCallbackProps: rerenderCallbackProps
}));
}
return {
result,
rerender,
unmount
};
} // just re-export everything from dom-testing-library
/* eslint func-name-matching:0 */