@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,108 @@
1
+ import { ASCApiError } from '~/core/errors';
2
+ import { disableCache, enableCache, pushToCache } from '~/cache/api';
3
+ import { client, channelQueryResponse } from '~/utils/tests';
4
+
5
+ import { pushToTombstone } from '~/cache/api/pushToTombstone';
6
+ import { isInTombstone } from '~/cache/api/isInTombstone';
7
+
8
+ import { getChannel } from '../getChannel';
9
+
10
+ const { channelId } = channelQueryResponse.data.channels[0];
11
+ const channel = channelQueryResponse.data.channels[0];
12
+
13
+ describe('getChannel', () => {
14
+ test('it should return a channel', async () => {
15
+ client.http.get = jest.fn().mockResolvedValueOnce(channelQueryResponse);
16
+
17
+ const expected = channel;
18
+ const { data: received } = await getChannel(channelId);
19
+
20
+ expect(received).toStrictEqual(expected);
21
+ });
22
+
23
+ test('it should update cache after fetch from server', async () => {
24
+ enableCache();
25
+ client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
26
+ await getChannel(channelId);
27
+
28
+ expect(getChannel.locally(channelId)).toBeDefined();
29
+
30
+ disableCache();
31
+ });
32
+
33
+ test('it should return an error', async () => {
34
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
35
+
36
+ await expect(getChannel(channelId)).rejects.toThrow('error');
37
+ });
38
+
39
+ test('it should return an error if channel in cache but api throws not found', async () => {
40
+ enableCache();
41
+ pushToCache(['channel', 'get', channelId], channel, { cachedAt: Date.now() });
42
+
43
+ client.http.get = jest
44
+ .fn()
45
+ .mockRejectedValueOnce(
46
+ new ASCApiError('not found!', Amity.ServerError.ITEM_NOT_FOUND, Amity.ErrorLevel.ERROR),
47
+ );
48
+
49
+ await expect(getChannel(channelId)).rejects.toThrow();
50
+ expect(getChannel.locally(channelId)).toBeUndefined();
51
+
52
+ disableCache();
53
+ });
54
+ });
55
+
56
+ describe('getChannel locally', () => {
57
+ test('it should return data from cache', () => {
58
+ enableCache();
59
+
60
+ const cachedAt = Date.now();
61
+
62
+ pushToCache(['channel', 'get', channelId], channel, { cachedAt });
63
+
64
+ const data = getChannel.locally(channelId);
65
+
66
+ expect(data).toBeDefined();
67
+ expect(data?.data).toEqual(channel);
68
+ expect(data?.cachedAt).toEqual(cachedAt);
69
+
70
+ disableCache();
71
+ });
72
+
73
+ test('should return undefined if channel not in cache', () => {
74
+ expect(getChannel.locally('non-existent-channel')).toBeUndefined();
75
+ });
76
+
77
+ test('should return undefined if cache not enabled', () => {
78
+ expect(getChannel.locally(channelId)).toBeUndefined();
79
+ });
80
+ });
81
+
82
+ describe('getChannel tombostone', () => {
83
+ test('it should add channel to tombostone if 404', async () => {
84
+ enableCache();
85
+
86
+ client.http.get = jest
87
+ .fn()
88
+ .mockRejectedValueOnce(
89
+ new ASCApiError('not found!', Amity.ServerError.ITEM_NOT_FOUND, Amity.ErrorLevel.ERROR),
90
+ );
91
+
92
+ await expect(getChannel(channelId)).rejects.toThrow();
93
+ expect(() => {
94
+ isInTombstone('channel', channelId);
95
+ }).toThrow();
96
+
97
+ disableCache();
98
+ });
99
+
100
+ test('it should throw error if channel not found in tombostone', async () => {
101
+ enableCache();
102
+
103
+ pushToTombstone('channel', channelId);
104
+ await expect(getChannel(channelId)).rejects.toThrow();
105
+
106
+ disableCache();
107
+ });
108
+ });
@@ -85,6 +85,26 @@ describe('queryChannels.locally', () => {
85
85
  disableCache();
86
86
  });
87
87
 
