@amityco/ts-sdk 0.0.1-beta.31 → 0.0.1-beta.32
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/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/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 +35 -45
- package/dist/index.esm.js +34 -45
- 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/post.d.ts +12 -1
- package/dist/utils/tests/dummy/post.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/cache/api/backupCache.ts +0 -1
- 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/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 +1 -4
- package/src/reaction/api/removeReaction.ts +1 -4
- package/src/reaction/api/tests/addReaction.test.ts +37 -0
- package/src/reaction/api/tests/removeReaction.test.ts +43 -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/post.ts +26 -3
- package/src/utils/tests/dummy/user.ts +1 -1
- package/dist/message/tests/api/getMessage.test.d.ts.map +0 -1
- package/src/message/tests/api/getMessage.test.ts +0 -96
|
@@ -1,76 +1,99 @@
|
|
|
1
1
|
import { UNSYNCED_OBJECT_CACHED_AT_VALUE } from '~/utils/constants';
|
|
2
|
-
import { disableCache, enableCache, pullFromCache } from '~/cache/api';
|
|
2
|
+
import { disableCache, enableCache, pullFromCache, pushToCache } from '~/cache/api';
|
|
3
3
|
|
|
4
4
|
import { client, message11 } from '~/utils/tests';
|
|
5
5
|
|
|
6
6
|
import { onMessageCreated } from '../../events';
|
|
7
7
|
import { createMessage } from '../createMessage';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const { messageId, ...messageBundle } = message11;
|
|
9
|
+
const messageToCreate = message11;
|
|
10
|
+
const { messageId, ...messageWithoutId } = message11;
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
const getResolvedMessageValue = () => ({
|
|
13
|
+
data: {
|
|
14
|
+
messages: [messageToCreate],
|
|
15
|
+
users: [],
|
|
16
|
+
files: [],
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('createMessage', () => {
|
|
21
|
+
test('should return created message', async () => {
|
|
22
|
+
client.http.post = jest.fn().mockResolvedValue(getResolvedMessageValue());
|
|
23
|
+
|
|
24
|
+
const recieved = createMessage(messageWithoutId);
|
|
25
|
+
|
|
26
|
+
await expect(recieved).resolves.toEqual(expect.objectContaining({ data: messageToCreate }));
|
|
19
27
|
});
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
test('should throw an error if request fails', async () => {
|
|
30
|
+
client.http.post = jest.fn().mockRejectedValueOnce(new Error('error'));
|
|
31
|
+
|
|
32
|
+
await expect(createMessage(messageWithoutId)).rejects.toThrow('error');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('should create cache after created messages', async () => {
|
|
36
|
+
enableCache();
|
|
37
|
+
client.http.post = jest.fn().mockResolvedValue(getResolvedMessageValue());
|
|
38
|
+
|
|
39
|
+
const created = await createMessage(messageWithoutId);
|
|
40
|
+
const recieved = pullFromCache(['message', 'get', created.data.messageId])?.data;
|
|
41
|
+
|
|
42
|
+
expect(recieved).toEqual(expect.objectContaining(messageWithoutId));
|
|
43
|
+
|
|
44
|
+
disableCache();
|
|
32
45
|
});
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
test('should fire event `onMessageCreated`', async () => {
|
|
48
|
+
let dispose;
|
|
49
|
+
client.http.post = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
51
|
+
const callbackPromise = new Promise(resolve => {
|
|
52
|
+
dispose = onMessageCreated(resolve);
|
|
53
|
+
}).finally(dispose);
|
|
42
54
|
|
|
43
|
-
|
|
44
|
-
const { channelId } = messageBundle;
|
|
55
|
+
await createMessage(messageWithoutId);
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
await expect(callbackPromise).resolves.toEqual(expect.objectContaining(messageWithoutId));
|
|
58
|
+
});
|
|
59
|
+
});
|
|
48
60
|
|
|
49
|
-
|
|
61
|
+
describe('createMessage.optimistically', () => {
|
|
62
|
+
beforeEach(() => enableCache());
|
|
63
|
+
afterEach(() => disableCache());
|
|
50
64
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
65
|
+
test('should create cache after created message', () => {
|
|
66
|
+
const optimisticId = createMessage.optimistically(messageWithoutId)?.data?.messageId;
|
|
67
|
+
const recieved = pullFromCache(['message', 'get', optimisticId])?.data;
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
let dispose;
|
|
69
|
+
expect(recieved).toEqual(expect.objectContaining(messageWithoutId));
|
|
70
|
+
});
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
test('should increase message count after created message', () => {
|
|
73
|
+
const { channelId } = messageWithoutId;
|
|
74
|
+
pushToCache(['channel', 'get', channelId], { channelId, messageCount: 2 });
|
|
63
75
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
76
|
+
createMessage.optimistically(messageWithoutId);
|
|
77
|
+
const recieved = pullFromCache<Amity.Channel>(['channel', 'get', channelId])?.data;
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
expect(recieved?.messageCount).toBe(3);
|
|
80
|
+
});
|
|
70
81
|
|
|
71
|
-
|
|
82
|
+
test('should fire event `onMessageCreated`', async () => {
|
|
83
|
+
let dispose;
|
|
84
|
+
|
|
85
|
+
const callbackPromise = new Promise(resolve => {
|
|
86
|
+
dispose = onMessageCreated(resolve);
|
|
87
|
+
}).finally(dispose);
|
|
88
|
+
|
|
89
|
+
createMessage.optimistically(messageWithoutId);
|
|
90
|
+
|
|
91
|
+
await expect(callbackPromise).resolves.toEqual(expect.objectContaining(messageWithoutId));
|
|
92
|
+
});
|
|
72
93
|
|
|
73
|
-
|
|
74
|
-
|
|
94
|
+
test('should define object as unsynced object', async () => {
|
|
95
|
+
expect(createMessage.optimistically(messageWithoutId)?.cachedAt).toEqual(
|
|
96
|
+
UNSYNCED_OBJECT_CACHED_AT_VALUE,
|
|
97
|
+
);
|
|
75
98
|
});
|
|
76
99
|
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { disableCache, enableCache, pullFromCache, pushToCache } from '~/cache/api';
|
|
2
|
+
import { client, message11 } from '~/utils/tests';
|
|
3
|
+
|
|
4
|
+
import { deleteMessage } from '../deleteMessage';
|
|
5
|
+
import { onMessageDeleted } from '../../events';
|
|
6
|
+
|
|
7
|
+
const messageToDelete = { ...message11, isDeleted: false };
|
|
8
|
+
const { messageId: deleteId } = messageToDelete;
|
|
9
|
+
const deletedMessage = { ...messageToDelete, isDeleted: true };
|
|
10
|
+
const { updatedAt, ...deletedMessageWithoutTS } = deletedMessage;
|
|
11
|
+
|
|
12
|
+
const getResolvedMessageValue = () => ({
|
|
13
|
+
data: {
|
|
14
|
+
messages: [deletedMessage],
|
|
15
|
+
users: [],
|
|
16
|
+
files: [],
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('deleteMessage', () => {
|
|
21
|
+
test('should return deleted message', async () => {
|
|
22
|
+
client.http.delete = jest.fn();
|
|
23
|
+
client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
|
|
24
|
+
|
|
25
|
+
await expect(deleteMessage(deleteId)).resolves.toEqual(deletedMessageWithoutTS);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('should throw an error if request fails', async () => {
|
|
29
|
+
client.http.delete = jest.fn().mockRejectedValueOnce(new Error('error'));
|
|
30
|
+
|
|
31
|
+
await expect(deleteMessage(deleteId)).rejects.toThrow('error');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should update cache after deleted messages', async () => {
|
|
35
|
+
enableCache();
|
|
36
|
+
client.http.delete = jest.fn();
|
|
37
|
+
client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
|
|
38
|
+
pushToCache(['message', 'get', deleteId], messageToDelete);
|
|
39
|
+
|
|
40
|
+
await deleteMessage(deleteId);
|
|
41
|
+
const recieved = pullFromCache<Amity.Message>(['message', 'get', deleteId])?.data;
|
|
42
|
+
|
|
43
|
+
expect(recieved).toEqual(deletedMessageWithoutTS);
|
|
44
|
+
|
|
45
|
+
disableCache();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('should fire event `onMessageDeleted`', async () => {
|
|
49
|
+
let dispose;
|
|
50
|
+
client.http.delete = jest.fn();
|
|
51
|
+
client.http.get = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
|
|
52
|
+
|
|
53
|
+
const callbackPromise = new Promise(resolve => {
|
|
54
|
+
dispose = onMessageDeleted(resolve);
|
|
55
|
+
}).finally(dispose);
|
|
56
|
+
|
|
57
|
+
await deleteMessage(deleteId);
|
|
58
|
+
|
|
59
|
+
await expect(callbackPromise).resolves.toEqual(deletedMessageWithoutTS);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('deleteMessage.optimistically', () => {
|
|
64
|
+
beforeEach(() => enableCache());
|
|
65
|
+
afterEach(() => disableCache());
|
|
66
|
+
|
|
67
|
+
test('should update `isDeleted` in cache after deleted message', () => {
|
|
68
|
+
pushToCache(['message', 'get', deleteId], messageToDelete);
|
|
69
|
+
|
|
70
|
+
deleteMessage.optimistically(deleteId);
|
|
71
|
+
const recieved = pullFromCache<Amity.Message>(['message', 'get', deleteId])?.data;
|
|
72
|
+
|
|
73
|
+
expect(recieved).toEqual(expect.objectContaining(deletedMessageWithoutTS));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
/* TODO: re-enable this after fixed channel message count calculation */
|
|
77
|
+
test.skip('should decrease message count after deleted message', () => {
|
|
78
|
+
const { channelId } = messageToDelete;
|
|
79
|
+
pushToCache(['channel', 'get', channelId], { channelId, messageCount: 2 });
|
|
80
|
+
pushToCache(['message', 'get', deleteId], { ...messageToDelete, channelId });
|
|
81
|
+
|
|
82
|
+
deleteMessage.optimistically(deleteId);
|
|
83
|
+
const recieved = pullFromCache<Amity.Channel>(['channel', 'get', channelId])?.data;
|
|
84
|
+
|
|
85
|
+
expect(recieved?.messageCount).toBe(1);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('should fire event `onMessageDeleted`', async () => {
|
|
89
|
+
pushToCache(['message', 'get', deleteId], messageToDelete);
|
|
90
|
+
let dispose;
|
|
91
|
+
|
|
92
|
+
const callbackPromise = new Promise(resolve => {
|
|
93
|
+
dispose = onMessageDeleted(data => {
|
|
94
|
+
resolve(data);
|
|
95
|
+
});
|
|
96
|
+
}).finally(dispose);
|
|
97
|
+
|
|
98
|
+
await deleteMessage.optimistically(deleteId);
|
|
99
|
+
|
|
100
|
+
await expect(callbackPromise).resolves.toEqual(
|
|
101
|
+
expect.objectContaining(deletedMessageWithoutTS),
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('should define object as unsynced object', () => {
|
|
106
|
+
pushToCache(['message', 'get', deleteId], messageToDelete);
|
|
107
|
+
|
|
108
|
+
expect(deleteMessage.optimistically(deleteId)?.cachedAt).toBe(-1);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -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
|
+
});
|