Skip to content

Commit

Permalink
Convert ReactBrowserEventEmitter to createRoot (#28253)
Browse files Browse the repository at this point in the history
pretty boring
  • Loading branch information
rickhanlonii authored Feb 6, 2024
1 parent 65d95b8 commit 5446b09
Showing 1 changed file with 153 additions and 78 deletions.
231 changes: 153 additions & 78 deletions packages/react-dom/src/__tests__/ReactBrowserEventEmitter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
'use strict';

let React;
let ReactDOM;
let ReactDOMClient;
let ReactTestUtils;
let act;

let idCallOrder;
const recordID = function (id) {
Expand All @@ -34,6 +35,7 @@ let PARENT;
let CHILD;
let BUTTON;

let renderTree;
let putListener;
let deleteAllListeners;

Expand All @@ -47,9 +49,9 @@ describe('ReactBrowserEventEmitter', () => {
LISTENER.mockClear();

React = require('react');
ReactDOM = require('react-dom');
ReactDOMClient = require('react-dom/client');
ReactTestUtils = require('react-dom/test-utils');

act = require('internal-test-utils').act;
container = document.createElement('div');
document.body.appendChild(container);

Expand All @@ -68,21 +70,26 @@ describe('ReactBrowserEventEmitter', () => {
}
}

function renderTree() {
ReactDOM.render(
<div ref={c => (GRANDPARENT = c)} {...GRANDPARENT_PROPS}>
<div ref={c => (PARENT = c)} {...PARENT_PROPS}>
<ChildWrapper {...CHILD_PROPS} />
<button disabled={true} ref={c => (BUTTON = c)} {...BUTTON_PROPS} />
</div>
</div>,
container,
);
}

renderTree();
const root = ReactDOMClient.createRoot(container);

renderTree = async function () {
await act(() => {
root.render(
<div ref={c => (GRANDPARENT = c)} {...GRANDPARENT_PROPS}>
<div ref={c => (PARENT = c)} {...PARENT_PROPS}>
<ChildWrapper {...CHILD_PROPS} />
<button
disabled={true}
ref={c => (BUTTON = c)}
{...BUTTON_PROPS}
/>
</div>
</div>,
);
});
};

putListener = function (node, eventName, listener) {
putListener = async function (node, eventName, listener) {
switch (node) {
case CHILD:
CHILD_PROPS[eventName] = listener;
Expand All @@ -98,9 +105,10 @@ describe('ReactBrowserEventEmitter', () => {
break;
}
// Rerender with new event listeners
renderTree();
await renderTree();
};
deleteAllListeners = function (node) {

deleteAllListeners = async function (node) {
switch (node) {
case CHILD:
CHILD_PROPS = {};
Expand All @@ -115,7 +123,7 @@ describe('ReactBrowserEventEmitter', () => {
BUTTON_PROPS = {};
break;
}
renderTree();
await renderTree();
};

idCallOrder = [];
Expand All @@ -126,120 +134,178 @@ describe('ReactBrowserEventEmitter', () => {
container = null;
});

it('should bubble simply', () => {
putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, PARENT));
putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, GRANDPARENT));
CHILD.click();
it('should bubble simply', async () => {
await renderTree();
await putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
await putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, PARENT));
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, GRANDPARENT),
);
await act(() => {
CHILD.click();
});
expect(idCallOrder.length).toBe(3);
expect(idCallOrder[0]).toBe(CHILD);
expect(idCallOrder[1]).toBe(PARENT);
expect(idCallOrder[2]).toBe(GRANDPARENT);
});

it('should bubble to the right handler after an update', () => {
putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, 'GRANDPARENT'));
putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, 'PARENT'));
putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, 'CHILD'));
CHILD.click();
it('should bubble to the right handler after an update', async () => {
await renderTree();
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, 'GRANDPARENT'),
);
await putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, 'PARENT'));
await putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, 'CHILD'));
await act(() => {
CHILD.click();
});
expect(idCallOrder).toEqual(['CHILD', 'PARENT', 'GRANDPARENT']);

idCallOrder = [];

// Update just the grand parent without updating the child.
putListener(
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, 'UPDATED_GRANDPARENT'),
);

CHILD.click();
await act(() => {
CHILD.click();
});
expect(idCallOrder).toEqual(['CHILD', 'PARENT', 'UPDATED_GRANDPARENT']);
});

it('should continue bubbling if an error is thrown', () => {
putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
putListener(PARENT, ON_CLICK_KEY, function () {
it('should continue bubbling if an error is thrown', async () => {
await renderTree();
await putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
await putListener(PARENT, ON_CLICK_KEY, function () {
recordID(PARENT);
throw new Error('Handler interrupted');
});
putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, GRANDPARENT));
expect(function () {
ReactTestUtils.Simulate.click(CHILD);
}).toThrow();
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, GRANDPARENT),
);
await expect(
act(() => {
ReactTestUtils.Simulate.click(CHILD);
}),
).rejects.toThrow();
expect(idCallOrder.length).toBe(3);
expect(idCallOrder[0]).toBe(CHILD);
expect(idCallOrder[1]).toBe(PARENT);
expect(idCallOrder[2]).toBe(GRANDPARENT);
});

