@amityco/ts-sdk 0.0.1-beta.31 → 0.0.1-beta.33

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 (110) hide show
  1. package/dist/cache/api/backupCache.d.ts.map +1 -1
  2. package/dist/cache/api/ingestInCache.d.ts +1 -1
  3. package/dist/cache/api/tests/ingestInCache.test.d.ts +2 -0
  4. package/dist/cache/api/tests/ingestInCache.test.d.ts.map +1 -0
  5. package/dist/cache/api/tests/pushToCache.test.d.ts +2 -0
  6. package/dist/cache/api/tests/pushToCache.test.d.ts.map +1 -0
  7. package/dist/channel/api/addChannelMembers.d.ts.map +1 -1
  8. package/dist/channel/api/getChannel.d.ts.map +1 -1
  9. package/dist/channel/api/tests/addChannelMembers.test.d.ts +2 -0
  10. package/dist/channel/api/tests/addChannelMembers.test.d.ts.map +1 -0
  11. package/dist/channel/api/tests/getChannel.test.d.ts +2 -0
  12. package/dist/channel/api/tests/getChannel.test.d.ts.map +1 -0
  13. package/dist/channel/events/onChannelMemberAdded.d.ts.map +1 -1
  14. package/dist/core/events.d.ts +1 -1
  15. package/dist/core/events.d.ts.map +1 -1
  16. package/dist/core/model/idResolvers.d.ts.map +1 -1
  17. package/dist/core/transports/http.d.ts +5 -0
  18. package/dist/core/transports/http.d.ts.map +1 -1
  19. package/dist/core/transports/test/http.test.d.ts +2 -0
  20. package/dist/core/transports/test/http.test.d.ts.map +1 -0
  21. package/dist/index.cjs.js +61 -51
  22. package/dist/index.esm.js +60 -51
  23. package/dist/index.umd.js +4 -4
  24. package/dist/message/api/deleteMessage.d.ts.map +1 -1
  25. package/dist/message/api/tests/deleteMessage.test.d.ts +2 -0
  26. package/dist/message/api/tests/deleteMessage.test.d.ts.map +1 -0
  27. package/dist/message/{tests/api → api/tests}/getMessage.test.d.ts +0 -0
  28. package/dist/message/api/tests/getMessage.test.d.ts.map +1 -0
  29. package/dist/message/api/tests/getMessages.test.d.ts +2 -0
  30. package/dist/message/api/tests/getMessages.test.d.ts.map +1 -0
  31. package/dist/message/api/tests/queryMessages.test.d.ts +2 -0
  32. package/dist/message/api/tests/queryMessages.test.d.ts.map +1 -0
  33. package/dist/message/api/tests/updateMessage.test.d.ts +2 -0
  34. package/dist/message/api/tests/updateMessage.test.d.ts.map +1 -0
  35. package/dist/reaction/api/addReaction.d.ts.map +1 -1
  36. package/dist/reaction/api/removeReaction.d.ts.map +1 -1
  37. package/dist/reaction/api/tests/addReaction.test.d.ts +2 -0
  38. package/dist/reaction/api/tests/addReaction.test.d.ts.map +1 -0
  39. package/dist/reaction/api/tests/removeReaction.test.d.ts +2 -0
  40. package/dist/reaction/api/tests/removeReaction.test.d.ts.map +1 -0
  41. package/dist/user/api/getUser.d.ts.map +1 -1
  42. package/dist/user/api/queryUsers.d.ts.map +1 -1
  43. package/dist/user/api/tests/queryUsers.test.d.ts +2 -0
  44. package/dist/user/api/tests/queryUsers.test.d.ts.map +1 -0
  45. package/dist/utils/tests/dummy/channel.d.ts +6 -0
  46. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  47. package/dist/utils/tests/dummy/community.d.ts +4 -0
  48. package/dist/utils/tests/dummy/community.d.ts.map +1 -0
  49. package/dist/utils/tests/dummy/file.d.ts +2 -0
  50. package/dist/utils/tests/dummy/file.d.ts.map +1 -0
  51. package/dist/utils/tests/dummy/follow.d.ts +1 -0
  52. package/dist/utils/tests/dummy/follow.d.ts.map +1 -1
  53. package/dist/utils/tests/dummy/index.d.ts +5 -0
  54. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  55. package/dist/utils/tests/dummy/message.d.ts +5 -0
  56. package/dist/utils/tests/dummy/message.d.ts.map +1 -1
  57. package/dist/utils/tests/dummy/poll.d.ts +3 -0
  58. package/dist/utils/tests/dummy/poll.d.ts.map +1 -0
  59. package/dist/utils/tests/dummy/post.d.ts +15 -1
  60. package/dist/utils/tests/dummy/post.d.ts.map +1 -1
  61. package/dist/utils/tests/dummy/reaction.d.ts +4 -0
  62. package/dist/utils/tests/dummy/reaction.d.ts.map +1 -0
  63. package/dist/utils/tests/dummy/role.d.ts +4 -0
  64. package/dist/utils/tests/dummy/role.d.ts.map +1 -0
  65. package/dist/utils/tests/dummy/user.d.ts +1 -0
  66. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  67. package/package.json +2 -1
  68. package/src/cache/api/backupCache.ts +0 -1
  69. package/src/cache/api/ingestInCache.ts +2 -2
  70. package/src/cache/api/tests/ingestInCache.test.ts +87 -0
  71. package/src/cache/api/tests/pushToCache.test.ts +57 -0
  72. package/src/channel/api/addChannelMembers.ts +9 -1
  73. package/src/channel/api/getChannel.ts +20 -5
  74. package/src/channel/api/tests/addChannelMembers.test.ts +95 -0
  75. package/src/channel/api/tests/getChannel.test.ts +108 -0
  76. package/src/channel/api/tests/queryChannels.test.ts +20 -0
  77. package/src/channel/events/onChannelMemberAdded.ts +1 -1
  78. package/src/channel/observers/tests/liveChannels.test.ts +0 -1
  79. package/src/core/events.ts +1 -1
  80. package/src/core/model/idResolvers.ts +1 -1
  81. package/src/core/transports/http.ts +3 -17
  82. package/src/core/transports/test/http.test.ts +83 -0
  83. package/src/message/api/deleteMessage.ts +2 -3
  84. package/src/message/api/tests/createMessage.test.ts +74 -51
  85. package/src/message/api/tests/deleteMessage.test.ts +110 -0
  86. package/src/message/api/tests/getMessage.test.ts +121 -0
  87. package/src/message/api/tests/getMessages.test.ts +108 -0
  88. package/src/message/api/tests/queryMessages.test.ts +115 -0
  89. package/src/message/api/tests/updateMessage.test.ts +100 -0
  90. package/src/post/tests/api/queryPosts.test.ts +117 -18
  91. package/src/reaction/api/addReaction.ts +17 -6
  92. package/src/reaction/api/removeReaction.ts +17 -6
  93. package/src/reaction/api/tests/addReaction.test.ts +73 -0
  94. package/src/reaction/api/tests/removeReaction.test.ts +79 -0
  95. package/src/user/api/getUser.ts +1 -2
  96. package/src/user/api/queryUsers.ts +24 -5
  97. package/src/user/api/tests/queryUsers.test.ts +124 -0
  98. package/src/utils/tests/dummy/channel.ts +9 -1
  99. package/src/utils/tests/dummy/community.ts +44 -0
  100. package/src/utils/tests/dummy/file.ts +20 -0
  101. package/src/utils/tests/dummy/follow.ts +6 -0
  102. package/src/utils/tests/dummy/index.ts +9 -0
  103. package/src/utils/tests/dummy/message.ts +8 -1
  104. package/src/utils/tests/dummy/poll.ts +43 -0
  105. package/src/utils/tests/dummy/post.ts +65 -4
  106. package/src/utils/tests/dummy/reaction.ts +22 -0
  107. package/src/utils/tests/dummy/role.ts +21 -0
  108. package/src/utils/tests/dummy/user.ts +7 -1
  109. package/dist/message/tests/api/getMessage.test.d.ts.map +0 -1
  110. package/src/message/tests/api/getMessage.test.ts +0 -96
