@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.
Files changed (84) hide show
  1. package/CHANGELOG.md +16 -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--koeDtxd.js → feeds-client-C09giTf1.js} +177 -79
  11. package/dist/feeds-client-C09giTf1.js.map +1 -0
  12. package/dist/{index-Zde8UE5f.mjs → feeds-client-CFadXO-B.mjs} +190 -92
  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/event-models.d.ts +7 -2
  18. package/dist/types/common/real-time/event-models.d.ts.map +1 -1
  19. package/dist/types/common/types.d.ts +1 -0
  20. package/dist/types/common/types.d.ts.map +1 -1
  21. package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts.map +1 -1
  22. package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
  23. package/dist/types/feed/feed.d.ts +1 -1
  24. package/dist/types/feed/feed.d.ts.map +1 -1
  25. package/dist/types/feeds-client/feeds-client.d.ts +9 -1
  26. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  27. package/dist/types/utils/throttling/index.d.ts +3 -0
  28. package/dist/types/utils/throttling/index.d.ts.map +1 -0
  29. package/dist/types/utils/throttling/throttle.d.ts +34 -0
  30. package/dist/types/utils/throttling/throttle.d.ts.map +1 -0
  31. package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts +14 -0
  32. package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts.map +1 -0
  33. package/package.json +7 -3
  34. package/react-bindings.d.ts +11 -0
  35. package/react-bindings.js +7 -0
  36. package/react-bindings.mjs +11 -0
  37. package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +21 -73
  38. package/src/common/real-time/event-models.ts +8 -2
  39. package/src/common/types.ts +1 -0
  40. package/src/feed/event-handlers/activity/handle-activity-added.ts +9 -1
  41. package/src/feed/event-handlers/activity/handle-activity-updated.ts +4 -0
  42. package/src/feed/feed.ts +18 -3
  43. package/src/feeds-client/feeds-client.ts +106 -3
  44. package/src/utils/throttling/index.ts +2 -0
  45. package/src/utils/throttling/throttle.ts +123 -0
  46. package/src/utils/throttling/throttled-get-batched-own-capabilities.ts +42 -0
  47. package/dist/index--koeDtxd.js.map +0 -1
  48. package/dist/index-Zde8UE5f.mjs.map +0 -1
  49. package/src/feed/event-handlers/activity/activity-marked-utils.test.ts +0 -208
  50. package/src/feed/event-handlers/activity/activity-reaction-utils.test.ts +0 -371
  51. package/src/feed/event-handlers/activity/handle-activity-added.test.ts +0 -97
  52. package/src/feed/event-handlers/activity/handle-activity-deleted.test.ts +0 -117
  53. package/src/feed/event-handlers/activity/handle-activity-pinned.test.ts +0 -60
  54. package/src/feed/event-handlers/activity/handle-activity-reaction-added.test.ts +0 -257
  55. package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.test.ts +0 -317
  56. package/src/feed/event-handlers/activity/handle-activity-reaction-updated.test.ts +0 -282
  57. package/src/feed/event-handlers/activity/handle-activity-unpinned.test.ts +0 -95
  58. package/src/feed/event-handlers/activity/handle-activity-updated.test.ts +0 -245
  59. package/src/feed/event-handlers/add-aggregated-activities-to-state.test.ts +0 -510
  60. package/src/feed/event-handlers/bookmark/bookmark-utils.test.ts +0 -521
  61. package/src/feed/event-handlers/bookmark/handle-bookmark-added.test.ts +0 -178
  62. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.test.ts +0 -188
  63. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.test.ts +0 -196
  64. package/src/feed/event-handlers/comment/handle-comment-added.test.ts +0 -271
  65. package/src/feed/event-handlers/comment/handle-comment-deleted.test.ts +0 -255
  66. package/src/feed/event-handlers/comment/handle-comment-reaction-added.test.ts +0 -329
  67. package/src/feed/event-handlers/comment/handle-comment-reaction-deleted.test.ts +0 -343
  68. package/src/feed/event-handlers/comment/handle-comment-reaction-updated.test.ts +0 -350
  69. package/src/feed/event-handlers/comment/handle-comment-updated.test.ts +0 -267
  70. package/src/feed/event-handlers/comment/utils/update-comment-count.test.ts +0 -322
  71. package/src/feed/event-handlers/feed-member/handle-feed-member-added.test.ts +0 -75
  72. package/src/feed/event-handlers/feed-member/handle-feed-member-removed.test.ts +0 -82
  73. package/src/feed/event-handlers/feed-member/handle-feed-member-updated.test.ts +0 -84
  74. package/src/feed/event-handlers/follow/follow-state-update-queue.test.ts +0 -219
  75. package/src/feed/event-handlers/follow/handle-follow-created.test.ts +0 -250
  76. package/src/feed/event-handlers/follow/handle-follow-deleted.test.ts +0 -268
  77. package/src/feed/event-handlers/follow/handle-follow-updated.test.ts +0 -131
  78. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.test.ts +0 -182
  79. package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.test.ts +0 -45
  80. package/src/feed/feed.test.ts +0 -90
  81. package/src/feeds-client/event-handlers/user/handle-user-updated.test.ts +0 -53
  82. package/src/utils/event-triggered-by-connected-user.test.ts +0 -73
  83. package/src/utils/state-update-queue.test.ts +0 -129
  84. package/src/utils/unique-array-merge.test.ts +0 -179