it('should set currentTarget', () => {
putListener(CHILD, ON_CLICK_KEY, function (event) {
it('should set currentTarget', async () => {
await renderTree();
await putListener(CHILD, ON_CLICK_KEY, function (event) {
recordID(CHILD);
expect(event.currentTarget).toBe(CHILD);
});
putListener(PARENT, ON_CLICK_KEY, function (event) {
await putListener(PARENT, ON_CLICK_KEY, function (event) {
recordID(PARENT);
expect(event.currentTarget).toBe(PARENT);
});
putListener(GRANDPARENT, ON_CLICK_KEY, function (event) {
await putListener(GRANDPARENT, ON_CLICK_KEY, function (event) {
recordID(GRANDPARENT);
expect(event.currentTarget).toBe(GRANDPARENT);
});
CHILD.click();
await act(() => {
CHILD.click();
});
expect(idCallOrder.length).toBe(3);
expect(idCallOrder[0]).toBe(CHILD);
expect(idCallOrder[1]).toBe(PARENT);
expect(idCallOrder[2]).toBe(GRANDPARENT);
});

it('should support stopPropagation()', () => {
putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
putListener(
it('should support stopPropagation()', async () => {
await renderTree();
await putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
await putListener(
PARENT,
ON_CLICK_KEY,
recordIDAndStopPropagation.bind(null, PARENT),
);
putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, GRANDPARENT));
CHILD.click();
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, GRANDPARENT),
);
await act(() => {
CHILD.click();
});
expect(idCallOrder.length).toBe(2);
expect(idCallOrder[0]).toBe(CHILD);
expect(idCallOrder[1]).toBe(PARENT);
});

it('should support overriding .isPropagationStopped()', () => {
it('should support overriding .isPropagationStopped()', async () => {
await renderTree();
// Ew. See D4504876.
putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
putListener(PARENT, ON_CLICK_KEY, function (e) {
await putListener(CHILD, ON_CLICK_KEY, recordID.bind(null, CHILD));
await putListener(PARENT, ON_CLICK_KEY, function (e) {
recordID(PARENT, e);
// This stops React bubbling but avoids touching the native event
e.isPropagationStopped = () => true;
});
putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, GRANDPARENT));
CHILD.click();
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, GRANDPARENT),
);
await act(() => {
CHILD.click();
});
expect(idCallOrder.length).toBe(2);
expect(idCallOrder[0]).toBe(CHILD);
expect(idCallOrder[1]).toBe(PARENT);
});

it('should stop after first dispatch if stopPropagation', () => {
putListener(
it('should stop after first dispatch if stopPropagation', async () => {
await renderTree();
await putListener(
CHILD,
ON_CLICK_KEY,
recordIDAndStopPropagation.bind(null, CHILD),
);
putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, PARENT));
putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, GRANDPARENT));
CHILD.click();
await putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, PARENT));
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, GRANDPARENT),
);
await act(() => {
CHILD.click();
});
expect(idCallOrder.length).toBe(1);
expect(idCallOrder[0]).toBe(CHILD);
});

it('should not stopPropagation if false is returned', () => {
putListener(CHILD, ON_CLICK_KEY, recordIDAndReturnFalse.bind(null, CHILD));
putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, PARENT));
putListener(GRANDPARENT, ON_CLICK_KEY, recordID.bind(null, GRANDPARENT));
CHILD.click();
it('should not stopPropagation if false is returned', async () => {
await renderTree();
await putListener(
CHILD,
ON_CLICK_KEY,
recordIDAndReturnFalse.bind(null, CHILD),
);
await putListener(PARENT, ON_CLICK_KEY, recordID.bind(null, PARENT));
await putListener(
GRANDPARENT,
ON_CLICK_KEY,
recordID.bind(null, GRANDPARENT),
);
await act(() => {
CHILD.click();
});
expect(idCallOrder.length).toBe(3);
expect(idCallOrder[0]).toBe(CHILD);
expect(idCallOrder[1]).toBe(PARENT);
Expand All @@ -255,30 +321,39 @@ describe('ReactBrowserEventEmitter', () => {
* these new listeners.
*/

it('should invoke handlers that were removed while bubbling', () => {
it('should invoke handlers that were removed while bubbling', async () => {
await renderTree();
const handleParentClick = jest.fn();
const handleChildClick = function (event) {
deleteAllListeners(PARENT);
const handleChildClick = async function (event) {
await deleteAllListeners(PARENT);
};
putListener(CHILD, ON_CLICK_KEY, handleChildClick);
putListener(PARENT, ON_CLICK_KEY, handleParentClick);
CHILD.click();
await putListener(CHILD, ON_CLICK_KEY, handleChildClick);
await putListener(PARENT, ON_CLICK_KEY, handleParentClick);
await act(() => {
CHILD.click();
});
expect(handleParentClick).toHaveBeenCalledTimes(1);
});

it('should not invoke newly inserted handlers while bubbling', () => {
it('should not invoke newly inserted handlers while bubbling', async () => {
await renderTree();
const handleParentClick = jest.fn();
const handleChildClick = function (event) {
putListener(PARENT, ON_CLICK_KEY, handleParentClick);
const handleChildClick = async function (event) {
await putListener(PARENT, ON_CLICK_KEY, handleParentClick);
};
putListener(CHILD, ON_CLICK_KEY, handleChildClick);
CHILD.click();
await putListener(CHILD, ON_CLICK_KEY, handleChildClick);
await act(() => {
CHILD.click();
});
expect(handleParentClick).toHaveBeenCalledTimes(0);
});

it('should have mouse enter simulated by test utils', () => {
putListener(CHILD, ON_MOUSE_ENTER_KEY, recordID.bind(null, CHILD));
ReactTestUtils.Simulate.mouseEnter(CHILD);
it('should have mouse enter simulated by test utils', async () => {
await renderTree();
await putListener(CHILD, ON_MOUSE_ENTER_KEY, recordID.bind(null, CHILD));
await act(() => {
ReactTestUtils.Simulate.mouseEnter(CHILD);
});
expect(idCallOrder.length).toBe(1);
expect(idCallOrder[0]).toBe(CHILD);
});
Expand Down

0 comments on commit 5446b09

Please sign in to comment.