@@ -0,0 +1,121 @@
1
+ import { disableCache, enableCache, pullFromCache, pushToCache } from '~/cache/api';
2
+ import { isInTombstone } from '~/cache/api/isInTombstone';
3
+ import { pushToTombstone } from '~/cache/api/pushToTombstone';
4
+ import { ASCApiError } from '~/core/errors';
5
+ import { client, message11 } from '~/utils/tests';
6
+
7
+ import { getMessage } from '../getMessage';
8
+ import { onMessageFetched } from '../../events';
9
+
10
+ const messageToGet = message11;
11
+ const { messageId } = messageToGet;
12
+
13
+ const getResolvedMessageValue = () => ({
14
+ data: {
15
+ messages: [messageToGet],
16
+ users: [],
17
+ files: [],
18
+ },
19
+ });
20
+
21
+ describe('getMessage', () => {
22
+ test('should return fetched message', async () => {
23
+ client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
24
+
25
+ await expect(getMessage(messageId)).resolves.toEqual(
26
+ expect.objectContaining({ data: messageToGet }),
27
+ );
28
+ });
29
+
30
+ test('should update cache after fetching message', async () => {
31
+ enableCache();
32
+ client.http.get = jest.fn().mockResolvedValue(getResolvedMessageValue());
33
+
34
+ await getMessage(messageId);
35
+ const recieved = pullFromCache(['message', 'get', messageId])?.data;
36
+
37
+ expect(recieved).toEqual(messageToGet);
38
+
39
+ disableCache();
40
+ });
41
+
42
+ test('should throw an error if request fails', async () => {
43
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
44
+
45
+ await expect(getMessage(messageId)).rejects.toThrow('error');
46
+ });
47
+
48
+ test('should fire event `onMessageFetched`', async () => {
49
+ let dispose;
50
+ client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
51
+
52
+ const callbackPromise = new Promise(resolve => {
53
+ dispose = onMessageFetched(resolve);
54
+ }).finally(dispose);
55
+
56
+ await getMessage(messageId);
57
+
58
+ await expect(callbackPromise).resolves.toEqual(messageToGet);
59
+ });
60
+ });
61
+
62
+ describe('getMessage tombostone', () => {
63
+ beforeEach(() => enableCache());
64
+ afterEach(() => disableCache());
65
+
66
+ test('should add message to tombostone if 404', async () => {
67
+ expect.assertions(2);
68
+
69
+ client.http.get = jest
70
+ .fn()
71
+ .mockRejectedValueOnce(
72
+ new ASCApiError('not found!', Amity.ServerError.ITEM_NOT_FOUND, Amity.ErrorLevel.ERROR),
73
+ );
74
+
75
+ await expect(getMessage(messageId)).rejects.toThrow();
76
+
77
+ expect(() => isInTombstone('message', messageId)).toThrow();
78
+ });
79
+
80
+ test('should throw error if message not found in tombostone', async () => {
81
+ pushToTombstone('message', messageId);
82
+
83
+ await expect(getMessage(messageId)).rejects.toThrow();
84
+ });
85
+ });
86
+
87
+ describe('getMessage.locally', () => {
88
+ beforeEach(() => enableCache());
89
+ afterEach(() => disableCache());
90
+
91
+ test('should return cached message', () => {
92
+ pushToCache(['message', 'get', messageId], messageToGet);
93
+
94
+ expect(getMessage.locally(messageId)?.data).toBe(messageToGet);
95
+ });
96
+
97
+ test('it should return undefined if message not in cache', () => {
98
+ expect(getMessage.locally('non-existent-message')).toBeUndefined();
99
+ });
100
+
101
+ test('should return undefined if cache not enabled', () => {
102
+ disableCache();
103
+ pushToCache(['message', 'get', messageId], messageToGet);
104
+
105
+ expect(getMessage.locally(messageId)).toBeUndefined();
106
+ });
107
+
108
+ test('should return undefined if 404', async () => {
109
+ expect.assertions(2);
110
+ pushToCache(['message', 'get', messageId], messageToGet);
111
+
112
+ client.http.get = jest
113
+ .fn()
114
+ .mockRejectedValueOnce(
115
+ new ASCApiError('not found!', Amity.ServerError.ITEM_NOT_FOUND, Amity.ErrorLevel.ERROR),
116
+ );
117
+
118
+ await expect(getMessage(messageId)).rejects.toThrow();
119
+ expect(getMessage.locally(messageId)).toBeUndefined();
120
+ });
121
+ });
@@ -0,0 +1,108 @@
1
+ import { disableCache, enableCache, pullFromCache, pushToCache } from '~/cache/api';
2
+ import { ASCApiError } from '~/core/errors';
3
+ import { client, message11 } from '~/utils/tests';
4
+
5
+ import { getMessages } from '../getMessages';
6
+ import { onMessageFetched } from '../../events';
7
+
8
+ const messagesToGet = [
9
+ { ...message11, messageId: 'message11' },
10
+ { ...message11, messageId: 'message12' },
11
+ ];
12
+ const messageIds = ['message11', 'message12'];
13
+
14
+ const getResolvedMessageValue = () => ({
15
+ data: {
16
+ messages: messagesToGet,
17
+ users: [],
18
+ files: [],
19
+ },
20
+ });
21
+
22
+ describe('getMessages', () => {
23
+ test('should return fetched messages', async () => {
24
+ client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
25
+
26
+ await expect(getMessages(messageIds)).resolves.toEqual(
27
+ expect.objectContaining({ data: messagesToGet }),
28
+ );
29
+ });
30
+
31
+ test('should update cache after fetching messages', async () => {
32
+ enableCache();
33
+ client.http.get = jest.fn().mockResolvedValue(getResolvedMessageValue());
34
+
35
+ await getMessages(messageIds);
36
+
37
+ const recieved = messageIds.map(
38
+ messageId => pullFromCache(['message', 'get', messageId])?.data,
39
+ );
40
+
41
+ expect(recieved).toEqual(messagesToGet);
42
+
43
+ disableCache();
44
+ });
45
+
46
+ test('should throw an error if request fails', async () => {
47
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
48
+
49
+ await expect(getMessages(messageIds)).rejects.toThrow('error');
50
+ });
51
+
52
+ test('should fire event `onMessageFetched`', async () => {
53
+ let dispose;
54
+ client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
55
+
56
+ const callbackPromise = new Promise(resolve => {
57
+ dispose = onMessageFetched(resolve);
58
+ }).finally(dispose);
59
+
60
+ await getMessages(messageIds);
61
+ await expect(callbackPromise).resolves.toEqual(messagesToGet[0]);
62
+ });
63
+ });
64
+
65
+ describe('getMessages tombostone', () => {
66
+ test.todo('should add messages to tombostone if 404');
67
+ test.todo('should throw error if messages not found in tombostone');
68
+ });
69
+
70
+ describe('getMessages.locally', () => {
71
+ beforeEach(() => enableCache());
72
+ afterEach(() => disableCache());
73
+
74
+ test('should return cached messages', () => {
75
+ messagesToGet.forEach(message => pushToCache(['message', 'get', message.messageId], message));
76
+
77
+ expect(getMessages.locally(messageIds)?.data).toEqual(messagesToGet);
78
+ });
79
+
80
+ test('it should return undefined if message not in cache', () => {
81
+ expect(getMessages.locally(['non-existent-message'])).toBeUndefined();
82
+ });
83
+
84
+ test('should return undefined if cache not enabled', () => {
85
+ disableCache();
86
+ messagesToGet.forEach(message => pushToCache(['message', 'get', message.messageId], message));
87
+
88
+ expect(getMessages.locally(messageIds)).toBeUndefined();
89
+ });
90
+
91
+ /* TODO: re-enable this once tombstone has been implemented */
92
+ test.skip('should return undefined if 404', async () => {
93
+ expect.assertions(2);
94
+
95
+ const error = new ASCApiError(
96
+ 'not found!',
97
+ Amity.ServerError.ITEM_NOT_FOUND,
98
+ Amity.ErrorLevel.ERROR,
99
+ );
100
+
101
+ client.http.get = jest.fn().mockRejectedValueOnce(error);
102
+ messagesToGet.forEach(message => pushToCache(['message', 'get', message.messageId], message));
103
+
104
+ await expect(getMessages(messageIds)).rejects.toThrow();
105
+
106
+ expect(getMessages.locally(messageIds)).toBeUndefined();
107
+ });
108
+ });
@@ -0,0 +1,115 @@
1
+ import { disableCache, enableCache, pullFromCache, pushToCache } from '~/cache/api';
2
+ import { client, message11 } from '~/utils/tests';
3
+
4
+ import { queryMessages } from '../queryMessages';
5
+ import { onMessageFetched } from '../../events';
6
+
7
+ const messagesToQuery = [
8
+ { ...message11, messageId: 'message11' },
9
+ { ...message11, messageId: 'message12' },
10
+ ];
11
+ const messageIds = ['message11', 'message12'];
12
+ const queryCriteriaWithoutPage = { channelId: messagesToQuery[0].channelId };
13
+ const pagingCriteria = { limit: 10 };
14
+ const queryCriteria = { ...queryCriteriaWithoutPage, page: pagingCriteria };
15
+ const pagingToken = {
16
+ previous: 'eyJiZWZvcmUiOjU1LCJsYXN0IjoxMH0=',
17
+ next: 'eyJiZWZvcmUiOjU1LCJsYXN0IjoxMH0=',
18
+ };
19
+
20
+ const getResolvedMessageValue = () => ({
21
+ data: {
22
+ messages: messagesToQuery,
23
+ files: [],
24
+ users: [],
25
+ paging: pagingToken,
26
+ },
27
+ });
28
+
29
+ describe('queryMessages', () => {
30
+ test('should return fetched messages with correct paging', async () => {
31
+ client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
32
+
33
+ await expect(queryMessages(queryCriteria)).resolves.toEqual(
34
+ expect.objectContaining({
35
+ data: messagesToQuery,
36
+ prevPage: { before: 55, limit: 10 },
37
+ nextPage: { before: 55, limit: 10 },
38
+ }),
39
+ );
40
+ });
41
+
42
+ test('should update cache after fetching messages', async () => {
43
+ enableCache();
44
+ client.http.get = jest.fn().mockResolvedValue(getResolvedMessageValue());
45
+
46
+ await queryMessages(queryCriteria);
47
+
48
+ const recieved = pullFromCache([
49
+ 'message',
50
+ 'query',
51
+ { ...queryCriteriaWithoutPage, options: pagingCriteria },
52
+ ])?.data;
53
+
54
+ expect(recieved).toEqual({
55
+ messages: messageIds,
56
+ paging: pagingToken,
57
+ });
58
+
59
+ disableCache();
60
+ });
61
+
62
+ test('should throw an error if request fails', async () => {
63
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
64
+
65
+ await expect(queryMessages(queryCriteria)).rejects.toThrow('error');
66
+ });
67
+
68
+ test('should fire event `onMessageFetched`', async () => {
69
+ let dispose;
70
+
71
+ client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
72
+
73
+ const callbackPromise = new Promise(resolve => {
74
+ dispose = onMessageFetched(resolve);
75
+ }).finally(dispose);
76
+
77
+ await queryMessages(queryCriteria);
78
+ await expect(callbackPromise).resolves.toEqual(messagesToQuery[0]);
79
+ });
80
+ });
81
+
82
+ describe('queryMessages.locally', () => {
83
+ beforeEach(() => enableCache());
84
+ afterEach(() => disableCache());
85
+
86
+ test('should return cached messages', () => {
87
+ messagesToQuery.forEach(message => pushToCache(['message', 'get', message.messageId], message));
88
+
89
+ pushToCache(['message', 'query', { ...queryCriteriaWithoutPage, options: pagingCriteria }], {
90
+ messages: messageIds,
91
+ paging: pagingToken,
92
+ });
93
+
94
+ expect(queryMessages.locally(queryCriteria)).toEqual(
95
+ expect.objectContaining({
96
+ data: messagesToQuery,
97
+ prevPage: { before: 55, limit: 10 },
98
+ nextPage: { before: 55, limit: 10 },
99
+ }),
100
+ );
101
+ });
102
+
103
+ test(`shouldn't return if individual message cache not exist`, () => {
104
+ pushToCache(['message', 'query', { ...queryCriteriaWithoutPage, options: pagingCriteria }], {
105
+ messages: messageIds,
106
+ paging: pagingToken,
107
+ });
108
+
109
+ expect(queryMessages.locally(queryCriteria)).toBeUndefined();
110
+ });
111
+
112
+ test('it should return undefined if message not in cache', () => {
113
+ expect(queryMessages.locally({ channelId: 'non-existent' })).toBeUndefined();
114
+ });
115
+ });
@@ -0,0 +1,100 @@
1
+ import { disableCache, enableCache, pullFromCache, pushToCache } from '~/cache/api';
2
+ import { client, message11 } from '~/utils/tests';
3
+
4
+ import { updateMessage } from '../updateMessage';
5
+ import { onMessageUpdated } from '../../events';
6
+
7
+ const messageToUpdate = message11;
8
+ const { messageId } = messageToUpdate;
9
+ const patch = { data: { text: 'hello world' } };
10
+ const updatedMessage = { ...messageToUpdate, ...patch };
11
+ const { updatedAt, ...updatedMessageWithoutTS } = updatedMessage;
12
+
13
+ const getResolvedMessageValue = () => ({
14
+ data: {
15
+ messages: [updatedMessage],
16
+ users: [],
17
+ files: [],
18
+ },
19
+ });
20
+
21
+ describe('updateMessage', () => {
22
+ test('should return updated message', async () => {
23
+ client.http.put = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
24
+
25
+ const recieved = updateMessage(messageId, patch);
26
+
27
+ await expect(recieved).resolves.toEqual(
28
+ expect.objectContaining({ data: updatedMessageWithoutTS }),
29
+ );
30
+ });
31
+
32
+ test('should throw an error if request fails', async () => {
33
+ client.http.put = jest.fn().mockRejectedValueOnce(new Error('error'));
34
+
35
+ await expect(updateMessage(messageId, patch)).rejects.toThrow('error');
36
+ });
37
+
38
+ test('should update cache after updated messages', async () => {
39
+ enableCache();
40
+ client.http.put = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
41
+
42
+ await updateMessage(messageId, patch);
43
+ const recieved = pullFromCache<Amity.Message>(['message', 'get', messageId])?.data;
44
+
45
+ expect(recieved).toEqual(expect.objectContaining(patch));
46
+
47
+ disableCache();
48
+ });
49
+
50
+ test('should fire event `onMessageUpdated`', async () => {
51
+ let dispose;
52
+ client.http.put = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
53
+
54
+ const callbackPromise = new Promise(resolve => {
55
+ dispose = onMessageUpdated(resolve);
56
+ }).finally(dispose);
57
+
58
+ await updateMessage(messageId, patch);
59
+
60
+ await expect(callbackPromise).resolves.toEqual(
61
+ expect.objectContaining(updatedMessageWithoutTS),
62
+ );
63
+ });
64
+ });
65
+
66
+ describe('updateMessage.optimistically', () => {
67
+ beforeEach(() => enableCache());
68
+ afterEach(() => disableCache());
69
+
70
+ test('should update cache after updated message', () => {
71
+ pushToCache(['message', 'get', messageId], messageToUpdate);
72
+
73
+ updateMessage.optimistically(messageId, patch);
74
+ const recieved = pullFromCache<Amity.Message>(['message', 'get', messageId])?.data;
75
+
76
+ expect(recieved).toEqual(expect.objectContaining(patch));
77
+ });
78
+
79
+ test('should fire event `onMessageUpdated`', async () => {
80
+ let dispose;
81
+
82
+ const callbackPromise = new Promise(resolve => {
83
+ dispose = onMessageUpdated(data => {
84
+ resolve(data);
85
+ });
86
+ }).finally(dispose);
87
+
88
+ updateMessage.optimistically(messageId, patch);
89
+
90
+ await expect(callbackPromise).resolves.toEqual(
91
+ expect.objectContaining(updatedMessageWithoutTS),
92
+ );
93
+ });
94
+
95
+ test('should define object as unsynced object', () => {
96
+ pushToCache(['message', 'get', messageId], messageToUpdate);
97
+
98
+ expect(updateMessage.optimistically(messageId, patch)?.cachedAt).toBe(-1);
99
+ });
100
+ });
@@ -1,23 +1,122 @@
1
- import { queryPosts } from '~/post/api';
2
- import { client, posts } from '~/utils/tests';
3
-
4
- describe('post/api', () => {
5
- test('should return a post query', async () => {
6
- const returnValue = [{ postId: posts.page1[0] }];
7
-
8
- client.http.get = jest.fn().mockResolvedValue({
9
- data: {
10
- posts: returnValue,
11
- paging: {},
12
- },
13
- });
1
+ import { getResolver } from '~/core/model';
2
+
3
+ import { disableCache, enableCache, pushToCache } from '~/cache/api';
4
+ import { ingestInCache } from '~/cache/api/ingestInCache';
5
+
6
+ import { client, postQueryResponse } from '~/utils/tests';
7
+
8
+ import { queryPosts } from '../../api/queryPosts';
9
+
10
+ const params = { targetType: 'user', targetId: 'test' } as Amity.QueryPosts;
11
+
12
+ describe('queryPosts', () => {
13
+ test('it should return posts', async () => {
14
+ const { posts: expected } = postQueryResponse.data;
15
+ client.http.get = jest.fn().mockResolvedValue(postQueryResponse);
16
+
17
+ const { data } = await queryPosts(params);
18
+
19
+ expect(data).toEqual(expected);
20
+ });
21
+
22
+ test('it should throw error', async () => {
23
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
24
+
25
+ await expect(queryPosts(params)).rejects.toThrow('error');
26
+ });
27
+
28
+ test('it should update cache upon fetching data from server', async () => {
29
+ enableCache();
30
+
31
+ client.http.get = jest.fn().mockResolvedValue(postQueryResponse);
32
+
33
+ const { data: expected } = await queryPosts(params);
34
+ const { data: received } = queryPosts.locally(params)!;
35
+
36
+ expect(received).toBeDefined();
37
+ expect(received).toEqual(expected);
38
+
39
+ disableCache();
40
+ });
41
+ });
42
+
43
+ describe('queryPosts.locally', () => {
44
+ const cacheKey = ['post', 'query', { ...params, options: { limit: 10 } } as Amity.Serializable];
45
+
46
+ test('it should fetch query locally if present in cache', () => {
47
+ enableCache();
48
+
49
+ const { data } = postQueryResponse;
50
+ const { posts: expected, paging } = data;
51
+
52
+ ingestInCache(data as Amity.PostPayload);
53
+
54
+ pushToCache(cacheKey, { posts: expected.map(getResolver('post')), paging });
14
55
 
15
- const data = await queryPosts({
16
- targetId: posts.targetId,
17
- targetType: posts.targetType,
56
+ const { data: received } = queryPosts.locally(params)!;
57
+
58
+ expect(received).toBeDefined();
59
+ expect(received).toEqual(expected);
60
+
61
+ disableCache();
62
+ });
63
+
64
+ test('it should return undefined if only partial data in cache', () => {
65
+ enableCache();
66
+
67
+ const { data } = postQueryResponse;
68
+ const { posts, paging } = data;
69
+
70
+ // ingest incomplete data
71
+ ingestInCache({
72
+ ...data,
73
+ posts: [data.posts[0]],
74
+ } as Amity.PostPayload);
75
+
76
+ pushToCache(cacheKey, {
77
+ posts: posts.map(getResolver('post')),
78
+ paging,
18
79
  });
19
80
 
20
- expect(data).toBeDefined();
21
- expect(data?.data).toEqual(returnValue);
81
+ const received = queryPosts.locally(params)!;
82
+
83
+ expect(received).toBeUndefined();
84
+
85
+ disableCache();
86
+ });
87
+
88
+ // added because of comment above cache key in queryPosts
89
+ test('it should return undefined if params do not match', () => {
90
+ enableCache();
91
+
92
+ const { data } = postQueryResponse;
93
+ const { posts: expected, paging } = data;
94
+
95
+ ingestInCache(data as Amity.PostPayload);
96
+
97
+ pushToCache(cacheKey, { posts: expected.map(getResolver('post')), paging });
98
+
99
+ const { data: received } = queryPosts.locally(params)!;
100
+ const received2 = queryPosts.locally({ ...params, tags: ['tag1'] })!;
101
+
102
+ expect(received).toBeDefined();
103
+ expect(received).toEqual(expected);
104
+ expect(received2).toBeUndefined();
105
+
106
+ disableCache();
107
+ });
108
+
109
+ test('it should return undefined if data not in cache', () => {
110
+ enableCache();
111
+
112
+ const received = queryPosts.locally(params);
113
+
114
+ expect(received).toBeUndefined();
115
+
116
+ disableCache();
117
+ });
118
+
119
+ test('it should return undefined if cache disabled', () => {
120
+ expect(queryPosts.locally(params)).toBeUndefined();
22
121
  });
23
122
  });
@@ -1,8 +1,9 @@
1
1
  import { getActiveClient } from '~/client/api';
2
2
 
3
- import { upsertInCache, pullFromCache } from '~/cache/api';
3
+ import { upsertInCache, pullFromCache, pushToCache } from '~/cache/api';
4
4
 
5
- import { dispatchReactable, fetchReference } from '../utils';
5
+ import { UNSYNCED_OBJECT_CACHED_AT_VALUE } from '~/utils/constants';
6
+ import { dispatchReactable } from '../utils';
6
7
 
7
8
  /**
8
9
  * ```js
@@ -38,10 +39,18 @@ export const addReaction = async (
38
39
  reactionName,
39
40
  });
40
41
 
41
- const model = await fetchReference(referenceType, referenceId);
42
- dispatchReactable(referenceType, model.data);
42
+ if (client.cache) {
43
+ const model = pullFromCache<Amity.Model[Amity.ReactableType]>([
44
+ referenceType,
45
+ 'get',
46
+ referenceId,
47
+ ]);
43
48
 
44
- return model.data.myReactions?.includes(reactionName) ?? false;
49
+ model?.data &&
50
+ pushToCache([referenceType, 'get', referenceId], model.data, { cachedAt: Date.now() });
51
+ }
52
+
53
+ return true;
45
54
  };
46
55
 
47
56
  /**
@@ -91,7 +100,9 @@ addReaction.optimistically = (
91
100
  },
92
101
  } as Amity.Model[Amity.ReactableType];
93
102
 
94
- upsertInCache([referenceType, 'get', referenceId], reaction, { cachedAt: -1 });
103
+ upsertInCache([referenceType, 'get', referenceId], reaction, {
104
+ cachedAt: UNSYNCED_OBJECT_CACHED_AT_VALUE,
105
+ });
95
106
 
96
107
  dispatchReactable(referenceType, reaction);
97
108
 
@@ -1,8 +1,9 @@
1
1
  import { getActiveClient } from '~/client/api';
2
2
 
3
- import { upsertInCache, pullFromCache } from '~/cache/api';
3
+ import { upsertInCache, pullFromCache, pushToCache } from '~/cache/api';
4
4
 
5
- import { dispatchReactable, fetchReference } from '../utils';
5
+ import { UNSYNCED_OBJECT_CACHED_AT_VALUE } from '~/utils/constants';
6
+ import { dispatchReactable } from '../utils';
6
7
 
7
8
  /**
8
9
  * ```js
@@ -36,10 +37,18 @@ export const removeReaction = async (
36
37
  data: { referenceId, referenceType, reactionName },
37
38
  });
38
39
 
39
- const model = await fetchReference(referenceType, referenceId);
40
- dispatchReactable(referenceType, model.data);
40
+ if (client.cache) {
41
+ const model = pullFromCache<Amity.Model[Amity.ReactableType]>([
42
+ referenceType,
43
+ 'get',
44
+ referenceId,
45
+ ]);
41
46
 
42
- return !model.data.myReactions?.includes(reactionName) ?? false;
47
+ model?.data &&
48
+ pushToCache([referenceType, 'get', referenceId], model.data, { cachedAt: Date.now() });
49
+ }
50
+
51
+ return true;
43
52
  };
44
53
 
45
54
  /**
@@ -89,7 +98,9 @@ removeReaction.optimistically = (
89
98
  },
90
99
  } as Amity.Model[Amity.ReactableType];
91
100
 
92
- upsertInCache([referenceType, 'get', referenceId], reaction, { cachedAt: -1 });
101
+ upsertInCache([referenceType, 'get', referenceId], reaction, {
102
+ cachedAt: UNSYNCED_OBJECT_CACHED_AT_VALUE,
103
+ });
93
104
 
94
105
  dispatchReactable(referenceType, reaction);
95
106