Skip to content

Commit a1a6a97

Browse files
jeryjgetdavejeryjaduthMamaduka
authored
Fix popover not calling onClose on unmount (#71252)
* Run onClose when unmounting component There was a cancelBlurCheck running on unmount, which prevented the onClose for the popover from running when the popover was unmounted. * Add test coverage for hook * Improve useFocusOutside test with Promise.withResolvers() Replace fragile setTimeout approach with Promise.withResolvers() to make the test more reliable and faster. The test now waits for the actual callback to be called rather than an arbitrary timeout. Addresses feedback from PR #71252 review. * Fix Node.js compatibility: replace Promise.withResolvers() with manual deferred pattern Promise.withResolvers() is only available in Node.js 22+, but the project requires Node.js >=20.10.0. Use the traditional manual deferred promise pattern for better compatibility. This maintains the same improved test reliability while ensuring compatibility with the project's Node.js version requirements. --------- Co-authored-by: Dave Smith <getdavemail@gmail.com> Co-authored-by: jeryj <jeryj@git.wordpress.org> Co-authored-by: getdave <get_dave@git.wordpress.org> Co-authored-by: aduth <aduth@git.wordpress.org> Co-authored-by: Mamaduka <mamaduka@git.wordpress.org> Co-authored-by: ciampo <mciampini@git.wordpress.org> Co-authored-by: stokesman <presstoke@git.wordpress.org>
1 parent d95302f commit a1a6a97

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

packages/compose/src/hooks/use-focus-outside/index.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ export default function useFocusOutside(
8787
clearTimeout( blurCheckTimeoutIdRef.current );
8888
}, [] );
8989

90-
// Cancel blur checks on unmount.
91-
useEffect( () => {
92-
return () => cancelBlurCheck();
93-
}, [] );
94-
9590
// Cancel a blur check if the callback or ref is no longer provided.
9691
useEffect( () => {
9792
if ( ! onFocusOutside ) {

packages/compose/src/hooks/use-focus-outside/test/index.js

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,14 @@ describe( 'useFocusOutside', () => {
116116
mockedDocumentHasFocus.mockRestore();
117117
} );
118118

119-
it( 'should cancel check when unmounting while queued', async () => {
120-
const mockOnFocusOutside = jest.fn();
119+
it( 'should call handler when unmounting while queued', async () => {
120+
let resolvePromise;
121+
const promise = new Promise( ( resolve ) => {
122+
resolvePromise = resolve;
123+
} );
124+
const mockOnFocusOutside = jest
125+
.fn()
126+
.mockImplementation( resolvePromise );
121127
const user = userEvent.setup();
122128

123129
const { unmount } = render(
@@ -130,11 +136,19 @@ describe( 'useFocusOutside', () => {
130136
} );
131137
await user.click( button );
132138

133-
// Simulate a blur event and the wrapper unmounting while the blur event
134-
// handler is queued
135-
button.blur();
139+
// Click outside the wrapper to trigger a blur event and queue the callback
140+
const outsideButton = screen.getByRole( 'button', {
141+
name: 'Button outside the wrapper',
142+
} );
143+
await user.click( outsideButton );
144+
145+
// Immediately unmount the component while the blur event is queued
146+
// The callback should still be called.
136147
unmount();
137148

138-
expect( mockOnFocusOutside ).not.toHaveBeenCalled();
149+
// Wait for the callback to be called
150+
await promise;
151+
152+
expect( mockOnFocusOutside ).toHaveBeenCalled();
139153
} );
140154
} );

0 commit comments

Comments
 (0)