diff --git a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js
index e4412632e17ee..d884b92d7fd49 100644
--- a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js
@@ -12,30 +12,37 @@
describe('ReactDOMEventListener', () => {
let React;
let ReactDOM;
+ let ReactDOMClient;
let ReactDOMServer;
+ let act;
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOM = require('react-dom');
+ ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
+ act = require('internal-test-utils').act;
});
describe('Propagation', () => {
- it('should propagate events one level down', () => {
+ it('should propagate events one level down', async () => {
const mouseOut = jest.fn();
const onMouseOut = event => mouseOut(event.currentTarget);
const childContainer = document.createElement('div');
const parentContainer = document.createElement('div');
- const childNode = ReactDOM.render(
-
Child
,
- childContainer,
- );
- const parentNode = ReactDOM.render(
- div
,
- parentContainer,
- );
+
+ const childRoot = ReactDOMClient.createRoot(childContainer);
+ const parentRoot = ReactDOMClient.createRoot(parentContainer);
+
+ await act(() => {
+ childRoot.render(Child
);
+ parentRoot.render(Parent
);
+ });
+ const parentNode = parentContainer.firstChild;
+ const childNode = childContainer.firstChild;
+
parentNode.appendChild(childContainer);
document.body.appendChild(parentContainer);
@@ -44,34 +51,35 @@ describe('ReactDOMEventListener', () => {
nativeEvent.initEvent('mouseout', true, true);
childNode.dispatchEvent(nativeEvent);
- expect(mouseOut).toBeCalled();
expect(mouseOut).toHaveBeenCalledTimes(2);
- expect(mouseOut.mock.calls[0][0]).toEqual(childNode);
- expect(mouseOut.mock.calls[1][0]).toEqual(parentNode);
+ expect(mouseOut).toHaveBeenNthCalledWith(1, childNode);
+ expect(mouseOut).toHaveBeenNthCalledWith(2, parentNode);
} finally {
document.body.removeChild(parentContainer);
}
});
- it('should propagate events two levels down', () => {
+ it('should propagate events two levels down', async () => {
const mouseOut = jest.fn();
const onMouseOut = event => mouseOut(event.currentTarget);
const childContainer = document.createElement('div');
const parentContainer = document.createElement('div');
const grandParentContainer = document.createElement('div');
- const childNode = ReactDOM.render(
- Child
,
- childContainer,
- );
- const parentNode = ReactDOM.render(
- Parent
,
- parentContainer,
- );
- const grandParentNode = ReactDOM.render(
- Parent
,
- grandParentContainer,
- );
+
+ const childRoot = ReactDOMClient.createRoot(childContainer);
+ const parentRoot = ReactDOMClient.createRoot(parentContainer);
+ const grandParentRoot = ReactDOMClient.createRoot(grandParentContainer);
+
+ await act(() => {
+ childRoot.render(Child
);
+ parentRoot.render(Parent
);
+ grandParentRoot.render(Grandparent
);
+ });
+ const childNode = childContainer.firstChild;
+ const parentNode = parentContainer.firstChild;
+ const grandParentNode = grandParentContainer.firstChild;
+
parentNode.appendChild(childContainer);
grandParentNode.appendChild(parentContainer);
@@ -82,18 +90,17 @@ describe('ReactDOMEventListener', () => {
nativeEvent.initEvent('mouseout', true, true);
childNode.dispatchEvent(nativeEvent);
- expect(mouseOut).toBeCalled();
expect(mouseOut).toHaveBeenCalledTimes(3);
- expect(mouseOut.mock.calls[0][0]).toEqual(childNode);
- expect(mouseOut.mock.calls[1][0]).toEqual(parentNode);
- expect(mouseOut.mock.calls[2][0]).toEqual(grandParentNode);
+ expect(mouseOut).toHaveBeenNthCalledWith(1, childNode);
+ expect(mouseOut).toHaveBeenNthCalledWith(2, parentNode);
+ expect(mouseOut).toHaveBeenNthCalledWith(3, grandParentNode);
} finally {
document.body.removeChild(grandParentContainer);
}
});
// Regression test for https://github.com/facebook/react/issues/1105
- it('should not get confused by disappearing elements', () => {
+ it('should not get confused by disappearing elements', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
@@ -119,12 +126,17 @@ describe('ReactDOMEventListener', () => {
}
}
}
- ReactDOM.render( , container);
- container.firstChild.dispatchEvent(
- new MouseEvent('click', {
- bubbles: true,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render( );
+ });
+ await act(() => {
+ container.firstChild.dispatchEvent(
+ new MouseEvent('click', {
+ bubbles: true,
+ }),
+ );
+ });
expect(container.firstChild.textContent).toBe('clicked!');
} finally {
document.body.removeChild(container);
@@ -188,22 +200,17 @@ describe('ReactDOMEventListener', () => {
});
});
- it('should not fire duplicate events for a React DOM tree', () => {
+ it('should not fire duplicate events for a React DOM tree', async () => {
const mouseOut = jest.fn();
const onMouseOut = event => mouseOut(event.target);
+ const innerRef = React.createRef();
class Wrapper extends React.Component {
- innerRef = React.createRef();
- getInner = () => {
- return this.innerRef.current;
- };
-
render() {
- const inner = Inner
;
return (
);
@@ -211,25 +218,28 @@ describe('ReactDOMEventListener', () => {
}
const container = document.createElement('div');
- const instance = ReactDOM.render( , container);
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render( );
+ });
document.body.appendChild(container);
try {
const nativeEvent = document.createEvent('Event');
nativeEvent.initEvent('mouseout', true, true);
- instance.getInner().dispatchEvent(nativeEvent);
+ await act(() => {
+ innerRef.current.dispatchEvent(nativeEvent);
+ });
- expect(mouseOut).toBeCalled();
- expect(mouseOut).toHaveBeenCalledTimes(1);
- expect(mouseOut.mock.calls[0][0]).toEqual(instance.getInner());
+ expect(mouseOut).toBeCalledWith(innerRef.current);
} finally {
document.body.removeChild(container);
}
});
// Regression test for https://github.com/facebook/react/pull/12877
- it('should not fire form events twice', () => {
+ it('should not fire form events twice', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
@@ -239,43 +249,54 @@ describe('ReactDOMEventListener', () => {
const handleInvalid = jest.fn();
const handleReset = jest.fn();
const handleSubmit = jest.fn();
- ReactDOM.render(
- ,
- container,
- );
- inputRef.current.dispatchEvent(
- new Event('invalid', {
- // https://developer.mozilla.org/en-US/docs/Web/Events/invalid
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+ ,
+ );
+ });
+
+ await act(() => {
+ inputRef.current.dispatchEvent(
+ new Event('invalid', {
+ // https://developer.mozilla.org/en-US/docs/Web/Events/invalid
+ bubbles: false,
+ }),
+ );
+ });
expect(handleInvalid).toHaveBeenCalledTimes(1);
- formRef.current.dispatchEvent(
- new Event('reset', {
- // https://developer.mozilla.org/en-US/docs/Web/Events/reset
- bubbles: true,
- }),
- );
+ await act(() => {
+ formRef.current.dispatchEvent(
+ new Event('reset', {
+ // https://developer.mozilla.org/en-US/docs/Web/Events/reset
+ bubbles: true,
+ }),
+ );
+ });
expect(handleReset).toHaveBeenCalledTimes(1);
- formRef.current.dispatchEvent(
- new Event('submit', {
- // https://developer.mozilla.org/en-US/docs/Web/Events/submit
- bubbles: true,
- }),
- );
+ await act(() => {
+ formRef.current.dispatchEvent(
+ new Event('submit', {
+ // https://developer.mozilla.org/en-US/docs/Web/Events/submit
+ bubbles: true,
+ }),
+ );
+ });
expect(handleSubmit).toHaveBeenCalledTimes(1);
- formRef.current.dispatchEvent(
- new Event('submit', {
- // Might happen on older browsers.
- bubbles: true,
- }),
- );
+ await act(() => {
+ formRef.current.dispatchEvent(
+ new Event('submit', {
+ // Might happen on older browsers.
+ bubbles: true,
+ }),
+ );
+ });
expect(handleSubmit).toHaveBeenCalledTimes(2); // It already fired in this test.
document.body.removeChild(container);
@@ -284,7 +305,7 @@ describe('ReactDOMEventListener', () => {
// This tests an implementation detail that submit/reset events are listened to
// at the document level, which is necessary for event replaying to work.
// They bubble in all modern browsers.
- it('should not receive submit events if native, interim DOM handler prevents it', () => {
+ it('should not receive submit events if native, interim DOM handler prevents it', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
@@ -294,30 +315,34 @@ describe('ReactDOMEventListener', () => {
const handleSubmit = jest.fn();
const handleReset = jest.fn();
- ReactDOM.render(
-
-
-
,
- container,
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+
+
,
+ );
+ });
interimRef.current.onsubmit = nativeEvent =>
nativeEvent.stopPropagation();
interimRef.current.onreset = nativeEvent => nativeEvent.stopPropagation();
- formRef.current.dispatchEvent(
- new Event('submit', {
- // https://developer.mozilla.org/en-US/docs/Web/Events/submit
- bubbles: true,
- }),
- );
+ await act(() => {
+ formRef.current.dispatchEvent(
+ new Event('submit', {
+ // https://developer.mozilla.org/en-US/docs/Web/Events/submit
+ bubbles: true,
+ }),
+ );
- formRef.current.dispatchEvent(
- new Event('reset', {
- // https://developer.mozilla.org/en-US/docs/Web/Events/reset
- bubbles: true,
- }),
- );
+ formRef.current.dispatchEvent(
+ new Event('reset', {
+ // https://developer.mozilla.org/en-US/docs/Web/Events/reset
+ bubbles: true,
+ }),
+ );
+ });
expect(handleSubmit).not.toHaveBeenCalled();
expect(handleReset).not.toHaveBeenCalled();
@@ -326,7 +351,7 @@ describe('ReactDOMEventListener', () => {
}
});
- it('should dispatch loadstart only for media elements', () => {
+ it('should dispatch loadstart only for media elements', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
@@ -336,35 +361,41 @@ describe('ReactDOMEventListener', () => {
const handleImgLoadStart = jest.fn();
const handleVideoLoadStart = jest.fn();
- ReactDOM.render(
-
-
-
-
,
- container,
- );
-
- // Note for debugging: loadstart currently doesn't fire in Chrome.
- // https://bugs.chromium.org/p/chromium/issues/detail?id=458851
- imgRef.current.dispatchEvent(
- new ProgressEvent('loadstart', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+
+
+
,
+ );
+ });
+
+ await act(() => {
+ // Note for debugging: loadstart currently doesn't fire in Chrome.
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=458851
+ imgRef.current.dispatchEvent(
+ new ProgressEvent('loadstart', {
+ bubbles: false,
+ }),
+ );
+ });
expect(handleImgLoadStart).toHaveBeenCalledTimes(0);
- videoRef.current.dispatchEvent(
- new ProgressEvent('loadstart', {
- bubbles: false,
- }),
- );
+ await act(() => {
+ videoRef.current.dispatchEvent(
+ new ProgressEvent('loadstart', {
+ bubbles: false,
+ }),
+ );
+ });
expect(handleVideoLoadStart).toHaveBeenCalledTimes(1);
} finally {
document.body.removeChild(container);
}
});
- it('should not attempt to listen to unnecessary events on the top level', () => {
+ it('should not attempt to listen to unnecessary events on the top level', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
@@ -451,22 +482,25 @@ describe('ReactDOMEventListener', () => {
try {
// We expect that mounting this tree will
// *not* attach handlers for any top-level events.
- ReactDOM.render(
- ,
- container,
- );
-
- // Also verify dispatching one of them works
- videoRef.current.dispatchEvent(
- new Event('play', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+ ,
+ );
+ });
+ await act(() => {
+ // Also verify dispatching one of them works
+ videoRef.current.dispatchEvent(
+ new Event('play', {
+ bubbles: false,
+ }),
+ );
+ });
expect(handleVideoPlay).toHaveBeenCalledTimes(1);
// Unlike browsers, we delegate media events.
// (This doesn't make a lot of sense but it would be a breaking change not to.)
@@ -478,26 +512,28 @@ describe('ReactDOMEventListener', () => {
}
});
- it('should dispatch load for embed elements', () => {
+ it('should dispatch load for embed elements', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
try {
const ref = React.createRef();
const handleLoad = jest.fn();
-
- ReactDOM.render(
-
-
-
,
- container,
- );
-
- ref.current.dispatchEvent(
- new ProgressEvent('load', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+
+
,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new ProgressEvent('load', {
+ bubbles: false,
+ }),
+ );
+ });
expect(handleLoad).toHaveBeenCalledTimes(1);
} finally {
@@ -507,24 +543,29 @@ describe('ReactDOMEventListener', () => {
// Unlike browsers, we delegate media events.
// (This doesn't make a lot of sense but it would be a breaking change not to.)
- it('should delegate media events even without a direct listener', () => {
+ it('should delegate media events even without a direct listener', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const handleVideoPlayDelegated = jest.fn();
document.body.appendChild(container);
try {
- ReactDOM.render(
-
- {/* Intentionally no handler on the target: */}
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('play', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+ {/* Intentionally no handler on the target: */}
+
+
,
+ );
+ });
+
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('play', {
+ bubbles: false,
+ }),
+ );
+ });
// Regression test: ensure React tree delegation still works
// even if the actual DOM element did not have a handler.
expect(handleVideoPlayDelegated).toHaveBeenCalledTimes(1);
@@ -533,30 +574,34 @@ describe('ReactDOMEventListener', () => {
}
});
- it('should delegate dialog events even without a direct listener', () => {
+ it('should delegate dialog events even without a direct listener', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const onCancel = jest.fn();
const onClose = jest.fn();
document.body.appendChild(container);
try {
- ReactDOM.render(
-
- {/* Intentionally no handler on the target: */}
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('close', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('cancel', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+ {/* Intentionally no handler on the target: */}
+
+
,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('close', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('cancel', {
+ bubbles: false,
+ }),
+ );
+ });
// Regression test: ensure React tree delegation still works
// even if the actual DOM element did not have a handler.
expect(onCancel).toHaveBeenCalledTimes(1);
@@ -566,52 +611,60 @@ describe('ReactDOMEventListener', () => {
}
});
- it('should bubble non-native bubbling toggle events', () => {
+ it('should bubble non-native bubbling toggle events', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const onToggle = jest.fn();
document.body.appendChild(container);
try {
- ReactDOM.render(
-
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('toggle', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+
+
,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('toggle', {
+ bubbles: false,
+ }),
+ );
+ });
expect(onToggle).toHaveBeenCalledTimes(2);
} finally {
document.body.removeChild(container);
}
});
- it('should bubble non-native bubbling cancel/close events', () => {
+ it('should bubble non-native bubbling cancel/close events', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const onCancel = jest.fn();
const onClose = jest.fn();
document.body.appendChild(container);
try {
- ReactDOM.render(
-
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('cancel', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('close', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+
+
,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('cancel', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('close', {
+ bubbles: false,
+ }),
+ );
+ });
expect(onCancel).toHaveBeenCalledTimes(2);
expect(onClose).toHaveBeenCalledTimes(2);
} finally {
@@ -619,53 +672,62 @@ describe('ReactDOMEventListener', () => {
}
});
- it('should bubble non-native bubbling media events events', () => {
+ it('should bubble non-native bubbling media events events', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const onPlay = jest.fn();
document.body.appendChild(container);
try {
- ReactDOM.render(
-
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('play', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+
+
+
,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('play', {
+ bubbles: false,
+ }),
+ );
+ });
expect(onPlay).toHaveBeenCalledTimes(2);
} finally {
document.body.removeChild(container);
}
});
- it('should bubble non-native bubbling invalid events', () => {
+ it('should bubble non-native bubbling invalid events', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const onInvalid = jest.fn();
document.body.appendChild(container);
try {
- ReactDOM.render(
- ,
- container,
- );
- ref.current.dispatchEvent(
- new Event('invalid', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+ ,
+ );
+ });
+
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('invalid', {
+ bubbles: false,
+ }),
+ );
+ });
expect(onInvalid).toHaveBeenCalledTimes(2);
} finally {
document.body.removeChild(container);
}
});
- it('should handle non-bubbling capture events correctly', () => {
+ it('should handle non-bubbling capture events correctly', async () => {
const container = document.createElement('div');
const innerRef = React.createRef();
const outerRef = React.createRef();
@@ -673,30 +735,36 @@ describe('ReactDOMEventListener', () => {
const log = [];
document.body.appendChild(container);
try {
- ReactDOM.render(
- ,
- container,
- );
- innerRef.current.dispatchEvent(
- new Event('play', {
- bubbles: false,
- }),
- );
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
+ ,
+ );
+ });
+ await act(() => {
+ innerRef.current.dispatchEvent(
+ new Event('play', {
+ bubbles: false,
+ }),
+ );
+ });
expect(onPlayCapture).toHaveBeenCalledTimes(3);
expect(log).toEqual([
outerRef.current,
outerRef.current.firstChild,
innerRef.current,
]);
- outerRef.current.dispatchEvent(
- new Event('play', {
- bubbles: false,
- }),
- );
+ await act(() => {
+ outerRef.current.dispatchEvent(
+ new Event('play', {
+ bubbles: false,
+ }),
+ );
+ });
expect(onPlayCapture).toHaveBeenCalledTimes(4);
expect(log).toEqual([
outerRef.current,
@@ -712,7 +780,7 @@ describe('ReactDOMEventListener', () => {
// We're moving towards aligning more closely with the browser.
// Currently we emulate bubbling for all non-bubbling events except scroll.
// We may expand this list in the future, removing emulated bubbling altogether.
- it('should not emulate bubbling of scroll events', () => {
+ it('should not emulate bubbling of scroll events', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const log = [];
@@ -730,41 +798,46 @@ describe('ReactDOMEventListener', () => {
);
document.body.appendChild(container);
try {
- ReactDOM.render(
-
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('scroll', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('scrollend', {
- bubbles: false,
- }),
- );
+ onScrollEndCapture={onScrollEndCapture}>
+
+
+ ,
+ );
+ });
+
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('scroll', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('scrollend', {
+ bubbles: false,
+ }),
+ );
+ });
expect(log).toEqual([
['onScroll', 'capture', 'grand'],
['onScroll', 'capture', 'parent'],
@@ -783,7 +856,7 @@ describe('ReactDOMEventListener', () => {
// We're moving towards aligning more closely with the browser.
// Currently we emulate bubbling for all non-bubbling events except scroll.
// We may expand this list in the future, removing emulated bubbling altogether.
- it('should not emulate bubbling of scroll events (no own handler)', () => {
+ it('should not emulate bubbling of scroll events (no own handler)', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const log = [];
@@ -801,35 +874,39 @@ describe('ReactDOMEventListener', () => {
);
document.body.appendChild(container);
try {
- ReactDOM.render(
-
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
- {/* Intentionally no handler on the child: */}
-
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('scroll', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('scrollend', {
- bubbles: false,
- }),
- );
+
+ {/* Intentionally no handler on the child: */}
+
+
+ ,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('scroll', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('scrollend', {
+ bubbles: false,
+ }),
+ );
+ });
expect(log).toEqual([
['onScroll', 'capture', 'grand'],
['onScroll', 'capture', 'parent'],
@@ -841,7 +918,7 @@ describe('ReactDOMEventListener', () => {
}
});
- it('should subscribe to scroll during updates', () => {
+ it('should subscribe to scroll during updates', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const log = [];
@@ -859,51 +936,57 @@ describe('ReactDOMEventListener', () => {
);
document.body.appendChild(container);
try {
- ReactDOM.render(
-
+ const root = ReactDOMClient.createRoot(container);
+ await act(() => {
+ root.render(
-
,
- container,
- );
+
+ ,
+ );
+ });
- // Update to attach.
- ReactDOM.render(
- onScroll(e)}
- onScrollCapture={e => onScrollCapture(e)}
- onScrollEnd={e => onScrollEnd(e)}
- onScrollEndCapture={e => onScrollEndCapture(e)}>
+ await act(() => {
+ // Update to attach.
+ root.render(
onScroll(e)}
onScrollCapture={e => onScrollCapture(e)}
onScrollEnd={e => onScrollEnd(e)}
onScrollEndCapture={e => onScrollEndCapture(e)}>
onScroll(e)}
onScrollCapture={e => onScrollCapture(e)}
onScrollEnd={e => onScrollEnd(e)}
- onScrollEndCapture={e => onScrollEndCapture(e)}
- ref={ref}
- />
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('scroll', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('scrollend', {
- bubbles: false,
- }),
- );
+ onScrollEndCapture={e => onScrollEndCapture(e)}>
+
onScroll(e)}
+ onScrollCapture={e => onScrollCapture(e)}
+ onScrollEnd={e => onScrollEnd(e)}
+ onScrollEndCapture={e => onScrollEndCapture(e)}
+ ref={ref}
+ />
+
+
,
+ );
+ });
+
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('scroll', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('scrollend', {
+ bubbles: false,
+ }),
+ );
+ });
expect(log).toEqual([
['onScroll', 'capture', 'grand'],
['onScroll', 'capture', 'parent'],
@@ -917,43 +1000,46 @@ describe('ReactDOMEventListener', () => {
// Update to verify deduplication.
log.length = 0;
- ReactDOM.render(
- onScroll(e)}
- onScrollCapture={e => onScrollCapture(e)}
- onScrollEnd={e => onScrollEnd(e)}
- onScrollEndCapture={e => onScrollEndCapture(e)}>
+ await act(() => {
+ root.render(
onScroll(e)}
onScrollCapture={e => onScrollCapture(e)}
onScrollEnd={e => onScrollEnd(e)}
onScrollEndCapture={e => onScrollEndCapture(e)}>
onScroll(e)}
onScrollCapture={e => onScrollCapture(e)}
onScrollEnd={e => onScrollEnd(e)}
- onScrollEndCapture={e => onScrollEndCapture(e)}
- ref={ref}
- />
-
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('scroll', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('scrollend', {
- bubbles: false,
- }),
- );
+ onScrollEndCapture={e => onScrollEndCapture(e)}>
+
onScroll(e)}
+ onScrollCapture={e => onScrollCapture(e)}
+ onScrollEnd={e => onScrollEnd(e)}
+ onScrollEndCapture={e => onScrollEndCapture(e)}
+ ref={ref}
+ />
+
+
,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('scroll', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('scrollend', {
+ bubbles: false,
+ }),
+ );
+ });
expect(log).toEqual([
['onScroll', 'capture', 'grand'],
['onScroll', 'capture', 'parent'],
@@ -967,24 +1053,27 @@ describe('ReactDOMEventListener', () => {
// Update to detach.
log.length = 0;
- ReactDOM.render(
-
+ await act(() => {
+ root.render(
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('scroll', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('scrollend', {
- bubbles: false,
- }),
- );
+
+ ,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('scroll', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('scrollend', {
+ bubbles: false,
+ }),
+ );
+ });
expect(log).toEqual([]);
} finally {
document.body.removeChild(container);
@@ -992,7 +1081,7 @@ describe('ReactDOMEventListener', () => {
});
// Regression test.
- it('should subscribe to scroll during hydration', () => {
+ it('should subscribe to scroll during hydration', async () => {
const container = document.createElement('div');
const ref = React.createRef();
const log = [];
@@ -1036,17 +1125,22 @@ describe('ReactDOMEventListener', () => {
document.body.appendChild(container);
try {
container.innerHTML = ReactDOMServer.renderToString(tree);
- ReactDOM.hydrate(tree, container);
- ref.current.dispatchEvent(
- new Event('scroll', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('scrollend', {
- bubbles: false,
- }),
- );
+ let root;
+ await act(() => {
+ root = ReactDOMClient.hydrateRoot(container, tree);
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('scroll', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('scrollend', {
+ bubbles: false,
+ }),
+ );
+ });
expect(log).toEqual([
['onScroll', 'capture', 'grand'],
['onScroll', 'capture', 'parent'],
@@ -1059,31 +1153,34 @@ describe('ReactDOMEventListener', () => {
]);
log.length = 0;
- ReactDOM.render(
-
+ await act(() => {
+ root.render(
-
,
- container,
- );
- ref.current.dispatchEvent(
- new Event('scroll', {
- bubbles: false,
- }),
- );
- ref.current.dispatchEvent(
- new Event('scrollend', {
- bubbles: false,
- }),
- );
+
+ ,
+ );
+ });
+ await act(() => {
+ ref.current.dispatchEvent(
+ new Event('scroll', {
+ bubbles: false,
+ }),
+ );
+ ref.current.dispatchEvent(
+ new Event('scrollend', {
+ bubbles: false,
+ }),
+ );
+ });
expect(log).toEqual([]);
} finally {
document.body.removeChild(container);
}
});
- it('should not subscribe to selectionchange twice', () => {
+ it('should not subscribe to selectionchange twice', async () => {
const log = [];
const originalDocAddEventListener = document.addEventListener;
@@ -1099,8 +1196,13 @@ describe('ReactDOMEventListener', () => {
}
};
try {
- ReactDOM.render( , document.createElement('div'));
- ReactDOM.render( , document.createElement('div'));
+ const rootOne = ReactDOMClient.createRoot(document.createElement('div'));
+ const rootTwo = ReactDOMClient.createRoot(document.createElement('div'));
+
+ await act(() => {
+ rootOne.render( );
+ rootTwo.render( );
+ });
} finally {
document.addEventListener = originalDocAddEventListener;
}