@wordpress/compose 5.16.1-next.4d3b314fd5.0 → 5.18.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +3 -0
  3. package/build/higher-order/with-global-events/listener.js +7 -7
  4. package/build/higher-order/with-global-events/listener.js.map +1 -1
  5. package/build/higher-order/with-safe-timeout/index.js +1 -7
  6. package/build/higher-order/with-safe-timeout/index.js.map +1 -1
  7. package/build/hooks/use-disabled/index.js +10 -104
  8. package/build/hooks/use-disabled/index.js.map +1 -1
  9. package/build/hooks/use-focus-outside/index.js +2 -8
  10. package/build/hooks/use-focus-outside/index.js.map +1 -1
  11. package/build/hooks/use-focus-outside/index.native.js +2 -8
  12. package/build/hooks/use-focus-outside/index.native.js.map +1 -1
  13. package/build/hooks/use-keyboard-shortcut/index.js +2 -3
  14. package/build/hooks/use-keyboard-shortcut/index.js.map +1 -1
  15. package/build/hooks/use-merge-refs/index.js +4 -2
  16. package/build/hooks/use-merge-refs/index.js.map +1 -1
  17. package/build/hooks/use-resize-observer/index.native.js +1 -0
  18. package/build/hooks/use-resize-observer/index.native.js.map +1 -1
  19. package/build-module/higher-order/with-global-events/listener.js +7 -6
  20. package/build-module/higher-order/with-global-events/listener.js.map +1 -1
  21. package/build-module/higher-order/with-safe-timeout/index.js +1 -6
  22. package/build-module/higher-order/with-safe-timeout/index.js.map +1 -1
  23. package/build-module/hooks/use-disabled/index.js +10 -102
  24. package/build-module/hooks/use-disabled/index.js.map +1 -1
  25. package/build-module/hooks/use-focus-outside/index.js +2 -7
  26. package/build-module/hooks/use-focus-outside/index.js.map +1 -1
  27. package/build-module/hooks/use-focus-outside/index.native.js +2 -7
  28. package/build-module/hooks/use-focus-outside/index.native.js.map +1 -1
  29. package/build-module/hooks/use-keyboard-shortcut/index.js +2 -2
  30. package/build-module/hooks/use-keyboard-shortcut/index.js.map +1 -1
  31. package/build-module/hooks/use-merge-refs/index.js +4 -2
  32. package/build-module/hooks/use-merge-refs/index.js.map +1 -1
  33. package/build-module/hooks/use-resize-observer/index.native.js +1 -0
  34. package/build-module/hooks/use-resize-observer/index.native.js.map +1 -1
  35. package/build-types/higher-order/with-global-events/listener.d.ts.map +1 -1
  36. package/build-types/higher-order/with-safe-timeout/index.d.ts.map +1 -1
  37. package/build-types/hooks/use-disabled/index.d.ts +4 -1
  38. package/build-types/hooks/use-disabled/index.d.ts.map +1 -1
  39. package/build-types/hooks/use-focus-outside/index.d.ts.map +1 -1
  40. package/build-types/hooks/use-keyboard-shortcut/index.d.ts.map +1 -1
  41. package/build-types/hooks/use-merge-refs/index.d.ts.map +1 -1
  42. package/package.json +8 -10
  43. package/src/higher-order/with-global-events/listener.js +6 -8
  44. package/src/higher-order/with-global-events/test/index.js +18 -29
  45. package/src/higher-order/with-safe-timeout/index.tsx +1 -6
  46. package/src/higher-order/with-state/test/index.js +13 -26
  47. package/src/hooks/use-disabled/index.ts +81 -0
  48. package/src/hooks/use-disabled/test/index.js +4 -36
  49. package/src/hooks/use-focus-outside/index.js +2 -8
  50. package/src/hooks/use-focus-outside/index.native.js +2 -8
  51. package/src/hooks/use-focus-outside/test/index.js +44 -45
  52. package/src/hooks/use-instance-id/test/index.js +9 -16
  53. package/src/hooks/use-keyboard-shortcut/index.js +4 -2
  54. package/src/hooks/use-media-query/test/index.js +33 -53
  55. package/src/hooks/use-merge-refs/index.js +6 -1
  56. package/src/hooks/use-merge-refs/test/index.js +44 -0
  57. package/src/hooks/use-resize-observer/index.native.js +5 -1
  58. package/src/hooks/use-resize-observer/test/index.native.js +18 -22
  59. package/src/hooks/use-viewport-match/test/index.js +78 -78
  60. package/tsconfig.tsbuildinfo +1 -1
  61. package/src/hooks/use-disabled/index.js +0 -203
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { create, act } from 'react-test-renderer';
4
+ import { render } from '@testing-library/react';
5
5
 
