|
1 | 1 | import { FeathersError, GeneralError } from '@feathersjs/errors';
|
2 |
| -import type { Application, Params } from '@feathersjs/feathers'; |
| 2 | +import type { Application, Paginated, Params } from '@feathersjs/feathers'; |
3 | 3 | import { flushPromises } from '@vue/test-utils';
|
4 | 4 | import { beforeEach, describe, expect, it, vi } from 'vitest';
|
5 | 5 | import { nextTick, ref } from 'vue';
|
@@ -423,6 +423,36 @@ describe('Find composition', () => {
|
423 | 423 | expect(findComposition && findComposition.error.value).toBeTruthy();
|
424 | 424 | });
|
425 | 425 |
|
| 426 | + it('should load single entity response', async () => { |
| 427 | + expect.assertions(3); |
| 428 | + |
| 429 | + // given |
| 430 | + const serviceFind = vi.fn(() => testModel); |
| 431 | + |
| 432 | + const feathersMock = { |
| 433 | + service: () => ({ |
| 434 | + find: serviceFind, |
| 435 | + on: vi.fn(), |
| 436 | + off: vi.fn(), |
| 437 | + }), |
| 438 | + on: vi.fn(), |
| 439 | + off: vi.fn(), |
| 440 | + } as unknown as Application; |
| 441 | + const useFind = useFindOriginal(feathersMock); |
| 442 | + |
| 443 | + // when |
| 444 | + let findComposition = null as UseFind<TestModel> | null; |
| 445 | + mountComposition(() => { |
| 446 | + findComposition = useFind('testModels'); |
| 447 | + }); |
| 448 | + await nextTick(); |
| 449 | + |
| 450 | + // then |
| 451 | + expect(serviceFind).toHaveBeenCalledTimes(1); |
| 452 | + expect(findComposition).toBeTruthy(); |
| 453 | + expect(findComposition && findComposition.data.value).toStrictEqual([testModel]); |
| 454 | + }); |
| 455 | + |
426 | 456 | describe('Event Handlers', () => {
|
427 | 457 | it('should listen to "create" events', () => {
|
428 | 458 | expect.assertions(2);
|
@@ -935,4 +965,173 @@ describe('Find composition', () => {
|
935 | 965 | expect(serviceOff).toHaveBeenCalledTimes(4); // unload of: created, updated, patched, removed events
|
936 | 966 | });
|
937 | 967 | });
|
| 968 | + |
| 969 | + describe('pagination', () => { |
| 970 | + it('should handle paginated data', async () => { |
| 971 | + expect.assertions(3); |
| 972 | + |
| 973 | + // given |
| 974 | + let startItemIndex = 0; |
| 975 | + const serviceFind = vi.fn(() => { |
| 976 | + const page: Paginated<TestModel> = { |
| 977 | + total: testModels.length, |
| 978 | + skip: startItemIndex, |
| 979 | + limit: 1, |
| 980 | + data: testModels.slice(startItemIndex, startItemIndex + 1), |
| 981 | + }; |
| 982 | + startItemIndex++; |
| 983 | + return page; |
| 984 | + }); |
| 985 | + |
| 986 | + const feathersMock = { |
| 987 | + service: () => ({ |
| 988 | + find: serviceFind, |
| 989 | + on: vi.fn(), |
| 990 | + off: vi.fn(), |
| 991 | + }), |
| 992 | + on: vi.fn(), |
| 993 | + off: vi.fn(), |
| 994 | + } as unknown as Application; |
| 995 | + const useFind = useFindOriginal(feathersMock); |
| 996 | + |
| 997 | + // when |
| 998 | + let findComposition = null as UseFind<TestModel> | null; |
| 999 | + mountComposition(() => { |
| 1000 | + findComposition = useFind('testModels'); |
| 1001 | + }); |
| 1002 | + await nextTick(); |
| 1003 | + |
| 1004 | + // then |
| 1005 | + expect(serviceFind).toHaveBeenCalledTimes(1); |
| 1006 | + expect(findComposition).toBeTruthy(); |
| 1007 | + expect(findComposition && findComposition.data.value).toStrictEqual(testModels.slice(0, 1)); |
| 1008 | + }); |
| 1009 | + |
| 1010 | + it('should load all data with chunking', async () => { |
| 1011 | + expect.assertions(3); |
| 1012 | + |
| 1013 | + // given |
| 1014 | + let startItemIndex = 0; |
| 1015 | + const serviceFind = vi.fn(() => { |
| 1016 | + const page: Paginated<TestModel> = { |
| 1017 | + total: testModels.length, |
| 1018 | + skip: startItemIndex, |
| 1019 | + limit: 1, |
| 1020 | + data: testModels.slice(startItemIndex, startItemIndex + 1), |
| 1021 | + }; |
| 1022 | + startItemIndex++; |
| 1023 | + return page; |
| 1024 | + }); |
| 1025 | + |
| 1026 | + const feathersMock = { |
| 1027 | + service: () => ({ |
| 1028 | + find: serviceFind, |
| 1029 | + on: vi.fn(), |
| 1030 | + off: vi.fn(), |
| 1031 | + }), |
| 1032 | + on: vi.fn(), |
| 1033 | + off: vi.fn(), |
| 1034 | + } as unknown as Application; |
| 1035 | + const useFind = useFindOriginal(feathersMock); |
| 1036 | + |
| 1037 | + // when |
| 1038 | + let findComposition = null as UseFind<TestModel> | null; |
| 1039 | + mountComposition(() => { |
| 1040 | + findComposition = useFind('testModels', undefined, { loadAllPages: true }); |
| 1041 | + }); |
| 1042 | + await nextTick(); |
| 1043 | + |
| 1044 | + // then |
| 1045 | + expect(serviceFind).toHaveBeenCalledTimes(2); |
| 1046 | + expect(findComposition).toBeTruthy(); |
| 1047 | + expect(findComposition && findComposition.data.value).toStrictEqual(testModels); |
| 1048 | + }); |
| 1049 | + |
| 1050 | + it('should load data with pagination using lastEvaluatedKey patterns', async () => { |
| 1051 | + expect.assertions(3); |
| 1052 | + |
| 1053 | + // given |
| 1054 | + const serviceFind = vi.fn((params?: Params) => { |
| 1055 | + const startItemIndex = testModels.findIndex(({ _id }) => _id === params?.query?.$skip) + 1; |
| 1056 | + const data = testModels.slice(startItemIndex, startItemIndex + 1); |
| 1057 | + const page: Paginated<TestModel> = { |
| 1058 | + total: testModels.length, |
| 1059 | + skip: data[data.length - 1]._id as unknown as number, |
| 1060 | + limit: 1, |
| 1061 | + data, |
| 1062 | + }; |
| 1063 | + return page; |
| 1064 | + }); |
| 1065 | + |
| 1066 | + const feathersMock = { |
| 1067 | + service: () => ({ |
| 1068 | + find: serviceFind, |
| 1069 | + on: vi.fn(), |
| 1070 | + off: vi.fn(), |
| 1071 | + }), |
| 1072 | + on: vi.fn(), |
| 1073 | + off: vi.fn(), |
| 1074 | + } as unknown as Application; |
| 1075 | + const useFind = useFindOriginal(feathersMock); |
| 1076 | + |
| 1077 | + // when |
| 1078 | + let findComposition = null as UseFind<TestModel> | null; |
| 1079 | + mountComposition(() => { |
| 1080 | + findComposition = useFind('testModels', undefined, { loadAllPages: true }); |
| 1081 | + }); |
| 1082 | + await nextTick(); |
| 1083 | + |
| 1084 | + // then |
| 1085 | + expect(serviceFind).toHaveBeenCalledTimes(2); |
| 1086 | + expect(findComposition).toBeTruthy(); |
| 1087 | + expect(findComposition && findComposition.data.value).toStrictEqual(testModels); |
| 1088 | + }); |
| 1089 | + |
| 1090 | + it('should stop further page requests if find was retriggered due to a change to params or connection reset', async () => { |
| 1091 | + expect.assertions(3); |
| 1092 | + |
| 1093 | + // given |
| 1094 | + let startItemIndex = 0; |
| 1095 | + let data = [additionalTestModel, ...testModels]; |
| 1096 | + const serviceFind = vi.fn(() => { |
| 1097 | + const page: Paginated<TestModel> = { |
| 1098 | + total: data.length, |
| 1099 | + skip: startItemIndex, |
| 1100 | + limit: 1, |
| 1101 | + data: data.slice(startItemIndex, startItemIndex + 1), |
| 1102 | + }; |
| 1103 | + startItemIndex++; |
| 1104 | + return page; |
| 1105 | + }); |
| 1106 | + const emitter = eventHelper(); |
| 1107 | + const feathersMock = { |
| 1108 | + service: () => ({ |
| 1109 | + find: serviceFind, |
| 1110 | + on: vi.fn(), |
| 1111 | + off: vi.fn(), |
| 1112 | + }), |
| 1113 | + on: emitter.on, |
| 1114 | + off: vi.fn(), |
| 1115 | + } as unknown as Application; |
| 1116 | + const useFind = useFindOriginal(feathersMock); |
| 1117 | + let findComposition = null as UseFind<TestModel> | null; |
| 1118 | + mountComposition(() => { |
| 1119 | + findComposition = useFind('testModels', undefined, { loadAllPages: true }); |
| 1120 | + }); |
| 1121 | + await nextTick(); |
| 1122 | + serviceFind.mockClear(); |
| 1123 | + data = testModels; |
| 1124 | + startItemIndex = 0; |
| 1125 | + |
| 1126 | + // when |
| 1127 | + emitter.emit('connect'); |
| 1128 | + await nextTick(); |
| 1129 | + await nextTick(); |
| 1130 | + |
| 1131 | + // then |
| 1132 | + expect(serviceFind).toHaveBeenCalledTimes(2); |
| 1133 | + expect(findComposition).toBeTruthy(); |
| 1134 | + expect(findComposition && findComposition.data.value).toStrictEqual(testModels); |
| 1135 | + }); |
| 1136 | + }); |
938 | 1137 | });
|
0 commit comments