import * as React from 'react'; import { expect } from 'chai'; import { spy } from 'sinon'; import { createRenderer, reactMajor, isJsdom } from '@mui/internal-test-utils'; import Portal, { PortalProps } from '@mui/material/Portal'; describe('', () => { const { render, renderToString } = createRenderer(); describe.skipIf(!isJsdom())('server-side', () => { it('render nothing on the server', () => { const { container } = renderToString(
Bar
, ); expect(container.firstChild).to.equal(null); }); }); describe('ref', () => { it('should have access to the mountNode when disabledPortal={false}', () => { const refSpy = spy(); const { unmount } = render(

Foo

, ); expect(refSpy.args).to.deep.equal([[document.body]]); unmount(); expect(refSpy.args).to.deep.equal([[document.body], [null]]); }); it('should have access to the mountNode when disabledPortal={true}', () => { const refSpy = spy(); const { unmount } = render(

Foo

, { strict: reactMajor <= 18 }, ); const mountNode = document.querySelector('.woofPortal'); expect(refSpy.args).to.deep.equal([[mountNode]]); unmount(); expect(refSpy.args).to.deep.equal([[mountNode], [null]]); }); it('should have access to the mountNode when switching disabledPortal', () => { const refSpy = spy(); const { setProps, unmount } = render(

Foo

, { strict: reactMajor <= 18 }, ); const mountNode = document.querySelector('.woofPortal'); expect(refSpy.args).to.deep.equal([[mountNode]]); setProps({ disablePortal: false, ref: refSpy, }); expect(refSpy.args).to.deep.equal([[mountNode], [null], [document.body]]); unmount(); expect(refSpy.args).to.deep.equal([[mountNode], [null], [document.body], [null]]); }); }); it('should render in a different node', () => { render(

Foo

Foo

, ); const rootElement = document.querySelector('#test1')!; expect(rootElement.contains(document.querySelector('.woofPortal1'))).to.equal(true); expect(rootElement.contains(document.querySelector('.woofPortal2'))).to.equal(false); }); it('should unmount when parent unmounts', () => { function Child() { const containerRef = React.useRef(null); return (
containerRef.current}>
); } function Parent(props: { show?: boolean }) { const { show = true } = props; return
{show ? : null}
; } const { setProps } = render(); expect(document.querySelectorAll('#test1').length).to.equal(1); setProps({ show: false }); expect(document.querySelectorAll('#test1').length).to.equal(0); }); it('should render overlay into container (document)', () => { render(
, ); expect(document.querySelectorAll('.test2').length).to.equal(2); }); it('should render overlay into container (DOMNode)', () => { const container = document.createElement('div'); render(
, ); expect(container.querySelectorAll('#test2').length).to.equal(1); }); it('should change container on prop change', () => { type ContainerProps = { disablePortal?: boolean; containerElement?: boolean; }; function ContainerTest(props: ContainerProps) { const { containerElement = false, disablePortal = true } = props; const containerRef = React.useRef(null); const container = React.useCallback( () => (containerElement ? containerRef.current : null), [containerElement], ); return (
); } const { setProps } = render(); expect(document.querySelector('#test3')?.parentElement?.nodeName).to.equal('SPAN'); setProps({ containerElement: true, disablePortal: true, }); expect(document.querySelector('#test3')?.parentElement?.nodeName).to.equal('SPAN'); setProps({ containerElement: true, disablePortal: false, }); expect(document.querySelector('#test3')?.parentElement?.nodeName).to.equal('STRONG'); setProps({ containerElement: false, disablePortal: false, }); expect(document.querySelector('#test3')?.parentElement?.nodeName).to.equal('BODY'); }); it('should call ref after child effect', () => { const callOrder: Array = []; const handleRef = (node: Element | null) => { if (node) { callOrder.push('ref'); } }; const updateFunction = () => { callOrder.push('effect'); }; function Test(props: PortalProps) { const { container } = props; const containerRef = React.useRef(null); React.useEffect(() => { if (containerRef.current !== container) { updateFunction(); } containerRef.current = container; }, [container]); return (
); } const { setProps } = render(); setProps({ container: null }); setProps({ container: document.createElement('div') }); setProps({ container: null }); expect(callOrder).to.deep.equal([ 'effect', 'ref', 'effect', 'ref', 'effect', 'ref', 'effect', 'ref', ]); }); });