@webkrafters/react-observable-context 5.0.0-rc.2 → 5.0.0-rc.3

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,1298 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const react_1 = __importDefault(require("react"));
7
- const react_2 = require("@testing-library/react");
8
- require("@testing-library/jest-dom");
9
- const _1 = require(".");
10
- const normal_1 = require("./test-apps/normal");
11
- beforeAll(() => {
12
- jest.spyOn(console, 'log').mockImplementation(() => { });
13
- jest.spyOn(console, 'error').mockImplementation(() => { });
14
- });
15
- afterAll(() => jest.resetAllMocks());
16
- afterEach(react_2.cleanup);
17
- const tranformRenderCount = (renderCount, baseRenderCount = {}) => {
18
- const netCount = {};
19
- for (const k of new Set([
20
- ...Object.keys(renderCount.current),
21
- ...Object.keys(baseRenderCount)
22
- ])) {
23
- netCount[k] = (renderCount.current[k]?.value || 0) - (baseRenderCount[k] || 0);
24
- }
25
- return netCount;
26
- };
27
- describe('ReactObservableContext', () => {
28
- test('throws usage error on attempts to use context store outside of the Provider component tree', () => {
29
- // note: TallyDisplay component utilizes the ReactObservableContext store
30
- expect(() => (0, react_2.render)(react_1.default.createElement(normal_1.TallyDisplay, null))).toThrow(_1.UsageError);
31
- });
32
- // describe( 'store updates from within the Provider tree', () => {
33
- // describe( 'updates only subscribed components', () => {
34
- // describe( 'using connected store subscribers', () => {
35
- // test( 'scenario 1', async () => {
36
- // const { renderCount } = perf( React );
37
- // render( <AppWithConnectedChildren /> );
38
- // let baseRenderCount;
39
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
40
- // fireEvent.change( screen.getByLabelText( 'New Price:' ), { target: { value: '123' } } );
41
- // fireEvent.click( screen.getByRole( 'button', { name: 'update price' } ) );
42
- // await wait(() => {
43
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
44
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for price data
45
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for price data
46
- // expect( netCount.PriceSticker ).toBe( 1 );
47
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no use for price data
48
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for price data
49
- // expect( netCount.TallyDisplay ).toBe( 1 );
50
- // });
51
- // cleanupPerfTest();
52
- // } );
53
- // test( 'scenario 2', async () => {
54
- // const { renderCount } = perf( React );
55
- // render( <AppWithConnectedChildren /> );
56
- // let baseRenderCount;
57
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
58
- // fireEvent.change( screen.getByLabelText( 'New Color:' ), { target: { value: 'Navy' } } );
59
- // fireEvent.click( screen.getByRole( 'button', { name: 'update color' } ) );
60
- // await wait(() => {
61
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
62
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product color data
63
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product color data
64
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product color data
65
- // expect( netCount.ProductDescription ).toBe( 1 );
66
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product color data
67
- // expect( netCount.TallyDisplay ).toBe( 1 );
68
- // });
69
- // cleanupPerfTest();
70
- // } );
71
- // test( 'scenario 3', async () => {
72
- // const { renderCount } = perf( React );
73
- // render( <AppWithConnectedChildren /> );
74
- // let baseRenderCount;
75
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
76
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
77
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
78
- // await wait(() => {
79
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
80
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product type data
81
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
82
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
83
- // expect( netCount.ProductDescription ).toBe( 1 );
84
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product type data
85
- // expect( netCount.TallyDisplay ).toBe( 1 );
86
- // });
87
- // cleanupPerfTest();
88
- // } );
89
- // test( 'does not render subscribed components for resubmitted changes', async () => {
90
- // const { renderCount } = perf( React );
91
- // render( <AppWithConnectedChildren /> );
92
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
93
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
94
- // let baseRenderCount;
95
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
96
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
97
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
98
- // await wait(() => {
99
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
100
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no new product type data
101
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no new product type data
102
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no new product type data
103
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no new product type data
104
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no new product type data
105
- // expect( netCount.TallyDisplay ).toBe( 0 ); // unaffected: no new product type data
106
- // });
107
- // cleanupPerfTest();
108
- // } );
109
- // } );
110
- // describe( 'using pure-component store subscribers', () => {
111
- // test( 'scenario 1', async () => {
112
- // const { renderCount } = perf( React );
113
- // render( <AppWithPureChildren /> );
114
- // let baseRenderCount;
115
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
116
- // fireEvent.change( screen.getByLabelText( 'New Price:' ), { target: { value: '123' } } );
117
- // fireEvent.click( screen.getByRole( 'button', { name: 'update price' } ) );
118
- // await wait(() => {
119
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
120
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for price data
121
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for price data
122
- // expect( netCount.PriceSticker ).toBe( 1 );
123
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no use for price data
124
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for price data
125
- // expect( netCount.TallyDisplay ).toBe( 1 );
126
- // });
127
- // cleanupPerfTest();
128
- // } );
129
- // test( 'scenario 2', async () => {
130
- // const { renderCount } = perf( React );
131
- // render( <AppWithPureChildren /> );
132
- // let baseRenderCount;
133
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
134
- // fireEvent.change( screen.getByLabelText( 'New Color:' ), { target: { value: 'Navy' } } );
135
- // fireEvent.click( screen.getByRole( 'button', { name: 'update color' } ) );
136
- // await wait(() => {
137
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
138
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product color data
139
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product color data
140
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product color data
141
- // expect( netCount.ProductDescription ).toBe( 1 );
142
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product color data
143
- // expect( netCount.TallyDisplay ).toBe( 1 );
144
- // });
145
- // cleanupPerfTest();
146
- // } );
147
- // test( 'scenario 3', async () => {
148
- // const { renderCount } = perf( React );
149
- // render( <AppWithPureChildren /> );
150
- // let baseRenderCount;
151
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
152
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
153
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
154
- // await wait(() => {
155
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
156
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product type data
157
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
158
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
159
- // expect( netCount.ProductDescription ).toBe( 1 );
160
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product type data
161
- // expect( netCount.TallyDisplay ).toBe( 1 );
162
- // });
163
- // cleanupPerfTest();
164
- // } );
165
- // test( 'does not render subscribed components for resubmitted changes', async () => {
166
- // const { renderCount } = perf( React );
167
- // render( <AppWithPureChildren /> );
168
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
169
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
170
- // let baseRenderCount;
171
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
172
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
173
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
174
- // await wait(() => {
175
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
176
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 );
177
- // expect( netCount.Editor ).toBe( 0 );
178
- // expect( netCount.PriceSticker ).toBe( 0 );
179
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no new product type data
180
- // expect( netCount.Reset ).toBe( 0 );
181
- // expect( netCount.TallyDisplay ).toBe( 0 ); // unaffected: no new product type data
182
- // });
183
- // cleanupPerfTest();
184
- // } );
185
- // } );
186
- // describe( 'using non pure-component store subscribers', () => {
187
- // test( 'scenario 1', async () => {
188
- // const { renderCount } = perf( React );
189
- // render( <AppNormal /> );
190
- // let baseRenderCount;
191
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
192
- // fireEvent.change( screen.getByLabelText( 'New Price:' ), { target: { value: '123' } } );
193
- // fireEvent.click( screen.getByRole( 'button', { name: 'update price' } ) );
194
- // await wait(() => {
195
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
196
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
197
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product price data
198
- // expect( netCount.PriceSticker ).toBe( 1 );
199
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no use for product price data
200
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
201
- // expect( netCount.TallyDisplay ).toBe( 1 );
202
- // });
203
- // cleanupPerfTest();
204
- // } );
205
- // test( 'scenario 2', async () => {
206
- // const { renderCount } = perf( React );
207
- // render( <AppNormal /> );
208
- // let baseRenderCount;
209
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
210
- // fireEvent.change( screen.getByLabelText( 'New Color:' ), { target: { value: 'Navy' } } );
211
- // fireEvent.click( screen.getByRole( 'button', { name: 'update color' } ) );
212
- // await wait(() => {
213
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
214
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
215
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product price data
216
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product price data
217
- // expect( netCount.ProductDescription ).toBe( 1 );
218
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
219
- // expect( netCount.TallyDisplay ).toBe( 1 );
220
- // });
221
- // cleanupPerfTest();
222
- // } );
223
- // test( 'scenario 3', async () => {
224
- // const { renderCount } = perf( React );
225
- // render( <AppNormal /> );
226
- // let baseRenderCount;
227
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
228
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
229
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
230
- // await wait(() => {
231
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
232
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
233
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
234
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
235
- // expect( netCount.ProductDescription ).toBe( 1 );
236
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
237
- // expect( netCount.TallyDisplay ).toBe( 1 );
238
- // });
239
- // cleanupPerfTest();
240
- // } );
241
- // test( 'does not render resubmitted changes', async () => {
242
- // const { renderCount } = perf( React );
243
- // render( <AppNormal /> );
244
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
245
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
246
- // let baseRenderCount;
247
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
248
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
249
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
250
- // await wait(() => {
251
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
252
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 );
253
- // expect( netCount.Editor ).toBe( 0 );
254
- // expect( netCount.PriceSticker ).toBe( 0 );
255
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no new product type data
256
- // expect( netCount.Reset ).toBe( 0 );
257
- // expect( netCount.TallyDisplay ).toBe( 0 ); // unaffected: no new product type data
258
- // });
259
- // cleanupPerfTest();
260
- // } );
261
- // } );
262
- // } );
263
- // } );
264
- // describe( 'store updates from outside the Provider tree', () => {
265
- // describe( 'with connected component children', () => {
266
- // test( 'only re-renders Provider children affected by the Provider parent prop change', async () => {
267
- // const { renderCount } = perf( React );
268
- // render( <AppWithConnectedChildren /> );
269
- // let baseRenderCount;
270
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ); });
271
- // fireEvent.keyUp( screen.getByLabelText( 'Type:' ), { target: { value: 'A' } } );
272
- // await wait(() => {
273
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
274
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product type data
275
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
276
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
277
- // expect( netCount.ProductDescription ).toBe( 1 );
278
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product type data
279
- // expect( netCount.TallyDisplay ).toBe( 1 );
280
- // });
281
- // cleanupPerfTest();
282
- // } );
283
- // test( 'only re-renders parts of the Provider tree directly affected by the Provider parent state update', async () => {
284
- // const { renderCount } = perf( React );
285
- // render( <AppWithConnectedChildren /> );
286
- // let baseRenderCount;
287
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
288
- // fireEvent.keyUp( screen.getByLabelText( '$', {
289
- // key: '5',
290
- // code: 'Key5'
291
- // } as SelectorMatcherOptions ) );
292
- // await wait(() => {
293
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
294
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product price data
295
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product price data
296
- // expect( netCount.PriceSticker ).toBe( 1 );
297
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no use for product price data
298
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product price data
299
- // expect( netCount.TallyDisplay ).toBe( 1 );
300
- // });
301
- // cleanupPerfTest();
302
- // } );
303
- // } );
304
- // describe( 'with pure-component children', () => {
305
- // test( 'only re-renders Provider children affected by the Provider parent prop change', async () => {
306
- // const { renderCount } = perf( React );
307
- // render( <AppWithPureChildren /> );
308
- // let baseRenderCount;
309
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ); });
310
- // fireEvent.keyUp( screen.getByLabelText( 'Type:' ), { target: { value: 'A' } } );
311
- // await wait(() => {
312
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
313
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product type data
314
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
315
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
316
- // expect( netCount.ProductDescription ).toBe( 1 );
317
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product type data
318
- // expect( netCount.TallyDisplay ).toBe( 1 );
319
- // });
320
- // cleanupPerfTest();
321
- // } );
322
- // test( 'only re-renders parts of the Provider tree directly affected by the Provider parent state update', async () => {
323
- // const { renderCount } = perf( React );
324
- // render( <AppWithPureChildren /> );
325
- // let baseRenderCount;
326
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ); });
327
- // fireEvent.keyUp( screen.getByLabelText( '$', { key: '5', code: 'Key5' } as SelectorMatcherOptions ) );
328
- // await wait(() => {
329
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
330
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product price data
331
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product price data
332
- // expect( netCount.PriceSticker ).toBe( 1 );
333
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no use for product price data
334
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product price data
335
- // expect( netCount.TallyDisplay ).toBe( 1 );
336
- // });
337
- // cleanupPerfTest();
338
- // } );
339
- // } );
340
- // describe( 'with non pure-component children ', () => {
341
- // test( 'only re-renders Provider children affected by the Provider parent prop change', async () => {
342
- // const { renderCount } = perf( React );
343
- // render( <AppNormal /> );
344
- // let baseRenderCount;
345
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ); });
346
- // fireEvent.keyUp( screen.getByLabelText( 'Type:' ), { target: { value: 'A' } } );
347
- // await wait(() => {
348
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
349
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
350
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
351
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
352
- // expect( netCount.ProductDescription ).toBe( 1 );
353
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
354
- // expect( netCount.TallyDisplay ).toBe( 1 );
355
- // });
356
- // cleanupPerfTest();
357
- // } );
358
- // test( 'oonly re-renders parts of the Provider tree directly affected by the Provider parent state update', async () => {
359
- // const { renderCount } = perf( React );
360
- // render( <AppNormal /> );
361
- // let baseRenderCount;
362
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ); });
363
- // fireEvent.keyUp( screen.getByLabelText( '$', { key: '5', code: 'Key5' } as SelectorMatcherOptions ) );
364
- // await wait(() => {
365
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;;
366
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
367
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product price data
368
- // expect( netCount.PriceSticker ).toBe( 1 );
369
- // expect( netCount.ProductDescription ).toBe( 0 ); // unaffected: no use for product price data
370
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
371
- // expect( netCount.TallyDisplay ).toBe( 1 );
372
- // });
373
- // cleanupPerfTest();
374
- // } );
375
- // } );
376
- // } );
377
- // describe( 'prehooks', () => {
378
- // describe( 'resetState prehook', () => {
379
- // describe( 'when `resetState` prehook does not exist on the context', () => {
380
- // test( 'completes `store.resetState` method call', async () => {
381
- // const { renderCount } = perf( React );
382
- // const prehooks = {};
383
- // render( <Product prehooks={ prehooks } type="Computer" /> );
384
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
385
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
386
- // let baseRenderCount;
387
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
388
- // fireEvent.click( screen.getByRole( 'button', { name: 'reset context' } ) );
389
- // await wait(() => {
390
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
391
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
392
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
393
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
394
- // expect( netCount.ProductDescription ).toBe( 1 ); // DULY UPDATED WITH NEW STATE RESET
395
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
396
- // expect( netCount.TallyDisplay ).toBe( 1 ); // DULY UPDATED WITH NEW STATE RESET
397
- // });
398
- // cleanupPerfTest();
399
- // } );
400
- // } );
401
- // describe( 'when `resetState` prehook exists on the context', () => {
402
- // test( 'is called by the `store.resetState` method', async () => {
403
- // const prehooks = Object.freeze({ resetState: jest.fn().mockReturnValue( false ) });
404
- // render( <Product prehooks={ prehooks } type="Computer" /> );
405
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
406
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
407
- // fireEvent.change( screen.getByLabelText( 'New Color:' ), { target: { value: 'Teal' } } );
408
- // fireEvent.click( screen.getByRole( 'button', { name: 'update color' } ) );
409
- // prehooks.resetState.mockClear();
410
- // fireEvent.click( screen.getByRole( 'button', { name: 'reset context' } ) );
411
- // expect( prehooks.resetState ).toHaveBeenCalledTimes( 1 );
412
- // expect( prehooks.resetState ).toHaveBeenCalledWith({
413
- // [ REPLACE_TAG ]: {
414
- // // data slices from original state to reset current state slices
415
- // color: 'Burgundy',
416
- // customer: {
417
- // name: { first: null, last: null },
418
- // phone: null
419
- // },
420
- // price: 22.5,
421
- // type: 'Computer'
422
- // }
423
- // }, {
424
- // // current: context state value after the `update type` & `update color` button clicks
425
- // current: {
426
- // color: 'Teal',
427
- // customer: {
428
- // name: { first: null, last: null },
429
- // phone: null
430
- // },
431
- // price: 22.5,
432
- // type: 'Bag'
433
- // },
434
- // // original: obtained from the './normal' Product >> Provider value prop
435
- // original: {
436
- // color: 'Burgundy',
437
- // customer: {
438
- // name: { first: null, last: null },
439
- // phone: null
440
- // },
441
- // price: 22.5,
442
- // type: 'Computer'
443
- // }
444
- // });
445
- // } );
446
- // test( 'completes `store.setState` method call if `setState` prehook returns TRUTHY', async () => {
447
- // const { renderCount } = perf( React );
448
- // const prehooks = Object.freeze({ resetState: jest.fn().mockReturnValue( true ) });
449
- // render( <Product prehooks={ prehooks } type="Computer" /> );
450
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
451
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
452
- // let baseRenderCount;
453
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
454
- // fireEvent.click( screen.getByRole( 'button', { name: 'reset context' } ) );
455
- // await wait(() => {
456
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;;
457
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
458
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
459
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
460
- // expect( netCount.ProductDescription ).toBe( 1 ); // DULY UPDATED WITH NEW STATE RESET
461
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
462
- // expect( netCount.TallyDisplay ).toBe( 1 ); // DULY UPDATED WITH NEW STATE RESET
463
- // });
464
- // cleanupPerfTest();
465
- // } );
466
- // test( 'aborts `store.setState` method call if `setState` prehook returns FALSY', async () => {
467
- // const { renderCount } = perf( React );
468
- // const prehooks = Object.freeze({ resetState: jest.fn().mockReturnValue( false ) });
469
- // render( <Product prehooks={ prehooks } type="Computer" /> );
470
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
471
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
472
- // let baseRenderCount;
473
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
474
- // fireEvent.click( screen.getByRole( 'button', { name: 'reset context' } ) );
475
- // await wait(() => {
476
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
477
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product type data
478
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
479
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
480
- // expect( netCount.ProductDescription ).toBe( 0 ); // NORMAL UPDATE DUE CANCELED: RESET STATE ABORTED
481
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product type data
482
- // expect( netCount.TallyDisplay ).toBe( 0 ); // NORMAL UPDATE DUE CANCELED: RESET STATE ABORTED
483
- // });
484
- // cleanupPerfTest();
485
- // } );
486
- // } );
487
- // } );
488
- // describe( 'setState prehook', () => {
489
- // describe( 'when `setState` prehook does not exist on the context', () => {
490
- // test( 'completes `store.setState` method call', async () => {
491
- // const { renderCount } = perf( React );
492
- // const prehooks = Object.freeze( expect.any( Object ) );
493
- // render( <Product prehooks={ prehooks } type="Computer" /> );
494
- // let baseRenderCount;
495
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
496
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
497
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
498
- // await wait(() => {
499
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
500
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
501
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
502
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
503
- // expect( netCount.ProductDescription ).toBe( 1 ); // DULY UPDATED WITH NEW STATE CHANGE
504
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
505
- // expect( netCount.TallyDisplay ).toBe( 1 ); // DULY UPDATED WITH NEW STATE CHANGE
506
- // });
507
- // cleanupPerfTest();
508
- // } );
509
- // } );
510
- // describe( 'when `setState` prehook exists on the context', () => {
511
- // test( 'is called by the `store.setState` method', async () => {
512
- // const prehooks = Object.freeze({ setState: jest.fn().mockReturnValue( false ) });
513
- // render( <Product prehooks={ prehooks } type="Computer" /> );
514
- // prehooks.setState.mockClear();
515
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
516
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
517
- // expect( prehooks.setState ).toHaveBeenCalledTimes( 1 );
518
- // expect( prehooks.setState ).toHaveBeenCalledWith({ type: 'Bag' });
519
- // } );
520
- // test( 'completes `store.setState` method call if `setState` prehook returns TRUTHY', async () => {
521
- // const { renderCount } = perf( React );
522
- // const prehooks = Object.freeze({ setState: jest.fn().mockReturnValue( true ) });
523
- // render( <Product prehooks={ prehooks } type="Computer" /> );
524
- // let baseRenderCount;
525
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
526
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
527
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
528
- // await wait(() => {
529
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
530
- // expect( netCount.CustomerPhoneDisplay ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
531
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
532
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
533
- // expect( netCount.ProductDescription ).toBe( 1 ); // DULY UPDATED WITH NEW STATE CHANGE
534
- // expect( netCount.Reset ).toBe( 1 ); // UPDATED BY REACT PROPAGATION (b/c no memoization)
535
- // expect( netCount.TallyDisplay ).toBe( 1 ); // DULY UPDATED WITH NEW STATE CHANGE
536
- // });
537
- // cleanupPerfTest();
538
- // } );
539
- // test( 'aborts `store.setState` method call if `setState` prehook returns FALSY', async () => {
540
- // const { renderCount } = perf( React );
541
- // const prehooks = Object.freeze({ setState: jest.fn().mockReturnValue( false ) });
542
- // render( <Product prehooks={ prehooks } type="Computer" /> );
543
- // let baseRenderCount;
544
- // await wait(() => { baseRenderCount = tranformRenderCount( renderCount ) });
545
- // fireEvent.change( screen.getByLabelText( 'New Type:' ), { target: { value: 'Bag' } } );
546
- // fireEvent.click( screen.getByRole( 'button', { name: 'update type' } ) );
547
- // await wait(() => {
548
- // const netCount = tranformRenderCount( renderCount, baseRenderCount ) as any;
549
- // expect( netCount.CustomerPhoneDisplay ).toBe( 0 ); // unaffected: no use for product type data
550
- // expect( netCount.Editor ).toBe( 0 ); // unaffected: no use for product type data
551
- // expect( netCount.PriceSticker ).toBe( 0 ); // unaffected: no use for product type data
552
- // expect( netCount.ProductDescription ).toBe( 0 ); // NORMAL UPDATE DUE CANCELED: SET STATE ABORTED
553
- // expect( netCount.Reset ).toBe( 0 ); // unaffected: no use for product type data
554
- // expect( netCount.TallyDisplay ).toBe( 0 ); // NORMAL UPDATE DUE CANCELED: SET STATE ABORTED
555
- // });
556
- // cleanupPerfTest();
557
- // } );
558
- // } );
559
- // } );
560
- // } );
561
- // describe( 'API', () => {
562
- // describe( 'connect(...)', () => {
563
- // let connector, selectorMap;
564
- // let ConnectedComponent1, ConnectedComponent2, ConnectedRefForwardingComponent, ConnectedMemoizedComponent;
565
- // let compOneProps, compTwoProps, refForwardingCompProps, memoCompProps;
566
- // beforeAll(() => {
567
- // selectorMap = { box: 'items.1.name', all: FULL_STATE_SELECTOR };
568
- // connector = connect( ObservableContext, selectorMap );
569
- // ConnectedComponent1 = connector( props => { compOneProps = props; return null } );
570
- // ConnectedComponent2 = connector( props => { compTwoProps = props; return null } );
571
- // const RefForwardingComponent = React.forwardRef(( props, ref ) => { refForwardingCompProps = props; return null });
572
- // RefForwardingComponent.displayName = 'Connect.RefForwardingComponent';
573
- // ConnectedRefForwardingComponent = connector( RefForwardingComponent );
574
- // const MemoizedComponent = React.memo( props => { memoCompProps = props; return null });
575
- // MemoizedComponent.displayName = 'Connect.MemoizedComponent';
576
- // ConnectedMemoizedComponent = connector( MemoizedComponent );
577
- // });
578
- // test( 'returns a function', () => expect( connector ).toBeInstanceOf( Function ) );
579
- // describe( 'returned function\'s return value', () => {
580
- // let state : {items: Array<{name: string}>};
581
- // beforeAll(() => {
582
- // state = {
583
- // items: [
584
- // { name: 'box_0' },
585
- // { name: 'box_1' },
586
- // { name: 'box_2' },
587
- // { name: 'box_3' }
588
- // ]
589
- // };
590
- // const Ui = () => (
591
- // <article>
592
- // <header>Just a Nested Content Tester</header>
593
- // <main>
594
- // <ConnectedComponent1 />
595
- // <ConnectedComponent2 />
596
- // <ConnectedRefForwardingComponent />
597
- // <ConnectedMemoizedComponent />
598
- // </main>
599
- // <footer>The End</footer>
600
- // </article>
601
- // );
602
- // render(
603
- // <ObservableContext.Provider value={ state }>
604
- // <Ui />
605
- // </ObservableContext.Provider>
606
- // );
607
- // });
608
- // test( 'is always a memoized component', () => {
609
- // expect( 'compare' in ConnectedComponent1 ).toBe( true );
610
- // expect( 'compare' in ConnectedComponent2 ).toBe( true );
611
- // expect( 'compare' in ConnectedRefForwardingComponent ).toBe( true );
612
- // expect( 'compare' in ConnectedMemoizedComponent ).toBe( true );
613
- // } );
614
- // test( 'is always interested in the same context state data', () => {
615
- // expect( compOneProps.data ).toStrictEqual( compTwoProps.data );
616
- // expect( compOneProps.data ).toStrictEqual( refForwardingCompProps.data );
617
- // expect( compOneProps.data ).toStrictEqual( memoCompProps.data );
618
- // } );
619
- // test( 'contains the store\'s public API', () => {
620
- // const data = {};
621
- // for( const k in selectorMap ) { data[ k ] = expect.anything() }
622
- // expect( compOneProps ).toEqual({
623
- // data,
624
- // resetState: expect.any( Function ),
625
- // setState: expect.any( Function )
626
- // });
627
- // } );
628
- // test( 'accepts own props (i.e. additional props at runtime)', () => {
629
- // let capturedProps;
630
- // const selectorMap = {
631
- // fullBox2: 'items[1]',
632
- // nameFirstBox: 'items.0.name'
633
- // };
634
- // const ownProps = {
635
- // anotherOwnProp: expect.anything(),
636
- // ownProp: expect.anything()
637
- // };
638
- // const WrappedComponent : React.ComponentType<ConnectProps<
639
- // typeof ownProps,
640
- // typeof state,
641
- // typeof selectorMap
642
- // >> = props => {
643
- // capturedProps = props;
644
- // return ( <div /> );
645
- // };
646
- // const ConnectedComponent = connect( ObservableContext, selectorMap )( WrappedComponent )
647
- // render(
648
- // <ObservableContext.Provider value={ state }>
649
- // <ConnectedComponent { ...ownProps } ref={ React.useRef() } />
650
- // </ObservableContext.Provider>
651
- // );
652
- // const data = {};
653
- // for( const k in selectorMap ) { data[ k ] = expect.anything() }
654
- // expect( capturedProps ).toEqual({
655
- // ...ownProps,
656
- // data,
657
- // resetState: expect.any( Function ),
658
- // setState: expect.any( Function )
659
- // });
660
- // } );
661
- // describe( 'prop name conflict resolution: ownProps vs store API props', () => {
662
- // test( 'defaults to ownProps', () => {
663
- // let capturedProps;
664
- // const selectorMap = {
665
- // fullBox2: 'items[1]',
666
- // nameFirstBox: 'items.0.name'
667
- // };
668
- // const T = props => {
669
- // capturedProps = props;
670
- // return null
671
- // };
672
- // const ownProps = {
673
- // data: {
674
- // anotherOwnProp: expect.anything(),
675
- // ownProp: expect.anything()
676
- // }
677
- // };
678
- // const ConnectedComponent = connect( ObservableContext, selectorMap )( T );
679
- // render(
680
- // <ObservableContext.Provider value={ state }>
681
- // <ConnectedComponent { ...ownProps } />
682
- // </ObservableContext.Provider>
683
- // );
684
- // const data = {};
685
- // for( const k in selectorMap ) { data[ k ] = expect.anything() }
686
- // expect( capturedProps ).toEqual({
687
- // ...ownProps, // using `data` from ownProps
688
- // resetState: expect.any( Function ),
689
- // setState: expect.any( Function )
690
- // });
691
- // } );
692
- // } );
693
- // } );
694
- // } );
695
- // describe( 'createContext(...)', () => {
696
- // test( 'returns observable context', () => {
697
- // expect( ObservableContext ).toEqual(
698
- // expect.objectContaining({
699
- // displayName: expect.any( String ),
700
- // Consumer: expect.any( Object ),
701
- // Provider: expect.any( Object )
702
- // })
703
- // );
704
- // expect( ObservableContext.Consumer.$$typeof.toString() )
705
- // .toEqual( 'Symbol(react.context)' );
706
- // expect( ObservableContext.Provider.$$typeof.toString() )
707
- // .toEqual( 'Symbol(react.forward_ref)' );
708
- // } );
709
- // describe( 'Context provider component property', () => {
710
- // test( 'also allows for no children', () => {
711
- // let renderResult;
712
- // expect(() => { renderResult = render( <ObservableContext.Provider value={{}} /> ) }).not.toThrow();
713
- // expect( renderResult.container ).toBeEmptyDOMElement();
714
- // } );
715
- // describe( 'with store object reference for external exposure', () => {
716
- // let state, storeRef, TestProvider;
717
- // beforeAll(() => {
718
- // state = {
719
- // color: 'Burgundy',
720
- // customer: {
721
- // name: { first: 'tFirst', last: 'tLast' },
722
- // phone: null
723
- // },
724
- // price: 22.5,
725
- // type: 'TEST TYPE'
726
- // }
727
- // TestProvider = () => { // eslint-disable-line react/display-name
728
- // storeRef = React.useRef();
729
- // return (
730
- // <ObservableContext.Provider ref={ storeRef } value={ state }>
731
- // <TallyDisplay />
732
- // </ObservableContext.Provider>
733
- // );
734
- // };
735
- // });
736
- // test( 'is provided', () => {
737
- // render( <TestProvider /> );
738
- // expect( storeRef.current ).toStrictEqual( expect.objectContaining({
739
- // getState: expect.any( Function ),
740
- // resetState: expect.any( Function ),
741
- // setState: expect.any( Function ),
742
- // subscribe: expect.any( Function )
743
- // }) );
744
- // } );
745
- // test( 'gets a copy of the current state', () => {
746
- // render( <TestProvider /> );
747
- // const currentState = storeRef.current.getState();
748
- // expect( currentState ).not.toBe( state );
749
- // expect( currentState ).toStrictEqual( state );
750
- // } );
751
- // test( 'updates internal state', async () => {
752
- // const { renderCount } = perf( React );
753
- // render( <TestProvider /> );
754
- // await wait(() => {});
755
- // expect( ( renderCount.current.TallyDisplay as RenderCountField ).value ).toBe( 1 );
756
- // const currentState = storeRef.current.getState();
757
- // storeRef.current.setState({ price: 45 });
758
- // const newState = { ...state, price: 45 };
759
- // await wait(() => {});
760
- // await new Promise( resolve => setTimeout( resolve, 50 ) );
761
- // expect( ( renderCount.current.TallyDisplay as RenderCountField ).value ).toBe( 2 );
762
- // expect( currentState ).not.toEqual( newState );
763
- // expect( storeRef.current.getState() ).toEqual( newState );
764
- // storeRef.current.resetState([ FULL_STATE_SELECTOR ]); // resets store internal state
765
- // await wait(() => {});
766
- // await new Promise( resolve => setTimeout( resolve, 50 ) );
767
- // expect( ( renderCount.current.TallyDisplay as RenderCountField ).value ).toBe( 3 );
768
- // const currentState2 = storeRef.current.getState();
769
- // expect( currentState2 ).not.toBe( state );
770
- // expect( currentState2 ).toStrictEqual( state );
771
- // expect( currentState2 ).not.toBe( currentState );
772
- // expect( currentState2 ).toStrictEqual( currentState );
773
- // cleanupPerfTest();
774
- // } );
775
- // test( 'subscribes to state changes', async () => {
776
- // render( <TestProvider /> );
777
- // const changes = { price: 45 };
778
- // const onChangeMock = jest.fn();
779
- // const unsub = storeRef.current.subscribe( onChangeMock );
780
- // expect( onChangeMock ).not.toHaveBeenCalled();
781
- // storeRef.current.setState( changes );
782
- // expect( onChangeMock ).toHaveBeenCalled();
783
- // expect( onChangeMock ).toHaveBeenCalledWith( changes );
784
- // onChangeMock.mockClear();
785
- // storeRef.current.resetState([ FULL_STATE_SELECTOR ]);
786
- // expect( onChangeMock ).toHaveBeenCalled();
787
- // expect( onChangeMock ).toHaveBeenCalledWith({ [ REPLACE_TAG ]: state });
788
- // onChangeMock.mockClear();
789
- // unsub();
790
- // storeRef.current.setState( changes );
791
- // expect( onChangeMock ).not.toHaveBeenCalled();
792
- // storeRef.current.resetState([ FULL_STATE_SELECTOR ]);
793
- // expect( onChangeMock ).not.toHaveBeenCalled();
794
- // } );
795
- // } );
796
- // } );
797
- // } );
798
- // describe( 'useContext(...)', () => {
799
- // let Client, renderUseContextHook, Wrapper;
800
- // beforeAll(() => {
801
- // /**
802
- // * @type {(initialProps: RenderUseContextProps) => RenderHookResult<
803
- // * RenderUseContextProps, ContextConsumerMock, Renderer<RenderUseContextProps>
804
- // * >}
805
- // */
806
- // renderUseContextHook = initialProps => renderHook(
807
- // p => useContext( p.context, p.selectorMap ),
808
- // { initialProps }
809
- // );
810
- // /* eslint-disable react/display-name */
811
- // Client = ({ selectorMap, onChange }) => {
812
- // const store = useContext( ObservableContext, selectorMap );
813
- // React.useMemo(() => onChange( store ), [ store ]);
814
- // return null;
815
- // };
816
- // Client.displayName = 'Client';
817
- // Wrapper = ({ children }) => (
818
- // <ObservableContext.Provider value={ createSourceData() }>
819
- // { children }
820
- // </ObservableContext.Provider>
821
- // );
822
- // Wrapper.displayName = 'Wrapper';
823
- // /* eslint-disable react/display-name */
824
- // });
825
- // test( 'returns a observable context store', () => {
826
- // /** @type {Store<SourceData>} */
827
- // let store;
828
- // const onChange = s => { store = s };
829
- // render(
830
- // <Wrapper>
831
- // <Client onChange={ onChange } selectorMap={{ tags: 'tags', all: FULL_STATE_SELECTOR }} />
832
- // </Wrapper>
833
- // );
834
- // expect( store ).toEqual({
835
- // data: expect.any( Object ),
836
- // resetState: expect.any( Function ),
837
- // setState: expect.any( Function )
838
- // });
839
- // } );
840
- // describe( 'selectorMap update', () => {
841
- // describe( 'normal flow', () => {
842
- // let mockConsumer, mockSetData, mockUnsubscribe;
843
- // let reactUseEffectSpy, reactUseContextSpy, reactUseStateSpy;
844
- // let selectorMapOnRender : Record<string, string>;
845
- // let selectorMapOnRerender : Record<string, string>;
846
- // beforeAll(() => {
847
- // selectorMapOnRender = {
848
- // year3: 'history.places[2].year',
849
- // isActive: 'isActive',
850
- // tag6: 'tags[5]'
851
- // };
852
- // selectorMapOnRerender = clonedeep( selectorMapOnRender );
853
- // selectorMapOnRerender.country3 = 'history.places[2].country';
854
- // mockSetData = jest.fn();
855
- // mockUnsubscribe = jest.fn();
856
- // reactUseEffectSpy = jest.spyOn( React, 'useEffect' );
857
- // reactUseStateSpy = jest.spyOn( React, 'useState' ).mockReturnValue([
858
- // Object.values( selectorMapOnRender ).reduce(
859
- // ( o, k ) => { o[ k ] = expect.anything(); return o }, {}
860
- // ),
861
- // mockSetData
862
- // ]);
863
- // mockConsumer = {
864
- // getState: () => Object.values( selectorMapOnRerender ).reduce(
865
- // ( o, k ) => { o[ k ] = expect.anything(); return o }, {}
866
- // ),
867
- // resetState: () => {},
868
- // subscribe: jest.fn().mockReturnValue( mockUnsubscribe ),
869
- // unlinkCache: jest.fn()
870
- // };
871
- // reactUseContextSpy = jest.spyOn( React, 'useContext' ).mockReturnValue( mockConsumer );
872
- // const { rerender } = renderUseContextHook({
873
- // context: ObservableContext,
874
- // selectorMap: selectorMapOnRender
875
- // });
876
- // mockConsumer.subscribe.mockClear();
877
- // mockConsumer.unlinkCache.mockClear();
878
- // reactUseEffectSpy.mockClear();
879
- // rerender({
880
- // context: ObservableContext,
881
- // selectorMap: selectorMapOnRerender
882
- // });
883
- // });
884
- // afterAll(() => {
885
- // reactUseContextSpy.mockRestore();
886
- // reactUseEffectSpy.mockRestore();
887
- // reactUseStateSpy.mockRestore();
888
- // } );
889
- // test( 'adjusts the store on selctorMap change', () => {
890
- // expect( reactUseEffectSpy.mock.calls[ 0 ][ 1 ] ).toEqual([
891
- // Object.values( selectorMapOnRerender )
892
- // ]);
893
- // } );
894
- // test( 'cleans up all previous associations to the consumer', () => {
895
- // expect( mockUnsubscribe ).toHaveBeenCalled();
896
- // expect( mockConsumer.unlinkCache ).toHaveBeenCalled();
897
- // } );
898
- // describe( 'when the new selectorMap is not empty', () => {
899
- // test( 'refreshes state data', () => {
900
- // expect( mockSetData ).toHaveBeenCalled();
901
- // } );
902
- // test( 'sets up new subscription with the consumer', () => {
903
- // expect( mockConsumer.subscribe ).toHaveBeenCalled();
904
- // } );
905
- // } );
906
- // } );
907
- // describe( 'accepting an array of propertyPaths in place of a selector map', () => {
908
- // /** @type {Store<SourceData>} */ let store;
909
- // beforeAll(() => {
910
- // const onChange = s => { store = s };
911
- // render(
912
- // <Wrapper>
913
- // <Client onChange={ onChange } selectorMap={[
914
- // 'history.places[2].year',
915
- // 'isActive',
916
- // 'tags[5]',
917
- // FULL_STATE_SELECTOR
918
- // ]} />
919
- // </Wrapper>
920
- // );
921
- // });
922
- // test( 'produces an indexed-based context state data object', () => {
923
- // const stateSource = createSourceData();
924
- // expect( store.data ).toStrictEqual({
925
- // 0: stateSource.history.places[ 2 ].year,
926
- // 1: stateSource.isActive,
927
- // 2: stateSource.tags[ 5 ],
928
- // 3: stateSource
929
- // });
930
- // } );
931
- // } );
932
- // describe( 'when the new selectorMap is empty', () => {
933
- // describe( 'and existing data is not empty', () => {
934
- // let mockConsumer, mockSetData, mockUnsubscribe;
935
- // let reactUseEffectSpy, reactUseContextSpy, reactUseStateSpy;
936
- // let selectorMapOnRender : Record<string, string>;
937
- // let selectorMapOnRerender : Record<string, string>;
938
- // beforeAll(() => {
939
- // selectorMapOnRender = {
940
- // year3: 'history.places[2].year',
941
- // isActive: 'isActive',
942
- // tag6: 'tags[5]'
943
- // };
944
- // selectorMapOnRerender = {};
945
- // mockSetData = jest.fn();
946
- // mockUnsubscribe = jest.fn();
947
- // reactUseEffectSpy = jest.spyOn( React, 'useEffect' );
948
- // reactUseStateSpy = jest.spyOn( React, 'useState' ).mockReturnValue([
949
- // Object.values( selectorMapOnRender ).reduce(
950
- // ( o, k ) => { o[ k ] = expect.anything(); return o }, {}
951
- // ),
952
- // mockSetData
953
- // ]);
954
- // mockConsumer = {
955
- // getState: () => Object.values( selectorMapOnRerender ).reduce(
956
- // ( o, k ) => { o[ k ] = expect.anything(); return o }, {}
957
- // ),
958
- // resetState: () => {},
959
- // subscribe: jest.fn().mockReturnValue( mockUnsubscribe ),
960
- // unlinkCache: jest.fn()
961
- // };
962
- // reactUseContextSpy = jest.spyOn( React, 'useContext' ).mockReturnValue( mockConsumer );
963
- // const { rerender } = renderUseContextHook({
964
- // context: ObservableContext,
965
- // selectorMap: selectorMapOnRender
966
- // });
967
- // mockConsumer.subscribe.mockClear();
968
- // mockConsumer.unlinkCache.mockClear();
969
- // reactUseEffectSpy.mockClear();
970
- // mockUnsubscribe.mockClear();
971
- // rerender({
972
- // context: ObservableContext,
973
- // selectorMap: selectorMapOnRerender
974
- // });
975
- // });
976
- // afterAll(() => {
977
- // reactUseContextSpy.mockRestore();
978
- // reactUseEffectSpy.mockRestore();
979
- // reactUseStateSpy.mockRestore();
980
- // } );
981
- // test( 'adjusts the store on selctorMap change', () => {
982
- // expect( reactUseEffectSpy.mock.calls[ 0 ][ 1 ] ).toEqual([[]]);
983
- // } );
984
- // test( 'cleans up all previous associations to the consumer', () => {
985
- // expect( mockUnsubscribe ).toHaveBeenCalled();
986
- // expect( mockConsumer.unlinkCache ).toHaveBeenCalled();
987
- // } );
988
- // test( 'refreshes state data with empty object', () => {
989
- // expect( mockSetData ).toHaveBeenCalledWith({});
990
- // } );
991
- // test( 'does not set up new subscription with the consumer', () => {
992
- // expect( mockConsumer.subscribe ).not.toHaveBeenCalled();
993
- // } );
994
- // } );
995
- // describe( 'and existing data is empty', () => {
996
- // let mockConsumer, mockSetData, mockUnsubscribe;
997
- // let reactUseEffectSpy, reactUseContextSpy, reactUseStateSpy;
998
- // let selectorMapOnRender;
999
- // beforeAll(() => {
1000
- // selectorMapOnRender = {
1001
- // year3: 'history.places[2].year',
1002
- // isActive: 'isActive',
1003
- // tag6: 'tags[5]'
1004
- // };
1005
- // mockSetData = jest.fn();
1006
- // mockUnsubscribe = jest.fn();
1007
- // reactUseEffectSpy = jest.spyOn( React, 'useEffect' );
1008
- // reactUseStateSpy = jest.spyOn( React, 'useState' ).mockReturnValue([ {}, mockSetData ]);
1009
- // mockConsumer = {
1010
- // getState: () => ({}),
1011
- // resetState: () => {},
1012
- // subscribe: jest.fn().mockReturnValue( mockUnsubscribe ),
1013
- // unlinkCache: jest.fn()
1014
- // };
1015
- // reactUseContextSpy = jest.spyOn( React, 'useContext' ).mockReturnValue( mockConsumer );
1016
- // const { rerender } = renderUseContextHook({
1017
- // context: ObservableContext,
1018
- // selectorMap: selectorMapOnRender
1019
- // });
1020
- // mockConsumer.subscribe.mockClear();
1021
- // mockConsumer.unlinkCache.mockClear();
1022
- // reactUseEffectSpy.mockClear();
1023
- // mockUnsubscribe.mockClear();
1024
- // rerender({ context: ObservableContext });
1025
- // });
1026
- // afterAll(() => {
1027
- // reactUseContextSpy.mockRestore();
1028
- // reactUseEffectSpy.mockRestore();
1029
- // reactUseStateSpy.mockRestore();
1030
- // } );
1031
- // test( 'adjusts the store on selctorMap change', () => {
1032
- // expect( reactUseEffectSpy.mock.calls[ 0 ][ 1 ] ).toEqual([[]]);
1033
- // } );
1034
- // test( 'performs no state data update', () => {
1035
- // expect( mockSetData ).not.toHaveBeenCalled();
1036
- // } );
1037
- // test( 'does not set up new subscription with the consumer', () => {
1038
- // expect( mockConsumer.subscribe ).not.toHaveBeenCalled();
1039
- // } );
1040
- // describe( 'and previous property path is empty', () => {
1041
- // test( 'skips cleanup: no previous associations to the consumer', () => {
1042
- // const mockSetData = jest.fn();
1043
- // const mockUnsubscribe = jest.fn();
1044
- // const reactUseEffectSpy = jest.spyOn( React, 'useEffect' );
1045
- // const reactUseStateSpy = jest.spyOn( React, 'useState' ).mockReturnValue([ {}, mockSetData ]);
1046
- // const mockConsumer = {
1047
- // getState: () => ({}),
1048
- // resetState: () => {},
1049
- // subscribe: jest.fn().mockReturnValue( mockUnsubscribe ),
1050
- // unlinkCache: jest.fn()
1051
- // };
1052
- // const reactUseContextSpy = jest.spyOn( React, 'useContext' ).mockReturnValue( mockConsumer );
1053
- // const { rerender } = renderUseContextHook({ context: ObservableContext });
1054
- // mockConsumer.subscribe.mockClear();
1055
- // mockConsumer.unlinkCache.mockClear();
1056
- // reactUseEffectSpy.mockClear();
1057
- // mockUnsubscribe.mockClear();
1058
- // rerender({ context: ObservableContext, selectorMap: {} });
1059
- // expect( mockConsumer.unlinkCache ).not.toHaveBeenCalled();
1060
- // expect( mockUnsubscribe ).not.toHaveBeenCalled();
1061
- // reactUseContextSpy.mockRestore();
1062
- // reactUseEffectSpy.mockRestore();
1063
- // reactUseStateSpy.mockRestore();
1064
- // } );
1065
- // } );
1066
- // } );
1067
- // } );
1068
- // } );
1069
- // describe( 'store.data', () => {
1070
- // let Client;
1071
- // beforeAll(() => {
1072
- // Client = ({ selectorMap, onChange }) => {
1073
- // const store = useContext( ObservableContext, selectorMap );
1074
- // React.useMemo(() => onChange( store ), [ store ]);
1075
- // return null;
1076
- // };
1077
- // Client.displayName = 'Client';
1078
- // });
1079
- // test( 'carries the latest state data as referenced by the selectorMap', async () => {
1080
- // /** @type {Store<SourceData>} */
1081
- // let store;
1082
- // const onChange = s => { store = s };
1083
- // render(
1084
- // <Wrapper>
1085
- // <Client onChange={ onChange } selectorMap={{
1086
- // city3: 'history.places[2].city',
1087
- // country3: 'history.places[2].country',
1088
- // friends: 'friends',
1089
- // year3: 'history.places[2].year',
1090
- // isActive: 'isActive',
1091
- // tag6: 'tags[5]',
1092
- // tag7: 'tags[6]',
1093
- // tags: 'tags'
1094
- // }} />
1095
- // </Wrapper>
1096
- // );
1097
- // const defaultState = createSourceData();
1098
- // const expectedValue = {
1099
- // city3: defaultState.history.places[ 2 ].city,
1100
- // country3: defaultState.history.places[ 2 ].country,
1101
- // friends: defaultState.friends,
1102
- // year3: defaultState.history.places[ 2 ].year,
1103
- // isActive: defaultState.isActive,
1104
- // tag6: defaultState.tags[ 5 ],
1105
- // tag7: defaultState.tags[ 6 ],
1106
- // tags: defaultState.tags
1107
- // };
1108
- // expect( store.data ).toEqual( expectedValue );
1109
- // store.setState({
1110
- // friends: { [ MOVE_TAG ]: [ -1, 1 ] },
1111
- // isActive: true,
1112
- // history: {
1113
- // places: {
1114
- // 2: {
1115
- // city: 'Marakesh',
1116
- // country: 'Morocco'
1117
- // }
1118
- // }
1119
- // },
1120
- // tags: { [ DELETE_TAG ]: [ 3, 5 ] }
1121
- // });
1122
- // await new Promise( resolve => setTimeout( resolve, 10 ) );
1123
- // expect( store.data ).toEqual({
1124
- // ...expectedValue,
1125
- // city3: 'Marakesh',
1126
- // country3: 'Morocco',
1127
- // friends: [ 0, 2, 1 ].map( i => defaultState.friends[ i ] ),
1128
- // isActive: true,
1129
- // tag6: undefined,
1130
- // tag7: undefined,
1131
- // tags: [ 0, 1, 2, 4, 6 ].map( i => defaultState.tags[ i ] )
1132
- // });
1133
- // } );
1134
- // test( 'holds the complete current state object whenever `@@STATE` entry appears in the selectorMap', async () => {
1135
- // /** @type {Store<SourceData>} */
1136
- // let store;
1137
- // const onChange = s => { store = s };
1138
- // render(
1139
- // <Wrapper>
1140
- // <Client onChange={ onChange } selectorMap={{
1141
- // city3: 'history.places[2].city',
1142
- // country3: 'history.places[2].country',
1143
- // year3: 'history.places[2].year',
1144
- // isActive: 'isActive',
1145
- // tag6: 'tags[5]',
1146
- // tag7: 'tags[6]',
1147
- // state: '@@STATE'
1148
- // }} />
1149
- // </Wrapper>
1150
- // );
1151
- // const defaultState = createSourceData();
1152
- // const expectedValue = {
1153
- // city3: defaultState.history.places[ 2 ].city,
1154
- // country3: defaultState.history.places[ 2 ].country,
1155
- // year3: defaultState.history.places[ 2 ].year,
1156
- // isActive: defaultState.isActive,
1157
- // tag6: defaultState.tags[ 5 ],
1158
- // tag7: defaultState.tags[ 6 ],
1159
- // state: defaultState
1160
- // };
1161
- // expect( store.data ).toEqual( expectedValue );
1162
- // store.setState({
1163
- // isActive: true,
1164
- // history: {
1165
- // places: {
1166
- // 2: {
1167
- // city: 'Marakesh',
1168
- // country: 'Morocco'
1169
- // }
1170
- // }
1171
- // }
1172
- // });
1173
- // await new Promise( resolve => setTimeout( resolve, 10 ) );
1174
- // const updatedDataEquiv = createSourceData();
1175
- // updatedDataEquiv.history.places[ 2 ].city = 'Marakesh';
1176
- // updatedDataEquiv.history.places[ 2 ].country = 'Morocco';
1177
- // updatedDataEquiv.isActive = true;
1178
- // expect( store.data ).toEqual({
1179
- // ...expectedValue,
1180
- // city3: 'Marakesh',
1181
- // country3: 'Morocco',
1182
- // isActive: true,
1183
- // state: updatedDataEquiv
1184
- // });
1185
- // } );
1186
- // test( 'holds an empty object when no renderKeys provided ', async () => {
1187
- // /** @type {Store<SourceData>} */
1188
- // let store;
1189
- // const onChange = s => { store = s };
1190
- // render( <Wrapper><Client onChange={ onChange } /></Wrapper> );
1191
- // expect( store.data ).toEqual({});
1192
- // store.setState({ // can still update state
1193
- // isActive: true,
1194
- // history: {
1195
- // places: {
1196
- // 2: {
1197
- // city: 'Marakesh',
1198
- // country: 'Morocco'
1199
- // }
1200
- // }
1201
- // }
1202
- // });
1203
- // await new Promise( resolve => setTimeout( resolve, 10 ) );
1204
- // expect( store.data ).toEqual({});
1205
- // } );
1206
- // } );
1207
- // describe( 'store.resetState', () => {
1208
- // describe( 'when selectorMap is present in the consumer', () => {
1209
- // let reactUseEffectSpy, reactUseContextSpy, reactUseStateSpy;
1210
- // let mockConsumer, resetState;
1211
- // let selectorMap : Record<string, string>;
1212
- // beforeAll(() => {
1213
- // selectorMap = { a: 'aggregation', b: 'blatant', c: 'charitable' };
1214
- // mockConsumer = {
1215
- // getState: () => ({}),
1216
- // resetState: jest.fn(),
1217
- // subscribe: () => () => {},
1218
- // unlinkCache: () => {}
1219
- // };
1220
- // reactUseEffectSpy = jest.spyOn( React, 'useEffect' );
1221
- // reactUseStateSpy = jest.spyOn( React, 'useState' ).mockReturnValue([
1222
- // Object.values( selectorMap ).reduce(
1223
- // ( o, k ) => { o[ k ] = expect.anything(); return o }, {}
1224
- // ),
1225
- // () => {}
1226
- // ]);
1227
- // reactUseContextSpy = jest.spyOn( React, 'useContext' ).mockReturnValue( mockConsumer );
1228
- // const { result } = renderUseContextHook({ context: expect.anything(), selectorMap });
1229
- // resetState = result.current.resetState;
1230
- // });
1231
- // afterAll(() => {
1232
- // reactUseContextSpy.mockRestore();
1233
- // reactUseEffectSpy.mockRestore();
1234
- // reactUseStateSpy.mockRestore();
1235
- // } );
1236
- // describe( 'and called with own state property paths to reset', () => {
1237
- // test( 'calculates setstate changes using state slice matching the supplied property paths', () => {
1238
- // const args = [ 'blatant', 'xylophone', 'yodellers', 'zenith' ];
1239
- // resetState( args );
1240
- // expect( mockConsumer.resetState ).toHaveBeenCalledWith( args );
1241
- // } );
1242
- // } );
1243
- // describe( 'and called with NO state property paths to reset', () => {
1244
- // test( 'calculates setstate changes using state slice matching property paths derived from the selectorMap', () => {
1245
- // resetState();
1246
- // expect( mockConsumer.resetState ).toHaveBeenCalledWith( Object.values( selectorMap ) )
1247
- // } );
1248
- // } );
1249
- // } );
1250
- // describe( 'when selectorMap is NOT present in the consumer', () => {
1251
- // let reactUseEffectSpy, reactUseContextSpy, reactUseStateSpy;
1252
- // let mockConsumer, resetState;
1253
- // beforeAll(() => {
1254
- // mockConsumer = {
1255
- // getState: () => ({}),
1256
- // resetState: jest.fn(),
1257
- // subscribe: () => () => {},
1258
- // unlinkCache: () => {}
1259
- // };
1260
- // reactUseEffectSpy = jest.spyOn( React, 'useEffect' );
1261
- // reactUseStateSpy = jest.spyOn( React, 'useState' ).mockReturnValue([ {}, () => {} ]);
1262
- // reactUseContextSpy = jest.spyOn( React, 'useContext' ).mockReturnValue( mockConsumer );
1263
- // const { result } = renderUseContextHook({ context: expect.anything() });
1264
- // resetState = result.current.resetState;
1265
- // });
1266
- // afterAll(() => {
1267
- // reactUseContextSpy.mockRestore();
1268
- // reactUseEffectSpy.mockRestore();
1269
- // reactUseStateSpy.mockRestore();
1270
- // } );
1271
- // describe( 'and called with own state property paths to reset', () => {
1272
- // test( 'calculates setstate changes using state slice matching the supplied property paths', () => {
1273
- // const args = [ 'blatant', 'xylophone', 'yodellers', 'zenith' ];
1274
- // resetState( args );
1275
- // expect( mockConsumer.resetState ).toHaveBeenCalledWith( args );
1276
- // } );
1277
- // } );
1278
- // describe( 'and called with NO state property paths to reset', () => {
1279
- // test( 'calculates setstate changes using no property paths -- the consumer applies no store reset [see usestore(...)]', () => {
1280
- // resetState();
1281
- // expect( mockConsumer.resetState ).toHaveBeenCalledWith([]);
1282
- // } );
1283
- // } );
1284
- // } );
1285
- // } );
1286
- // } );
1287
- // } );
1288
- });
1289
- /**
1290
- * @typedef {import('@testing-library/react-hooks').Renderer<TProps>} Renderer
1291
- * @template TProps
1292
- */
1293
- /**
1294
- * @typedef {import('@testing-library/react-hooks').RenderHookResult<TProps, TValue, TRenderer>} RenderHookResult
1295
- * @template TProps
1296
- * @template TValue
1297
- * @template {Renderer<TProps>} TRenderer
1298
- */