@openapi-qraft/react 1.0.0-beta.4 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +35 -0
  3. package/dist/ServiceOperation.d.ts +58 -9
  4. package/dist/ServiceOperation.d.ts.map +1 -1
  5. package/dist/callbacks/getMutationKey.d.ts +2 -2
  6. package/dist/callbacks/getMutationKey.d.ts.map +1 -1
  7. package/dist/callbacks/getMutationKey.js +2 -19
  8. package/dist/callbacks/getMutationKey.js.map +1 -1
  9. package/dist/callbacks/useInfiniteQuery.d.ts +0 -6
  10. package/dist/callbacks/useInfiniteQuery.d.ts.map +1 -1
  11. package/dist/callbacks/useInfiniteQuery.js +1 -27
  12. package/dist/callbacks/useInfiniteQuery.js.map +1 -1
  13. package/dist/callbacks/useMutation.d.ts.map +1 -1
  14. package/dist/callbacks/useMutation.js +4 -16
  15. package/dist/callbacks/useMutation.js.map +1 -1
  16. package/dist/callbacks/useMutationState.d.ts +7 -0
  17. package/dist/callbacks/useMutationState.d.ts.map +1 -0
  18. package/dist/callbacks/useMutationState.js +30 -0
  19. package/dist/callbacks/useMutationState.js.map +1 -0
  20. package/dist/callbacks/useSuspenseInfiniteQuery.d.ts +9 -0
  21. package/dist/callbacks/useSuspenseInfiniteQuery.d.ts.map +1 -0
  22. package/dist/callbacks/useSuspenseInfiniteQuery.js +25 -0
  23. package/dist/callbacks/useSuspenseInfiniteQuery.js.map +1 -0
  24. package/dist/callbacks/useSuspenseQuery.d.ts +9 -0
  25. package/dist/callbacks/useSuspenseQuery.d.ts.map +1 -0
  26. package/dist/callbacks/useSuspenseQuery.js +28 -0
  27. package/dist/callbacks/useSuspenseQuery.js.map +1 -0
  28. package/dist/lib/composeMutationKey.d.ts +10 -0
  29. package/dist/lib/composeMutationKey.d.ts.map +1 -0
  30. package/dist/lib/composeMutationKey.js +21 -0
  31. package/dist/lib/composeMutationKey.js.map +1 -0
  32. package/dist/lib/shelfMerge.d.ts +7 -0
  33. package/dist/lib/shelfMerge.d.ts.map +1 -0
  34. package/dist/lib/shelfMerge.js +28 -0
  35. package/dist/lib/shelfMerge.js.map +1 -0
  36. package/package.json +2 -2
  37. package/src/ServiceOperation.ts +156 -8
  38. package/src/callbacks/getMutationKey.ts +6 -34
  39. package/src/callbacks/useInfiniteQuery.ts +1 -36
  40. package/src/callbacks/useMutation.ts +7 -19
  41. package/src/callbacks/useMutationState.ts +73 -0
  42. package/src/callbacks/useSuspenseInfiniteQuery.ts +60 -0
  43. package/src/callbacks/useSuspenseQuery.ts +64 -0
  44. package/src/lib/composeMutationKey.test.ts +43 -0
  45. package/src/lib/composeMutationKey.ts +50 -0
  46. package/src/{callbacks → lib}/shelfMerge.test.ts +1 -1
  47. package/src/lib/shelfMerge.ts +35 -0
  48. package/src/qraftAPIClient.test.tsx +358 -2
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Merges objects with provided depth
3
+ * @param depth
4
+ * @param args
5
+ */
6
+ export function shelfMerge<T>(depth = 2, ...args: T[]): T {
7
+ return args.reduce((acc, arg) => {
8
+ if (!arg || typeof arg !== 'object') return acc;
9
+
10
+ Object.entries(arg).forEach(([key, value]) => {
11
+ if (typeof value !== 'object') {
12
+ acc[key as never] = value as never;
13
+ return;
14
+ }
15
+
16
+ if (Array.isArray(value)) {
17
+ acc[key as never] = value as never;
18
+ return;
19
+ }
20
+
21
+ if (depth > 1) {
22
+ acc[key as never] = shelfMerge(
23
+ depth - 1,
24
+ acc[key as never],
25
+ value
26
+ ) as never;
27
+ return;
28
+ }
29
+
30
+ acc[key as never] = value as never;
31
+ });
32
+
33
+ return acc;
34
+ }, {} as T);
35
+ }
@@ -9,8 +9,8 @@ import {
9
9
  import { act, renderHook, waitFor } from '@testing-library/react';
10
10
 
11
11
  import { createAPIClient } from './fixtures/api/index.js';
12
- import { bodySerializer, urlSerializer, request } from './lib/request.js';
13
- import { QraftContext, QraftContextValue } from './QraftContext.js';
12
+ import { bodySerializer, request, urlSerializer } from './lib/request.js';
13
+ import { QraftContextValue } from './QraftContext.js';
14
14
  import type { RequestClient } from './RequestClient.js';
15
15
 
16
16
  const qraft = createAPIClient();
@@ -130,6 +130,58 @@ describe('Qraft uses Queries', () => {
130
130
  });
131
131
  });
