@stream-io/feeds-client 0.2.18 → 0.2.19
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/CHANGELOG.md +16 -0
- package/dist/cjs/index.js +94 -25
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react-bindings.js +26 -55
- package/dist/cjs/react-bindings.js.map +1 -1
- package/dist/es/index.mjs +86 -17
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/react-bindings.mjs +19 -48
- package/dist/es/react-bindings.mjs.map +1 -1
- package/dist/{index--koeDtxd.js → feeds-client-C09giTf1.js} +177 -79
- package/dist/feeds-client-C09giTf1.js.map +1 -0
- package/dist/{index-Zde8UE5f.mjs → feeds-client-CFadXO-B.mjs} +190 -92
- package/dist/feeds-client-CFadXO-B.mjs.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts +2 -32
- package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts.map +1 -1
- package/dist/types/common/real-time/event-models.d.ts +7 -2
- package/dist/types/common/real-time/event-models.d.ts.map +1 -1
- package/dist/types/common/types.d.ts +1 -0
- package/dist/types/common/types.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
- package/dist/types/feed/feed.d.ts +1 -1
- package/dist/types/feed/feed.d.ts.map +1 -1
- package/dist/types/feeds-client/feeds-client.d.ts +9 -1
- package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
- package/dist/types/utils/throttling/index.d.ts +3 -0
- package/dist/types/utils/throttling/index.d.ts.map +1 -0
- package/dist/types/utils/throttling/throttle.d.ts +34 -0
- package/dist/types/utils/throttling/throttle.d.ts.map +1 -0
- package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts +14 -0
- package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts.map +1 -0
- package/package.json +7 -3
- package/react-bindings.d.ts +11 -0
- package/react-bindings.js +7 -0
- package/react-bindings.mjs +11 -0
- package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +21 -73
- package/src/common/real-time/event-models.ts +8 -2
- package/src/common/types.ts +1 -0
- package/src/feed/event-handlers/activity/handle-activity-added.ts +9 -1
- package/src/feed/event-handlers/activity/handle-activity-updated.ts +4 -0
- package/src/feed/feed.ts +18 -3
- package/src/feeds-client/feeds-client.ts +106 -3
- package/src/utils/throttling/index.ts +2 -0
- package/src/utils/throttling/throttle.ts +123 -0
- package/src/utils/throttling/throttled-get-batched-own-capabilities.ts +42 -0
- package/dist/index--koeDtxd.js.map +0 -1
- package/dist/index-Zde8UE5f.mjs.map +0 -1
- package/src/feed/event-handlers/activity/activity-marked-utils.test.ts +0 -208
- package/src/feed/event-handlers/activity/activity-reaction-utils.test.ts +0 -371
- package/src/feed/event-handlers/activity/handle-activity-added.test.ts +0 -97
- package/src/feed/event-handlers/activity/handle-activity-deleted.test.ts +0 -117
- package/src/feed/event-handlers/activity/handle-activity-pinned.test.ts +0 -60
- package/src/feed/event-handlers/activity/handle-activity-reaction-added.test.ts +0 -257
- package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.test.ts +0 -317
- package/src/feed/event-handlers/activity/handle-activity-reaction-updated.test.ts +0 -282
- package/src/feed/event-handlers/activity/handle-activity-unpinned.test.ts +0 -95
- package/src/feed/event-handlers/activity/handle-activity-updated.test.ts +0 -245
- package/src/feed/event-handlers/add-aggregated-activities-to-state.test.ts +0 -510
- package/src/feed/event-handlers/bookmark/bookmark-utils.test.ts +0 -521
- package/src/feed/event-handlers/bookmark/handle-bookmark-added.test.ts +0 -178
- package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.test.ts +0 -188
- package/src/feed/event-handlers/bookmark/handle-bookmark-updated.test.ts +0 -196
- package/src/feed/event-handlers/comment/handle-comment-added.test.ts +0 -271
- package/src/feed/event-handlers/comment/handle-comment-deleted.test.ts +0 -255
- package/src/feed/event-handlers/comment/handle-comment-reaction-added.test.ts +0 -329
- package/src/feed/event-handlers/comment/handle-comment-reaction-deleted.test.ts +0 -343
- package/src/feed/event-handlers/comment/handle-comment-reaction-updated.test.ts +0 -350
- package/src/feed/event-handlers/comment/handle-comment-updated.test.ts +0 -267
- package/src/feed/event-handlers/comment/utils/update-comment-count.test.ts +0 -322
- package/src/feed/event-handlers/feed-member/handle-feed-member-added.test.ts +0 -75
- package/src/feed/event-handlers/feed-member/handle-feed-member-removed.test.ts +0 -82
- package/src/feed/event-handlers/feed-member/handle-feed-member-updated.test.ts +0 -84
- package/src/feed/event-handlers/follow/follow-state-update-queue.test.ts +0 -219
- package/src/feed/event-handlers/follow/handle-follow-created.test.ts +0 -250
- package/src/feed/event-handlers/follow/handle-follow-deleted.test.ts +0 -268
- package/src/feed/event-handlers/follow/handle-follow-updated.test.ts +0 -131
- package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.test.ts +0 -182
- package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.test.ts +0 -45
- package/src/feed/feed.test.ts +0 -90
- package/src/feeds-client/event-handlers/user/handle-user-updated.test.ts +0 -53
- package/src/utils/event-triggered-by-connected-user.test.ts +0 -73
- package/src/utils/state-update-queue.test.ts +0 -129
- package/src/utils/unique-array-merge.test.ts +0 -179
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { Feed } from '../../../feed';
|
|
3
|
-
import { FeedsClient } from '../../../feeds-client';
|
|
4
|
-
import { handleActivityReactionDeleted } from './handle-activity-reaction-deleted';
|
|
5
|
-
import { handleActivityReactionAdded } from './handle-activity-reaction-added';
|
|
6
|
-
import {
|
|
7
|
-
generateActivityPinResponse,
|
|
8
|
-
generateActivityResponse,
|
|
9
|
-
generateFeedReactionResponse,
|
|
10
|
-
generateFeedResponse,
|
|
11
|
-
generateOwnUser,
|
|
12
|
-
getHumanId,
|
|
13
|
-
generateActivityReactionDeletedEvent,
|
|
14
|
-
} from '../../../test-utils';
|
|
15
|
-
import { shouldUpdateState } from '../../../utils';
|
|
16
|
-
import type { EventPayload } from '../../../types-internal';
|
|
17
|
-
|
|
18
|
-
describe(handleActivityReactionDeleted.name, () => {
|
|
19
|
-
let feed: Feed;
|
|
20
|
-
let client: FeedsClient;
|
|
21
|
-
let currentUserId: string;
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
client = new FeedsClient('mock-api-key');
|
|
25
|
-
currentUserId = getHumanId();
|
|
26
|
-
client.state.partialNext({
|
|
27
|
-
connected_user: generateOwnUser({ id: currentUserId }),
|
|
28
|
-
});
|
|
29
|
-
const feedResponse = generateFeedResponse({
|
|
30
|
-
id: 'main',
|
|
31
|
-
group_id: 'user',
|
|
32
|
-
created_by: { id: currentUserId },
|
|
33
|
-
});
|
|
34
|
-
feed = new Feed(
|
|
35
|
-
client,
|
|
36
|
-
feedResponse.group_id,
|
|
37
|
-
feedResponse.id,
|
|
38
|
-
feedResponse,
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('removes a reaction from the correct activity for current user & updates activities with event.activity', () => {
|
|
43
|
-
const event = generateActivityReactionDeletedEvent({
|
|
44
|
-
activity: {
|
|
45
|
-
reaction_count: 0,
|
|
46
|
-
},
|
|
47
|
-
reaction: {
|
|
48
|
-
type: 'like',
|
|
49
|
-
user: { id: currentUserId },
|
|
50
|
-
},
|
|
51
|
-
user: { id: currentUserId },
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const activity = generateActivityResponse({
|
|
55
|
-
reaction_count: 1,
|
|
56
|
-
own_reactions: [
|
|
57
|
-
generateFeedReactionResponse({
|
|
58
|
-
type: 'like',
|
|
59
|
-
user: { id: currentUserId },
|
|
60
|
-
activity_id: event.activity.id,
|
|
61
|
-
}),
|
|
62
|
-
],
|
|
63
|
-
id: event.activity.id,
|
|
64
|
-
});
|
|
65
|
-
const activityPin = generateActivityPinResponse({
|
|
66
|
-
activity: { ...activity },
|
|
67
|
-
});
|
|
68
|
-
feed.state.partialNext({
|
|
69
|
-
activities: [activity],
|
|
70
|
-
pinned_activities: [activityPin],
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const stateBefore = feed.currentState;
|
|
74
|
-
expect(stateBefore.activities![0].own_reactions).toHaveLength(1);
|
|
75
|
-
expect(
|
|
76
|
-
stateBefore.pinned_activities![0].activity.own_reactions,
|
|
77
|
-
).toHaveLength(1);
|
|
78
|
-
expect(stateBefore.activities![0].reaction_count).toBe(1);
|
|
79
|
-
expect(stateBefore.pinned_activities![0].activity.reaction_count).toBe(
|
|
80
|
-
1,
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
handleActivityReactionDeleted.call(feed, event);
|
|
84
|
-
|
|
85
|
-
const stateAfter = feed.currentState;
|
|
86
|
-
expect(stateAfter.activities![0].own_reactions).toHaveLength(0);
|
|
87
|
-
expect(
|
|
88
|
-
stateAfter.pinned_activities![0].activity.own_reactions,
|
|
89
|
-
).toHaveLength(0);
|
|
90
|
-
expect(stateAfter.activities![0].reaction_count).toBe(0);
|
|
91
|
-
expect(stateAfter.pinned_activities![0].activity.reaction_count).toBe(0);
|
|
92
|
-
expect(stateAfter.activities![0].own_bookmarks).toBe(
|
|
93
|
-
stateBefore.activities![0].own_bookmarks,
|
|
94
|
-
);
|
|
95
|
-
expect(stateAfter.pinned_activities![0].activity.own_bookmarks).toBe(
|
|
96
|
-
stateBefore.pinned_activities![0].activity.own_bookmarks,
|
|
97
|
-
);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('does not remove from own_reactions if reaction is from another user but still updates activity', () => {
|
|
101
|
-
const event = generateActivityReactionDeletedEvent({
|
|
102
|
-
activity: {
|
|
103
|
-
reaction_count: 0,
|
|
104
|
-
},
|
|
105
|
-
reaction: {
|
|
106
|
-
type: 'like',
|
|
107
|
-
user: { id: 'other-user-id' },
|
|
108
|
-
},
|
|
109
|
-
user: { id: 'other-user-id' },
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const activity = generateActivityResponse({
|
|
113
|
-
reaction_count: 1,
|
|
114
|
-
own_reactions: [
|
|
115
|
-
generateFeedReactionResponse({
|
|
116
|
-
type: 'like',
|
|
117
|
-
user: { id: currentUserId },
|
|
118
|
-
activity_id: event.activity.id,
|
|
119
|
-
}),
|
|
120
|
-
],
|
|
121
|
-
id: event.activity.id,
|
|
122
|
-
});
|
|
123
|
-
const activityPin = generateActivityPinResponse({
|
|
124
|
-
activity: { ...activity },
|
|
125
|
-
});
|
|
126
|
-
feed.state.partialNext({
|
|
127
|
-
activities: [activity],
|
|
128
|
-
pinned_activities: [activityPin],
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const stateBefore = feed.currentState;
|
|
132
|
-
expect(stateBefore.activities![0].own_reactions).toHaveLength(1);
|
|
133
|
-
expect(
|
|
134
|
-
stateBefore.pinned_activities![0].activity.own_reactions,
|
|
135
|
-
).toHaveLength(1);
|
|
136
|
-
expect(stateBefore.activities![0].reaction_count).toBe(1);
|
|
137
|
-
expect(stateBefore.pinned_activities![0].activity.reaction_count).toBe(
|
|
138
|
-
1,
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
handleActivityReactionDeleted.call(feed, event);
|
|
142
|
-
|
|
143
|
-
const stateAfter = feed.currentState;
|
|
144
|
-
expect(stateAfter.activities![0].own_reactions).toHaveLength(1);
|
|
145
|
-
expect(stateAfter.activities![0].own_reactions).toBe(
|
|
146
|
-
stateBefore.activities![0].own_reactions,
|
|
147
|
-
);
|
|
148
|
-
expect(stateAfter.pinned_activities![0].activity.own_reactions).toBe(
|
|
149
|
-
stateBefore.pinned_activities![0].activity.own_reactions,
|
|
150
|
-
);
|
|
151
|
-
expect(stateAfter.activities![0].own_bookmarks).toBe(
|
|
152
|
-
stateBefore.activities![0].own_bookmarks,
|
|
153
|
-
);
|
|
154
|
-
expect(stateAfter.pinned_activities![0].activity.own_bookmarks).toBe(
|
|
155
|
-
stateBefore.pinned_activities![0].activity.own_bookmarks,
|
|
156
|
-
);
|
|
157
|
-
expect(
|
|
158
|
-
stateAfter.pinned_activities![0].activity.own_reactions,
|
|
159
|
-
).toHaveLength(1);
|
|
160
|
-
expect(stateAfter.activities![0].reaction_count).toBe(0);
|
|
161
|
-
expect(stateAfter.pinned_activities![0].activity.reaction_count).toBe(0);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('does nothing if activity is not found', () => {
|
|
165
|
-
const event = generateActivityReactionDeletedEvent({
|
|
166
|
-
activity: {
|
|
167
|
-
reaction_count: 0,
|
|
168
|
-
},
|
|
169
|
-
reaction: {
|
|
170
|
-
type: 'like',
|
|
171
|
-
user: { id: currentUserId },
|
|
172
|
-
},
|
|
173
|
-
user: { id: currentUserId },
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
const activity = generateActivityResponse({
|
|
177
|
-
reaction_count: 1,
|
|
178
|
-
own_reactions: [
|
|
179
|
-
generateFeedReactionResponse({
|
|
180
|
-
type: 'like',
|
|
181
|
-
user: { id: currentUserId },
|
|
182
|
-
activity_id: 'activity1',
|
|
183
|
-
}),
|
|
184
|
-
],
|
|
185
|
-
id: 'activity1',
|
|
186
|
-
});
|
|
187
|
-
const activityPin = generateActivityPinResponse({
|
|
188
|
-
activity: { ...activity },
|
|
189
|
-
});
|
|
190
|
-
feed.state.partialNext({
|
|
191
|
-
activities: [activity],
|
|
192
|
-
pinned_activities: [activityPin],
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const stateBefore = feed.currentState;
|
|
196
|
-
|
|
197
|
-
handleActivityReactionDeleted.call(feed, event);
|
|
198
|
-
|
|
199
|
-
const stateAfter = feed.currentState;
|
|
200
|
-
|
|
201
|
-
expect(stateAfter).toBe(stateBefore);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
describe(`Activity reaction deleted ${shouldUpdateState.name} integration`, () => {
|
|
205
|
-
const activityId = 'reacted-activity';
|
|
206
|
-
let currentUserPayload: EventPayload<'feeds.activity.reaction.deleted'>;
|
|
207
|
-
let otherUserPayload: EventPayload<'feeds.activity.reaction.deleted'>;
|
|
208
|
-
|
|
209
|
-
beforeEach(() => {
|
|
210
|
-
currentUserPayload = generateActivityReactionDeletedEvent({
|
|
211
|
-
reaction: { user: { id: currentUserId }, activity_id: activityId },
|
|
212
|
-
activity: { id: activityId }
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
otherUserPayload = generateActivityReactionDeletedEvent({
|
|
216
|
-
reaction: { user: { id: getHumanId() }, activity_id: activityId },
|
|
217
|
-
activity: { id: activityId }
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
feed.state.partialNext({ activities: [currentUserPayload.activity]});
|
|
221
|
-
feed.state.partialNext({ watch: true });
|
|
222
|
-
|
|
223
|
-
handleActivityReactionAdded.call(feed, currentUserPayload, false);
|
|
224
|
-
handleActivityReactionAdded.call(feed, otherUserPayload, false);
|
|
225
|
-
|
|
226
|
-
(feed as any).stateUpdateQueue.clear();
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
it(`skips update if ${shouldUpdateState.name} returns false`, () => {
|
|
230
|
-
// 1. HTTP and then WS
|
|
231
|
-
|
|
232
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload, false);
|
|
233
|
-
|
|
234
|
-
let stateBefore = feed.currentState;
|
|
235
|
-
|
|
236
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload);
|
|
237
|
-
|
|
238
|
-
let stateAfter = feed.currentState;
|
|
239
|
-
|
|
240
|
-
expect(stateAfter).toBe(stateBefore);
|
|
241
|
-
// @ts-expect-error Using Feed internals for tests only
|
|
242
|
-
expect(feed.stateUpdateQueue.size).toEqual(0);
|
|
243
|
-
|
|
244
|
-
// 2. WS and the HTTP
|
|
245
|
-
|
|
246
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload);
|
|
247
|
-
|
|
248
|
-
stateBefore = feed.currentState;
|
|
249
|
-
|
|
250
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload, false);
|
|
251
|
-
|
|
252
|
-
stateAfter = feed.currentState;
|
|
253
|
-
|
|
254
|
-
expect(stateAfter).toBe(stateBefore);
|
|
255
|
-
// @ts-expect-error Using Feed internals for tests only
|
|
256
|
-
expect(feed.stateUpdateQueue.size).toEqual(0);
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
it('allows update again from WS after clearing the stateUpdateQueue', () => {
|
|
260
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload);
|
|
261
|
-
|
|
262
|
-
let activities = feed.currentState.activities!;
|
|
263
|
-
let activity = activities.find((a) => a.id === activityId);
|
|
264
|
-
|
|
265
|
-
expect(activity?.own_reactions.length).toEqual(0);
|
|
266
|
-
|
|
267
|
-
// Clear the queue and reinitialize the state
|
|
268
|
-
handleActivityReactionAdded.call(feed, currentUserPayload, false);
|
|
269
|
-
(feed as any).stateUpdateQueue.clear();
|
|
270
|
-
|
|
271
|
-
// Now update should be allowed from another WS event
|
|
272
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload);
|
|
273
|
-
|
|
274
|
-
activities = feed.currentState.activities!;
|
|
275
|
-
activity = activities.find((a) => a.id === activityId);
|
|
276
|
-
|
|
277
|
-
expect(activity?.own_reactions.length).toEqual(0);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('allows update again from HTTP response after clearing the stateUpdateQueue', () => {
|
|
281
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload, false);
|
|
282
|
-
|
|
283
|
-
let activities = feed.currentState.activities!;
|
|
284
|
-
let activity = activities.find((a) => a.id === activityId);
|
|
285
|
-
|
|
286
|
-
expect(activity?.own_reactions.length).toEqual(0);
|
|
287
|
-
|
|
288
|
-
// Clear the queue and reinitialize the state
|
|
289
|
-
handleActivityReactionAdded.call(feed, currentUserPayload, false);
|
|
290
|
-
(feed as any).stateUpdateQueue.clear();
|
|
291
|
-
|
|
292
|
-
// Now update should be allowed from another HTTP response
|
|
293
|
-
handleActivityReactionDeleted.call(feed, currentUserPayload, false);
|
|
294
|
-
|
|
295
|
-
activities = feed.currentState.activities!;
|
|
296
|
-
activity = activities.find((a) => a.id === activityId);
|
|
297
|
-
|
|
298
|
-
expect(activity?.own_reactions.length).toEqual(0);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should not insert anything into the stateUpdateQueue if the connected_user did not trigger the reaction', () => {
|
|
302
|
-
handleActivityReactionDeleted.call(feed, otherUserPayload);
|
|
303
|
-
|
|
304
|
-
expect((feed as any).stateUpdateQueue).toEqual(new Set());
|
|
305
|
-
|
|
306
|
-
handleActivityReactionDeleted.call(feed, otherUserPayload);
|
|
307
|
-
|
|
308
|
-
const activities = feed.currentState.activities!;
|
|
309
|
-
const activity = activities.find((a) => a.id === activityId);
|
|
310
|
-
const [latestOwnReaction] = activity?.own_reactions ?? [];
|
|
311
|
-
|
|
312
|
-
expect((feed as any).stateUpdateQueue).toEqual(new Set());
|
|
313
|
-
expect(activity?.own_reactions.length).toEqual(1);
|
|
314
|
-
expect(latestOwnReaction).toBe(currentUserPayload.reaction);
|
|
315
|
-
});
|
|
316
|
-
})
|
|
317
|
-
});
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { Feed, handleActivityReactionUpdated } from '../../../feed';
|
|
3
|
-
import { FeedsClient } from '../../../feeds-client';
|
|
4
|
-
import {
|
|
5
|
-
generateActivityPinResponse,
|
|
6
|
-
generateActivityResponse,
|
|
7
|
-
generateFeedResponse,
|
|
8
|
-
generateOwnUser,
|
|
9
|
-
getHumanId,
|
|
10
|
-
generateActivityReactionUpdatedEvent,
|
|
11
|
-
generateFeedReactionResponse,
|
|
12
|
-
} from '../../../test-utils';
|
|
13
|
-
import { shouldUpdateState } from '../../../utils';
|
|
14
|
-
import type { EventPayload } from '../../../types-internal';
|
|
15
|
-
|
|
16
|
-
describe(handleActivityReactionUpdated.name, () => {
|
|
17
|
-
let feed: Feed;
|
|
18
|
-
let client: FeedsClient;
|
|
19
|
-
let currentUserId: string;
|
|
20
|
-
let activityId: string;
|
|
21
|
-
|
|
22
|
-
beforeEach(() => {
|
|
23
|
-
client = new FeedsClient('mock-api-key');
|
|
24
|
-
currentUserId = getHumanId();
|
|
25
|
-
activityId = getHumanId();
|
|
26
|
-
client.state.partialNext({
|
|
27
|
-
connected_user: generateOwnUser({ id: currentUserId }),
|
|
28
|
-
});
|
|
29
|
-
const feedResponse = generateFeedResponse({
|
|
30
|
-
id: 'main',
|
|
31
|
-
group_id: 'user',
|
|
32
|
-
created_by: { id: currentUserId },
|
|
33
|
-
});
|
|
34
|
-
feed = new Feed(
|
|
35
|
-
client,
|
|
36
|
-
feedResponse.group_id,
|
|
37
|
-
feedResponse.id,
|
|
38
|
-
feedResponse,
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('updates the reaction in the correct activity for current user & updates activities with event.activity', () => {
|
|
43
|
-
const event = generateActivityReactionUpdatedEvent({
|
|
44
|
-
reaction: {
|
|
45
|
-
user: { id: currentUserId },
|
|
46
|
-
type: 'downvote',
|
|
47
|
-
activity_id: activityId,
|
|
48
|
-
},
|
|
49
|
-
activity: {
|
|
50
|
-
reaction_count: 1,
|
|
51
|
-
latest_reactions: [],
|
|
52
|
-
reaction_groups: {},
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const existingReaction = generateFeedReactionResponse({
|
|
57
|
-
user: { id: currentUserId },
|
|
58
|
-
type: 'like',
|
|
59
|
-
activity_id: activityId,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const activity = generateActivityResponse({
|
|
63
|
-
id: event.activity.id,
|
|
64
|
-
reaction_count: 1,
|
|
65
|
-
own_reactions: [existingReaction],
|
|
66
|
-
latest_reactions: [],
|
|
67
|
-
reaction_groups: {},
|
|
68
|
-
});
|
|
69
|
-
const activityPin = generateActivityPinResponse({
|
|
70
|
-
activity: { ...activity },
|
|
71
|
-
});
|
|
72
|
-
feed.state.partialNext({
|
|
73
|
-
activities: [activity],
|
|
74
|
-
pinned_activities: [activityPin],
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const stateBefore = feed.currentState;
|
|
78
|
-
|
|
79
|
-
expect(stateBefore.activities![0].reaction_count).toBe(1);
|
|
80
|
-
expect(stateBefore.pinned_activities![0].activity.reaction_count).toBe(1);
|
|
81
|
-
|
|
82
|
-
handleActivityReactionUpdated.call(feed, event);
|
|
83
|
-
|
|
84
|
-
const stateAfter = feed.currentState;
|
|
85
|
-
|
|
86
|
-
expect(stateAfter.activities![0].own_reactions).toContain(event.reaction);
|
|
87
|
-
expect(stateAfter.pinned_activities![0].activity.own_reactions).toContain(
|
|
88
|
-
event.reaction,
|
|
89
|
-
);
|
|
90
|
-
expect(stateAfter.activities![0].own_bookmarks).toBe(
|
|
91
|
-
stateBefore.activities![0].own_bookmarks,
|
|
92
|
-
);
|
|
93
|
-
expect(stateAfter.pinned_activities![0].activity.own_bookmarks).toBe(
|
|
94
|
-
stateBefore.pinned_activities![0].activity.own_bookmarks,
|
|
95
|
-
);
|
|
96
|
-
expect(stateAfter.activities![0].reaction_count).toBe(1);
|
|
97
|
-
expect(stateAfter.pinned_activities![0].activity.reaction_count).toBe(1);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('does not update own_reactions if the reaction is from another user but still updates activity', () => {
|
|
101
|
-
const event = generateActivityReactionUpdatedEvent({
|
|
102
|
-
reaction: {
|
|
103
|
-
user: { id: 'other-user-id' },
|
|
104
|
-
type: 'downvote',
|
|
105
|
-
activity_id: activityId,
|
|
106
|
-
},
|
|
107
|
-
activity: {
|
|
108
|
-
reaction_count: 2,
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const existingReaction = generateFeedReactionResponse({
|
|
113
|
-
user: { id: currentUserId },
|
|
114
|
-
type: 'like',
|
|
115
|
-
activity_id: activityId,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const activity = generateActivityResponse({
|
|
119
|
-
id: event.activity.id,
|
|
120
|
-
reaction_count: 1,
|
|
121
|
-
own_reactions: [existingReaction],
|
|
122
|
-
latest_reactions: [],
|
|
123
|
-
reaction_groups: {},
|
|
124
|
-
});
|
|
125
|
-
const activityPin = generateActivityPinResponse({
|
|
126
|
-
activity: { ...activity },
|
|
127
|
-
});
|
|
128
|
-
feed.state.partialNext({
|
|
129
|
-
activities: [activity],
|
|
130
|
-
pinned_activities: [activityPin],
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const stateBefore = feed.currentState;
|
|
134
|
-
|
|
135
|
-
expect(stateBefore.activities![0].reaction_count).toBe(1);
|
|
136
|
-
expect(stateBefore.pinned_activities![0].activity.reaction_count).toBe(1);
|
|
137
|
-
|
|
138
|
-
handleActivityReactionUpdated.call(feed, event);
|
|
139
|
-
|
|
140
|
-
const stateAfter = feed.currentState;
|
|
141
|
-
|
|
142
|
-
expect(stateAfter.activities![0].own_reactions).toHaveLength(1);
|
|
143
|
-
expect(
|
|
144
|
-
stateAfter.pinned_activities![0].activity.own_reactions,
|
|
145
|
-
).toHaveLength(1);
|
|
146
|
-
expect(stateAfter.activities![0].reaction_count).toBe(2);
|
|
147
|
-
expect(stateAfter.pinned_activities![0].activity.reaction_count).toBe(2);
|
|
148
|
-
expect(stateAfter.activities![0].own_bookmarks).toBe(
|
|
149
|
-
stateBefore.activities![0].own_bookmarks,
|
|
150
|
-
);
|
|
151
|
-
expect(stateAfter.pinned_activities![0].activity.own_bookmarks).toBe(
|
|
152
|
-
stateBefore.pinned_activities![0].activity.own_bookmarks,
|
|
153
|
-
);
|
|
154
|
-
expect(stateAfter.activities![0].own_reactions).toBe(
|
|
155
|
-
stateBefore.activities![0].own_reactions,
|
|
156
|
-
);
|
|
157
|
-
expect(stateAfter.pinned_activities![0].activity.own_reactions).toBe(
|
|
158
|
-
stateBefore.pinned_activities![0].activity.own_reactions,
|
|
159
|
-
);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('does nothing if activity is not found', () => {
|
|
163
|
-
const event = generateActivityReactionUpdatedEvent({
|
|
164
|
-
reaction: { user: { id: currentUserId } },
|
|
165
|
-
});
|
|
166
|
-
const activity = generateActivityResponse({
|
|
167
|
-
id: 'unrelated',
|
|
168
|
-
});
|
|
169
|
-
const activityPin = generateActivityPinResponse({
|
|
170
|
-
activity: { ...activity },
|
|
171
|
-
});
|
|
172
|
-
feed.state.partialNext({
|
|
173
|
-
activities: [activity],
|
|
174
|
-
pinned_activities: [activityPin],
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const stateBefore = feed.currentState;
|
|
178
|
-
|
|
179
|
-
handleActivityReactionUpdated.call(feed, event);
|
|
180
|
-
|
|
181
|
-
const stateAfter = feed.currentState;
|
|
182
|
-
|
|
183
|
-
expect(stateAfter).toBe(stateBefore);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
describe(`Activity reaction updated ${shouldUpdateState.name} integration`, () => {
|
|
187
|
-
let currentUserPayload: EventPayload<'feeds.activity.reaction.updated'>;
|
|
188
|
-
|
|
189
|
-
beforeEach(() => {
|
|
190
|
-
currentUserPayload = generateActivityReactionUpdatedEvent({
|
|
191
|
-
reaction: { user: { id: currentUserId }, activity_id: activityId },
|
|
192
|
-
activity: { id: activityId },
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
feed.state.partialNext({ activities: [currentUserPayload.activity] });
|
|
196
|
-
feed.state.partialNext({ watch: true });
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it(`skips update if ${shouldUpdateState.name} returns false`, () => {
|
|
200
|
-
// 1. HTTP and then WS
|
|
201
|
-
|
|
202
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload, false);
|
|
203
|
-
|
|
204
|
-
let stateBefore = feed.currentState;
|
|
205
|
-
|
|
206
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload);
|
|
207
|
-
|
|
208
|
-
let stateAfter = feed.currentState;
|
|
209
|
-
|
|
210
|
-
expect(stateAfter).toBe(stateBefore);
|
|
211
|
-
// @ts-expect-error Using Feed internals for tests only
|
|
212
|
-
expect(feed.stateUpdateQueue.size).toEqual(0);
|
|
213
|
-
|
|
214
|
-
// 2. WS and the HTTP
|
|
215
|
-
|
|
216
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload);
|
|
217
|
-
|
|
218
|
-
stateBefore = feed.currentState;
|
|
219
|
-
|
|
220
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload, false);
|
|
221
|
-
|
|
222
|
-
stateAfter = feed.currentState;
|
|
223
|
-
|
|
224
|
-
expect(stateAfter).toBe(stateBefore);
|
|
225
|
-
// @ts-expect-error Using Feed internals for tests only
|
|
226
|
-
expect(feed.stateUpdateQueue.size).toEqual(0);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it('allows update again from WS after clearing the stateUpdateQueue', () => {
|
|
230
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload);
|
|
231
|
-
|
|
232
|
-
// Clear the queue
|
|
233
|
-
(feed as any).stateUpdateQueue.clear();
|
|
234
|
-
|
|
235
|
-
// Now update should be allowed from another WS event
|
|
236
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload);
|
|
237
|
-
|
|
238
|
-
const activities = feed.currentState.activities!;
|
|
239
|
-
const activity = activities.find((a) => a.id === activityId);
|
|
240
|
-
const [latestReaction] = activity?.own_reactions ?? [];
|
|
241
|
-
|
|
242
|
-
expect(activity?.own_reactions.length).toEqual(1);
|
|
243
|
-
expect(latestReaction).toMatchObject(currentUserPayload.reaction);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it('allows update again from HTTP response after clearing the stateUpdateQueue', () => {
|
|
247
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload, false);
|
|
248
|
-
|
|
249
|
-
// Clear the queue
|
|
250
|
-
(feed as any).stateUpdateQueue.clear();
|
|
251
|
-
|
|
252
|
-
// Now update should be allowed from another HTTP response
|
|
253
|
-
handleActivityReactionUpdated.call(feed, currentUserPayload, false);
|
|
254
|
-
|
|
255
|
-
const activities = feed.currentState.activities!;
|
|
256
|
-
const activity = activities.find((a) => a.id === activityId);
|
|
257
|
-
const [latestReaction] = activity?.own_reactions ?? [];
|
|
258
|
-
|
|
259
|
-
expect(activity?.own_reactions.length).toEqual(1);
|
|
260
|
-
expect(latestReaction).toMatchObject(currentUserPayload.reaction);
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it('should not insert anything into the stateUpdateQueue if the connected_user did not trigger the reaction', () => {
|
|
264
|
-
const otherUserPayload = generateActivityReactionUpdatedEvent({
|
|
265
|
-
reaction: { user: { id: getHumanId() }, activity_id: activityId },
|
|
266
|
-
activity: { id: activityId },
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
handleActivityReactionUpdated.call(feed, otherUserPayload);
|
|
270
|
-
|
|
271
|
-
expect((feed as any).stateUpdateQueue).toEqual(new Set());
|
|
272
|
-
|
|
273
|
-
handleActivityReactionUpdated.call(feed, otherUserPayload);
|
|
274
|
-
|
|
275
|
-
const activities = feed.currentState.activities!;
|
|
276
|
-
const activity = activities.find((a) => a.id === activityId);
|
|
277
|
-
|
|
278
|
-
expect((feed as any).stateUpdateQueue).toEqual(new Set());
|
|
279
|
-
expect(activity?.own_reactions.length).toEqual(0);
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
});
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { Feed } from '../../../feed';
|
|
4
|
-
import { FeedsClient } from '../../../feeds-client';
|
|
5
|
-
import { handleActivityUnpinned } from './handle-activity-unpinned';
|
|
6
|
-
import {
|
|
7
|
-
generateActivityPinResponse,
|
|
8
|
-
generateFeedResponse,
|
|
9
|
-
} from '../../../test-utils/response-generators';
|
|
10
|
-
import type { ActivityPinResponse } from '../../../gen/models';
|
|
11
|
-
import type { EventPayload } from '../../../types-internal';
|
|
12
|
-
|
|
13
|
-
// Helper to construct the event payload for 'feeds.activity.unpinned'
|
|
14
|
-
function makeUnpinnedEvent(
|
|
15
|
-
pinnedActivity: ActivityPinResponse,
|
|
16
|
-
): EventPayload<'feeds.activity.unpinned'> {
|
|
17
|
-
return {
|
|
18
|
-
type: 'feeds.activity.unpinned',
|
|
19
|
-
created_at: pinnedActivity.created_at,
|
|
20
|
-
fid: pinnedActivity.feed,
|
|
21
|
-
custom: {},
|
|
22
|
-
pinned_activity: {
|
|
23
|
-
created_at: pinnedActivity.created_at,
|
|
24
|
-
duration: '0',
|
|
25
|
-
feed: pinnedActivity.feed,
|
|
26
|
-
user_id: pinnedActivity.user.id,
|
|
27
|
-
activity: pinnedActivity.activity,
|
|
28
|
-
},
|
|
29
|
-
user: pinnedActivity.user,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
describe(handleActivityUnpinned.name, () => {
|
|
34
|
-
let feed: Feed;
|
|
35
|
-
let client: FeedsClient;
|
|
36
|
-
let pinnedActivity: ActivityPinResponse;
|
|
37
|
-
let otherPinnedActivity: ActivityPinResponse;
|
|
38
|
-
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
client = new FeedsClient('mock-api-key');
|
|
41
|
-
const feedResponse = generateFeedResponse({ id: 'main', group_id: 'user' });
|
|
42
|
-
feed = new Feed(
|
|
43
|
-
client,
|
|
44
|
-
feedResponse.group_id,
|
|
45
|
-
feedResponse.id,
|
|
46
|
-
feedResponse,
|
|
47
|
-
);
|
|
48
|
-
pinnedActivity = generateActivityPinResponse();
|
|
49
|
-
otherPinnedActivity = generateActivityPinResponse();
|
|
50
|
-
feed.state.next((currentState) => ({
|
|
51
|
-
...currentState,
|
|
52
|
-
pinned_activities: [pinnedActivity, otherPinnedActivity],
|
|
53
|
-
}));
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('removes the correct activity from pinned_activities', () => {
|
|
57
|
-
const event = makeUnpinnedEvent(pinnedActivity);
|
|
58
|
-
handleActivityUnpinned.call(feed, event);
|
|
59
|
-
const { pinned_activities } = feed.currentState;
|
|
60
|
-
expect(pinned_activities).toHaveLength(1);
|
|
61
|
-
expect(pinned_activities![0]).toBe(otherPinnedActivity);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('does nothing if the activity is not found', () => {
|
|
65
|
-
const unrelatedActivity = generateActivityPinResponse();
|
|
66
|
-
const event = makeUnpinnedEvent(unrelatedActivity);
|
|
67
|
-
const stateBefore = feed.currentState;
|
|
68
|
-
handleActivityUnpinned.call(feed, event);
|
|
69
|
-
const stateAfter = feed.currentState;
|
|
70
|
-
expect(stateAfter.pinned_activities).toBe(stateBefore.pinned_activities);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('does nothing if pinned_activities is empty', () => {
|
|
74
|
-
feed.state.next((currentState) => ({
|
|
75
|
-
...currentState,
|
|
76
|
-
pinned_activities: [],
|
|
77
|
-
}));
|
|
78
|
-
const event = makeUnpinnedEvent(pinnedActivity);
|
|
79
|
-
const stateBefore = feed.currentState;
|
|
80
|
-
handleActivityUnpinned.call(feed, event);
|
|
81
|
-
const stateAfter = feed.currentState;
|
|
82
|
-
expect(stateAfter).toBe(stateBefore);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('does nothing if pinned_activities is undefined', () => {
|
|
86
|
-
feed.state.next((currentState) => ({
|
|
87
|
-
...currentState,
|
|
88
|
-
pinned_activities: undefined,
|
|
89
|
-
}));
|
|
90
|
-
const event = makeUnpinnedEvent(pinnedActivity);
|
|
91
|
-
handleActivityUnpinned.call(feed, event);
|
|
92
|
-
const stateAfter = feed.currentState;
|
|
93
|
-
expect(stateAfter.pinned_activities).toBeUndefined();
|
|
94
|
-
});
|
|
95
|
-
});
|