'use strict';
let JSDOM;
let React;
let ReactDOMClient;
let act;
let document;
let Fragment;
describe('FragmentRefs', () => {
beforeEach(() => {
jest.resetModules();
JSDOM = require('jsdom');
React = require('react');
Fragment = React.Fragment;
ReactDOMClient = require('react-dom/client');
act = require('internal-test-utils').act;
const jsdom = new JSDOM.JSDOM('');
document = jsdom.window.document;
global.window = jsdom.window;
global.document = global.window.document;
global.navigator = global.window.navigator;
global.Event = global.window.Event;
});
describe('focus methods', () => {
describe('blur()', () => {
it('throws when the nearest host parent is a Document container', async () => {
const fragmentRef = React.createRef();
const root = ReactDOMClient.createRoot(document);
await act(() => {
root.render(
<Fragment ref={fragmentRef}>
<html>
<body>
<a id="child-a" href="/">
A
</a>
</body>
</html>
</Fragment>,
);
});
await act(() => {
document.getElementById('child-a').focus();
});
expect(document.activeElement.id).toEqual('child-a');
await act(() => {
fragmentRef.current.blur();
});
expect(document.activeElement).toEqual(document.body);
});
});
});
describe('events', () => {
describe('dispatchEvent()', () => {
it('fires events when the fragment is a child of a HostSingleton in a document root', async () => {
const fragmentRef = React.createRef();
const bodyRef = React.createRef();
const root = ReactDOMClient.createRoot(document);
await act(() => {
root.render(
<html>
<body ref={bodyRef}>
<Fragment ref={fragmentRef} />
</body>
</html>,
);
});
const fragmentListener = jest.fn();
fragmentRef.current.addEventListener('custom', fragmentListener);
const bodyListener = jest.fn();
bodyRef.current.addEventListener('custom', bodyListener);
fragmentRef.current.dispatchEvent(new Event('custom', {bubbles: true}));
expect(fragmentListener).toHaveBeenCalledTimes(1);
expect(bodyListener).toHaveBeenCalledTimes(1);
});
});
describe('addEventListener()', () => {
it('attaches listeners to the host children inside singletons', async () => {
const fragmentRef = React.createRef();
const childRef = React.createRef();
const root = ReactDOMClient.createRoot(document);
await act(() => {
root.render(
<Fragment ref={fragmentRef}>
<html>
<body>
<div ref={childRef} id="child" />
</body>
</html>
</Fragment>,
);
});
const currentTargets = [];
fragmentRef.current.addEventListener('click', event => {
currentTargets.push(event.currentTarget);
});
childRef.current.dispatchEvent(new Event('click', {bubbles: true}));
expect(currentTargets).toEqual([document.documentElement]);
});
it('attaches listeners to a singleton mounted into the fragment, but not to its content', async () => {
const fragmentRef = React.createRef();
const childRef = React.createRef();
const root = ReactDOMClient.createRoot(document);
function Test({showShell}) {
return (
<Fragment ref={fragmentRef}>
{showShell && (
<html>
<body>
<div ref={childRef} id="child" />
</body>
</html>
)}
</Fragment>
);
}
await act(() => {
root.render(<Test showShell={false} />);
});
const currentTargets = [];
fragmentRef.current.addEventListener('click', event => {
currentTargets.push(event.currentTarget);
});
await act(() => {
root.render(<Test showShell={true} />);
});
childRef.current.dispatchEvent(new Event('click', {bubbles: true}));
expect(currentTargets).toEqual([document.documentElement]);
});
it('attributes new children inside a singleton to fragments below it, not above it', async () => {
const outerFragmentRef = React.createRef();
const innerFragmentRef = React.createRef();
const lateChildRef = React.createRef();
const root = ReactDOMClient.createRoot(document);
function Test({showLateChild}) {
return (
<Fragment ref={outerFragmentRef}>
<html>
<body>
<Fragment ref={innerFragmentRef}>
<div id="child" />
{showLateChild && <span ref={lateChildRef} id="late" />}
</Fragment>
</body>
</html>
</Fragment>
);
}
await act(() => {
root.render(<Test showLateChild={false} />);
});
const outerCurrentTargets = [];
outerFragmentRef.current.addEventListener('click', event => {
outerCurrentTargets.push(event.currentTarget);
});
const innerCurrentTargets = [];
innerFragmentRef.current.addEventListener('click', event => {
innerCurrentTargets.push(event.currentTarget);
});
await act(() => {
root.render(<Test showLateChild={true} />);
});
lateChildRef.current.dispatchEvent(new Event('click', {bubbles: true}));
expect(innerCurrentTargets).toEqual([lateChildRef.current]);
expect(outerCurrentTargets).toEqual([document.documentElement]);
});
});
});
describe('getClientRects()', () => {
it('measures the host children inside singletons', async () => {
const fragmentRef = React.createRef();
const childRef = React.createRef();
const root = ReactDOMClient.createRoot(document);
await act(() => {
root.render(
<Fragment ref={fragmentRef}>
<html>
<body>
<div ref={childRef} id="child" />
</body>
</html>
</Fragment>,
);
});
childRef.current.getClientRects = jest.fn(() => ['child-rect']);
document.documentElement.getClientRects = jest.fn(() => ['html-rect']);
expect(fragmentRef.current.getClientRects()).toEqual(['html-rect']);
});
});
});