@promoboxx/use-filter 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/lib/buildDefaultFilterInfo.js +35 -0
- package/dist/lib/getOffsetFromPage.js +6 -0
- package/dist/lib/getPageFromOffset.js +6 -0
- package/dist/lib/shallowEqual.js +23 -0
- package/dist/lib/shallowEqual.test.js +54 -0
- package/dist/store/index.js +15 -0
- package/dist/store/memoryStore.js +15 -0
- package/dist/useFilter.js +184 -0
- package/dist/useFilter.test.js +581 -0
- package/package.json +14 -3
- package/.eslintrc.js +0 -19
- package/.github/workflows/main.yml +0 -32
- package/.vscode/settings.json +0 -3
- package/Makefile +0 -31
- package/jest.config.js +0 -196
- package/prettier.config.js +0 -1
- package/src/lib/buildDefaultFilterInfo.ts +0 -35
- package/src/lib/getOffsetFromPage.ts +0 -5
- package/src/lib/getPageFromOffset.ts +0 -5
- package/src/lib/shallowEqual.test.ts +0 -71
- package/src/lib/shallowEqual.ts +0 -26
- package/src/store/index.ts +0 -21
- package/src/store/memoryStore.ts +0 -19
- package/src/useFilter.test.tsx +0 -449
- package/src/useFilter.ts +0 -280
- package/tsconfig.json +0 -75
package/src/useFilter.test.tsx
DELETED
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
import { act, cleanup, fireEvent, render, screen } from '@testing-library/react'
|
|
2
|
-
import React, { useState } from 'react'
|
|
3
|
-
|
|
4
|
-
import buildDefaultFilterInfo from './lib/buildDefaultFilterInfo'
|
|
5
|
-
import { setFilterStore } from './store'
|
|
6
|
-
import memoryStore from './store/memoryStore'
|
|
7
|
-
import useFilter, { FilterInfo } from './useFilter'
|
|
8
|
-
|
|
9
|
-
describe('useFilter', () => {
|
|
10
|
-
const defaultFilterInfo = buildDefaultFilterInfo({
|
|
11
|
-
filter: {
|
|
12
|
-
foo: 'bar',
|
|
13
|
-
},
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
it('calls on mount', async () => {
|
|
17
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
18
|
-
|
|
19
|
-
expect(onChangeMock).toHaveBeenCalledTimes(1)
|
|
20
|
-
expect(onChangeMock).toHaveBeenLastCalledWith(
|
|
21
|
-
expect.objectContaining({ filter: { foo: 'bar' } }),
|
|
22
|
-
)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('calls when data changes', async () => {
|
|
26
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
27
|
-
|
|
28
|
-
await actAndWait(() => {
|
|
29
|
-
fireEvent.click(screen.getByTestId('updateFilterButton'))
|
|
30
|
-
})
|
|
31
|
-
expect(onChangeMock).toHaveBeenCalledTimes(2)
|
|
32
|
-
expect(onChangeMock).toHaveBeenLastCalledWith(
|
|
33
|
-
expect.objectContaining({ filter: { foo: '42' } }),
|
|
34
|
-
)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('uses shallowEqual be default', async () => {
|
|
38
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
39
|
-
|
|
40
|
-
await actAndWait(() => {
|
|
41
|
-
fireEvent.click(screen.getByTestId('updateFilterButton'))
|
|
42
|
-
})
|
|
43
|
-
await actAndWait(() => {
|
|
44
|
-
fireEvent.click(screen.getByTestId('updateFilterButton'))
|
|
45
|
-
})
|
|
46
|
-
// 2 is still the correct number of times, as there is one from the initial
|
|
47
|
-
// mount and the other from updateFilter.
|
|
48
|
-
expect(onChangeMock).toHaveBeenCalledTimes(2)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('can reset and keeps defaults', async () => {
|
|
52
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
53
|
-
|
|
54
|
-
await actAndWait(() => {
|
|
55
|
-
fireEvent.click(screen.getByTestId('resetFilterButton'))
|
|
56
|
-
})
|
|
57
|
-
expect(onChangeMock).toHaveBeenCalledTimes(2)
|
|
58
|
-
expect(onChangeMock).toHaveBeenLastCalledWith(
|
|
59
|
-
expect.objectContaining({ filter: { foo: 'bar' } }),
|
|
60
|
-
)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('can setSort', async () => {
|
|
64
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
65
|
-
|
|
66
|
-
await actAndWait(() => {
|
|
67
|
-
fireEvent.click(screen.getByTestId('setSortButton'))
|
|
68
|
-
})
|
|
69
|
-
expect(onChangeMock).toHaveBeenCalledTimes(2)
|
|
70
|
-
expect(onChangeMock).toHaveBeenLastCalledWith(
|
|
71
|
-
expect.objectContaining({ filter: { foo: 'bar' }, sort: 'foo:bar' }),
|
|
72
|
-
)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('renders the current filter', async () => {
|
|
76
|
-
await setup({ defaultFilterInfo })
|
|
77
|
-
|
|
78
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
79
|
-
expect.objectContaining({ filter: { foo: 'bar' } }),
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
await actAndWait(() => {
|
|
83
|
-
fireEvent.click(screen.getByTestId('updateFilterButton'))
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
87
|
-
expect.objectContaining({ filter: { foo: '42' } }),
|
|
88
|
-
)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('handles onChange.filterInfo', async () => {
|
|
92
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
93
|
-
|
|
94
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
95
|
-
expect.objectContaining({ totalResults: 1 }),
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
// Say the server response with a new totalResults.
|
|
99
|
-
onChangeMock.mockImplementation(() => ({
|
|
100
|
-
filterInfo: {
|
|
101
|
-
totalResults: 100,
|
|
102
|
-
},
|
|
103
|
-
}))
|
|
104
|
-
await actAndWait(() => {
|
|
105
|
-
fireEvent.click(screen.getByTestId('forceRefreshButton'))
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
109
|
-
expect.objectContaining({ totalResults: 100 }),
|
|
110
|
-
)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('handles onChange.filterInfo.totalResults', async () => {
|
|
114
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
115
|
-
|
|
116
|
-
// Say the server response with a new totalResults.
|
|
117
|
-
onChangeMock.mockImplementation(() => ({
|
|
118
|
-
filterInfo: {
|
|
119
|
-
totalResults: 99,
|
|
120
|
-
},
|
|
121
|
-
}))
|
|
122
|
-
await actAndWait(() => {
|
|
123
|
-
fireEvent.click(screen.getByTestId('forceRefreshButton'))
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
127
|
-
expect.objectContaining({ totalResults: 99 }),
|
|
128
|
-
)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
// it("handles onChange.data", async () => {
|
|
132
|
-
// onChangeMock.mockImplementation((filterInfo) => ({
|
|
133
|
-
// data: [{ name: filterInfo.filter.foo }],
|
|
134
|
-
// }));
|
|
135
|
-
|
|
136
|
-
// getByTestId(wrapper, "updateFilterButton").simulate("click");
|
|
137
|
-
// await actWrapperUpdate(wrapper);
|
|
138
|
-
|
|
139
|
-
// expect(JSON.parse(getByTestId(wrapper, "responseDataJson").text())).toEqual(
|
|
140
|
-
// [{ name: "42" }]
|
|
141
|
-
// );
|
|
142
|
-
|
|
143
|
-
// getByTestId(wrapper, "resetFilterButton").simulate("click");
|
|
144
|
-
// await actWrapperUpdate(wrapper);
|
|
145
|
-
|
|
146
|
-
// expect(JSON.parse(getByTestId(wrapper, "responseDataJson").text())).toEqual(
|
|
147
|
-
// [{ name: "bar" }]
|
|
148
|
-
// );
|
|
149
|
-
// });
|
|
150
|
-
|
|
151
|
-
it('handles async onChange.filterInfo', async () => {
|
|
152
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
153
|
-
|
|
154
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
155
|
-
expect.objectContaining({ totalResults: 1 }),
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
// Say the server response with a new totalResults.
|
|
159
|
-
onChangeMock.mockImplementation(() =>
|
|
160
|
-
Promise.resolve({
|
|
161
|
-
filterInfo: {
|
|
162
|
-
totalResults: 100,
|
|
163
|
-
},
|
|
164
|
-
}),
|
|
165
|
-
)
|
|
166
|
-
await actAndWait(() => {
|
|
167
|
-
fireEvent.click(screen.getByTestId('forceRefreshButton'))
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
171
|
-
expect.objectContaining({ totalResults: 100 }),
|
|
172
|
-
)
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
it('handles async onChange.filterInfo.totalResults', async () => {
|
|
176
|
-
const { onChangeMock } = await setup({ defaultFilterInfo })
|
|
177
|
-
|
|
178
|
-
// Say the server response with a new totalResults.
|
|
179
|
-
onChangeMock.mockImplementation(() =>
|
|
180
|
-
Promise.resolve({
|
|
181
|
-
filterInfo: {
|
|
182
|
-
totalResults: 99,
|
|
183
|
-
},
|
|
184
|
-
}),
|
|
185
|
-
)
|
|
186
|
-
await actAndWait(() => {
|
|
187
|
-
fireEvent.click(screen.getByTestId('forceRefreshButton'))
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
191
|
-
expect.objectContaining({ totalPages: 5 }),
|
|
192
|
-
)
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
// it("handles async onChange.data", async () => {
|
|
196
|
-
// onChangeMock.mockImplementation((filterInfo) =>
|
|
197
|
-
// Promise.resolve({
|
|
198
|
-
// data: [{ name: filterInfo.filter.foo }],
|
|
199
|
-
// })
|
|
200
|
-
// );
|
|
201
|
-
|
|
202
|
-
// getByTestId(wrapper, "updateFilterButton").simulate("click");
|
|
203
|
-
// await actWrapperUpdate(wrapper);
|
|
204
|
-
|
|
205
|
-
// expect(JSON.parse(getByTestId(wrapper, "responseDataJson").text())).toEqual(
|
|
206
|
-
// [{ name: "42" }]
|
|
207
|
-
// );
|
|
208
|
-
|
|
209
|
-
// getByTestId(wrapper, "resetFilterButton").simulate("click");
|
|
210
|
-
// await actWrapperUpdate(wrapper);
|
|
211
|
-
|
|
212
|
-
// expect(JSON.parse(getByTestId(wrapper, "responseDataJson").text())).toEqual(
|
|
213
|
-
// [{ name: "bar" }]
|
|
214
|
-
// );
|
|
215
|
-
// });
|
|
216
|
-
|
|
217
|
-
it('persists across mounts', async () => {
|
|
218
|
-
const { onChangeMock, ExampleComponent } = await setup({
|
|
219
|
-
defaultFilterInfo,
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
const ToggleComponent = () => {
|
|
223
|
-
const [shouldShow, setShouldShow] = useState(true)
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<div>
|
|
227
|
-
<button
|
|
228
|
-
data-testid="toggleShouldShow"
|
|
229
|
-
onClick={() => setShouldShow(!shouldShow)}
|
|
230
|
-
/>
|
|
231
|
-
{shouldShow ? <ExampleComponent /> : null}
|
|
232
|
-
</div>
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Simulate the filter being visible.
|
|
237
|
-
await actAndWait(() => {
|
|
238
|
-
// Cleanup the render done in `setup`.
|
|
239
|
-
cleanup()
|
|
240
|
-
render(<ToggleComponent />)
|
|
241
|
-
})
|
|
242
|
-
expect(screen.queryByTestId('updateFilterButton')).toBeTruthy()
|
|
243
|
-
|
|
244
|
-
// Simulate removing the filter.
|
|
245
|
-
await actAndWait(() => {
|
|
246
|
-
fireEvent.click(screen.getByTestId('toggleShouldShow'))
|
|
247
|
-
})
|
|
248
|
-
expect(screen.queryByTestId('updateFilterButton')).toBeFalsy()
|
|
249
|
-
|
|
250
|
-
// Simulate the filter being visible, again.
|
|
251
|
-
await actAndWait(() => {
|
|
252
|
-
fireEvent.click(screen.getByTestId('toggleShouldShow'))
|
|
253
|
-
})
|
|
254
|
-
expect(screen.queryByTestId('updateFilterButton')).toBeTruthy()
|
|
255
|
-
|
|
256
|
-
// onChange should still only be called once.
|
|
257
|
-
expect(onChangeMock).toHaveBeenCalledTimes(1)
|
|
258
|
-
})
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
describe('page based', () => {
|
|
262
|
-
const defaultFilterInfo = buildDefaultFilterInfo({
|
|
263
|
-
filter: {
|
|
264
|
-
foo: 'bar',
|
|
265
|
-
},
|
|
266
|
-
pageSize: 20,
|
|
267
|
-
page: 2,
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
const children: Wut = (wut) => (
|
|
271
|
-
<button data-testid="setPageButton" onClick={() => wut.setPage(3)} />
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
it('accepts initial page', async () => {
|
|
275
|
-
await setup({ defaultFilterInfo, children })
|
|
276
|
-
|
|
277
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
278
|
-
expect.objectContaining({ page: 2, offset: 20 }),
|
|
279
|
-
)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
it('can set page', async () => {
|
|
283
|
-
const { onChangeMock } = await setup({ defaultFilterInfo, children })
|
|
284
|
-
|
|
285
|
-
await actAndWait(() => {
|
|
286
|
-
fireEvent.click(screen.getByTestId('setPageButton'))
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
expect(onChangeMock).toHaveBeenCalledTimes(2)
|
|
290
|
-
expect(onChangeMock).toHaveBeenLastCalledWith(
|
|
291
|
-
expect.objectContaining({ page: 3, offset: 40 }),
|
|
292
|
-
)
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
it('can handle onChange.filterInfo.page', async () => {
|
|
296
|
-
const { onChangeMock } = await setup({ defaultFilterInfo, children })
|
|
297
|
-
|
|
298
|
-
// Intentionally respond with numbers that don't match what the button
|
|
299
|
-
// actually does.
|
|
300
|
-
// This is to test the actual response, the view updates immediately.
|
|
301
|
-
onChangeMock.mockImplementation(() => ({
|
|
302
|
-
filterInfo: {
|
|
303
|
-
page: 20,
|
|
304
|
-
},
|
|
305
|
-
}))
|
|
306
|
-
|
|
307
|
-
await actAndWait(() => {
|
|
308
|
-
fireEvent.click(screen.getByTestId('setPageButton'))
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
312
|
-
expect.objectContaining({ page: 20, offset: 380 }),
|
|
313
|
-
)
|
|
314
|
-
})
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
describe('offset based', () => {
|
|
318
|
-
const defaultFilterInfo = buildDefaultFilterInfo({
|
|
319
|
-
filter: {
|
|
320
|
-
foo: 'bar',
|
|
321
|
-
},
|
|
322
|
-
pageSize: 20,
|
|
323
|
-
offset: 80,
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
const children: Wut = (wut) => (
|
|
327
|
-
<button data-testid="setOffsetButton" onClick={() => wut.setOffset(100)} />
|
|
328
|
-
)
|
|
329
|
-
|
|
330
|
-
it('accepts initial offset', async () => {
|
|
331
|
-
await setup({ defaultFilterInfo, children })
|
|
332
|
-
|
|
333
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
334
|
-
expect.objectContaining({ offset: 80, page: 5 }),
|
|
335
|
-
)
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
it('can set offset', async () => {
|
|
339
|
-
const { onChangeMock } = await setup({ defaultFilterInfo, children })
|
|
340
|
-
|
|
341
|
-
await actAndWait(() => {
|
|
342
|
-
fireEvent.click(screen.getByTestId('setOffsetButton'))
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
expect(onChangeMock).toHaveBeenCalledTimes(2)
|
|
346
|
-
expect(onChangeMock).toHaveBeenLastCalledWith(
|
|
347
|
-
expect.objectContaining({ page: 6, offset: 100 }),
|
|
348
|
-
)
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
it('can handle onChange.filterInfo.offset', async () => {
|
|
352
|
-
const { onChangeMock } = await setup({ defaultFilterInfo, children })
|
|
353
|
-
|
|
354
|
-
// Intentionally respond with numbers that don't match what the button
|
|
355
|
-
// actually does.
|
|
356
|
-
// This is to test the actual response, the view updates immediately.
|
|
357
|
-
onChangeMock.mockImplementation(() => ({
|
|
358
|
-
filterInfo: {
|
|
359
|
-
offset: 380,
|
|
360
|
-
},
|
|
361
|
-
}))
|
|
362
|
-
await actAndWait(() => {
|
|
363
|
-
fireEvent.click(screen.getByTestId('setOffsetButton'))
|
|
364
|
-
})
|
|
365
|
-
|
|
366
|
-
expect(safeJsonParse(screen.getByTestId('filterJson').textContent)).toEqual(
|
|
367
|
-
expect.objectContaining({ page: 20, offset: 380 }),
|
|
368
|
-
)
|
|
369
|
-
})
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
function wait(n = 0) {
|
|
373
|
-
return new Promise((resolve) => setTimeout(resolve, n))
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function safeJsonParse(input: string | undefined | null = '') {
|
|
377
|
-
if (input) {
|
|
378
|
-
return JSON.parse(input)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
async function actAndWait(fn: () => void, n = 0) {
|
|
383
|
-
act(fn)
|
|
384
|
-
await act(async () => {
|
|
385
|
-
await wait(n)
|
|
386
|
-
})
|
|
387
|
-
// You'd think you could just write this:
|
|
388
|
-
// await act(async () => {
|
|
389
|
-
// fn();
|
|
390
|
-
// await wait(n);
|
|
391
|
-
// });
|
|
392
|
-
// But for some reason, doing it that way needs a longer wait duration than
|
|
393
|
-
// just a single tick. /shrug.
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
type Wut = (wut: ReturnType<typeof useFilter>) => React.ReactNode
|
|
397
|
-
|
|
398
|
-
async function setup<TFilterInfo extends FilterInfo<any>>(options: {
|
|
399
|
-
defaultFilterInfo: TFilterInfo
|
|
400
|
-
children?: Wut
|
|
401
|
-
}) {
|
|
402
|
-
memoryStore.clear()
|
|
403
|
-
setFilterStore(memoryStore)
|
|
404
|
-
|
|
405
|
-
const onChangeMock = jest.fn()
|
|
406
|
-
|
|
407
|
-
const ExampleComponent = () => {
|
|
408
|
-
const wut = useFilter('namespace', {
|
|
409
|
-
defaultFilterInfo: options.defaultFilterInfo,
|
|
410
|
-
debounceDuration: 0,
|
|
411
|
-
onChange: onChangeMock,
|
|
412
|
-
})
|
|
413
|
-
|
|
414
|
-
return (
|
|
415
|
-
<div>
|
|
416
|
-
{options.children?.(wut)}
|
|
417
|
-
<button
|
|
418
|
-
data-testid="updateFilterButton"
|
|
419
|
-
onClick={() => wut.updateFilter({ foo: '42' })}
|
|
420
|
-
/>
|
|
421
|
-
<button
|
|
422
|
-
data-testid="resetFilterButton"
|
|
423
|
-
onClick={() => wut.resetFilter()}
|
|
424
|
-
/>
|
|
425
|
-
<button
|
|
426
|
-
data-testid="forceRefreshButton"
|
|
427
|
-
onClick={() => wut.forceRefresh()}
|
|
428
|
-
/>
|
|
429
|
-
<button
|
|
430
|
-
data-testid="setSortButton"
|
|
431
|
-
onClick={() => wut.setSort('foo:bar')}
|
|
432
|
-
/>
|
|
433
|
-
<div data-testid="filterJson">{JSON.stringify(wut.filterInfo)}</div>
|
|
434
|
-
{/* <div data-testid="responseDataJson">
|
|
435
|
-
{JSON.stringify(wut.responseData)}
|
|
436
|
-
</div> */}
|
|
437
|
-
</div>
|
|
438
|
-
)
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
await actAndWait(() => {
|
|
442
|
-
render(<ExampleComponent />)
|
|
443
|
-
})
|
|
444
|
-
|
|
445
|
-
return {
|
|
446
|
-
onChangeMock,
|
|
447
|
-
ExampleComponent,
|
|
448
|
-
}
|
|
449
|
-
}
|