@amityco/ts-sdk 0.0.1-beta.28 → 0.0.1-beta.29

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 (83) hide show
  1. package/dist/@types/core/payload.d.ts +3 -3
  2. package/dist/@types/core/payload.d.ts.map +1 -1
  3. package/dist/@types/domains/channel.d.ts +12 -0
  4. package/dist/@types/domains/channel.d.ts.map +1 -1
  5. package/dist/@types/domains/community.d.ts +24 -2
  6. package/dist/@types/domains/community.d.ts.map +1 -1
  7. package/dist/@types/domains/content.d.ts +2 -1
  8. package/dist/@types/domains/content.d.ts.map +1 -1
  9. package/dist/@types/index.d.ts +1 -1
  10. package/dist/@types/index.d.ts.map +1 -1
  11. package/dist/channel/api/queryChannels.d.ts +1 -10
  12. package/dist/channel/api/queryChannels.d.ts.map +1 -1
  13. package/dist/channel/observers/index.d.ts +1 -0
  14. package/dist/channel/observers/index.d.ts.map +1 -1
  15. package/dist/channel/observers/liveChannels.d.ts +20 -0
  16. package/dist/channel/observers/liveChannels.d.ts.map +1 -0
  17. package/dist/channel/observers/tests/liveChannels.test.d.ts +2 -0
  18. package/dist/channel/observers/tests/liveChannels.test.d.ts.map +1 -0
  19. package/dist/community/api/createCommunity.d.ts +1 -1
  20. package/dist/community/api/createCommunity.d.ts.map +1 -1
  21. package/dist/community/api/getCommunities.d.ts.map +1 -1
  22. package/dist/community/api/getCommunity.d.ts.map +1 -1
  23. package/dist/community/api/getRecommendedCommunities.d.ts.map +1 -1
  24. package/dist/community/api/getTopTrendingCommunities.d.ts.map +1 -1
  25. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  26. package/dist/community/api/updateCommunity.d.ts +1 -1
  27. package/dist/community/api/updateCommunity.d.ts.map +1 -1
  28. package/dist/community/events/utils.d.ts.map +1 -1
  29. package/dist/community/utils/index.d.ts +2 -0
  30. package/dist/community/utils/index.d.ts.map +1 -0
  31. package/dist/community/utils/payload.d.ts +11 -0
  32. package/dist/community/utils/payload.d.ts.map +1 -0
  33. package/dist/follow/tests/observers/liveFollowers.test.d.ts +2 -0
  34. package/dist/follow/tests/observers/liveFollowers.test.d.ts.map +1 -0
  35. package/dist/follow/tests/observers/liveFollowings.test.d.ts +2 -0
  36. package/dist/follow/tests/observers/liveFollowings.test.d.ts.map +1 -0
  37. package/dist/index.cjs.js +201 -20
  38. package/dist/index.esm.js +198 -21
  39. package/dist/index.umd.js +4 -4
  40. package/dist/utils/tests/dummy/channel.d.ts +25 -2
  41. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  42. package/dist/utils/tests/dummy/follow.d.ts +12 -0
  43. package/dist/utils/tests/dummy/follow.d.ts.map +1 -0
  44. package/dist/utils/tests/dummy/index.d.ts +1 -0
  45. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  46. package/dist/utils/tests/dummy/user.d.ts +3 -0
  47. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  48. package/dist/utils/tests/index.d.ts +1 -0
  49. package/dist/utils/tests/index.d.ts.map +1 -1
  50. package/dist/utils/tests/utils.d.ts +2 -0
  51. package/dist/utils/tests/utils.d.ts.map +1 -0
  52. package/package.json +1 -1
  53. package/src/@types/core/payload.ts +3 -3
  54. package/src/@types/domains/channel.ts +18 -0
  55. package/src/@types/domains/community.ts +27 -2
  56. package/src/@types/domains/content.ts +2 -1
  57. package/src/@types/index.ts +1 -1
  58. package/src/channel/api/queryChannels.ts +3 -10
  59. package/src/channel/observers/index.ts +1 -0
  60. package/src/channel/observers/liveChannels.ts +178 -0
  61. package/src/channel/observers/tests/liveChannels.test.ts +173 -0
  62. package/src/community/api/createCommunity.ts +9 -3
  63. package/src/community/api/getCommunities.ts +10 -3
  64. package/src/community/api/getCommunity.ts +5 -1
  65. package/src/community/api/getRecommendedCommunities.ts +5 -2
  66. package/src/community/api/getTopTrendingCommunities.ts +4 -1
  67. package/src/community/api/queryCommunities.ts +5 -2
  68. package/src/community/api/updateCommunity.ts +7 -3
  69. package/src/community/events/utils.ts +13 -7
  70. package/src/community/utils/index.ts +1 -0
  71. package/src/community/utils/payload.ts +44 -0
  72. package/src/core/model/identifyModel.ts +1 -1
  73. package/src/follow/observers/liveFollowers.ts +1 -1
  74. package/src/follow/observers/liveFollowings.ts +1 -1
  75. package/src/follow/tests/observers/liveFollowers.test.ts +240 -0
  76. package/src/follow/tests/observers/liveFollowings.test.ts +239 -0
  77. package/src/message/observers/tests/liveMessages.test.ts +202 -22
  78. package/src/utils/tests/dummy/channel.ts +48 -4
  79. package/src/utils/tests/dummy/follow.ts +60 -0
  80. package/src/utils/tests/dummy/index.ts +1 -0
  81. package/src/utils/tests/dummy/user.ts +15 -0
  82. package/src/utils/tests/index.ts +1 -0
  83. package/src/utils/tests/utils.ts +3 -0
