A jest.config.js => jest.config.js +6 -0
@@ 0,0 1,6 @@
+const config = require('kcd-scripts/jest')
+
+module.exports = {
+ ...config,
+ testEnvironment: 'jsdom',
+}
M package.json => package.json +2 -2
@@ 51,7 51,7 @@
"devDependencies": {
"@testing-library/jest-dom": "^4.1.0",
"angular": "^1.7.8",
- "angular-mock": "^1.0.0",
+ "angular-mocks": "^1.7.8",
"cross-env": "^6.0.0",
"kcd-scripts": "^1.7.0",
"npm-run-all": "^4.1.5",
@@ 59,7 59,7 @@
},
"peerDependencies": {
"angular": "*",
- "angular-mock": "*"
+ "angular-mocks": "*"
},
"eslintConfig": {
"extends": "./node_modules/kcd-scripts/eslint.js",
M src/__tests__/__snapshots__/render.js.snap => src/__tests__/__snapshots__/render.js.snap +17 -6
@@ 2,11 2,22 @@
exports[`supports fragments 1`] = `
<DocumentFragment>
- <div>
- <code>
- DocumentFragment
- </code>
- is pretty cool!
- </div>
+ <atl-fragment
+ class="ng-scope ng-isolate-scope"
+ >
+
+
+ <div>
+
+
+ <code>
+ DocumentFragment
+ </code>
+ is pretty cool!
+
+ </div>
+
+
+ </atl-fragment>
</DocumentFragment>
`;
M src/__tests__/render.js => src/__tests__/render.js +17 -75
@@ 1,89 1,31 @@
-import React from 'react'
-import ReactDOM from 'react-dom'
+import angular from 'angular'
+import 'angular-mocks'
import {render} from '../'
-test('renders div into document', () => {
- const ref = React.createRef()
- const {container} = render(<div ref={ref} />)
- expect(container.firstChild).toBe(ref.current)
+beforeEach(() => {
+ angular.module('atl', [])
+ angular.mock.module('atl')
})
-test('works great with react portals', () => {
- class MyPortal extends React.Component {
- constructor(...args) {
- super(...args)
- this.portalNode = document.createElement('div')
- this.portalNode.dataset.testid = 'my-portal'
- }
- componentDidMount() {
- document.body.appendChild(this.portalNode)
- }
- componentWillUnmount() {
- this.portalNode.parentNode.removeChild(this.portalNode)
- }
- render() {
- return ReactDOM.createPortal(
- <Greet greeting="Hello" subject="World" />,
- this.portalNode,
- )
- }
- }
-
- function Greet({greeting, subject}) {
- return (
- <div>
- <strong>
- {greeting} {subject}
- </strong>
- </div>
- )
- }
-
- const {unmount, getByTestId, getByText} = render(<MyPortal />)
- expect(getByText('Hello World')).toBeInTheDocument()
- const portalNode = getByTestId('my-portal')
- expect(portalNode).toBeInTheDocument()
- unmount()
- expect(portalNode).not.toBeInTheDocument()
+test('renders div into document', () => {
+ const {container} = render(`<div id="child"></div>`)
+ expect(container.firstChild.id).toBe('child')
})
test('returns baseElement which defaults to document.body', () => {
- const {baseElement} = render(<div />)
+ const {baseElement} = render(`<div></div>`)
expect(baseElement).toBe(document.body)
})
test('supports fragments', () => {
- class Test extends React.Component {
- render() {
- return (
- <div>
- <code>DocumentFragment</code> is pretty cool!
- </div>
- )
- }
- }
-
- const {asFragment} = render(<Test />)
- expect(asFragment()).toMatchSnapshot()
-})
-
-test('renders options.wrapper around node', () => {
- const WrapperComponent = ({children}) => (
- <div data-testid="wrapper">{children}</div>
- )
-
- const {container, getByTestId} = render(<div data-testid="inner" />, {
- wrapper: WrapperComponent,
+ angular.module('atl').component('atlFragment', {
+ template: `
+ <div>
+ <code>DocumentFragment</code> is pretty cool!
+ </div>
+ `,
})
- expect(getByTestId('wrapper')).toBeInTheDocument()
- expect(container.firstChild).toMatchInlineSnapshot(`
-<div
- data-testid="wrapper"
->
- <div
- data-testid="inner"
- />
-</div>
-`)
+ const {asFragment} = render(`<atl-fragment></atl-fragment>`)
+ expect(asFragment()).toMatchSnapshot()
})
M src/pure.js => src/pure.js +19 -86
@@ 1,35 1,14 @@
-import React from 'react'
-import ReactDOM from 'react-dom'
+import angular from 'angular'
+import 'angular-mocks'
import {
getQueriesForElement,
prettyDOM,
fireEvent as dtlFireEvent,
- configure as configureDTL,
} from '@testing-library/dom'
-import act, {asyncAct} from './act-compat'
-
-configureDTL({
- asyncWrapper: async cb => {
- let result
- await asyncAct(async () => {
- result = await cb()
- })
- return result
- },
-})
const mountedContainers = new Set()
-function render(
- ui,
- {
- container,
- baseElement = container,
- queries,
- hydrate = false,
- wrapper: WrapperComponent,
- } = {},
-) {
+function render(ui, {container, baseElement = container, queries} = {}) {
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
@@ 44,18 23,19 @@ function render(
// they're passing us a custom container or not.
mountedContainers.add(container)
- const wrapUiIfNeeded = innerElement =>
- WrapperComponent
- ? React.createElement(WrapperComponent, null, innerElement)
- : innerElement
+ let $scope
+ angular.mock.inject([
+ '$compile',
+ '$rootScope',
+ ($compile, $rootScope) => {
+ $scope = $rootScope.$new()
- act(() => {
- if (hydrate) {
- ReactDOM.hydrate(wrapUiIfNeeded(ui), container)
- } else {
- ReactDOM.render(wrapUiIfNeeded(ui), container)
- }
- })
+ const element = $compile(ui)($scope)[0]
+ container.appendChild(element)
+
+ $scope.$digest()
+ },
+ ])
return {
container,
@@ 66,12 46,6 @@ function render(
el.forEach(e => console.log(prettyDOM(e)))
: // eslint-disable-next-line no-console,
console.log(prettyDOM(el)),
- unmount: () => ReactDOM.unmountComponentAtNode(container),
- rerender: rerenderUi => {
- render(wrapUiIfNeeded(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') {
@@ 84,6 58,7 @@ function render(
template.innerHTML = container.innerHTML
return template.content
},
+ $scope,
...getQueriesForElement(baseElement, queries),
}
}
@@ 95,63 70,21 @@ function cleanup() {
// 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) {
- ReactDOM.unmountComponentAtNode(container)
if (container.parentNode === document.body) {
document.body.removeChild(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
- act(() => {
- returnValue = dtlFireEvent(...args)
- })
- return returnValue
+ return dtlFireEvent(...args)
}
Object.keys(dtlFireEvent).forEach(key => {
fireEvent[key] = (...args) => {
- let returnValue
- act(() => {
- returnValue = dtlFireEvent[key](...args)
- })
- return returnValue
+ return dtlFireEvent[key](...args)
}
})
-// 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
export * from '@testing-library/dom'
-export {render, cleanup, fireEvent, act}
-
-// NOTE: we're not going to export asyncAct because that's our own compatibility
-// thing for people using react-dom@16.8.0. Anyone else doesn't need it and
-// people should just upgrade anyway.
-
-/* eslint func-name-matching:0 */
+export {render, cleanup, fireEvent}