import * as React from 'react'; import { mount, MountRendererProps, ReactWrapper } from 'enzyme'; import Portal from '../Portal'; describe('components/portal/Portal', () => { let attachTo: HTMLElement | null; let wrapper: ReactWrapper | null = null; /** * Helper method to mount things to the correct DOM element * this makes it easier to clean up after ourselves after each test. */ const mountToBody = (component: React.ReactElement, options?: MountRendererProps) => { wrapper = mount(component, { attachTo, ...options }); }; beforeEach(() => { // Set up a place to mount attachTo = document.createElement('div'); attachTo.setAttribute('data-mounting-point', ''); document.body.appendChild(attachTo); }); afterEach(() => { // Unmount and remove the mounting point after each test if (wrapper && wrapper.exists()) { wrapper.unmount(); wrapper = null; } document.body.removeChild(attachTo as HTMLElement); }); test('should render the portal as a child to body', () => { mountToBody(); const portalParentElement = document.querySelector('[data-portal]')?.parentElement; expect(portalParentElement && portalParentElement.tagName.toLowerCase()).toEqual('body'); }); test('should render the portal children as children node', () => { mountToBody(
bar
, ); const portal = document.querySelector('[data-portal]'); const child = portal ? portal.querySelector('#foo') : null; expect(child).toBeTruthy(); expect(attachTo && attachTo.textContent).toEqual(''); }); test('should pass Portal props as props to the React Root div', () => { mountToBody( , ); const portal = document.querySelector('[data-portal]'); const reactRoot = portal ? portal.querySelector('div') : null; expect(reactRoot && reactRoot.style.color).toEqual('blue'); }); test('should propagate parent context to the children', () => { /** * Test class with context */ const TestPortalContext = React.createContext({ name: 'fn-2187' }); class TestPortal extends React.PureComponent { static contextType = TestPortalContext; render() { return ; } } TestPortal.contextType = TestPortalContext; const ChildComponent = (context: { name: string }) => { expect(context.name).toEqual('fn-2187'); return
; }; mountToBody( {context => } , ); expect(document.querySelector('#sanity')).toBeTruthy(); }); test('should remove the portal from the DOM when unmounting', () => { mountToBody(); expect(document.querySelector('[data-portal]')).toBeTruthy(); if (wrapper) { wrapper.unmount(); } expect(document.querySelector('[data-portal]')).toBeFalsy(); }); test('should update portaled DOM when updating React props', () => { mountToBody(wee); if (wrapper) { wrapper.setProps({ children: 'boo' }); } const portal = document.querySelector('[data-portal]'); expect(portal && portal.textContent).toEqual('boo'); }); test('should used a passed in document if provided', () => { const newDoc = document.implementation.createHTMLDocument('doc'); mountToBody(text); const portal = newDoc.querySelector('[data-portal]'); expect(portal && portal.ownerDocument && portal.ownerDocument.title).toEqual('doc'); }); });