6
6
  /**
7
7
  * Internal dependencies
@@ -14,23 +14,16 @@ describe( 'useInstanceId', () => {
14
14
  };
15
15
 
16
16
  it( 'should manage ids', async () => {
17
- let test0;
17
+ const { container, rerender } = render( <TestComponent /> );
18
18
 
19
- await act( async () => {
20
- test0 = create( <TestComponent /> );
21
- } );
19
+ expect( container ).toHaveTextContent( '0' );
22
20
 
23
- expect( test0.toJSON() ).toBe( '0' );
21
+ rerender(
22
+ <div>
23
+ <TestComponent />
24
+ </div>
25
+ );
24
26
 
25
- let test1;
26
-
27
- await act( async () => {
28
- test1 = create( <TestComponent /> );
29
- } );
30
-
31
- expect( test1.toJSON() ).toBe( '1' );
32
-
33
- test0.unmount();
34
- test1.unmount();
27
+ expect( container ).toHaveTextContent( '1' );
35
28
  } );
36
29
  } );
@@ -3,7 +3,6 @@
3
3
  */
4
4
  import Mousetrap from 'mousetrap';
5
5
  import 'mousetrap/plugins/global-bind/mousetrap-global-bind';
6
- import { castArray } from 'lodash';
7
6
 
8
7
  /**
9
8
  * WordPress dependencies
@@ -60,7 +59,10 @@ function useKeyboardShortcut(
60
59
  // necessary to maintain the existing behavior.
61
60
  /** @type {Element} */ ( /** @type {unknown} */ ( document ) )
62
61
  );
