@wordpress/compose 8.7.2-next.v.202609031004.0 → 8.8.2-next.v.202609171837.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -1
- package/README.md +90 -90
- package/build/hooks/use-fixed-window-list/index.cjs.map +2 -2
- package/build/hooks/use-focus-outside/index.cjs +1 -0
- package/build/hooks/use-focus-outside/index.cjs.map +2 -2
- package/build/hooks/use-keyboard-shortcut/index.cjs.map +2 -2
- package/build/hooks/use-resize-observer/use-resize-observer.cjs +9 -0
- package/build/hooks/use-resize-observer/use-resize-observer.cjs.map +2 -2
- package/build-module/hooks/use-fixed-window-list/index.mjs.map +2 -2
- package/build-module/hooks/use-focus-outside/index.mjs +1 -0
- package/build-module/hooks/use-focus-outside/index.mjs.map +2 -2
- package/build-module/hooks/use-keyboard-shortcut/index.mjs.map +2 -2
- package/build-module/hooks/use-resize-observer/use-resize-observer.mjs +10 -1
- package/build-module/hooks/use-resize-observer/use-resize-observer.mjs.map +2 -2
- package/build-types/hooks/use-focus-outside/index.d.ts.map +1 -1
- package/build-types/hooks/use-resize-observer/use-resize-observer.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/higher-order/pure/test/index.jsdom.test.jsx +1 -0
- package/src/higher-order/with-global-events/test/index.jsdom.test.jsx +18 -15
- package/src/higher-order/with-global-events/test/listener.jsdom.test.js +13 -4
- package/src/higher-order/with-instance-id/test/index.jsdom.test.jsx +1 -0
- package/src/higher-order/with-state/test/index.jsdom.test.jsx +1 -0
- package/src/hooks/use-copy-on-click/test/index.jsdom.test.tsx +18 -17
- package/src/hooks/use-copy-to-clipboard/test/index.jsdom.test.tsx +12 -11
- package/src/hooks/use-dialog/test/index.jsdom.test.tsx +14 -13
- package/src/hooks/use-disabled/test/index.jsdom.test.jsx +1 -0
- package/src/hooks/use-drop-zone/test/index.jsdom.test.jsx +1 -0
- package/src/hooks/use-fixed-window-list/index.ts +1 -1
- package/src/hooks/use-focus-outside/index.ts +3 -3
- package/src/hooks/use-focus-outside/test/index.jsdom.test.jsx +7 -8
- package/src/hooks/use-instance-id/test/index.jsdom.test.jsx +1 -0
- package/src/hooks/use-keyboard-shortcut/index.ts +3 -3
- package/src/hooks/use-media-query/test/{index.jsdom.test.jsx → index.browser.test.jsx} +23 -21
- package/src/hooks/use-merge-refs/test/index.jsdom.test.jsx +1 -0
- package/src/hooks/use-observable-value/test/index.jsdom.test.jsx +2 -1
- package/src/hooks/use-resize-observer/test/index.browser.test.ts +24 -0
- package/src/hooks/use-resize-observer/use-resize-observer.ts +13 -1
- package/src/hooks/use-state-with-history/test/index.jsdom.test.jsx +1 -0
- package/src/hooks/use-viewport-match/test/index.jsdom.test.jsx +2 -3
- package/src/utils/subscribe-delegated-listener/test/index.jsdom.test.js +17 -16
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
1
2
|
import { render, screen } from '@testing-library/react';
|
|
2
3
|
import userEvent from '@testing-library/user-event';
|
|
3
4
|
import { createPortal } from 'react-dom';
|
|
@@ -20,7 +21,7 @@ function Dialog( { onClose }: { onClose?: () => void } ) {
|
|
|
20
21
|
describe( 'useDialog', () => {
|
|
21
22
|
it( 'should call onClose when Escape is pressed', async () => {
|
|
22
23
|
const user = userEvent.setup();
|
|
23
|
-
const onClose =
|
|
24
|
+
const onClose = vi.fn();
|
|
24
25
|
|
|
25
26
|
render( <Dialog onClose={ onClose } /> );
|
|
26
27
|
|
|
@@ -32,7 +33,7 @@ describe( 'useDialog', () => {
|
|
|
32
33
|
|
|
33
34
|
it( 'should not call onClose when Escape is pressed if defaultPrevented', async () => {
|
|
34
35
|
const user = userEvent.setup();
|
|
35
|
-
const onClose =
|
|
36
|
+
const onClose = vi.fn();
|
|
36
37
|
|
|
37
38
|
function DialogWithChild() {
|
|
38
39
|
const [ ref, props ] = useDialog( {
|
|
@@ -69,8 +70,8 @@ describe( 'useDialog', () => {
|
|
|
69
70
|
|
|
70
71
|
it( 'should stop Escape event from propagating to parent elements', async () => {
|
|
71
72
|
const user = userEvent.setup();
|
|
72
|
-
const onClose =
|
|
73
|
-
const parentKeyDownHandler =
|
|
73
|
+
const onClose = vi.fn();
|
|
74
|
+
const parentKeyDownHandler = vi.fn();
|
|
74
75
|
|
|
75
76
|
render(
|
|
76
77
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
@@ -88,7 +89,7 @@ describe( 'useDialog', () => {
|
|
|
88
89
|
|
|
89
90
|
it( 'should let Escape propagate when there is no onClose handler', async () => {
|
|
90
91
|
const user = userEvent.setup();
|
|
91
|
-
const parentKeyDownHandler =
|
|
92
|
+
const parentKeyDownHandler = vi.fn();
|
|
92
93
|
|
|
93
94
|
render(
|
|
94
95
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
@@ -105,8 +106,8 @@ describe( 'useDialog', () => {
|
|
|
105
106
|
|
|
106
107
|
it( 'should not close when a portaled descendant handles Escape and stops propagation', async () => {
|
|
107
108
|
const user = userEvent.setup();
|
|
108
|
-
const onClose =
|
|
109
|
-
const descendantHandled =
|
|
109
|
+
const onClose = vi.fn();
|
|
110
|
+
const descendantHandled = vi.fn();
|
|
110
111
|
|
|
111
112
|
const portalTarget = document.createElement( 'div' );
|
|
112
113
|
document.body.appendChild( portalTarget );
|
|
@@ -153,8 +154,8 @@ describe( 'useDialog', () => {
|
|
|
153
154
|
|
|
154
155
|
it( 'should close only the innermost dialog when nested', async () => {
|
|
155
156
|
const user = userEvent.setup();
|
|
156
|
-
const outerOnClose =
|
|
157
|
-
const innerOnClose =
|
|
157
|
+
const outerOnClose = vi.fn();
|
|
158
|
+
const innerOnClose = vi.fn();
|
|
158
159
|
|
|
159
160
|
function NestedDialogs() {
|
|
160
161
|
const [ outerRef, outerProps ] = useDialog( {
|
|
@@ -196,8 +197,8 @@ describe( 'useDialog', () => {
|
|
|
196
197
|
|
|
197
198
|
it( 'should call the consumer-provided onKeyDown alongside close-on-Escape', async () => {
|
|
198
199
|
const user = userEvent.setup();
|
|
199
|
-
const onClose =
|
|
200
|
-
const consumerOnKeyDown =
|
|
200
|
+
const onClose = vi.fn();
|
|
201
|
+
const consumerOnKeyDown = vi.fn();
|
|
201
202
|
|
|
202
203
|
function DialogWithConsumerOnKeyDown() {
|
|
203
204
|
const [ ref, props ] = useDialog( {
|
|
@@ -227,7 +228,7 @@ describe( 'useDialog', () => {
|
|
|
227
228
|
|
|
228
229
|
it( 'should let the consumer-provided onKeyDown opt out of close-on-Escape via preventDefault', async () => {
|
|
229
230
|
const user = userEvent.setup();
|
|
230
|
-
const onClose =
|
|
231
|
+
const onClose = vi.fn();
|
|
231
232
|
|
|
232
233
|
function DialogOptingOut() {
|
|
233
234
|
const [ ref, props ] = useDialog( {
|
|
@@ -255,7 +256,7 @@ describe( 'useDialog', () => {
|
|
|
255
256
|
|
|
256
257
|
it( 'should not call onClose for non-Escape keys', async () => {
|
|
257
258
|
const user = userEvent.setup();
|
|
258
|
-
const onClose =
|
|
259
|
+
const onClose = vi.fn();
|
|
259
260
|
|
|
260
261
|
render( <Dialog onClose={ onClose } /> );
|
|
261
262
|
|
|
@@ -86,7 +86,7 @@ export default function useFixedWindowList(
|
|
|
86
86
|
// Aim to keep opening list view fast, afterward we can optimize for scrolling.
|
|
87
87
|
const overscan = initRender
|
|
88
88
|
? visibleItems
|
|
89
|
-
: windowOverscan ?? visibleItems;
|
|
89
|
+
: ( windowOverscan ?? visibleItems );
|
|
90
90
|
const firstViewableIndex = Math.floor(
|
|
91
91
|
scrollContainer.scrollTop / itemHeight
|
|
92
92
|
);
|
|
@@ -12,9 +12,7 @@ const INPUT_BUTTON_TYPES = [ 'button', 'submit' ];
|
|
|
12
12
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
|
|
13
13
|
*/
|
|
14
14
|
type FocusNormalizedButton =
|
|
15
|
-
|
|
|
16
|
-
| HTMLLinkElement
|
|
17
|
-
| HTMLInputElement;
|
|
15
|
+
HTMLButtonElement | HTMLLinkElement | HTMLInputElement;
|
|
18
16
|
|
|
19
17
|
/**
|
|
20
18
|
* Returns true if the given element is a button element subject to focus
|
|
@@ -148,6 +146,8 @@ export default function useFocusOutside(
|
|
|
148
146
|
return;
|
|
149
147
|
}
|
|
150
148
|
|
|
149
|
+
// Keep only the latest blur check so a subsequent focus event can cancel it.
|
|
150
|
+
clearTimeout( blurCheckTimeoutIdRef.current );
|
|
151
151
|
blurCheckTimeoutIdRef.current = setTimeout( () => {
|
|
152
152
|
// If document is not focused then focus should remain
|
|
153
153
|
// inside the wrapped component and therefore we cancel
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
1
2
|
import { render, screen } from '@testing-library/react';
|
|
2
3
|
import userEvent from '@testing-library/user-event';
|
|
3
4
|
import useFocusOutside from '../';
|
|
@@ -19,7 +20,7 @@ const FocusOutsideComponent = ( { onFocusOutside: callback } ) => (
|
|
|
19
20
|
|
|
20
21
|
describe( 'useFocusOutside', () => {
|
|
21
22
|
it( 'should not call handler if focus shifts to element within component', async () => {
|
|
22
|
-
const mockOnFocusOutside =
|
|
23
|
+
const mockOnFocusOutside = vi.fn();
|
|
23
24
|
const user = userEvent.setup();
|
|
24
25
|
|
|
25
26
|
render(
|
|
@@ -40,7 +41,7 @@ describe( 'useFocusOutside', () => {
|
|
|
40
41
|
} );
|
|
41
42
|
|
|
42
43
|
it( 'should not call handler if focus transitions via click to button', async () => {
|
|
43
|
-
const mockOnFocusOutside =
|
|
44
|
+
const mockOnFocusOutside = vi.fn();
|
|
44
45
|
const user = userEvent.setup();
|
|
45
46
|
|
|
46
47
|
render(
|
|
@@ -57,7 +58,7 @@ describe( 'useFocusOutside', () => {
|
|
|
57
58
|
} );
|
|
58
59
|
|
|
59
60
|
it( 'should call handler if focus shifts to element outside component', async () => {
|
|
60
|
-
const mockOnFocusOutside =
|
|
61
|
+
const mockOnFocusOutside = vi.fn();
|
|
61
62
|
const user = userEvent.setup();
|
|
62
63
|
|
|
63
64
|
render(
|
|
@@ -82,10 +83,10 @@ describe( 'useFocusOutside', () => {
|
|
|
82
83
|
it( 'should not call handler if focus shifts outside the component when the document does not have focus', async () => {
|
|
83
84
|
// Force document.hasFocus() to return false to simulate the window/document losing focus
|
|
84
85
|
// See https://developer.mozilla.org/en-US/docs/Web/API/Document/hasFocus.
|
|
85
|
-
const mockedDocumentHasFocus =
|
|
86
|
+
const mockedDocumentHasFocus = vi
|
|
86
87
|
.spyOn( document, 'hasFocus' )
|
|
87
88
|
.mockImplementation( () => false );
|
|
88
|
-
const mockOnFocusOutside =
|
|
89
|
+
const mockOnFocusOutside = vi.fn();
|
|
89
90
|
const user = userEvent.setup();
|
|
90
91
|
|
|
91
92
|
render(
|
|
@@ -114,9 +115,7 @@ describe( 'useFocusOutside', () => {
|
|
|
114
115
|
const promise = new Promise( ( resolve ) => {
|
|
115
116
|
resolvePromise = resolve;
|
|
116
117
|
} );
|
|
117
|
-
const mockOnFocusOutside =
|
|
118
|
-
.fn()
|
|
119
|
-
.mockImplementation( resolvePromise );
|
|
118
|
+
const mockOnFocusOutside = vi.fn().mockImplementation( resolvePromise );
|
|
120
119
|
const user = userEvent.setup();
|
|
121
120
|
|
|
122
121
|
const { unmount } = render(
|
|
@@ -62,9 +62,9 @@ function useKeyboardShortcut(
|
|
|
62
62
|
target && target.current
|
|
63
63
|
? target.current
|
|
64
64
|
: // We were passing `document` here previously, so to successfully cast it to Element we must cast it first to `unknown`.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
// Not sure if this is a mistake but it was the behavior previous to the addition of types so we're just doing what's
|
|
66
|
+
// necessary to maintain the existing behavior.
|
|
67
|
+
( document as unknown as Element )
|
|
68
68
|
);
|
|
69
69
|
|
|
70
70
|
const shortcutsArray = Array.isArray( shortcuts )
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { page } from 'vitest/browser';
|
|
3
|
+
import { waitFor } from '@testing-library/react';
|
|
4
|
+
import { render } from 'vitest-browser-react';
|
|
3
5
|
import useMediaQuery from '../';
|
|
4
6
|
|
|
5
7
|
const TestComponent = ( { query } ) => {
|
|
@@ -8,23 +10,25 @@ const TestComponent = ( { query } ) => {
|
|
|
8
10
|
};
|
|
9
11
|
|
|
10
12
|
describe( 'useMediaQuery', () => {
|
|
13
|
+
let initialViewport;
|
|
14
|
+
|
|
11
15
|
beforeAll( () => {
|
|
12
|
-
|
|
16
|
+
initialViewport = {
|
|
17
|
+
width: window.innerWidth,
|
|
18
|
+
height: window.innerHeight,
|
|
19
|
+
};
|
|
13
20
|
} );
|
|
14
21
|
|
|
15
|
-
beforeEach( () => {
|
|
16
|
-
|
|
17
|
-
width: '960px',
|
|
18
|
-
} );
|
|
22
|
+
beforeEach( async () => {
|
|
23
|
+
await page.viewport( 960, 768 );
|
|
19
24
|
} );
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// reset media queries.
|
|
26
|
+
afterAll( async () => {
|
|
27
|
+
await page.viewport( initialViewport.width, initialViewport.height );
|
|
24
28
|
} );
|
|
25
29
|
|
|
26
30
|
it( 'should return true when the query matches', async () => {
|
|
27
|
-
const { container } = render(
|
|
31
|
+
const { container } = await render(
|
|
28
32
|
<TestComponent query="(min-width: 782px)" />
|
|
29
33
|
);
|
|
30
34
|
|
|
@@ -32,23 +36,21 @@ describe( 'useMediaQuery', () => {
|
|
|
32
36
|
} );
|
|
33
37
|
|
|
34
38
|
it( 'should correctly update the value when the query evaluation matches', async () => {
|
|
35
|
-
const { container } = render(
|
|
39
|
+
const { container } = await render(
|
|
36
40
|
<TestComponent query="(min-width: 782px)" />
|
|
37
41
|
);
|
|
38
42
|
|
|
39
43
|
expect( container ).toHaveTextContent( 'useMediaQuery: true' );
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
setMedia( {
|
|
43
|
-
width: '600px',
|
|
44
|
-
} );
|
|
45
|
-
} );
|
|
45
|
+
await page.viewport( 600, 768 );
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
await waitFor( () => {
|
|
48
|
+
expect( container ).toHaveTextContent( 'useMediaQuery: false' );
|
|
49
|
+
} );
|
|
48
50
|
} );
|
|
49
51
|
|
|
50
52
|
it( 'should return false when the query does not match', async () => {
|
|
51
|
-
const { container } = render(
|
|
53
|
+
const { container } = await render(
|
|
52
54
|
<TestComponent query="(max-width: 782px)" />
|
|
53
55
|
);
|
|
54
56
|
|
|
@@ -56,12 +58,12 @@ describe( 'useMediaQuery', () => {
|
|
|
56
58
|
} );
|
|
57
59
|
|
|
58
60
|
it( 'should return false when a query is not passed', async () => {
|
|
59
|
-
const { container, rerender } = render( <TestComponent /> );
|
|
61
|
+
const { container, rerender } = await render( <TestComponent /> );
|
|
60
62
|
|
|
61
63
|
// Query will be case to a boolean to simplify the return type.
|
|
62
64
|
expect( container ).toHaveTextContent( 'useMediaQuery: false' );
|
|
63
65
|
|
|
64
|
-
rerender( <TestComponent query={ false } /> );
|
|
66
|
+
await rerender( <TestComponent query={ false } /> );
|
|
65
67
|
|
|
66
68
|
expect( container ).toHaveTextContent( 'useMediaQuery: false' );
|
|
67
69
|
} );
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
1
2
|
import { render, screen, act } from '@testing-library/react';
|
|
2
3
|
import { observableMap } from '../../../utils/observable-map';
|
|
3
4
|
import useObservableValue from '..';
|
|
@@ -7,7 +8,7 @@ describe( 'useObservableValue', () => {
|
|
|
7
8
|
const map = observableMap();
|
|
8
9
|
map.set( 'a', 1 );
|
|
9
10
|
|
|
10
|
-
const MapUI =
|
|
11
|
+
const MapUI = vi.fn( () => {
|
|
11
12
|
const value = useObservableValue( map, 'a' );
|
|
12
13
|
return <div>value is { value }</div>;
|
|
13
14
|
} );
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { act } from '@testing-library/react';
|
|
3
|
+
import { renderHook } from 'vitest-browser-react';
|
|
4
|
+
import useResizeObserver from '..';
|
|
5
|
+
|
|
6
|
+
afterEach( () => {
|
|
7
|
+
vi.restoreAllMocks();
|
|
8
|
+
} );
|
|
9
|
+
|
|
10
|
+
describe( 'useResizeObserver', () => {
|
|
11
|
+
it( 'disconnects the observer on unmount', async () => {
|
|
12
|
+
const disconnect = vi.spyOn( ResizeObserver.prototype, 'disconnect' );
|
|
13
|
+
const { result, unmount } = await renderHook( () =>
|
|
14
|
+
useResizeObserver( vi.fn() )
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
act( () => result.current( document.createElement( 'div' ) ) );
|
|
18
|
+
expect( disconnect ).not.toHaveBeenCalled();
|
|
19
|
+
|
|
20
|
+
await unmount();
|
|
21
|
+
|
|
22
|
+
expect( disconnect ).toHaveBeenCalledOnce();
|
|
23
|
+
} );
|
|
24
|
+
} );
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useRef } from '@wordpress/element';
|
|
1
|
+
import { useEffect, useRef } from '@wordpress/element';
|
|
2
2
|
import useEvent from '../use-event';
|
|
3
3
|
|
|
4
4
|
// This is the current implementation of `useResizeObserver`.
|
|
@@ -14,6 +14,18 @@ export function useResizeObserver< T extends HTMLElement >(
|
|
|
14
14
|
|
|
15
15
|
const observedElementRef = useRef< T | null >( null );
|
|
16
16
|
const resizeObserverRef = useRef< ResizeObserver >( undefined );
|
|
17
|
+
useEffect( () => {
|
|
18
|
+
if ( observedElementRef.current ) {
|
|
19
|
+
resizeObserverRef.current?.observe(
|
|
20
|
+
observedElementRef.current,
|
|
21
|
+
resizeObserverOptions
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return () => resizeObserverRef.current?.disconnect();
|
|
25
|
+
// This effect owns the observer lifecycle. The returned ref handles
|
|
26
|
+
// element and option changes without recreating the observer.
|
|
27
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
+
}, [] );
|
|
17
29
|
return useEvent( ( element?: T | null ) => {
|
|
18
30
|
if ( element === observedElementRef.current ) {
|
|
19
31
|
return;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
1
2
|
import { render } from '@testing-library/react';
|
|
2
3
|
import useViewportMatch from '../';
|
|
3
|
-
jest.mock( '../../use-media-query', () => {
|
|
4
|
-
return jest.fn();
|
|
5
|
-
} );
|
|
6
4
|
import useMediaQueryMock from '../../use-media-query';
|
|
5
|
+
vi.mock( import( '../../use-media-query' ), () => ( { default: vi.fn() } ) );
|
|
7
6
|
|
|
8
7
|
describe( 'useViewportMatch', () => {
|
|
9
8
|
afterEach( () => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
1
2
|
import subscribeDelegatedListener from '..';
|
|
2
3
|
|
|
3
4
|
describe( 'subscribeDelegatedListener', () => {
|
|
@@ -27,14 +28,14 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
test( 'invokes element subscriber when event fires on that element', () => {
|
|
30
|
-
const cb =
|
|
31
|
+
const cb = vi.fn();
|
|
31
32
|
subscribeDelegatedListener( target, 'click', cb );
|
|
32
33
|
fire( target );
|
|
33
34
|
expect( cb ).toHaveBeenCalledTimes( 1 );
|
|
34
35
|
} );
|
|
35
36
|
|
|
36
37
|
test( 'invokes element subscriber when event fires on a descendant', () => {
|
|
37
|
-
const cb =
|
|
38
|
+
const cb = vi.fn();
|
|
38
39
|
const child = document.createElement( 'b' );
|
|
39
40
|
target.appendChild( child );
|
|
40
41
|
subscribeDelegatedListener( target, 'click', cb );
|
|
@@ -43,7 +44,7 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
43
44
|
} );
|
|
44
45
|
|
|
45
46
|
test( 'does not invoke element subscriber when event fires outside its subtree', () => {
|
|
46
|
-
const cb =
|
|
47
|
+
const cb = vi.fn();
|
|
47
48
|
const sibling = document.createElement( 'div' );
|
|
48
49
|
document.body.appendChild( sibling );
|
|
49
50
|
subscribeDelegatedListener( target, 'click', cb );
|
|
@@ -83,8 +84,8 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
83
84
|
} );
|
|
84
85
|
|
|
85
86
|
test( 'capture and bubble registries are independent', () => {
|
|
86
|
-
const captureCb =
|
|
87
|
-
const bubbleCb =
|
|
87
|
+
const captureCb = vi.fn();
|
|
88
|
+
const bubbleCb = vi.fn();
|
|
88
89
|
subscribeDelegatedListener( target, 'click', captureCb, true );
|
|
89
90
|
subscribeDelegatedListener( target, 'click', bubbleCb, false );
|
|
90
91
|
fire( target );
|
|
@@ -93,15 +94,15 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
93
94
|
} );
|
|
94
95
|
|
|
95
96
|
test( 'document subscriber always fires for events in the document', () => {
|
|
96
|
-
const cb =
|
|
97
|
+
const cb = vi.fn();
|
|
97
98
|
subscribeDelegatedListener( document, 'click', cb );
|
|
98
99
|
fire( target );
|
|
99
100
|
expect( cb ).toHaveBeenCalledTimes( 1 );
|
|
100
101
|
} );
|
|
101
102
|
|
|
102
103
|
test( 'window subscriber fans out independently of element subscribers', () => {
|
|
103
|
-
const winCb =
|
|
104
|
-
const elCb =
|
|
104
|
+
const winCb = vi.fn();
|
|
105
|
+
const elCb = vi.fn();
|
|
105
106
|
subscribeDelegatedListener( window, 'resize', winCb );
|
|
106
107
|
subscribeDelegatedListener( target, 'resize', elCb );
|
|
107
108
|
window.dispatchEvent( new Event( 'resize' ) );
|
|
@@ -111,8 +112,8 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
111
112
|
} );
|
|
112
113
|
|
|
113
114
|
test( 'multiple callbacks for the same element all fire', () => {
|
|
114
|
-
const a =
|
|
115
|
-
const b =
|
|
115
|
+
const a = vi.fn();
|
|
116
|
+
const b = vi.fn();
|
|
116
117
|
subscribeDelegatedListener( target, 'click', a );
|
|
117
118
|
subscribeDelegatedListener( target, 'click', b );
|
|
118
119
|
fire( target );
|
|
@@ -121,7 +122,7 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
121
122
|
} );
|
|
122
123
|
|
|
123
124
|
test( 'unsubscribe stops further dispatch', () => {
|
|
124
|
-
const cb =
|
|
125
|
+
const cb = vi.fn();
|
|
125
126
|
const unsub = subscribeDelegatedListener( target, 'click', cb );
|
|
126
127
|
fire( target );
|
|
127
128
|
expect( cb ).toHaveBeenCalledTimes( 1 );
|
|
@@ -131,12 +132,12 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
131
132
|
} );
|
|
132
133
|
|
|
133
134
|
test( 'attaches one native listener per (root, eventType, phase) regardless of subscriber count', () => {
|
|
134
|
-
const spy =
|
|
135
|
+
const spy = vi.spyOn( document, 'addEventListener' );
|
|
135
136
|
// First subscribe attaches the native listener; subsequent ones
|
|
136
137
|
// for the same key share it.
|
|
137
|
-
subscribeDelegatedListener( target, 'mousemove',
|
|
138
|
-
subscribeDelegatedListener( root, 'mousemove',
|
|
139
|
-
subscribeDelegatedListener( document, 'mousemove',
|
|
138
|
+
subscribeDelegatedListener( target, 'mousemove', vi.fn() );
|
|
139
|
+
subscribeDelegatedListener( root, 'mousemove', vi.fn() );
|
|
140
|
+
subscribeDelegatedListener( document, 'mousemove', vi.fn() );
|
|
140
141
|
const nativeMousemoves = spy.mock.calls.filter(
|
|
141
142
|
( [ type, , opts ] ) => type === 'mousemove' && ! opts // bubble-phase only
|
|
142
143
|
).length;
|
|
@@ -154,7 +155,7 @@ describe( 'subscribeDelegatedListener', () => {
|
|
|
154
155
|
const iframeTarget = iframeDoc.createElement( 'span' );
|
|
155
156
|
iframeDoc.body.appendChild( iframeTarget );
|
|
156
157
|
|
|
157
|
-
const cb =
|
|
158
|
+
const cb = vi.fn();
|
|
158
159
|
expect( () =>
|
|
159
160
|
subscribeDelegatedListener( iframeTarget, 'click', cb )
|
|
160
161
|
).not.toThrow();
|