UNPKG

react-testing-library

Version:

Simple and complete React DOM testing utilities that encourage good testing practices.

185 lines (156 loc) 5.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); var _exportNames = { render: true, testHook: true, cleanup: true, fireEvent: true, act: true }; exports.render = render; exports.testHook = testHook; exports.cleanup = cleanup; exports.fireEvent = fireEvent; Object.defineProperty(exports, "act", { enumerable: true, get: function () { return _actCompat.default; } }); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _domTestingLibrary = require("dom-testing-library"); Object.keys(_domTestingLibrary).forEach(function (key) { if (key === "default" || key === "__esModule") return; if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; Object.defineProperty(exports, key, { enumerable: true, get: function () { return _domTestingLibrary[key]; } }); }); var _actCompat = _interopRequireDefault(require("./act-compat")); const mountedContainers = new Set(); function render(ui, { container, baseElement = container, queries, hydrate = false } = {}) { if (!container) { // 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; container = document.body.appendChild(document.createElement('div')); } // 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); if (hydrate) { (0, _actCompat.default)(() => { _reactDom.default.hydrate(ui, container); }); } else { (0, _actCompat.default)(() => { _reactDom.default.render(ui, container); }); } return (0, _extends2.default)({ container, baseElement, // eslint-disable-next-line no-console debug: (el = baseElement) => console.log((0, _domTestingLibrary.prettyDOM)(el)), unmount: () => _reactDom.default.unmountComponentAtNode(container), rerender: rerenderUi => { render(rerenderUi, { container, baseElement }); // 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 if (jsdom limitation) */ if (typeof document.createRange === 'function') { return document.createRange().createContextualFragment(container.innerHTML); } const template = document.createElement('template'); template.innerHTML = container.innerHTML; return template.content; } }, (0, _domTestingLibrary.getQueriesForElement)(baseElement, queries)); } function TestHook({ callback }) { callback(); return null; } function testHook(callback) { const { unmount, rerender: rerenderComponent } = render(_react.default.createElement(TestHook, { callback: callback })); return { unmount, rerender: () => { rerenderComponent(_react.default.createElement(TestHook, { callback: callback })); } }; } function cleanup() { mountedContainers.forEach(cleanupAtContainer); } // maybe one day we'll expose this (perhaps even as a utility returned by render). // but let's wait until someone asks for it. function cleanupAtContainer(container) { if (container.parentNode === document.body) { document.body.removeChild(container); } _reactDom.default.unmountComponentAtNode(container); mountedContainers.delete(container); } // react-testing-library's version of fireEvent will call // dom-testing-library's version of fireEvent wrapped inside // an "act" call so that after all event callbacks have been // been called, the resulting useEffect callbacks will also // be called. function fireEvent(...args) { let returnValue; (0, _actCompat.default)(() => { returnValue = (0, _domTestingLibrary.fireEvent)(...args); }); return returnValue; } Object.keys(_domTestingLibrary.fireEvent).forEach(key => { fireEvent[key] = (...args) => { let returnValue; (0, _actCompat.default)(() => { returnValue = _domTestingLibrary.fireEvent[key](...args); }); return returnValue; }; }); // React event system tracks native mouseOver/mouseOut events for // running onMouseEnter/onMouseLeave handlers // @link https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/EnterLeaveEventPlugin.js#L24-L31 fireEvent.mouseEnter = fireEvent.mouseOver; fireEvent.mouseLeave = fireEvent.mouseOut; fireEvent.select = (node, init) => { // React tracks this event only on focused inputs node.focus(); // React creates this event when one of the following native events happens // - contextMenu // - mouseUp // - dragEnd // - keyUp // - keyDown // so we can use any here // @link https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/SelectEventPlugin.js#L203-L224 fireEvent.keyUp(node, init); }; // just re-export everything from dom-testing-library /* eslint func-name-matching:0 */