63
- castArray( shortcuts ).forEach( ( shortcut ) => {
62
+ const shortcutsArray = Array.isArray( shortcuts )
63
+ ? shortcuts
64
+ : [ shortcuts ];
65
+ shortcutsArray.forEach( ( shortcut ) => {
64
66
  const keys = shortcut.split( '+' );
65
67
  // Determines whether a key is a modifier by the length of the string.
66
68
  // E.g. if I add a pass a shortcut Shift+Cmd+M, it'll determine that
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { create, act } from 'react-test-renderer';
4
+ import { render, act } from '@testing-library/react';
5
5
 
6
6
  /**
7
7
  * Internal dependencies
@@ -33,18 +33,6 @@ describe( 'useMediaQuery', () => {
33
33
  return `useMediaQuery: ${ queryResult }`;
34
34
  };
35
35
 
36
- it( 'should return true when query matches on the first render', async () => {
37
- global.matchMedia.mockReturnValue( {
38
- addListener,
39
- removeListener,
40
- matches: true,
41
- } );
42
-
43
- const root = create( <TestComponent query="(min-width: 782px)" /> );
44
-
45
- expect( root.toJSON() ).toBe( 'useMediaQuery: true' );
46
- } );
47
-
48
36
  it( 'should return true when query matches', async () => {
49
37
  global.matchMedia.mockReturnValue( {
50
38
  addListener,
@@ -52,17 +40,14 @@ describe( 'useMediaQuery', () => {
52
40
  matches: true,
53
41
  } );
54
42
 
55
- let root;
43
+ const { container, unmount } = render(
44
+ <TestComponent query="(min-width: 782px)" />
45
+ );
56
46
 
57
- await act( async () => {
58
- root = create( <TestComponent query="(min-width: 782px)" /> );
59
- } );
47
+ expect( container ).toHaveTextContent( 'useMediaQuery: true' );
60
48
 
61
- expect( root.toJSON() ).toBe( 'useMediaQuery: true' );
49
+ unmount();
62
50
 
63
- await act( async () => {
64
- root.unmount();
65
- } );
66
51
  expect( removeListener ).toHaveBeenCalled();
67
52
  } );
68
53
 
@@ -90,24 +75,23 @@ describe( 'useMediaQuery', () => {
90
75
  matches: false,
91
76
  } );
92
77
 
93
- let root, updateMatchFunction;
94
- await act( async () => {
95
- root = create( <TestComponent query="(min-width: 782px)" /> );
96
- } );
97
- expect( root.toJSON() ).toBe( 'useMediaQuery: true' );
78
+ const { container, unmount } = render(
79
+ <TestComponent query="(min-width: 782px)" />
80
+ );
81
+
82
+ expect( container ).toHaveTextContent( 'useMediaQuery: true' );
98
83
 
84
+ let updateMatchFunction;
99
85
  await act( async () => {
100
86
  updateMatchFunction = addListener.mock.calls[ 0 ][ 0 ];
101
87
  updateMatchFunction();
102
88
  } );
103
- expect( root.toJSON() ).toBe( 'useMediaQuery: false' );
104
89
 
105
- await act( async () => {
106
- root.unmount();
107
- } );
108
- expect( removeListener.mock.calls ).toEqual( [
109
- [ updateMatchFunction ],
110
- ] );
90
+ expect( container ).toHaveTextContent( 'useMediaQuery: false' );
91
+
92
+ unmount();
93
+
94
+ expect( removeListener ).toHaveBeenCalledWith( updateMatchFunction );
111
95
  } );
112
96
 
113
97
  it( 'should return false when the query does not matches', async () => {
@@ -116,15 +100,15 @@ describe( 'useMediaQuery', () => {
116
100
  removeListener,
117
101
  matches: false,
118
102
  } );
119
- let root;
120
- await act( async () => {
121
- root = create( <TestComponent query="(min-width: 782px)" /> );
122
- } );
123
- expect( root.toJSON() ).toBe( 'useMediaQuery: false' );
124
103
 
125
- await act( async () => {
126
- root.unmount();
127
- } );
104
+ const { container, unmount } = render(
105
+ <TestComponent query="(min-width: 782px)" />
106
+ );
107
+
108
+ expect( container ).toHaveTextContent( 'useMediaQuery: false' );
109
+
110
+ unmount();
111
+
128
112
  expect( removeListener ).toHaveBeenCalled();
129
113
  } );
130
114
 
@@ -134,21 +118,17 @@ describe( 'useMediaQuery', () => {
134
118
  removeListener,
135
119
  matches: false,
136
120
  } );
137
- let root;
138
- await act( async () => {
139
- root = create( <TestComponent /> );
140
- } );
121
+
122
+ const { container, rerender, unmount } = render( <TestComponent /> );
123
+
141
124
  // Query will be case to a boolean to simplify the return type.
142
- expect( root.toJSON() ).toBe( 'useMediaQuery: false' );
125
+ expect( container ).toHaveTextContent( 'useMediaQuery: false' );
143
126
 
144
- await act( async () => {
145
- root.update( <TestComponent query={ false } /> );
146
- } );
147
- expect( root.toJSON() ).toBe( 'useMediaQuery: false' );
127
+ rerender( <TestComponent query={ false } /> );
148
128
 
149
- await act( async () => {
150
- root.unmount();
151
- } );
129
+ expect( container ).toHaveTextContent( 'useMediaQuery: false' );
130
+
131
+ unmount();
152
132
  expect( global.matchMedia ).not.toHaveBeenCalled();
153
133
  expect( addListener ).not.toHaveBeenCalled();
154
134
  expect( removeListener ).not.toHaveBeenCalled();
@@ -71,6 +71,7 @@ function assignRef( ref, value ) {
71
71
  */
72
72
  export default function useMergeRefs( refs ) {
73
73
  const element = useRef();
74
+ const isAttached = useRef( false );
74
75
  const didElementChange = useRef( false );
75
76
  /* eslint-disable jsdoc/no-undefined-types */
76
77
  /** @type {import('react').MutableRefObject<TRef[]>} */
@@ -86,7 +87,10 @@ export default function useMergeRefs( refs ) {
86
87
  // ref with the node, except when the element changes in the same cycle, in
87
88
  // which case the ref callbacks will already have been called.
88
89
  useLayoutEffect( () => {
89
- if ( didElementChange.current === false ) {
90
+ if (
91
+ didElementChange.current === false &&
92
+ isAttached.current === true
93
+ ) {
90
94
  refs.forEach( ( ref, index ) => {
91
95
  const previousRef = previousRefs.current[ index ];
92
96
  if ( ref !== previousRef ) {
@@ -113,6 +117,7 @@ export default function useMergeRefs( refs ) {
113
117
  assignRef( element, value );
114
118
 
115
119
  didElementChange.current = true;
120
+ isAttached.current = value !== null;
116
121
 
117
122
  // When an element changes, the current ref callback should be called
118
123
  // with the new element and the previous one with `null`.
@@ -41,6 +41,7 @@ describe( 'useMergeRefs', () => {
41
41
  tagName: TagName = 'div',
42
42
  disable1,
43
43
  disable2,
44
+ unused,
44
45
  } ) {
45
46
  function refCallback1( value ) {
46
47
  refCallback1.history.push( value );
@@ -63,6 +64,10 @@ describe( 'useMergeRefs', () => {
63
64
  ! disable2 && ref2,
64
65
  ] );
65
66
 
67
+ if ( unused ) {
68
+ return <TagName ref={ ref1 } />;
69
+ }
70
+
66
71
  return <TagName ref={ mergedRefs } />;
67
72
  }
68
73
 
@@ -327,4 +332,43 @@ describe( 'useMergeRefs', () => {
327
332
  [ [], [ originalElement, null ] ],
328
333
  ] );
329
334
  } );
335
+
336
+ it( 'should allow the hook being unused', () => {
337
+ const rootElement = document.getElementById( 'root' );
338
+
339
+ ReactDOM.render( <MergedRefs unused />, rootElement );
340
+
341
+ const originalElement = rootElement.firstElementChild;
342
+
343
+ // Render 1: ref 1 should updated, ref 2 should not.
344
+ expect( renderCallback.history ).toEqual( [
345
+ [ [ originalElement ], [] ],
346
+ ] );
347
+
348
+ ReactDOM.render( <MergedRefs />, rootElement );
349
+
350
+ // Render 2: ref 2 should be updated as well.
351
+ expect( renderCallback.history ).toEqual( [
352
+ [ [ originalElement, null, originalElement ], [ originalElement ] ],
353
+ [ [], [] ],
354
+ ] );
355
+
356
+ ReactDOM.render( <MergedRefs unused />, rootElement );
357
+
358
+ // Render 3: ref 2 should be updated with null
359
+ expect( renderCallback.history ).toEqual( [
360
+ [
361
+ [
362
+ originalElement,
363
+ null,
364
+ originalElement,
365
+ null,
366
+ originalElement,
367
+ ],
368
+ [ originalElement, null ],
369
+ ],
370
+ [ [], [] ],
371
+ [ [], [] ],
372
+ ] );
373
+ } );
330
374
  } );
@@ -47,7 +47,11 @@ const useResizeObserver = () => {
47
47
  }, [] );
48
48
 
49
49
  const observer = (
50
- <View style={ StyleSheet.absoluteFill } onLayout={ onLayout } />
50
+ <View
51
+ testID="resize-observer"
52
+ style={ StyleSheet.absoluteFill }
53
+ onLayout={ onLayout }
54
+ />
51
55
  );
52
56
 
53
57
  return [ observer, measurements ];
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { create, act } from 'react-test-renderer';
4
+ import { render, fireEvent } from 'test/helpers';
5
5
  import { View } from 'react-native';
6
6
 
7
7
  /**
@@ -13,36 +13,32 @@ const TestComponent = ( { onLayout } ) => {
13
13
  const [ resizeObserver, sizes ] = useResizeObserver();
14
14
 
15
15
  return (
16
- <View sizes={ sizes } onLayout={ onLayout }>
16
+ <View testID="test-component" sizes={ sizes } onLayout={ onLayout }>
17
17
  { resizeObserver }
18
18
  </View>
19
19
  );
20
20
  };
21
21
 
22
- const renderWithOnLayout = ( component ) => {
23
- const testComponent = create( component );
24
-
25
- const mockNativeEvent = {
26
- nativeEvent: {
27
- layout: {
28
- width: 300,
29
- height: 500,
22
+ describe( 'useResizeObserver()', () => {
23
+ it( 'should return "{ width: 300, height: 500 }"', () => {
24
+ const mockNativeEvent = {
25
+ nativeEvent: {
26
+ layout: {
27
+ width: 300,
28
+ height: 500,
29
+ },
30
30
  },
31
- },
32
- };
33
-
34
- act( () => {
35
- testComponent.toJSON().children[ 0 ].props.onLayout( mockNativeEvent );
36
- } );
31
+ };
37
32
 
38
- return testComponent.toJSON();
39
- };
33
+ const { getByTestId } = render(
34
+ <TestComponent onLayout={ mockNativeEvent } />
35
+ );
40
36
 
41
- describe( 'useResizeObserver()', () => {
42
- it( 'should return "{ width: 300, height: 500 }"', () => {
43
- const component = renderWithOnLayout( <TestComponent /> );
37
+ const resizeObserver = getByTestId( 'resize-observer' );
38
+ fireEvent( resizeObserver, 'layout', mockNativeEvent );
44
39
 
45
- expect( component.props.sizes ).toMatchObject( {
40
+ const testComponent = getByTestId( 'test-component' );
41
+ expect( testComponent.props.sizes ).toMatchObject( {
46
42
  width: 300,
47
43
  height: 500,
48
44
  } );
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { create, act } from 'react-test-renderer';
4
+ import { render } from '@testing-library/react';
5
5
 
6
6
  /**
7
7
  * Internal dependencies
@@ -25,105 +25,105 @@ describe( 'useViewportMatch', () => {
25
25
  };
26
26
 
27
27
  it( 'should return true when the viewport matches', async () => {
28
- let root;
29
28
  useMediaQueryMock.mockReturnValue( true );
30
29
 
31
- await act( async () => {
32
- root = create( <TestComponent breakpoint="wide" operator="<" /> );
33
- } );
34
- expect( root.toJSON() ).toBe( 'useViewportMatch: true' );
30
+ const { container, rerender } = render(
31
+ <TestComponent breakpoint="wide" operator="<" />
32
+ );
35
33
 
36
- await act( async () => {
37
- root.update( <TestComponent breakpoint="medium" operator=">=" /> );
38
- } );
39
- expect( root.toJSON() ).toBe( 'useViewportMatch: true' );
34
+ expect( container ).toHaveTextContent( 'useViewportMatch: true' );
40
35
 
41
- await act( async () => {
42
- root.update( <TestComponent breakpoint="small" operator=">=" /> );
43
- } );
44
- expect( root.toJSON() ).toBe( 'useViewportMatch: true' );
36
+ rerender( <TestComponent breakpoint="medium" operator=">=" /> );
45
37
 
46
- expect( useMediaQueryMock.mock.calls ).toEqual( [
47
- [ '(max-width: 1280px)' ],
48
- [ '(min-width: 782px)' ],
49
- [ '(min-width: 600px)' ],
50
- ] );
38
+ expect( container ).toHaveTextContent( 'useViewportMatch: true' );
51
39
 
52
- root.unmount();
40
+ rerender( <TestComponent breakpoint="small" operator=">=" /> );
41
+
42
+ expect( container ).toHaveTextContent( 'useViewportMatch: true' );
43
+
44
+ expect( useMediaQueryMock ).toHaveBeenCalledTimes( 3 );
45
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith(
46
+ 1,
47
+ '(max-width: 1280px)'
48
+ );
49
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith(
50
+ 2,
51
+ '(min-width: 782px)'
52
+ );
53
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith(
54
+ 3,
55
+ '(min-width: 600px)'
56
+ );
53
57
  } );
54
58
 
55
59
  it( 'should return false when the viewport matches', async () => {
56
- let root;
57
60
  useMediaQueryMock.mockReturnValue( false );
58
61
 
59
- await act( async () => {
60
- root = create( <TestComponent breakpoint="huge" operator=">=" /> );
61
- } );
62
- expect( root.toJSON() ).toBe( 'useViewportMatch: false' );
62
+ const { container, rerender } = render(
63
+ <TestComponent breakpoint="huge" operator=">=" />
64
+ );
65
+
66
+ expect( container ).toHaveTextContent( 'useViewportMatch: false' );
63
67
 
64
- await act( async () => {
65
- root.update( <TestComponent breakpoint="large" operator="<" /> );
66
- } );
67
- expect( root.toJSON() ).toBe( 'useViewportMatch: false' );
68
+ rerender( <TestComponent breakpoint="large" operator="<" /> );
68
69
 
69
- await act( async () => {
70
- root.update( <TestComponent breakpoint="mobile" operator="<" /> );
71
- } );
72
- expect( root.toJSON() ).toBe( 'useViewportMatch: false' );
70
+ expect( container ).toHaveTextContent( 'useViewportMatch: false' );
73
71
 
74
- expect( useMediaQueryMock.mock.calls ).toEqual( [
75
- [ '(min-width: 1440px)' ],
76
- [ '(max-width: 960px)' ],
77
- [ '(max-width: 480px)' ],
78
- ] );
72
+ rerender( <TestComponent breakpoint="mobile" operator="<" /> );
79
73
 
80
- root.unmount();
74
+ expect( container ).toHaveTextContent( 'useViewportMatch: false' );
75
+
76
+ expect( useMediaQueryMock ).toHaveBeenCalledTimes( 3 );
77
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith(
78
+ 1,
79
+ '(min-width: 1440px)'
80
+ );
81
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith(
82
+ 2,
83
+ '(max-width: 960px)'
84
+ );
85
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith(
86
+ 3,
87
+ '(max-width: 480px)'
88
+ );
81
89
  } );
82
90
 
83
91
  it( 'should correctly simulate a value', async () => {
84
- let root;
85
92
  useMediaQueryMock.mockReturnValue( true );
86
93
 
87
94
  const innerElement = <TestComponent breakpoint="wide" operator=">=" />;
88
95
  const WidthProvider = useViewportMatch.__experimentalWidthProvider;
89
96
 
90
- await act( async () => {
91
- root = create(
92
- <WidthProvider value={ 300 }>{ innerElement }</WidthProvider>
93
- );
94
- } );
95
- expect( root.toJSON() ).toBe( 'useViewportMatch: false' );
96
-
97
- await act( async () => {
98
- root.update(
99
- <WidthProvider value={ 1200 }>{ innerElement }</WidthProvider>
100
- );
101
- } );
102
- expect( root.toJSON() ).toBe( 'useViewportMatch: false' );
103
-
104
- await act( async () => {
105
- root.update(
106
- <WidthProvider value={ 1300 }>{ innerElement }</WidthProvider>
107
- );
108
- } );
109
- expect( root.toJSON() ).toBe( 'useViewportMatch: true' );
110
-
111
- await act( async () => {
112
- root.update(
113
- <WidthProvider value={ 1300 }>
114
- <TestComponent breakpoint="wide" operator="<" />
115
- </WidthProvider>
116
- );
117
- } );
118
- expect( root.toJSON() ).toBe( 'useViewportMatch: false' );
119
-
120
- expect( useMediaQueryMock.mock.calls ).toEqual( [
121
- [ undefined ],
122
- [ undefined ],
123
- [ undefined ],
124
- [ undefined ],
125
- ] );
126
-
127
- root.unmount();
97
+ const { container, rerender } = render(
98
+ <WidthProvider value={ 300 }>{ innerElement }</WidthProvider>
99
+ );
100
+ expect( container ).toHaveTextContent( 'useViewportMatch: false' );
101
+
102
+ rerender(
103
+ <WidthProvider value={ 1200 }>{ innerElement }</WidthProvider>
104
+ );
105
+
106
+ expect( container ).toHaveTextContent( 'useViewportMatch: false' );
107
+
108
+ rerender(
109
+ <WidthProvider value={ 1300 }>{ innerElement }</WidthProvider>
110
+ );
111
+
112
+ expect( container ).toHaveTextContent( 'useViewportMatch: true' );
113
+
114
+ rerender(
115
+ <WidthProvider value={ 1300 }>
116
+ <TestComponent breakpoint="wide" operator="<" />
117
+ </WidthProvider>
118
+ );
119
+
120
+ expect( container ).toHaveTextContent( 'useViewportMatch: false' );
121
+
122
+ expect( useMediaQueryMock ).toHaveBeenCalledTimes( 4 );
123
+ // `useMediaQuery` is expected to receive `undefined` when simulating width.
124
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith( 1, undefined );
125
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith( 2, undefined );
126
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith( 3, undefined );
127
+ expect( useMediaQueryMock ).toHaveBeenNthCalledWith( 4, undefined );
128
128
  } );
129
129
  } );