132
132
 
133
+ describe('Qraft uses Suspense Queries', () => {
134
+ it('supports useSuspenseQuery', async () => {
135
+ const hook = () => {
136
+ try {
137
+ return qraft.approvalPolicies.getApprovalPoliciesId.useSuspenseQuery({
138
+ header: {
139
+ 'x-monite-version': '1.0.0',
140
+ },
141
+ path: {
142
+ approval_policy_id: '1',
143
+ },
144
+ query: {
145
+ items_order: ['asc', 'desc'],
146
+ },
147
+ });
148
+ } catch (error) {
149
+ return error as Promise<unknown>;
150
+ }
151
+ };
152
+
153
+ const queryClient = new QueryClient();
154
+
155
+ const { result: resultWithErrorPromise } = renderHook(hook, {
156
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
157
+ });
158
+
159
+ expect(resultWithErrorPromise.current).toBeInstanceOf(Promise); // Suspense throws a promise
160
+
161
+ await resultWithErrorPromise.current;
162
+
163
+ const { result: resultWithData } = renderHook(hook, {
164
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
165
+ });
166
+
167
+ if (resultWithData.current instanceof Promise) {
168
+ throw new Error('Promise should be resolved');
169
+ }
170
+
171
+ expect(resultWithData.current.data).toEqual({
172
+ header: {
173
+ 'x-monite-version': '1.0.0',
174
+ },
175
+ path: {
176
+ approval_policy_id: '1',
177
+ },
178
+ query: {
179
+ items_order: ['asc', 'desc'],
180
+ },
181
+ });
182
+ });
183
+ });
184
+
133
185
  describe('Qraft uses Infinite Queries', () => {
134
186
  it('supports useInfiniteQuery', async () => {
135
187
  const { result } = renderHook(
@@ -292,6 +344,86 @@ describe('Qraft uses Infinite Queries', () => {
292
344
  });
293
345
  });
294
346
 
347
+ describe('Qraft uses Suspense Infinite Queries', () => {
348
+ it('supports useSuspenseInfiniteQuery', async () => {
349
+ const hook = () => {
350
+ try {
351
+ return qraft.files.getFiles.useSuspenseInfiniteQuery(
352
+ {
353
+ header: {
354
+ 'x-monite-version': '1.0.0',
355
+ },
356
+ query: {
357
+ id__in: ['1', '2'],
358
+ },
359
+ },
360
+ {
361
+ getNextPageParam: (lastPage, allPages, params) => {
362
+ return {
363
+ query: {
364
+ page: params.query?.page
365
+ ? String(Number(params.query.page) + 1)
366
+ : undefined,
367
+ },
368
+ };
369
+ },
370
+ initialPageParam: {
371
+ query: {
372
+ page: '1',
373
+ },
374
+ },
375
+ }
376
+ );
377
+ } catch (error) {
378
+ return error as Promise<unknown>;
379
+ }
380
+ };
381
+
382
+ const queryClient = new QueryClient();
383
+
384
+ const { result } = renderHook(hook, {
385
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
386
+ });
387
+
388
+ const { result: resultWithErrorPromise } = renderHook(hook, {
389
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
390
+ });
391
+
392
+ expect(resultWithErrorPromise.current).toBeInstanceOf(Promise); // Suspense throws a promise
393
+
394
+ await resultWithErrorPromise.current;
395
+
396
+ const { result: resultWithData } = renderHook(hook, {
397
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
398
+ });
399
+
400
+ if (resultWithData.current instanceof Promise) {
401
+ throw new Error('Promise should be resolved');
402
+ }
403
+
404
+ expect(resultWithData.current.data).toEqual({
405
+ pageParams: [
406
+ {
407
+ query: {
408
+ page: '1',
409
+ },
410
+ },
411
+ ],
412
+ pages: [
413
+ {
414
+ header: {
415
+ 'x-monite-version': '1.0.0',
416
+ },
417
+ query: {
418
+ id__in: ['1', '2'],
419
+ page: '1',
420
+ },
421
+ },
422
+ ],
423
+ });
424
+ });
425
+ });
426
+
295
427
  describe('Qraft uses Mutations', () => {
296
428
  it('supports useMutation without predefined parameters', async () => {
297
429
  const { result } = renderHook(
@@ -408,6 +540,230 @@ describe('Qraft uses Mutations', () => {
408
540
  });
409
541
  });
410
542
 
543
+ describe('Qraft uses Mutation State', () => {
544
+ const parameters = {
545
+ header: {
546
+ 'x-monite-version': '1.0.0',
547
+ },
548
+ path: {
549
+ entity_id: '1',
550
+ },
551
+ query: {
552
+ referer: 'https://example.com',
553
+ },
554
+ } as const;
555
+
556
+ it('supports useMutationState with filter', async () => {
557
+ const queryClient = new QueryClient();
558
+
559
+ const { result: mutationResult } = renderHook(
560
+ () => qraft.entities.postEntitiesIdDocuments.useMutation(parameters),
561
+ {
562
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
563
+ }
564
+ );
565
+
566
+ act(() => {
567
+ mutationResult.current.mutate({
568
+ verification_document_back: 'back',
569
+ verification_document_front: 'front',
570
+ });
571
+ });
572
+
573
+ await waitFor(() => {
574
+ expect(mutationResult.current.data).toBeDefined();
575
+ });
576
+
577
+ const { result: mutationStateResult } = renderHook(
578
+ () =>
579
+ qraft.entities.postEntitiesIdDocuments.useMutationState({
580
+ filters: {
581
+ parameters,
582
+ },
583
+ }),
584
+ {
585
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
586
+ }
587
+ );
588
+
589
+ expect(mutationStateResult.current.at(0)?.data).toEqual({
590
+ body: {
591
+ verification_document_back: 'back',
592
+ verification_document_front: 'front',
593
+ },
594
+ ...parameters,
595
+ });
596
+ });
597
+
598
+ it('supports useMutationState with filter and select', async () => {
599
+ const queryClient = new QueryClient();
600
+
601
+ const { result: mutationResult } = renderHook(
602
+ () => qraft.entities.postEntitiesIdDocuments.useMutation(parameters),
603
+ {
604
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
605
+ }
606
+ );
607
+
608
+ act(() => {
609
+ mutationResult.current.mutate({
610
+ verification_document_back: 'back',
611
+ verification_document_front: 'front',
612
+ });
613
+ });
614
+
615
+ await waitFor(() => {
616
+ expect(mutationResult.current.data).toBeDefined();
617
+ });
618
+
619
+ const { result: mutationStateResult } = renderHook(
620
+ () =>
621
+ qraft.entities.postEntitiesIdDocuments.useMutationState({
622
+ filters: {
623
+ parameters,
624
+ },
625
+ select(mutation) {
626
+ return (
627
+ mutation.state.data?.header?.['x-monite-version'] ===
628
+ parameters.header['x-monite-version']
629
+ );
630
+ },
631
+ }),
632
+ {
633
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
634
+ }
635
+ );
636
+
637
+ expect(mutationStateResult.current.at(0)).toEqual(true);
638
+ });
639
+
640
+ it('supports useMutationState with without filter', async () => {
641
+ const queryClient = new QueryClient();
642
+
643
+ const { result: mutationResult } = renderHook(
644
+ () => qraft.entities.postEntitiesIdDocuments.useMutation(parameters),
645
+ {
646
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
647
+ }
648
+ );
649
+
650
+ act(() => {
651
+ mutationResult.current.mutate({
652
+ verification_document_back: 'back',
653
+ verification_document_front: 'front',
654
+ });
655
+ });
656
+
657
+ await waitFor(() => {
658
+ expect(mutationResult.current.data).toBeDefined();
659
+ });
660
+
661
+ const { result: mutationStateResult } = renderHook(
662
+ () => qraft.entities.postEntitiesIdDocuments.useMutationState(),
663
+ {
664
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
665
+ }
666
+ );
667
+
668
+ expect(mutationStateResult.current.at(0)?.data).toEqual({
669
+ body: {
670
+ verification_document_back: 'back',
671
+ verification_document_front: 'front',
672
+ },
673
+ ...parameters,
674
+ });
675
+ });
676
+
677
+ it('supports useMutationState with mutationKey and select', async () => {
678
+ const queryClient = new QueryClient();
679
+
680
+ const { result: mutationHookResultToMatch } = renderHook(
681
+ () => qraft.entities.postEntitiesIdDocuments.useMutation(parameters),
682
+ {
683
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
684
+ }
685
+ );
686
+
687
+ act(() => {
688
+ mutationHookResultToMatch.current.mutate({
689
+ verification_document_back: 'back',
690
+ verification_document_front: 'front',
691
+ });
692
+ });
693
+
694
+ await waitFor(() => {
695
+ expect(mutationHookResultToMatch.current.data).toBeDefined();
696
+ });
697
+
698
+ const { result: mutationStateHookResult } = renderHook(
699
+ () =>
700
+ qraft.entities.postEntitiesIdDocuments.useMutationState({
701
+ filters: {
702
+ mutationKey:
703
+ qraft.entities.postEntitiesIdDocuments.getMutationKey(parameters),
704
+ },
705
+ select(mutation) {
706
+ return (
707
+ mutation.state.data?.header?.['x-monite-version'] ===
708
+ parameters.header['x-monite-version']
709
+ );
710
+ },
711
+ }),
712
+ {
713
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
714
+ }
715
+ );
716
+
717
+ expect(mutationStateHookResult.current.length).toEqual(1);
718
+ expect(mutationStateHookResult.current.at(0)).toEqual(true);
719
+ });
720
+
721
+ it('supports useMutationState with not partial parameters', async () => {
722
+ const queryClient = new QueryClient();
723
+
724
+ const { result: mutationHookResultToMatch } = renderHook(
725
+ () => qraft.entities.postEntitiesIdDocuments.useMutation(parameters),
726
+ {
727
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
728
+ }
729
+ );
730
+
731
+ act(() => {
732
+ mutationHookResultToMatch.current.mutate({
733
+ verification_document_back: 'back',
734
+ verification_document_front: 'front',
735
+ });
736
+ });
737
+
738
+ await waitFor(() => {
739
+ expect(mutationHookResultToMatch.current.data).toBeDefined();
740
+ });
741
+
742
+ const { result: mutationStateResult } = renderHook(
743
+ () =>
744
+ qraft.entities.postEntitiesIdDocuments.useMutationState({
745
+ filters: {
746
+ parameters: {
747
+ header: parameters.header,
748
+ },
749
+ },
750
+ select(mutation) {
751
+ return (
752
+ mutation.state.data?.header?.['x-monite-version'] ===
753
+ parameters.header['x-monite-version']
754
+ );
755
+ },
756
+ }),
757
+ {
758
+ wrapper: (props) => <Providers {...props} queryClient={queryClient} />,
759
+ }
760
+ );
761
+
762
+ expect(mutationStateResult.current.length).toEqual(1);
763
+ expect(mutationStateResult.current.at(0)).toEqual(true);
764
+ });
765
+ });
766
+
411
767
  describe('Qraft uses Query Function', () => {
412
768
  it('uses queryFn', async () => {
413
769
  const result = await qraft.approvalPolicies.getApprovalPoliciesId.queryFn(