@wordpress/data 7.3.0 → 7.4.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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { render, waitFor } from '@testing-library/react';
4
+ import { render, screen } from '@testing-library/react';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
@@ -109,8 +109,8 @@ describe( 'useSuspenseSelect', () => {
109
109
  </RegistryProvider>
110
110
  );
111
111
 
112
- const rendered = render( <App /> );
113
- await waitFor( () => rendered.getByLabelText( 'loaded' ) );
112
+ render( <App /> );
113
+ await screen.findByLabelText( 'loaded' );
114
114
 
115
115
  // Verify there were 3 attempts to render. Suspended twice because of
116
116
  // `getToken` and `getData` selectors not being resolved, and then finally
@@ -156,9 +156,9 @@ describe( 'useSuspenseSelect', () => {
156
156
  </RegistryProvider>
157
157
  );
158
158
 
159
- const rendered = render( <App /> );
160
- const label = await waitFor( () => rendered.getByLabelText( 'error' ) );
161
- expect( label.textContent ).toBe( 'resolution failed' );
159
+ render( <App /> );
160
+ const label = await screen.findByLabelText( 'error' );
161
+ expect( label ).toHaveTextContent( 'resolution failed' );
162
162
  expect( console ).toHaveErrored();
163
163
  } );
164
164
  } );
@@ -1,7 +1,13 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import TestRenderer, { act } from 'react-test-renderer';
4
+ import { render, screen } from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { memo } from '@wordpress/element';
5
11
 