88
+ test('it should return undefined if params do not match', () => {
89
+ enableCache();
90
+
91
+ const { data } = channelQueryResponse;
92
+ const { channels: expected, paging } = data;
93
+
94
+ ingestInCache(data as Amity.ChannelPayload);
95
+
96
+ pushToCache(cacheKey, { channels: expected.map(getResolver('channel')), paging });
97
+
98
+ const { data: received } = queryChannels.locally()!;
99
+ const received2 = queryChannels.locally({ displayName: 'test' })!;
100
+
101
+ expect(received).toBeDefined();
102
+ expect(received).toEqual(expected);
103
+ expect(received2).toBeUndefined();
104
+
105
+ disableCache();
106
+ });
107
+
88
108
  test('it should return undefined if data not in cache', () => {
89
109
  enableCache();
90
110
 
@@ -22,7 +22,7 @@ import { prepareChannelPayload } from '../utils';
22
22
  */
23
23
  export const onChannelMemberAdded = (
24
24
  callback: (channel: Amity.Channel, member: Amity.Membership<'channel'>) => void,
25
- ) => {
25
+ ): Amity.Unsubscriber => {
26
26
  const client = getActiveClient();
27
27
 
28
28
  const filter = (payload: Amity.ChannelMembershipPayload) => {
@@ -2,7 +2,6 @@ import { disableCache, enableCache, pushToCache } from '~/cache/api';
2
2
  import { getResolver } from '~/core/model';
3
3
 
4
4
  import { liveChannels } from '../liveChannels';
5
- import { queryChannels } from '~/channel/api';
6
5
  import { prepareChannelPayload } from '../../utils/prepareChannelPayload';
7
6
 
8
7
  import {
@@ -117,7 +117,7 @@ export const createEventSubscriber = <T extends keyof Amity.Events>(
117
117
  export const createMqttMessageSubscriber = <T extends keyof Amity.Events>(
118
118
  client: Amity.Client,
119
119
  namespace: string,
120
- event: string,
120
+ event: T,
121
121
  fn: (params: Record<string, unknown>) => void,
122
122
  ): Amity.Unsubscriber => {
123
123
  return createEventSubscriber(client, namespace, 'message', ([topic, message]) => {
@@ -38,4 +38,4 @@ const idResolvers: Resolvers = {
38
38
  * @param name the domain name for the resolve
39
39
  * @returns an idResolver function for the given domain name
40
40
  */
41
- export const getResolver = <T extends Amity.Domain>(name: T) => idResolvers[name];
41
+ export const getResolver = <T extends Amity.Domain>(name: T): Resolvers[T] => idResolvers[name];
@@ -1,4 +1,5 @@
1
1
  import axios from 'axios';
2
+ import qs from 'qs';
2
3
  import HttpAgent, { HttpsAgent } from 'agentkeepalive';
3
4
 
4
5
  import { unwrapPayload } from './utils';
@@ -7,23 +8,8 @@ import { unwrapPayload } from './utils';
7
8
  * Axios param serializer (for querystring)
8
9
  * @hidden
9
10
  */
10
- const stringify = (params: Record<string, unknown>, prefix?: string): string => {
11
- return Object.entries(params)
12
- .filter(([, value]) => value !== undefined)
13
- .map(([name, value]) => {
14
- const key = prefix ? `${prefix}[${name}]` : name;
15
-
16
- if (Array.isArray(value)) {
17
- return value.map(item => `${key}[]=${item}`).join('&');
18
- }
19
- if (typeof value !== 'object') {
20
- return `${key}=${value}`;
21
- }
22
-
23
- // @ts-ignore
24
- return stringify(value, prefix ?? name);
25
- })
26
- .join('&');
11
+ export const stringify = (params: Record<string, unknown>): string => {
12
+ return qs.stringify(params, { arrayFormat: 'brackets' });
27
13
  };
28
14
 
29
15
  /**
@@ -0,0 +1,83 @@
1
+ import { createHttpTransport, stringify } from '../http';
2
+
3
+ describe('core/transports', () => {
4
+ describe('stringify', () => {
5
+ test('should serializer simple string', () => {
6
+ const params = { a: 'c' };
7
+ const url = stringify(params);
8
+ expect(url).toBe('a=c');
9
+ });
10
+
11
+ test('should serializer empty string', () => {
12
+ const params = { a: '' };
13
+ const url = stringify(params);
14
+ expect(url).toBe('a=');
15
+ });
16
+
17
+ test('should serializer special character', () => {
18
+ const params = { a: '✓', b: 'ø' };
19
+ const url = stringify(params);
20
+ expect(url).toBe('a=%E2%9C%93&b=%C3%B8');
21
+ });
22
+
23
+ test('should serializer boolean', () => {
24
+ const params = { a: true, b: false };
25
+ const url = stringify(params);
26
+ expect(url).toBe('a=true&b=false');
27
+ });
28
+
29
+ test('should serializer null ', () => {
30
+ const params = { a: null };
31
+ const url = stringify(params);
32
+ expect(url).toBe('a=');
33
+ });
34
+
35
+ test('should serializer undefined', () => {
36
+ const params = { a: undefined };
37
+ const url = stringify(params);
38
+ expect(url).toBe('');
39
+ });
40
+
41
+ test('should serializer NaN', () => {
42
+ const params = { a: NaN };
43
+ const url = stringify(params);
44
+ expect(url).toBe('a=NaN');
45
+ });
46
+
47
+ test('should serializer simple array', () => {
48
+ const params = { a: ['b', 'c', 'd'] };
49
+ const url = stringify(params);
50
+ expect(url).toBe('a%5B%5D=b&a%5B%5D=c&a%5B%5D=d');
51
+ });
52
+
53
+ test('should serializer complex array', () => {
54
+ const params = { a: ['b', { c: 'd' }] };
55
+ const url = stringify(params);
56
+ expect(url).toBe('a%5B%5D=b&a%5B%5D%5Bc%5D=d');
57
+ });
58
+
59
+ test('should serializer nested object', () => {
60
+ const params = { a: { b: 'c' } };
61
+ const url = stringify(params);
62
+ expect(url).toBe('a%5Bb%5D=c');
63
+ });
64
+
65
+ test('should serializer deep nested object', () => {
66
+ const params = { a: { b: { c: { d: { e: { f: { g: { h: { i: 'j' } } } } } } } } };
67
+ const url = stringify(params);
68
+ expect(url).toBe('a%5Bb%5D%5Bc%5D%5Bd%5D%5Be%5D%5Bf%5D%5Bg%5D%5Bh%5D%5Bi%5D=j');
69
+ });
70
+
71
+ test('should serializer empty object', () => {
72
+ const params = { a: { b: [] } };
73
+ const url = stringify(params);
74
+ expect(url).toBe('');
75
+ });
76
+ });
77
+
78
+ describe('createHttpTransport', () => {
79
+ test('should create axios instance with out error', () => {
80
+ expect(createHttpTransport('/')).not.toThrow();
81
+ });
82
+ });
83
+ });
@@ -1,10 +1,9 @@
1
1
  import { getActiveClient } from '~/client/api';
2
-
3
- import { getMessage } from './getMessage';
4
-
5
2
  import { pullFromCache, upsertInCache } from '~/cache/api';
6
3
  import { fireEvent } from '~/core/events';
7
4
 
5
+ import { getMessage } from './getMessage';
6
+
8
7
  /**
9
8
  * ```js
10
9
  * import { deleteMessage } from '@amityco/ts-sdk'
@@ -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
- describe('message/api', () => {
10
- const message = message11;
11
- const { messageId, ...messageBundle } = message11;
9
+ const messageToCreate = message11;
10
+ const { messageId, ...messageWithoutId } = message11;
12
11
 
13
- const getResolvedMessageValue = () => ({
14
- data: {
15
- messages: [message],
16
- users: [],
17
- files: [],
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
- describe('createMessage', () => {
22
- test('should return message', async () => {
23
- client.http.post = jest.fn().mockResolvedValue(getResolvedMessageValue());
24
- const { data } = await createMessage(messageBundle);
25
- expect(data).toStrictEqual(message);
26
- });
27
-
28
- test('should throw an error if request fails', async () => {
29
- client.http.post = jest.fn().mockRejectedValueOnce(new Error('error'));
30
- await expect(createMessage(messageBundle)).rejects.toThrow('error');
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
- describe('createMessage.optimistically', () => {
35
- beforeEach(() => enableCache());
36
- afterEach(() => disableCache());
47
+ test('should fire event `onMessageCreated`', async () => {
48
+ let dispose;
49
+ client.http.post = jest.fn().mockResolvedValueOnce(getResolvedMessageValue());
37
50
 
38
- test('should create cache after created message', () => {
39
- const optimisticId = createMessage.optimistically(messageBundle)?.data?.messageId;
40
- expect(pullFromCache(['message', 'get', optimisticId])?.data).toBeDefined();
41
- });
51
+ const callbackPromise = new Promise(resolve => {
52
+ dispose = onMessageCreated(resolve);
53
+ }).finally(dispose);
42
54
 
43
- test('should increase message count after created message', () => {
44
- const { channelId } = messageBundle;
55
+ await createMessage(messageWithoutId);
45
56
 
46
- const currentCount =
47
- pullFromCache<Amity.Channel>(['channel', 'get', channelId])?.data?.messageCount ?? 0;
57
+ await expect(callbackPromise).resolves.toEqual(expect.objectContaining(messageWithoutId));
58
+ });
59
+ });
48
60
 
49
- createMessage.optimistically(messageBundle);
61
+ describe('createMessage.optimistically', () => {
62
+ beforeEach(() => enableCache());
63
+ afterEach(() => disableCache());
50
64
 
51
- expect(
52
- pullFromCache<Amity.Channel>(['channel', 'get', channelId])?.data?.messageCount,
53
- ).toEqual(currentCount + 1);
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
- test('should fire event `onMessageCreated`', () => {
57
- expect.assertions(1);
58
- let dispose;
69
+ expect(recieved).toEqual(expect.objectContaining(messageWithoutId));
70
+ });
59
71
 
60
- const callback = new Promise(resolve => {
61
- dispose = onMessageCreated(resolve);
62
- }).finally(dispose);
72
+ test('should increase message count after created message', () => {
73
+ const { channelId } = messageWithoutId;
74
+ pushToCache(['channel', 'get', channelId], { channelId, messageCount: 2 });
63
75
 
64
- createMessage.optimistically(messageBundle);
65
- return expect(callback).resolves.not.toThrow();
66
- });
76
+ createMessage.optimistically(messageWithoutId);
77
+ const recieved = pullFromCache<Amity.Channel>(['channel', 'get', channelId])?.data;
67
78
 
68
- test('should define object as unsynced object', async () => {
69
- const data = { channelId: 'test', data: { text: 'text' } };
79
+ expect(recieved?.messageCount).toBe(3);
80
+ });
70
81
 
71
- const message = createMessage.optimistically(data);
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
- expect(message?.cachedAt).toEqual(UNSYNCED_OBJECT_CACHED_AT_VALUE);
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
+ });