@@ -1,82 +0,0 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
2
- import { Feed } from '../../../feed';
3
- import { FeedsClient } from '../../../feeds-client';
4
- import { handleFeedMemberRemoved } from './handle-feed-member-removed';
5
- import {
6
- generateFeedResponse,
7
- generateFeedMemberRemovedEvent,
8
- generateFeedMemberResponse,
9
- generateOwnUser,
10
- getHumanId,
11
- } from '../../../test-utils/response-generators';
12
-
13
- describe(handleFeedMemberRemoved.name, () => {
14
- let feed: Feed;
15
- let client: FeedsClient;
16
- let currentUserId: string;
17
-
18
- beforeEach(() => {
19
- client = new FeedsClient('mock-api-key');
20
- currentUserId = getHumanId();
21
- client.state.partialNext({
22
- connected_user: generateOwnUser({ id: currentUserId }),
23
- });
24
- const feedResponse = generateFeedResponse({
25
- id: 'main',
26
- group_id: 'user',
27
- created_by: { id: currentUserId },
28
- });
29
- feed = new Feed(
30
- client,
31
- feedResponse.group_id,
32
- feedResponse.id,
33
- feedResponse,
34
- );
35
- });
36
-
37
- it('removes from members if present', () => {
38
- const memberToRemove = generateFeedMemberResponse();
39
- const memberToKeep = generateFeedMemberResponse();
40
- feed.state.partialNext({ members: [memberToRemove, memberToKeep] });
41
-
42
- const event = generateFeedMemberRemovedEvent({
43
- member_id: memberToRemove.user.id,
44
- });
45
-
46
- handleFeedMemberRemoved.call(feed, event);
47
-
48
- const stateAfter = feed.currentState;
49
- expect(stateAfter.members).toHaveLength(1);
50
- expect(stateAfter.members?.[0]).toBe(memberToKeep);
51
- });
52
-
53
- it('does not change state when members array is undefined', () => {
54
- const event = generateFeedMemberRemovedEvent();
55
-
56
- const stateBefore = feed.currentState;
57
- expect(stateBefore.members).toBeUndefined();
58
-
59
- handleFeedMemberRemoved.call(feed, event);
60
-
61
- const stateAfter = feed.currentState;
62
- expect(stateAfter).toBe(stateBefore);
63
- });
64
-
65
- it('deletes own_membership when the removed member is the connected user', () => {
66
- const ownMember = generateFeedMemberResponse({
67
- user: { id: currentUserId },
68
- });
69
- feed.state.partialNext({ own_membership: ownMember, members: [] });
70
-
71
- const event = generateFeedMemberRemovedEvent({ member_id: currentUserId });
72
-
73
- const stateBefore = feed.currentState;
74
- expect(stateBefore.own_membership).toBe(ownMember);
75
-
76
- handleFeedMemberRemoved.call(feed, event);
77
-
78
- const stateAfter = feed.currentState;
79
- expect(stateAfter.own_membership).toBeUndefined();
80
- expect(stateAfter.members).toBe(stateBefore.members);
81
- });
82
- });
@@ -1,84 +0,0 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
2
- import { Feed } from '../../../feed';
3
- import { FeedsClient } from '../../../feeds-client';
4
- import { handleFeedMemberUpdated } from './handle-feed-member-updated';
5
- import {
6
- generateFeedResponse,
7
- generateFeedMemberUpdatedEvent,
8
- generateFeedMemberResponse,
9
- generateOwnUser,
10
- getHumanId,
11
- } from '../../../test-utils/response-generators';
12
-
13
- describe(handleFeedMemberUpdated.name, () => {
14
- let feed: Feed;
15
- let client: FeedsClient;
16
- let currentUserId: string;
17
-
18
- beforeEach(() => {
19
- client = new FeedsClient('mock-api-key');
20
- currentUserId = getHumanId();
21
- client.state.partialNext({
22
- connected_user: generateOwnUser({ id: currentUserId }),
23
- });
24
- const feedResponse = generateFeedResponse({
25
- id: 'main',
26
- group_id: 'user',
27
- created_by: { id: currentUserId },
28
- });
29
- feed = new Feed(
30
- client,
31
- feedResponse.group_id,
32
- feedResponse.id,
33
- feedResponse,
34
- );
35
- });
36
-
37
- it('updates an existing member in members array', () => {
38
- const member1 = generateFeedMemberResponse();
39
- const member2 = generateFeedMemberResponse();
40
- feed.state.partialNext({ members: [member1, member2] });
41
-
42
- const event = generateFeedMemberUpdatedEvent({
43
- member: { user: { id: member1.user.id }, role: 'admin' },
44
- });
45
-
46
- handleFeedMemberUpdated.call(feed, event);
47
-
48
- const stateAfter = feed.currentState;
49
- expect(stateAfter.members).toHaveLength(2);
50
- expect(stateAfter.members?.[0]).toBe(event.member);
51
- expect(stateAfter.members?.[1]).toBe(member2);
52
- });
53
-
54
- it('does not modify members when target is not present', () => {
55
- const existingMember = generateFeedMemberResponse();
56
- feed.state.partialNext({ members: [existingMember] });
57
-
58
- const event = generateFeedMemberUpdatedEvent();
59
-
60
- const stateBefore = feed.currentState;
61
- handleFeedMemberUpdated.call(feed, event);
62
-
63
- const stateAfter = feed.currentState;
64
- expect(stateAfter).toBe(stateBefore);
65
- });
66
-
67
- it('sets own_membership when the updated member is the connected user', () => {
68
- const event = generateFeedMemberUpdatedEvent({
69
- member: {
70
- user: { id: currentUserId },
71
- role: 'owner',
72
- status: 'member',
73
- },
74
- });
75
-
76
- const stateBefore = feed.currentState;
77
- expect(stateBefore.own_membership).toBeUndefined();
78
-
79
- handleFeedMemberUpdated.call(feed, event);
80
-
81
- const stateAfter = feed.currentState;
82
- expect(stateAfter.own_membership).toBe(event.member);
83
- });
84
- });
@@ -1,219 +0,0 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
2
- import type { FollowResponse } from '../../../gen/models';
3
- import { shouldUpdateState } from '../../../utils/state-update-queue';
4
- import { handleFollowUpdated } from './handle-follow-updated';
5
- import { Feed, handleFollowCreated, handleFollowDeleted } from '../../../feed';
6
- import { FeedsClient } from '../../../feeds-client';
7
- import {
8
- generateFeedResponse,
9
- generateFollowResponse,
10
- generateOwnUser,
11
- getHumanId,
12
- } from '../../../test-utils';
13
-
14
- describe(`Follow ${shouldUpdateState.name} integration`, () => {
15
- let feed: Feed;
16
- let client: FeedsClient;
17
- let follow: FollowResponse;
18
- let otherFollow: FollowResponse;
19
- let ownFollow: FollowResponse;
20
- let userId: string;
21
-
22
- beforeEach(() => {
23
- userId = getHumanId();
24
- client = new FeedsClient('mock-api-key');
25
-
26
- client.state.partialNext({
27
- connected_user: generateOwnUser({ id: userId }),
28
- });
29
-
30
- const feedResponse = generateFeedResponse({
31
- id: 'main',
32
- group_id: 'user',
33
- created_by: { id: userId },
34
- });
35
- feed = new Feed(client, 'user', 'main', feedResponse);
36
- // Setup follows
37
- follow = generateFollowResponse({
38
- source_feed: generateFeedResponse({
39
- id: 'main',
40
- group_id: 'user',
41
- created_by: { id: userId },
42
- }),
43
- target_feed: generateFeedResponse({
44
- id: 'target',
45
- group_id: 'user',
46
- }),
47
- });
48
-
49
- otherFollow = generateFollowResponse({
50
- source_feed: generateFeedResponse({
51
- id: 'other',
52
- group_id: 'user',
53
- created_by: { id: getHumanId() },
54
- }),
55
- target_feed: generateFeedResponse({
56
- id: 'main',
57
- group_id: 'user',
58
- }),
59
- });
60
-
61
- ownFollow = generateFollowResponse({
62
- source_feed: generateFeedResponse({
63
- id: 'other',
64
- group_id: 'user',
65
- created_by: { id: userId },
66
- }),
67
- target_feed: generateFeedResponse({
68
- id: 'main',
69
- group_id: 'user',
70
- }),
71
- });
72
- // Set up initial state
73
- feed.state.next((currentState) => ({
74
- ...currentState,
75
- following: [follow],
76
- followers: [otherFollow],
77
- own_follows: [ownFollow],
78
- }));
79
- });
80
-
81
- describe.each(
82
- [
83
- {
84
- handler: handleFollowCreated,
85
- state: {
86
- status: 'accepted',
87
- },
88
- count: 2,
89
- },
90
- {
91
- handler: handleFollowUpdated,
92
- state: {
93
- status: 'accepted',
94
- },
95
- count: 1,
96
- },
97
- { handler: handleFollowDeleted, state: undefined, count: 0 },
98
- ].map(({ handler, state, count }) => [
99
- handler.name,
100
- handler,
101
- state as Partial<FollowResponse>,
102
- count,
103
- ]),
104
- )(`%s`, (_name, handler, state, count) => {
105
- it(`skips update if ${shouldUpdateState.name} returns false`, () => {
106
- // Prepare feed, set as watched
107
- feed.state.partialNext({ watch: true });
108
-
109
- const updatedFollow: FollowResponse = { ...follow, status: 'pending' };
110
-
111
- // 1. HTTP and then WS event
112
-
113
- // Call once as HTTP response to populate the queue
114
- handler.call(
115
- feed,
116
- {
117
- follow: { ...updatedFollow, ...state },
118
- },
119
- false,
120
- );
121
-
122
- // Call again as WS event, should be skipped
123
- let stateBefore = feed.currentState;
124
- handler.call(feed, { follow: updatedFollow });
125
-
126
- // State should not change
127
- let stateAfter = feed.currentState;
128
- expect(stateAfter).toBe(stateBefore);
129
- // @ts-expect-error Using Feed internals for tests only
130
- expect(feed.stateUpdateQueue.size).toEqual(0);
131
-
132
- // 2. WS and then HTTP
133
-
134
- // Call once as WS event to populate the queue
135
- handler.call(
136
- feed,
137
- {
138
- follow: { ...updatedFollow, ...state },
139
- },
140
- );
141
-
142
- // Call again as HTTP response, should be skipped
143
- stateBefore = feed.currentState;
144
- handler.call(feed, { follow: updatedFollow }, false);
145
-
146
- // State should not change
147
- stateAfter = feed.currentState;
148
- expect(stateAfter).toBe(stateBefore);
149
- // @ts-expect-error Using Feed internals for tests only
150
- expect(feed.stateUpdateQueue.size).toEqual(0);
151
- });
152
-
153
- it('allows update again from WS after clearing the stateUpdateQueue', () => {
154
- const updatedFollow: FollowResponse = { ...follow, status: 'pending' };
155
-
156
- handler.call(feed, { follow: updatedFollow });
157
-
158
- // Clear the queue
159
- (feed as any).stateUpdateQueue.clear();
160
-
161
- // Now update should be allowed from another WS event
162
- handler.call(feed, {
163
- follow: { ...updatedFollow, ...state },
164
- });
165
-
166
- const following = feed.currentState.following!;
167
- const [updatedFollowAfter] = following;
168
-
169
- expect(following.length).toEqual(count);
170
- expect(updatedFollowAfter).toMatchObject(state!);
171
- });
172
-
173
- it('allows update again from HTTP response after clearing the stateUpdateQueue', () => {
174
- const updatedFollow: FollowResponse = { ...follow, status: 'pending' };
175
-
176
- handler.call(feed, { follow: updatedFollow }, false);
177
-
178
- // Clear the queue
179
- (feed as any).stateUpdateQueue.clear();
180
-
181
- // Now update should be allowed from another HTTP response
182
- handler.call(
183
- feed,
184
- {
185
- follow: { ...updatedFollow, ...state },
186
- },
187
- false,
188
- );
189
-
190
- const following = feed.currentState.following!;
191
- const [updatedFollowAfter] = following;
192
-
193
- expect(following.length).toEqual(count);
194
- expect(updatedFollowAfter).toMatchObject(state!);
195
- });
196
-
197
- it('should not insert anything into the stateUpdateQueue if the connected_user did not trigger the follow', () => {
198
- const updatedFollow: FollowResponse = {
199
- ...otherFollow,
200
- status: 'pending',
201
- };
202
-
203
- handler.call(feed, { follow: updatedFollow });
204
-
205
- expect((feed as any).stateUpdateQueue).toEqual(new Set());
206
-
207
- handler.call(feed, {
208
- follow: { ...updatedFollow, ...state },
209
- });
210
-
211
- const following = feed.currentState.following!;
212
- const [updatedFollowAfter] = following;
213
-
214
- expect((feed as any).stateUpdateQueue).toEqual(new Set());
215
- expect(following.length).toEqual(1);
216
- expect(updatedFollowAfter).toMatchObject(follow);
217
- });
218
- });
219
- });
@@ -1,250 +0,0 @@
1
- import type {
2
- FeedResponse,
3
- FollowResponse,
4
- UserResponse,
5
- } from '../../../gen/models';
6
- import { generateFollowResponse } from '../../../test-utils';
7
- import { updateStateFollowCreated } from './handle-follow-created';
8
-
9
- import { describe, it, expect, beforeEach } from 'vitest';
10
-
11
- describe('handle-follow-created', () => {
12
- describe(updateStateFollowCreated.name, () => {
13
- let mockFollow: FollowResponse;
14
- let mockFeed: FeedResponse;
15
- let mockUser: UserResponse;
16
-
17
- beforeEach(() => {
18
- mockFollow = generateFollowResponse();
19
- mockFeed = mockFollow.source_feed;
20
- mockUser = mockFeed.created_by;
21
- });
22
-
23
- it('should return unchanged state for non-accepted follows', () => {
24
- const follow: FollowResponse = {
25
- ...mockFollow,
26
- status: 'pending',
27
- };
28
-
29
- // @ts-expect-error - we're not testing the full state here
30
- const currentState: FeedState = {
31
- followers: [],
32
- following: [],
33
- };
34
-
35
- const result = updateStateFollowCreated(
36
- follow,
37
- currentState,
38
- 'user:feed-1',
39
- 'user-1',
40
- );
41
-
42
- expect(result.changed).toBe(false);
43
- });
44
-
45
- it('should handle when this feed follows someone', () => {
46
- const follow: FollowResponse = {
47
- ...mockFollow,
48
- source_feed: {
49
- ...mockFeed,
50
- id: 'feed-x',
51
- feed: 'user:feed-x',
52
- created_by: {
53
- ...mockUser,
54
- id: 'user-x',
55
- },
56
- following_count: 1,
57
- },
58
- target_feed: {
59
- ...mockFeed,
60
- id: 'other-feed',
61
- feed: 'user:other-feed',
62
- created_by: mockUser,
63
- },
64
- };
65
-
66
- // @ts-expect-error - we're not testing the full state here
67
- const currentState: FeedState = {
68
- following: [],
69
- following_count: 0,
70
- };
71
-
72
- const result = updateStateFollowCreated(
73
- follow,
74
- currentState,
75
- 'user:feed-x',
76
- 'user-1',
77
- );
78
-
79
- expect(result.changed).toBe(true);
80
- expect(result.data.following).toHaveLength(1);
81
- expect(result.data.following?.[0]).toBe(follow);
82
- expect(result.data).toMatchObject(follow.source_feed);
83
- expect(result.data.own_follows).toBeUndefined();
84
- expect(result.data.following_count).toBe(1);
85
- });
86
-
87
- it('should handle when someone follows this feed', () => {
88
- const follow: FollowResponse = {
89
- ...mockFollow,
90
- source_feed: {
91
- ...mockFeed,
92
- id: 'other-feed',
93
- feed: 'user:other-feed',
94
- created_by: {
95
- ...mockUser,
96
- id: 'other-user',
97
- },
98
- },
99
- target_feed: {
100
- ...mockFeed,
101
- id: 'feed-1',
102
- feed: 'user:feed-1',
103
- created_by: mockUser,
104
- follower_count: 1,
105
- },
106
- };
107
-
108
- // @ts-expect-error - we're not testing the full state here
109
- const currentState: FeedState = {
110
- followers: [],
111
- follower_count: 0,
112
- };
113
-
114
- const result = updateStateFollowCreated(
115
- follow,
116
- currentState,
117
- 'user:feed-1',
118
- 'user-1',
119
- );
120
-
121
- expect(result.changed).toBe(true);
122
- expect(result.data.followers).toHaveLength(1);
123
- expect(result.data.followers?.[0]).toBe(follow);
124
- expect(result.data).toMatchObject(follow.target_feed);
125
- expect(result.data.own_follows).toBeUndefined();
126
- expect(result.data.follower_count).toBe(1);
127
- });
128
-
129
- it('should add to own_follows when connected user is the source', () => {
130
- const follow: FollowResponse = {
131
- ...mockFollow,
132
- source_feed: {
133
- ...mockFeed,
134
- id: 'feed-1',
135
- feed: 'user:feed-1',
136
- created_by: { ...mockUser, id: 'user-1' },
137
- },
138
- target_feed: {
139
- ...mockFeed,
140
- id: 'feed-x',
141
- feed: 'user:feed-x',
142
- created_by: {
143
- ...mockUser,
144
- id: 'user-x',
145
- },
146
- },
147
- };
148
-
149
- // @ts-expect-error - we're not testing the full state here
150
- const currentState: FeedState = {
151
- followers: [],
152
- own_follows: [],
153
- };
154
-
155
- const result = updateStateFollowCreated(
156
- follow,
157
- currentState,
158
- 'user:feed-x',
159
- 'user-1',
160
- );
161
-
162
- expect(result.changed).toBe(true);
163
- expect(result.data.own_follows).toHaveLength(1);
164
- expect(result.data.own_follows?.[0]).toBe(follow);
165
- });
166
-
167
- it('should not update followers/following when they are undefined', () => {
168
- const follow: FollowResponse = {
169
- ...mockFollow,
170
- source_feed: {
171
- ...mockFeed,
172
- id: 'other-feed',
173
- feed: 'user:other-feed',
174
- created_by: mockUser,
175
- },
176
- target_feed: {
177
- ...mockFeed,
178
- id: 'feed-1',
179
- feed: 'user:feed-1',
180
- created_by: mockUser,
181
- },
182
- };
183
-
184
- // @ts-expect-error - we're not testing the full state here
185
- const currentState: FeedState = {
186
- followers: undefined,
187
- following: undefined,
188
- own_follows: undefined,
189
- };
190
-
191
- const result = updateStateFollowCreated(
192
- follow,
193
- currentState,
194
- 'user:feed-1',
195
- 'user-1',
196
- );
197
-
198
- expect(result.changed).toBe(true);
199
- expect(result.data.followers).toBeUndefined();
200
- expect(result.data).toMatchObject(follow.target_feed);
201
- });
202
-
203
- it('should add new followers to the top of existing arrays', () => {
204
- const existingFollow: FollowResponse = {
205
- ...mockFollow,
206
- source_feed: {
207
- ...mockFeed,
208
- id: 'existing-feed',
209
- feed: 'user:existing-feed',
210
- created_by: mockUser,
211
- },
212
- };
213
-
214
- const follow: FollowResponse = {
215
- ...mockFollow,
216
- source_feed: {
217
- ...mockFeed,
218
- id: 'other-feed',
219
- feed: 'user:other-feed',
220
- created_by: mockUser,
221
- },
222
- target_feed: {
223
- ...mockFeed,
224
- id: 'feed-1',
225
- feed: 'user:feed-1',
226
- created_by: mockUser,
227
- },
228
- };
229
-
230
- // @ts-expect-error - we're not testing the full state here
231
- const currentState: FeedState = {
232
- followers: [existingFollow],
233
- following: undefined,
234
- own_follows: undefined,
235
- };
236
-
237
- const result = updateStateFollowCreated(
238
- follow,
239
- currentState,
240
- 'user:feed-1',
241
- 'user-1',
242
- );
243
-
244
- expect(result.changed).toBe(true);
245
- expect(result.data.followers).toHaveLength(2);
246
- expect(result.data.followers?.[0]).toBe(follow);
247
- expect(result.data.followers?.[1]).toBe(existingFollow);
248
- });
249
- });
250
- });