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