@@ -3,6 +3,8 @@ import { getActiveClient } from '~/client/api';
3
3
  import { pullFromCache } from '~/cache/api';
4
4
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
5
 
6
+ import { unpackCommunityPayload } from '../utils';
7
+
6
8
  /**
7
9
  * ```js
8
10
  * import { getCommunity } from '@amityco/ts-sdk'
@@ -24,10 +26,12 @@ export const getCommunity = async (
24
26
  client.log('community/getCommunity', communityId);
25
27
 
26
28
  // API-FIX: endpoint should not be /list, parameters should be querystring.
27
- const { data } = await client.http.get<Amity.CommunityPayload>(
29
+ const { data: payload } = await client.http.get<Amity.CommunityPayload>(
28
30
  `/api/v3/communities/${communityId}`,
29
31
  );
30
32
 
33
+ const data = unpackCommunityPayload(payload);
34
+
31
35
  const cachedAt = client.cache && Date.now();
32
36
  if (client.cache) ingestInCache(data, { cachedAt });
33
37
 
@@ -4,6 +4,8 @@ import { getResolver } from '~/core/model';
4
4
  import { pullFromCache, pushToCache } from '~/cache/api';
5
5
  import { ingestInCache } from '~/cache/api/ingestInCache';
6
6
 
7
+ import { unpackCommunityPayload } from '../utils';
8
+
7
9
  /**
8
10
  * ```js
9
11
  * import { getRecommendedCommunities } from '@amityco/ts-sdk'
@@ -27,12 +29,13 @@ export const getRecommendedCommunities = async (
27
29
  const { limit = 5 } = query ?? {};
28
30
 
29
31
  // API-FIX: backend doesnt answer Amity.Response
30
- // const { data } = await client.http.get<Amity.Response<CommunityPayload>>(
31
- const { data } = await client.http.get<Amity.CommunityPayload>(
32
+ // const { data: payload } = await client.http.get<Amity.Response<CommunityPayload>>(
33
+ const { data: payload } = await client.http.get<Amity.CommunityPayload>(
32
34
  `/api/v3/communities/recommended`,
33
35
  { params: { options: { limit } } },
34
36
  );
35
37
 
38
+ const data = unpackCommunityPayload(payload);
36
39
  const { communities } = data;
37
40
 
38
41
  const cachedAt = client.cache && Date.now();
@@ -4,6 +4,8 @@ import { getResolver } from '~/core/model';
4
4
  import { pullFromCache, pushToCache } from '~/cache/api';
5
5
  import { ingestInCache } from '~/cache/api/ingestInCache';
6
6
 
7
+ import { unpackCommunityPayload } from '../utils';
8
+
7
9
  /**
8
10
  * ```js
9
11
  * import { getTopTrendingCommunities } from '@amityco/ts-sdk'
@@ -28,11 +30,12 @@ export const getTopTrendingCommunities = async (
28
30
 
29
31
  // API-FIX: backend doesnt answer Amity.Response
30
32
  // const { data } = await client.http.get<Amity.Response<CommunityPayload>>(
31
- const { data } = await client.http.get<Amity.CommunityPayload>(
33
+ const { data: payload } = await client.http.get<Amity.CommunityPayload>(
32
34
  `/api/v3/communities/top-trending`,
33
35
  { params: { options: { limit } } },
34
36
  );
35
37
 
38
+ const data = unpackCommunityPayload(payload);
36
39
  const { communities } = data;
37
40
 
38
41
  const cachedAt = client.cache && Date.now();
@@ -5,6 +5,8 @@ import { pushToCache } from '~/cache/api';
5
5
  import { ingestInCache } from '~/cache/api/ingestInCache';
6
6
  import { getResolver } from '~/core/model';
7
7
 
8
+ import { unpackCommunityPayload } from '../utils';
9
+
8
10
  /**
9
11
  * ```js
10
12
  * import { queryCommunities } from '@amityco/ts-sdk'
@@ -54,12 +56,13 @@ export const queryCommunities = async (query?: {
54
56
  );
55
57
 
56
58
  const { paging, ...payload } = data;
57
- const { communities } = payload;
59
+ const unpackedPayload = unpackCommunityPayload(payload);
60
+ const { communities } = unpackedPayload;
58
61
 
59
62
  const cachedAt = client.cache && Date.now();
60
63
 
61
64
  if (client.cache) {
62
- ingestInCache(payload as Amity.CommunityPayload, { cachedAt });
65
+ ingestInCache(unpackedPayload as Amity.CommunityPayload, { cachedAt });
63
66
 
64
67
  const cacheKey = [
65
68
  'community',
@@ -3,6 +3,8 @@ import { getActiveClient } from '~/client/api';
3
3
  import { ingestInCache } from '~/cache/api/ingestInCache';
4
4
  import { fireEvent } from '~/core/events';
5
5
 
6
+ import { packCommunityPayload, unpackCommunityPayload } from '../utils';
7
+
6
8
  /**
7
9
  * ```js
8
10
  * import { updateCommunity } from '@amityco/ts-sdk'
@@ -22,17 +24,19 @@ export const updateCommunity = async (
22
24
  communityId: Amity.Community['communityId'],
23
25
  patch: Patch<
24
26
  Amity.Community,
25
- 'displayName' | 'description' | 'avatarFileId' | 'tags' | 'metadata'
27
+ 'displayName' | 'description' | 'avatarFileId' | 'postSetting' | 'tags' | 'metadata'
26
28
  >,
27
29
  ): Promise<Amity.Cached<Amity.Community>> => {
28
30
  const client = getActiveClient();
29
31
  client.log('community/updateCommunity', communityId, patch);
30
32
 
31
- const { data } = await client.http.put<Amity.CommunityPayload>(
33
+ const { data: payload } = await client.http.put<Amity.CommunityPayload>(
32
34
  `/api/v3/communities/${communityId}`,
33
- patch,
35
+ packCommunityPayload(patch),
34
36
  );
35
37
 
38
+ const data = unpackCommunityPayload(payload);
39
+
36
40
  const cachedAt = client.cache && Date.now();
37
41
  if (client.cache) ingestInCache(data, { cachedAt });
38
42
 
@@ -4,6 +4,8 @@ import { createEventSubscriber } from '~/core/events';
4
4
  import { pullFromCache } from '~/cache/api';
5
5
  import { getResolver } from '~/core/model';
6
6
 
7
+ import { unpackCommunityPayload } from '../utils';
8
+
7
9
  export const createCommunityEventSubscriber = (
8
10
  event: keyof Amity.MqttCommunityMessageEvents,
9
11
  callback: Amity.Listener<Amity.Community>,
@@ -11,16 +13,18 @@ export const createCommunityEventSubscriber = (
11
13
  const client = getActiveClient();
12
14
 
13
15
  const filter = (payload: Amity.CommunityPayload) => {
16
+ const unpackedPayload = unpackCommunityPayload(payload);
17
+
14
18
  if (!client.cache) {
15
19
  // TODO: here we are missing specific properties here!
16
- callback(payload.communities[0]);
20
+ callback(unpackedPayload.communities[0]);
17
21
  } else {
18
- ingestInCache(payload);
22
+ ingestInCache(unpackedPayload);
19
23
 
20
24
  const community = pullFromCache<Amity.Community>([
21
25
  'community',
22
26
  'get',
23
- payload.communities[0].communityId,
27
+ unpackedPayload.communities[0].communityId,
24
28
  ])!;
25
29
 
26
30
  callback(community.data);
@@ -77,21 +81,23 @@ export const createCommunityMemberEventSubscriber = (
77
81
  const client = getActiveClient();
78
82
 
79
83
  const filter = (payload: Amity.CommunityMembershipPayload) => {
84
+ const unpackedPayload = unpackCommunityPayload(payload);
85
+
80
86
  if (!client.cache) {
81
87
  // TODO: here we are missing specific properties here!
82
- callback(payload.communities[0], getEventRelatedMember(event, payload));
88
+ callback(unpackedPayload.communities[0], getEventRelatedMember(event, unpackedPayload));
83
89
  } else {
84
- ingestInCache(payload);
90
+ ingestInCache(unpackedPayload);
85
91
 
86
92
  const community = pullFromCache<Amity.Community>([
87
93
  'community',
88
94
  'get',
89
- payload.communities[0].communityId,
95
+ unpackedPayload.communities[0].communityId,
90
96
  ])!;
91
97
  const member = pullFromCache<Amity.Membership<'community'>>([
92
98
  'communityUsers',
93
99
  'get',
94
- getResolver('communityUsers')(getEventRelatedMember(event, payload)),
100
+ getResolver('communityUsers')(getEventRelatedMember(event, unpackedPayload)),
95
101
  ])!;
96
102
 
97
103
  callback(community.data, member.data);
@@ -0,0 +1 @@
1
+ export * from './payload';
@@ -0,0 +1,44 @@
1
+ import { CommunityPostSettingMaps, DefaultCommunityPostSetting } from '~/@types';
2
+
3
+ const getMatchPostSetting = (value: {
4
+ needApprovalOnPostCreation: Amity.RawCommunity['needApprovalOnPostCreation'];
5
+ onlyAdminCanPost: Amity.RawCommunity['onlyAdminCanPost'];
6
+ }): Amity.Community['postSetting'] =>
7
+ Object.keys(CommunityPostSettingMaps).find(
8
+ key =>
9
+ value.needApprovalOnPostCreation ===
10
+ CommunityPostSettingMaps[key].needApprovalOnPostCreation &&
11
+ value.onlyAdminCanPost === CommunityPostSettingMaps[key].onlyAdminCanPost,
12
+ ) ?? DefaultCommunityPostSetting;
13
+
14
+ /*
15
+ * Unpack community payload by mapping payload field to postSetting value.
16
+ */
17
+ export const unpackCommunityPayload = <T extends Amity.CommunityPayload>({
18
+ communities,
19
+ ...restPayload
20
+ }: T) => ({
21
+ communities: communities.map<Amity.Community>(
22
+ ({ needApprovalOnPostCreation, onlyAdminCanPost, ...restCommunityPayload }) => ({
23
+ postSetting: getMatchPostSetting({
24
+ needApprovalOnPostCreation,
25
+ onlyAdminCanPost,
26
+ }),
27
+ ...restCommunityPayload,
28
+ }),
29
+ ),
30
+ ...restPayload,
31
+ });
32
+
33
+ /*
34
+ * Repack community payload by mapping postSetting to the actual value.
35
+ */
36
+ export const packCommunityPayload = <
37
+ T extends { postSetting?: Amity.Community['postSetting']; [k: string]: any },
38
+ >({
39
+ postSetting = undefined,
40
+ ...restParam
41
+ }: T) => ({
42
+ ...restParam,
43
+ ...(postSetting ? CommunityPostSettingMaps[postSetting] : undefined),
44
+ });
@@ -26,7 +26,7 @@ const CRITERIAS: Criterias = {
26
26
  channel: ['channelId', 'rateLimit'],
27
27
  channelUsers: ['channelId', 'userId', 'membership'],
28
28
  message: ['messageId'],
29
- community: ['communityId', 'onlyAdminCanPost'],
29
+ community: ['communityId', 'postSetting'],
30
30
  category: ['categoryId'],
31
31
  communityUsers: ['userId', 'communityId', 'communityMembership'],
32
32
  post: ['postId', 'feedId'],
@@ -67,7 +67,7 @@ export const liveFollowers = (
67
67
  .filter(Boolean)
68
68
  .map(({ data }) => data) ?? [];
69
69
 
70
- if (params.status) {
70
+ if (params.status && params.status !== 'all') {
71
71
  followers = filterByPropEquality(followers, 'status', params.status);
72
72
  }
73
73
 
@@ -67,7 +67,7 @@ export const liveFollowings = (
67
67
  .filter(Boolean)
68
68
  .map(({ data }) => data) ?? [];
69
69
 
70
- if (params.status) {
70
+ if (params.status && params.status !== 'all') {
71
71
  followings = filterByPropEquality(followings, 'status', params.status);
72
72
  }
73
73
 
@@ -0,0 +1,240 @@
1
+ import { ASCApiError } from '~/core/errors';
2
+ import { disableCache, enableCache } from '~/cache/api';
3
+ import { ENABLE_CACHE_MESSAGE } from '~/utils/constants';
4
+
5
+ import { queryFollowers } from '../../api/queryFollowers';
6
+ import { liveFollowers } from '../../observers/liveFollowers';
7
+
8
+ import {
9
+ client,
10
+ connectClient,
11
+ disconnectClient,
12
+ follows,
13
+ encodeJson,
14
+ follow21,
15
+ } from '~/utils/tests';
16
+
17
+ const getSnapshot = () => {
18
+ return {
19
+ loading: true,
20
+ error: undefined as any,
21
+ data: [] as Amity.FollowStatus[],
22
+ };
23
+ };
24
+
25
+ describe('liveFollowers', () => {
26
+ beforeAll(async () => {
27
+ await connectClient();
28
+ });
29
+
30
+ afterAll(async () => {
31
+ await disconnectClient();
32
+ });
33
+
34
+ beforeEach(enableCache);
35
+
36
+ afterEach(disableCache);
37
+
38
+ const { userId } = follows;
39
+ const args: Amity.FollowerLiveCollection = { userId };
40
+
41
+ test('it should show message if cache not enabled', () => {
42
+ /*
43
+ * NOTE: at the time of writing this test cache is diabled by default, but
44
+ * there is a proposal to enable cache by default. So I'm disabling cache
45
+ * here to ensure cache is disabled
46
+ */
47
+ disableCache();
48
+
49
+ const callback = jest.fn();
50
+ jest.spyOn(global.console, 'log');
51
+ client.http.get = jest.fn();
52
+
53
+ // call liveFollowers check if mocked console get's called with the correct
54
+ // message
55
+ client.use();
56
+ liveFollowers(args, callback);
57
+
58
+ expect(console.log).toBeCalledWith(ENABLE_CACHE_MESSAGE);
59
+ });
60
+
61
+ test('it should return following collection', async () => {
62
+ const snapshot = getSnapshot();
63
+ const response = { data: { paging: {}, follows: follows.page2 } };
64
+
65
+ const callback = jest.fn();
66
+ client.http.get = jest.fn().mockResolvedValue(response);
67
+
68
+ liveFollowers(args, callback);
69
+
70
+ expect(callback).toHaveBeenCalledTimes(1);
71
+
72
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
73
+
74
+ await expect(queryFollowers(args)).resolves.toBeTruthy();
75
+
76
+ expect(callback).toHaveBeenCalledTimes(2);
77
+
78
+ snapshot.loading = false;
79
+ snapshot.data = response.data.follows;
80
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
81
+ });
82
+
83
+ test('it should return error on api failure', async () => {
84
+ const snapshot = getSnapshot();
85
+ const error = new ASCApiError(
86
+ 'server error!',
87
+ Amity.ServerError.ITEM_NOT_FOUND,
88
+ Amity.ErrorLevel.ERROR,
89
+ );
90
+
91
+ const callback = jest.fn();
92
+ client.http.get = jest.fn().mockRejectedValue(error);
93
+
94
+ liveFollowers(args, callback);
95
+
96
+ expect(callback).toHaveBeenCalledTimes(1);
97
+
98
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
99
+
100
+ await expect(queryFollowers(args)).rejects.toThrow();
101
+
102
+ expect(callback).toHaveBeenCalledTimes(2);
103
+
104
+ snapshot.error = error;
105
+ snapshot.loading = false;
106
+ expect(callback).toHaveBeenLastCalledWith(expect.objectContaining(snapshot));
107
+ });
108
+
109
+ const statusFilters: [string, Amity.FollowerLiveCollection][] = [
110
+ ['all', { ...args, status: 'all', limit: 10 }],
111
+ ['accepted', { ...args, status: 'accepted', limit: 10 }],
112
+ ['pending', { ...args, status: 'pending', limit: 10 }],
113
+ ];
114
+
115
+ test.each(statusFilters)('it should filter %s follows based on param', async (filter, params) => {
116
+ const snapshot = getSnapshot();
117
+ const response = { data: { paging: {}, follows: follows.page2 } };
118
+
119
+ const callback = jest.fn();
120
+ client.http.get = jest.fn().mockResolvedValue(response);
121
+
122
+ liveFollowers(params, callback);
123
+
124
+ expect(callback).toHaveBeenCalledTimes(1);
125
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
126
+
127
+ // TODO : why ts gives no shit about args here ? wrong type :D
128
+ const query = queryFollowers(params);
129
+
130
+ await expect(query).resolves.toBeTruthy();
131
+
132
+ expect(callback).toHaveBeenCalledTimes(2);
133
+
134
+ snapshot.loading = false;
135
+ snapshot.data =
136
+ filter === 'all'
137
+ ? response.data.follows
138
+ : response.data.follows.filter(fl => fl.status === filter);
139
+
140
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
141
+ });
142
+
143
+ test('it should return method to fetch next page', async () => {
144
+ const snapshot = getSnapshot();
145
+ const args: Amity.FollowerLiveCollection = { userId, limit: 3 };
146
+ const next = encodeJson({
147
+ limit: 3,
148
+ before: follows.page2[2].from,
149
+ updatedAt: follows.page2[2].updatedAt,
150
+ });
151
+
152
+ const response = { data: { follows: follows.page1, paging: {} } };
153
+ const responseWithNextPage = { data: { follows: follows.page2, paging: { next } } };
154
+
155
+ const callback = jest.fn();
156
+ client.http.get = jest.fn().mockResolvedValue(responseWithNextPage);
157
+
158
+ liveFollowers(args, callback);
159
+
160
+ expect(callback).toHaveBeenCalled();
161
+
162
+ await expect(queryFollowers(args)).resolves.toBeTruthy();
163
+
164
+ expect(callback.mock.lastCall).toHaveLength(1);
165
+
166
+ const { onNextPage, hasNextPage } = callback.mock.lastCall[0];
167
+
168
+ expect(hasNextPage).toBe(true);
169
+ expect(onNextPage).toBeTruthy();
170
+
171
+ client.http.get = jest.fn().mockResolvedValue(response);
172
+
173
+ onNextPage();
174
+
175
+ await expect(queryFollowers(args)).resolves.toBeTruthy();
176
+
177
+ expect(callback).toHaveBeenCalledTimes(4);
178
+
179
+ snapshot.loading = false;
180
+ snapshot.data = [...responseWithNextPage.data.follows, ...response.data.follows];
181
+ expect(callback).toHaveBeenNthCalledWith(4, expect.objectContaining(snapshot));
182
+ });
183
+
184
+ const createEvents: [keyof Amity.Events][] = [
185
+ ['follow.created'],
186
+ ['follow.requested'],
187
+ ['follow.accepted'],
188
+ ];
189
+
190
+ test.each(createEvents)('it should add new follow to collection on %s', async event => {
191
+ const snapshot = getSnapshot();
192
+ const newFollower: Amity.FollowStatus = {
193
+ ...follow21,
194
+ from: 'some-user',
195
+ };
196
+ const response = { data: { follows: follows.page2, paging: {} } };
197
+
198
+ const callback = jest.fn();
199
+ client.http.get = jest.fn().mockResolvedValue(response);
200
+
201
+ liveFollowers(args, callback);
202
+
203
+ await expect(queryFollowers(args)).resolves.toBeTruthy();
204
+ expect(callback).toHaveBeenCalledTimes(2);
205
+
206
+ client.emitter.emit(event, { follows: [newFollower] });
207
+
208
+ snapshot.loading = false;
209
+ snapshot.data = [newFollower, ...response.data.follows];
210
+ expect(callback).toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
211
+ });
212
+
213
+ const removeEvents: [keyof Amity.Events][] = [
214
+ ['follow.requestDeclined'],
215
+ ['follow.requestCanceled'],
216
+ ['follow.unfollowed'],
217
+ ['follow.followerDeleted'],
218
+ ];
219
+
220
+ test.each(removeEvents)('it should remove a follow to collection on %s', async event => {
221
+ const snapshot = getSnapshot();
222
+ const response = { data: { follows: follows.page2, paging: {} } };
223
+
224
+ const callback = jest.fn();
225
+ client.http.get = jest.fn().mockResolvedValue(response);
226
+
227
+ liveFollowers(args, callback);
228
+
229
+ await expect(queryFollowers(args)).resolves.toBeTruthy();
230
+ expect(callback).toHaveBeenCalledTimes(2);
231
+
232
+ client.emitter.emit(event, { follows: [response.data.follows[0]] });
233
+
234
+ const [first, ...data] = response.data.follows;
235
+
236
+ snapshot.data = data;
237
+ snapshot.loading = false;
238
+ expect(callback).toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
239
+ });
240
+ });