6
12
  /**
7
13
  * Internal dependencies
@@ -10,224 +16,156 @@ import withDispatch from '../';
10
16
  import { createRegistry } from '../../../registry';
11
17
  import { RegistryProvider } from '../../registry-provider';
12
18
 
13
- describe( 'withDispatch', () => {
14
- let registry;
15
- beforeEach( () => {
16
- registry = createRegistry();
17
- } );
19
+ jest.useRealTimers();
18
20
 
19
- it( 'passes the relevant data to the component', () => {
20
- const store = registry.registerStore( 'counter', {
21
- reducer: ( state = 0, action ) => {
22
- if ( action.type === 'increment' ) {
23
- return state + action.count;
24
- }
25
- return state;
26
- },
27
- actions: {
28
- increment: ( count = 1 ) => ( { type: 'increment', count } ),
29
- },
30
- } );
31
-
32
- const Component = withDispatch( ( _dispatch, ownProps ) => {
21
+ describe( 'withDispatch', () => {
22
+ const storeOptions = {
23
+ reducer: ( state = 0, action ) => {
24
+ if ( action.type === 'inc' ) {
25
+ return state + action.count;
26
+ }
27
+ return state;
28
+ },
29
+ actions: {
30
+ increment: ( count = 1 ) => ( { type: 'inc', count } ),
31
+ },
32
+ selectors: {
33
+ getCount: ( state ) => state,
34
+ },
35
+ };
36
+
37
+ it( 'passes the relevant data to the component', async () => {
38
+ const user = userEvent.setup();
39
+ const registry = createRegistry();
40
+ registry.registerStore( 'counter', storeOptions );
41
+
42
+ const ButtonSpy = jest.fn( ( { onClick } ) => (
43
+ <button onClick={ onClick } />
44
+ ) );
45
+ const Button = memo( ButtonSpy );
46
+
47
+ const Component = withDispatch( ( dispatch, ownProps ) => {
33
48
  const { count } = ownProps;
34
49
 
35
50
  return {
36
51
  increment: () => {
37
52
  const actionReturnedFromDispatch = Promise.resolve(
38
- _dispatch( 'counter' ).increment( count )
53
+ dispatch( 'counter' ).increment( count )
39
54
  );
40
55
  return expect(
41
56
  actionReturnedFromDispatch
42
57
  ).resolves.toEqual( {
43
- type: 'increment',
58
+ type: 'inc',
44
59
  count,
45
60
  } );
46
61
  },
47
62
  };
48
- } )( ( props ) => <button onClick={ props.increment } /> );
49
-
50
- let testRenderer;
51
- act( () => {
52
- testRenderer = TestRenderer.create(
53
- <RegistryProvider value={ registry }>
54
- <Component count={ 0 } />
55
- </RegistryProvider>
56
- );
57
- } );
58
- const testInstance = testRenderer.root;
63
+ } )( ( props ) => <Button onClick={ props.increment } /> );
59
64
 
60
- const incrementBeforeSetProps =
61
- testInstance.findByType( 'button' ).props.onClick;
65
+ const { rerender } = render(
66
+ <RegistryProvider value={ registry }>
67
+ <Component count={ 0 } />
68
+ </RegistryProvider>
69
+ );
62
70
 
63
71
  // Verify that dispatch respects props at the time of being invoked by
64
72
  // changing props after the initial mount.
65
- act( () => {
66
- testRenderer.update(
67
- <RegistryProvider value={ registry }>
68
- <Component count={ 2 } />
69
- </RegistryProvider>
70
- );
71
- } );
72
-
73
- // Function value reference should not have changed in props update.
74
- expect( testInstance.findByType( 'button' ).props.onClick ).toBe(
75
- incrementBeforeSetProps
73
+ rerender(
74
+ <RegistryProvider value={ registry }>
75
+ <Component count={ 2 } />
76
+ </RegistryProvider>
76
77
  );
77
78
 
78
- act( () => {
79
- incrementBeforeSetProps();
80
- } );
79
+ // Function value reference should not have changed in props update.
80
+ // The spy method is only called during inital render.
81
+ expect( ButtonSpy ).toBeCalledTimes( 1 );
81
82
 
82
- expect( store.getState() ).toBe( 2 );
83
+ await user.click( screen.getByRole( 'button' ) );
84
+ expect( registry.select( 'counter' ).getCount() ).toBe( 2 );
83
85
  } );
84
86
 
85
- it( 'calls dispatch on the correct registry if updated', () => {
86
- const reducer = ( state = null ) => state;
87
- const noop = () => ( { type: '__INERT__' } );
88
- const firstRegistryAction = jest.fn().mockImplementation( noop );
89
- const secondRegistryAction = jest.fn().mockImplementation( noop );
87
+ it( 'calls dispatch on the correct registry if updated', async () => {
88
+ const user = userEvent.setup();
90
89
 
91
- const firstRegistry = registry;
92
- firstRegistry.registerStore( 'demo', {
93
- reducer,
94
- actions: {
95
- noop: firstRegistryAction,
96
- },
97
- } );
90
+ const firstRegistry = createRegistry();
91
+ firstRegistry.registerStore( 'demo', storeOptions );
98
92
 
99
- const Component = withDispatch( ( _dispatch ) => {
100
- const noopByReference = _dispatch( 'demo' ).noop;
93
+ const secondRegistry = createRegistry();
94
+ secondRegistry.registerStore( 'demo', storeOptions );
101
95
 
96
+ const Component = withDispatch( ( dispatch ) => {
102
97
  return {
103
- noop() {
104
- _dispatch( 'demo' ).noop();
105
- noopByReference();
98
+ increment() {
99
+ dispatch( 'demo' ).increment();
106
100
  },
107
101
  };
108
- } )( ( props ) => <button onClick={ props.noop } /> );
109
-
110
- let testRenderer;
111
- act( () => {
112
- testRenderer = TestRenderer.create(
113
- <RegistryProvider value={ firstRegistry }>
114
- <Component />
115
- </RegistryProvider>
116
- );
117
- } );
118
- const testInstance = testRenderer.root;
119
-
120
- act( () => {
121
- testInstance.findByType( 'button' ).props.onClick();
122
- } );
123
- expect( firstRegistryAction ).toHaveBeenCalledTimes( 2 );
124
- expect( secondRegistryAction ).toHaveBeenCalledTimes( 0 );
102
+ } )( ( props ) => <button onClick={ props.increment } /> );
125
103
 
126
- const secondRegistry = createRegistry();
127
- secondRegistry.registerStore( 'demo', {
128
- reducer,
129
- actions: {
130
- noop: secondRegistryAction,
131
- },
132
- } );
133
-
134
- act( () => {
135
- testRenderer.update(
136
- <RegistryProvider value={ secondRegistry }>
137
- <Component />
138
- </RegistryProvider>
139
- );
140
- } );
141
- act( () => {
142
- testInstance.findByType( 'button' ).props.onClick();
143
- } );
144
- expect( firstRegistryAction ).toHaveBeenCalledTimes( 2 );
145
- expect( secondRegistryAction ).toHaveBeenCalledTimes( 2 );
104
+ const { rerender } = render(
105
+ <RegistryProvider value={ firstRegistry }>
106
+ <Component />
107
+ </RegistryProvider>
108
+ );
109
+
110
+ await user.click( screen.getByRole( 'button' ) );
111
+ expect( firstRegistry.select( 'demo' ).getCount() ).toBe( 1 );
112
+ expect( secondRegistry.select( 'demo' ).getCount() ).toBe( 0 );
113
+
114
+ rerender(
115
+ <RegistryProvider value={ secondRegistry }>
116
+ <Component />
117
+ </RegistryProvider>
118
+ );
119
+ await user.click( screen.getByRole( 'button' ) );
120
+ expect( firstRegistry.select( 'demo' ).getCount() ).toBe( 1 );
121
+ expect( secondRegistry.select( 'demo' ).getCount() ).toBe( 1 );
146
122
  } );
147
123
 
148
- it(
149
- 'always calls select with the latest state in the handler passed to ' +
150
- 'the component',
151
- () => {
152
- const store = registry.registerStore( 'counter', {
153
- reducer: ( state = 0, action ) => {
154
- if ( action.type === 'update' ) {
155
- return action.count;
156
- }
157
- return state;
158
- },
159
- actions: {
160
- update: ( count ) => ( { type: 'update', count } ),
161
- },
162
- selectors: {
163
- getCount: ( state ) => state,
124
+ it( 'always calls select with the latest state in the handler passed to the component', async () => {
125
+ const user = userEvent.setup();
126
+ const registry = createRegistry();
127
+ registry.registerStore( 'counter', storeOptions );
128
+
129
+ const Component = withDispatch( ( dispatch, ownProps, { select } ) => {
130
+ return {
131
+ update: () => {
132
+ const currentCount = select( 'counter' ).getCount();
133
+ dispatch( 'counter' ).increment( currentCount + 1 );
164
134
  },
165
- } );
166
-
167
- const Component = withDispatch(
168
- ( _dispatch, ownProps, { select: _select } ) => {
169
- const outerCount = _select( 'counter' ).getCount();
170
- return {
171
- update: () => {
172
- const innerCount = _select( 'counter' ).getCount();
173
- expect( innerCount ).toBe( outerCount );
174
- const actionReturnedFromDispatch = Promise.resolve(
175
- _dispatch( 'counter' ).update( innerCount + 1 )
176
- );
177
- return expect(
178
- actionReturnedFromDispatch
179
- ).resolves.toEqual( {
180
- type: 'update',
181
- count: innerCount + 1,
182
- } );
183
- },
184
- };
185
- }
186
- )( ( props ) => <button onClick={ props.update } /> );
187
-
188
- let testRenderer;
189
- act( () => {
190
- testRenderer = TestRenderer.create(
191
- <RegistryProvider value={ registry }>
192
- <Component />
193
- </RegistryProvider>
194
- );
195
- } );
196
-
197
- const counterUpdateHandler =
198
- testRenderer.root.findByType( 'button' ).props.onClick;
199
-
200
- act( () => {
201
- counterUpdateHandler();
202
- } );
203
- expect( store.getState() ).toBe( 1 );
204
-
205
- act( () => {
206
- counterUpdateHandler();
207
- } );
208
- expect( store.getState() ).toBe( 2 );
209
-
210
- act( () => {
211
- counterUpdateHandler();
212
- } );
213
- expect( store.getState() ).toBe( 3 );
214
- }
215
- );
135
+ };
136
+ } )( ( props ) => <button onClick={ props.update } /> );
137
+
138
+ render(
139
+ <RegistryProvider value={ registry }>
140
+ <Component />
141
+ </RegistryProvider>
142
+ );
143
+
144
+ await user.click( screen.getByRole( 'button' ) );
145
+ // expectedValue = 2 * currentValue + 1.
146
+ expect( registry.select( 'counter' ).getCount() ).toBe( 1 );
147
+
148
+ await user.click( screen.getByRole( 'button' ) );
149
+ expect( registry.select( 'counter' ).getCount() ).toBe( 3 );
150
+
151
+ await user.click( screen.getByRole( 'button' ) );
152
+ expect( registry.select( 'counter' ).getCount() ).toBe( 7 );
153
+ } );
216
154
 
217
155
  it( 'warns when mapDispatchToProps returns non-function property', () => {
156
+ const registry = createRegistry();
218
157
  const Component = withDispatch( () => {
219
158
  return {
220
159
  count: 3,
221
160
  };
222
161
  } )( () => null );
223
162
 
224
- act( () => {
225
- TestRenderer.create(
226
- <RegistryProvider value={ registry }>
227
- <Component />
228
- </RegistryProvider>
229
- );
230
- } );
163
+ render(
164
+ <RegistryProvider value={ registry }>
165
+ <Component />
166
+ </RegistryProvider>
167
+ );
168
+
231
169
  expect( console ).toHaveWarnedWith(
232
170
  'Property count returned from dispatchMap in useDispatchWithMap must be a function.'
233
171
  );