UNPKG

react-testing-library

Version:

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

190 lines (157 loc) 6.17 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var _extends = _interopDefault(require('@babel/runtime/helpers/extends')); var domTestingLibrary = require('dom-testing-library'); var React = _interopDefault(require('react')); var ReactDOM = _interopDefault(require('react-dom')); var testUtils = require('react-dom/test-utils'); // so for versions that don't have act from test utils // we do this little polyfill. No warnings, but it's // better than nothing. function actPolyfill(cb) { ReactDOM.unstable_batchedUpdates(cb); ReactDOM.render(React.createElement("div", null), document.createElement('div')); } var act = testUtils.act || actPolyfill; function rtlAct() { return act.apply(void 0, arguments); } var mountedContainers = new Set(); function render(ui, _temp) { var _ref = _temp === void 0 ? {} : _temp, container = _ref.container, _ref$baseElement = _ref.baseElement, baseElement = _ref$baseElement === void 0 ? container : _ref$baseElement, queries = _ref.queries, _ref$hydrate = _ref.hydrate, hydrate = _ref$hydrate === void 0 ? false : _ref$hydrate; 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) { rtlAct(function () { ReactDOM.hydrate(ui, container); }); } else { rtlAct(function () { ReactDOM.render(ui, container); }); } return _extends({ container: container, baseElement: baseElement, // eslint-disable-next-line no-console debug: function debug(el) { if (el === void 0) { el = baseElement; } return console.log(domTestingLibrary.prettyDOM(el)); }, unmount: function unmount() { return ReactDOM.unmountComponentAtNode(container); }, rerender: function rerender(rerenderUi) { render(rerenderUi, { container: container, baseElement: 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: function asFragment() { /* istanbul ignore if (jsdom limitation) */ if (typeof document.createRange === 'function') { return document.createRange().createContextualFragment(container.innerHTML); } var template = document.createElement('template'); template.innerHTML = container.innerHTML; return template.content; } }, domTestingLibrary.getQueriesForElement(baseElement, queries)); } function TestHook(_ref2) { var callback = _ref2.callback; callback(); return null; } function testHook(callback) { var _render = render(React.createElement(TestHook, { callback: callback })), unmount = _render.unmount, rerenderComponent = _render.rerender; return { unmount: unmount, rerender: function rerender() { rerenderComponent(React.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.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() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var returnValue; rtlAct(function () { returnValue = domTestingLibrary.fireEvent.apply(void 0, args); }); return returnValue; } Object.keys(domTestingLibrary.fireEvent).forEach(function (key) { fireEvent[key] = function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } var returnValue; rtlAct(function () { returnValue = domTestingLibrary.fireEvent[key].apply(domTestingLibrary.fireEvent, 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 = function (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 */ Object.keys(domTestingLibrary).forEach(function (key) { exports[key] = domTestingLibrary[key]; }); exports.render = render; exports.testHook = testHook; exports.cleanup = cleanup; exports.fireEvent = fireEvent; exports.act = rtlAct;