@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.
- package/dist/cache/api/backupCache.d.ts.map +1 -1
- package/dist/cache/api/ingestInCache.d.ts +1 -1
- package/dist/cache/api/tests/ingestInCache.test.d.ts +2 -0
- package/dist/cache/api/tests/ingestInCache.test.d.ts.map +1 -0
- package/dist/cache/api/tests/pushToCache.test.d.ts +2 -0
- package/dist/cache/api/tests/pushToCache.test.d.ts.map +1 -0
- package/dist/channel/api/addChannelMembers.d.ts.map +1 -1
- package/dist/channel/api/getChannel.d.ts.map +1 -1
- package/dist/channel/api/tests/addChannelMembers.test.d.ts +2 -0
- package/dist/channel/api/tests/addChannelMembers.test.d.ts.map +1 -0
- package/dist/channel/api/tests/getChannel.test.d.ts +2 -0
- package/dist/channel/api/tests/getChannel.test.d.ts.map +1 -0
- package/dist/channel/events/onChannelMemberAdded.d.ts.map +1 -1
- package/dist/core/events.d.ts +1 -1
- package/dist/core/events.d.ts.map +1 -1
- package/dist/core/model/idResolvers.d.ts.map +1 -1
- package/dist/core/transports/http.d.ts +5 -0
- package/dist/core/transports/http.d.ts.map +1 -1
- package/dist/core/transports/test/http.test.d.ts +2 -0
- package/dist/core/transports/test/http.test.d.ts.map +1 -0
- package/dist/index.cjs.js +61 -51
- package/dist/index.esm.js +60 -51
- package/dist/index.umd.js +4 -4
- package/dist/message/api/deleteMessage.d.ts.map +1 -1
- package/dist/message/api/tests/deleteMessage.test.d.ts +2 -0
- package/dist/message/api/tests/deleteMessage.test.d.ts.map +1 -0
- package/dist/message/{tests/api → api/tests}/getMessage.test.d.ts +0 -0
- package/dist/message/api/tests/getMessage.test.d.ts.map +1 -0
- package/dist/message/api/tests/getMessages.test.d.ts +2 -0
- package/dist/message/api/tests/getMessages.test.d.ts.map +1 -0
- package/dist/message/api/tests/queryMessages.test.d.ts +2 -0
- package/dist/message/api/tests/queryMessages.test.d.ts.map +1 -0
- package/dist/message/api/tests/updateMessage.test.d.ts +2 -0
- package/dist/message/api/tests/updateMessage.test.d.ts.map +1 -0
- package/dist/reaction/api/addReaction.d.ts.map +1 -1
- package/dist/reaction/api/removeReaction.d.ts.map +1 -1
- package/dist/reaction/api/tests/addReaction.test.d.ts +2 -0
- package/dist/reaction/api/tests/addReaction.test.d.ts.map +1 -0
- package/dist/reaction/api/tests/removeReaction.test.d.ts +2 -0
- package/dist/reaction/api/tests/removeReaction.test.d.ts.map +1 -0
- package/dist/user/api/getUser.d.ts.map +1 -1
- package/dist/user/api/queryUsers.d.ts.map +1 -1
- package/dist/user/api/tests/queryUsers.test.d.ts +2 -0
- package/dist/user/api/tests/queryUsers.test.d.ts.map +1 -0
- package/dist/utils/tests/dummy/channel.d.ts +6 -0
- package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
- package/dist/utils/tests/dummy/community.d.ts +4 -0
- package/dist/utils/tests/dummy/community.d.ts.map +1 -0
- package/dist/utils/tests/dummy/file.d.ts +2 -0
- package/dist/utils/tests/dummy/file.d.ts.map +1 -0
- package/dist/utils/tests/dummy/follow.d.ts +1 -0
- package/dist/utils/tests/dummy/follow.d.ts.map +1 -1
- package/dist/utils/tests/dummy/index.d.ts +5 -0
- package/dist/utils/tests/dummy/index.d.ts.map +1 -1
- package/dist/utils/tests/dummy/message.d.ts +5 -0
- package/dist/utils/tests/dummy/message.d.ts.map +1 -1
- package/dist/utils/tests/dummy/poll.d.ts +3 -0
- package/dist/utils/tests/dummy/poll.d.ts.map +1 -0
- package/dist/utils/tests/dummy/post.d.ts +15 -1
- package/dist/utils/tests/dummy/post.d.ts.map +1 -1
- package/dist/utils/tests/dummy/reaction.d.ts +4 -0
- package/dist/utils/tests/dummy/reaction.d.ts.map +1 -0
- package/dist/utils/tests/dummy/role.d.ts +4 -0
- package/dist/utils/tests/dummy/role.d.ts.map +1 -0
- package/dist/utils/tests/dummy/user.d.ts +1 -0
- package/dist/utils/tests/dummy/user.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/cache/api/backupCache.ts +0 -1
- package/src/cache/api/ingestInCache.ts +2 -2
- package/src/cache/api/tests/ingestInCache.test.ts +87 -0
- package/src/cache/api/tests/pushToCache.test.ts +57 -0
- package/src/channel/api/addChannelMembers.ts +9 -1
- package/src/channel/api/getChannel.ts +20 -5
- package/src/channel/api/tests/addChannelMembers.test.ts +95 -0
- package/src/channel/api/tests/getChannel.test.ts +108 -0
- package/src/channel/api/tests/queryChannels.test.ts +20 -0
- package/src/channel/events/onChannelMemberAdded.ts +1 -1
- package/src/channel/observers/tests/liveChannels.test.ts +0 -1
- package/src/core/events.ts +1 -1
- package/src/core/model/idResolvers.ts +1 -1
- package/src/core/transports/http.ts +3 -17
- package/src/core/transports/test/http.test.ts +83 -0
- package/src/message/api/deleteMessage.ts +2 -3
- package/src/message/api/tests/createMessage.test.ts +74 -51
- package/src/message/api/tests/deleteMessage.test.ts +110 -0
- package/src/message/api/tests/getMessage.test.ts +121 -0
- package/src/message/api/tests/getMessages.test.ts +108 -0
- package/src/message/api/tests/queryMessages.test.ts +115 -0
- package/src/message/api/tests/updateMessage.test.ts +100 -0
- package/src/post/tests/api/queryPosts.test.ts +117 -18
- package/src/reaction/api/addReaction.ts +17 -6
- package/src/reaction/api/removeReaction.ts +17 -6
- package/src/reaction/api/tests/addReaction.test.ts +73 -0
- package/src/reaction/api/tests/removeReaction.test.ts +79 -0
- package/src/user/api/getUser.ts +1 -2
- package/src/user/api/queryUsers.ts +24 -5
- package/src/user/api/tests/queryUsers.test.ts +124 -0
- package/src/utils/tests/dummy/channel.ts +9 -1
- package/src/utils/tests/dummy/community.ts +44 -0
- package/src/utils/tests/dummy/file.ts +20 -0
- package/src/utils/tests/dummy/follow.ts +6 -0
- package/src/utils/tests/dummy/index.ts +9 -0
- package/src/utils/tests/dummy/message.ts +8 -1
- package/src/utils/tests/dummy/poll.ts +43 -0
- package/src/utils/tests/dummy/post.ts +65 -4
- package/src/utils/tests/dummy/reaction.ts +22 -0
- package/src/utils/tests/dummy/role.ts +21 -0
- package/src/utils/tests/dummy/user.ts +7 -1
- package/dist/message/tests/api/getMessage.test.d.ts.map +0 -1
- 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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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 =
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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 {
|
|
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
|
-
|
|
42
|
-
|
|
42
|
+
if (client.cache) {
|
|
43
|
+
const model = pullFromCache<Amity.Model[Amity.ReactableType]>([
|
|
44
|
+
referenceType,
|
|
45
|
+
'get',
|
|
46
|
+
referenceId,
|
|
47
|
+
]);
|
|
43
48
|
|
|
44
|
-
|
|
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, {
|
|
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 {
|
|
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
|
-
|
|
40
|
-
|
|
40
|
+
if (client.cache) {
|
|
41
|
+
const model = pullFromCache<Amity.Model[Amity.ReactableType]>([
|
|
42
|
+
referenceType,
|
|
43
|
+
'get',
|
|
44
|
+
referenceId,
|
|
45
|
+
]);
|
|
41
46
|
|
|
42
|
-
|
|
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, {
|
|
101
|
+
upsertInCache([referenceType, 'get', referenceId], reaction, {
|
|
102
|
+
cachedAt: UNSYNCED_OBJECT_CACHED_AT_VALUE,
|
|
103
|
+
});
|
|
93
104
|
|
|
94
105
|
dispatchReactable(referenceType, reaction);
|
|
95
106
|
|