@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
package/src/feed/feed.test.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { FeedsClient } from '../feeds-client';
|
|
3
|
-
import { Feed } from './feed';
|
|
4
|
-
import type { ActivityResponse } from '../gen/models';
|
|
5
|
-
import { generateActivityResponse, generateFeedResponse } from '../test-utils';
|
|
6
|
-
|
|
7
|
-
describe('Feed derived state updates', () => {
|
|
8
|
-
let feed: Feed;
|
|
9
|
-
let client: FeedsClient;
|
|
10
|
-
let activities: ActivityResponse[];
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
client = new FeedsClient('mock-api-key');
|
|
14
|
-
const feedResponse = generateFeedResponse({ id: 'main', group_id: 'user' });
|
|
15
|
-
feed = new Feed(
|
|
16
|
-
client,
|
|
17
|
-
feedResponse.group_id,
|
|
18
|
-
feedResponse.id,
|
|
19
|
-
feedResponse,
|
|
20
|
-
);
|
|
21
|
-
activities = [
|
|
22
|
-
generateActivityResponse(),
|
|
23
|
-
generateActivityResponse(),
|
|
24
|
-
generateActivityResponse(),
|
|
25
|
-
];
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should update the cache if activities change in feed.state', () => {
|
|
29
|
-
let indexedActivityIds = (feed as any).indexedActivityIds;
|
|
30
|
-
expect(indexedActivityIds.size).toEqual(0);
|
|
31
|
-
|
|
32
|
-
feed.state.partialNext({ activities });
|
|
33
|
-
|
|
34
|
-
indexedActivityIds = (feed as any).indexedActivityIds;
|
|
35
|
-
expect(indexedActivityIds.size).toEqual(3);
|
|
36
|
-
for (const activity of activities) {
|
|
37
|
-
expect(indexedActivityIds.has(activity.id)).toBe(true);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should update the cache if activities are further updated', () => {
|
|
42
|
-
// Include all of them
|
|
43
|
-
feed.state.partialNext({ activities });
|
|
44
|
-
|
|
45
|
-
let indexedActivityIds = (feed as any).indexedActivityIds;
|
|
46
|
-
expect(indexedActivityIds.size).toEqual(3);
|
|
47
|
-
for (const activity of activities) {
|
|
48
|
-
expect(indexedActivityIds.has(activity.id)).toBe(true);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Take only the last 2
|
|
52
|
-
const newActivities = activities.slice(1);
|
|
53
|
-
feed.state.partialNext({ activities: newActivities });
|
|
54
|
-
|
|
55
|
-
indexedActivityIds = (feed as any).indexedActivityIds;
|
|
56
|
-
expect((feed as any).indexedActivityIds.size).toEqual(2);
|
|
57
|
-
for (const activity of newActivities) {
|
|
58
|
-
expect(indexedActivityIds.has(activity.id)).toBe(true);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Include all of them again
|
|
62
|
-
feed.state.partialNext({ activities });
|
|
63
|
-
|
|
64
|
-
indexedActivityIds = (feed as any).indexedActivityIds;
|
|
65
|
-
expect(indexedActivityIds.size).toEqual(3);
|
|
66
|
-
for (const activity of activities) {
|
|
67
|
-
expect(indexedActivityIds.has(activity.id)).toBe(true);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should not update the cache if the length of activities has not changed', () => {
|
|
72
|
-
feed.state.partialNext({ activities });
|
|
73
|
-
|
|
74
|
-
const indexedActivityIdsBefore = (feed as any).indexedActivityIds;
|
|
75
|
-
expect(indexedActivityIdsBefore.size).toEqual(3);
|
|
76
|
-
for (const activity of activities) {
|
|
77
|
-
expect(indexedActivityIdsBefore.has(activity.id)).toBe(true);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const reversedActivities = activities.toReversed();
|
|
81
|
-
feed.state.partialNext({ activities: reversedActivities });
|
|
82
|
-
|
|
83
|
-
const indexedActivityIdsAfter = (feed as any).indexedActivityIds;
|
|
84
|
-
expect(indexedActivityIdsAfter.size).toEqual(3);
|
|
85
|
-
for (const activity of activities) {
|
|
86
|
-
expect(indexedActivityIdsAfter.has(activity.id)).toBe(true);
|
|
87
|
-
}
|
|
88
|
-
expect(indexedActivityIdsBefore).toBe(indexedActivityIdsAfter);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { FeedsClient, handleUserUpdated } from '../..';
|
|
4
|
-
import { generateOwnUser, generateUserResponse } from '../../../test-utils';
|
|
5
|
-
import type { EventPayload } from '../../../types-internal';
|
|
6
|
-
|
|
7
|
-
describe('handleUserUpdated', () => {
|
|
8
|
-
let feedsClient: FeedsClient;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
feedsClient = new FeedsClient('mock-api-key');
|
|
12
|
-
const connectedUser = generateOwnUser();
|
|
13
|
-
|
|
14
|
-
feedsClient.state.partialNext({ connected_user: connectedUser });
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should update the connected user in the state', () => {
|
|
18
|
-
const stateBefore = feedsClient.state.getLatestValue();
|
|
19
|
-
|
|
20
|
-
const event: EventPayload<'user.updated'> = {
|
|
21
|
-
type: 'user.updated',
|
|
22
|
-
created_at: new Date(),
|
|
23
|
-
custom: {},
|
|
24
|
-
user: {
|
|
25
|
-
...generateUserResponse(),
|
|
26
|
-
...stateBefore.connected_user!,
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
handleUserUpdated.call(feedsClient, event);
|
|
31
|
-
|
|
32
|
-
const stateAfter = feedsClient.state.getLatestValue();
|
|
33
|
-
|
|
34
|
-
expect(stateAfter.connected_user).toMatchObject({ name: event.user.name });
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should not update the connected user if the incoming event contains other user', () => {
|
|
38
|
-
const event: EventPayload<'user.updated'> = {
|
|
39
|
-
type: 'user.updated',
|
|
40
|
-
created_at: new Date(),
|
|
41
|
-
custom: {},
|
|
42
|
-
user: generateUserResponse(),
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const stateBefore = feedsClient.state.getLatestValue();
|
|
46
|
-
|
|
47
|
-
handleUserUpdated.call(feedsClient, event);
|
|
48
|
-
|
|
49
|
-
const stateAfter = feedsClient.state.getLatestValue();
|
|
50
|
-
|
|
51
|
-
expect(stateAfter.connected_user).toBe(stateBefore.connected_user);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { eventTriggeredByConnectedUser as eventTriggeredByConnectedUserInternal } from './event-triggered-by-connected-user';
|
|
4
|
-
import { FeedsClient } from '../feeds-client';
|
|
5
|
-
import { Feed } from '../feed';
|
|
6
|
-
import {
|
|
7
|
-
generateFeedResponse,
|
|
8
|
-
generateOwnUser, generateUserResponse,
|
|
9
|
-
getHumanId,
|
|
10
|
-
} from '../test-utils';
|
|
11
|
-
|
|
12
|
-
describe('eventTriggeredByConnectedUser', () => {
|
|
13
|
-
let feed: Feed;
|
|
14
|
-
let client: FeedsClient;
|
|
15
|
-
let currentUserId: string;
|
|
16
|
-
|
|
17
|
-
let eventTriggeredByConnectedUser: OmitThisParameter<typeof eventTriggeredByConnectedUserInternal>
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
client = new FeedsClient('mock-api-key');
|
|
21
|
-
currentUserId = getHumanId();
|
|
22
|
-
|
|
23
|
-
client.state.partialNext({
|
|
24
|
-
connected_user: generateOwnUser({ id: currentUserId }),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const feedResponse = generateFeedResponse({
|
|
28
|
-
id: 'main',
|
|
29
|
-
group_id: 'user',
|
|
30
|
-
created_by: { id: currentUserId },
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
feed = new Feed(
|
|
34
|
-
client,
|
|
35
|
-
feedResponse.group_id,
|
|
36
|
-
feedResponse.id,
|
|
37
|
-
feedResponse,
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
eventTriggeredByConnectedUser = eventTriggeredByConnectedUserInternal.bind(feed);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
afterEach(() => {
|
|
44
|
-
vi.resetAllMocks();
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('returns true when payload.user.id matches connected_user.id', () => {
|
|
48
|
-
const user = generateUserResponse({ id: currentUserId });
|
|
49
|
-
const result = eventTriggeredByConnectedUser({ user });
|
|
50
|
-
expect(result).toBe(true);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('returns true when payload.user is undefined and connected_user exists', () => {
|
|
54
|
-
const result = eventTriggeredByConnectedUser({});
|
|
55
|
-
expect(result).toBe(true);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('returns false when payload.user.id differs from connected_user.id', () => {
|
|
59
|
-
const user = generateUserResponse({ id: getHumanId() });
|
|
60
|
-
const result = eventTriggeredByConnectedUser({ user });
|
|
61
|
-
expect(result).toBe(false);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('returns false when connected_user is undefined (even if payload.user present)', () => {
|
|
65
|
-
// @ts-expect-error using protected value only in tests
|
|
66
|
-
feed.client.state.partialNext({ connected_user: undefined });
|
|
67
|
-
const user = generateUserResponse({ id: currentUserId });
|
|
68
|
-
const result1 = eventTriggeredByConnectedUser({ user });
|
|
69
|
-
const result2 = eventTriggeredByConnectedUser({});
|
|
70
|
-
expect(result1).toBe(false);
|
|
71
|
-
expect(result2).toBe(false);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { shouldUpdateState } from './state-update-queue';
|
|
4
|
-
|
|
5
|
-
describe('state-update-queue', () => {
|
|
6
|
-
describe('shouldUpdateState', () => {
|
|
7
|
-
it('should return true when only watch is false', () => {
|
|
8
|
-
const result = shouldUpdateState({
|
|
9
|
-
stateUpdateQueueId: 'test-id',
|
|
10
|
-
stateUpdateQueue: new Set(['ws-other-id']),
|
|
11
|
-
watch: false,
|
|
12
|
-
isTriggeredByConnectedUser: true,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
expect(result).toBe(true);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should return true when only isTriggeredByConnectedUser is false', () => {
|
|
19
|
-
const result = shouldUpdateState({
|
|
20
|
-
stateUpdateQueueId: 'test-id',
|
|
21
|
-
stateUpdateQueue: new Set(['ws-other-id']),
|
|
22
|
-
watch: true,
|
|
23
|
-
isTriggeredByConnectedUser: false,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
expect(result).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should return true when watch is true and it is triggered by the connected_user, but queueId is not in queue', () => {
|
|
30
|
-
const stateUpdateQueue = new Set(['ws-other-id-1', 'ws-other-id-2']);
|
|
31
|
-
|
|
32
|
-
const result = shouldUpdateState({
|
|
33
|
-
stateUpdateQueueId: 'test-id',
|
|
34
|
-
stateUpdateQueue: stateUpdateQueue,
|
|
35
|
-
watch: true,
|
|
36
|
-
isTriggeredByConnectedUser: true,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
expect(stateUpdateQueue).toContain('ws-test-id');
|
|
40
|
-
expect(result).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should return false and remove queueId from queue when watch is true and WS initiated queueId is in queue', () => {
|
|
44
|
-
const stateUpdateQueue = new Set(['ws-test-id', 'ws-other-id']);
|
|
45
|
-
|
|
46
|
-
const result = shouldUpdateState({
|
|
47
|
-
stateUpdateQueueId: 'test-id',
|
|
48
|
-
stateUpdateQueue,
|
|
49
|
-
watch: true,
|
|
50
|
-
fromWs: false,
|
|
51
|
-
isTriggeredByConnectedUser: true,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
expect(result).toBe(false);
|
|
55
|
-
expect(stateUpdateQueue).toEqual(new Set(['ws-other-id']));
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should return false and remove queueId from queue when watch is true and HTTP initiated queueId is in queue', () => {
|
|
59
|
-
const stateUpdateQueue = new Set(['http-test-id', 'http-other-id']);
|
|
60
|
-
|
|
61
|
-
const result = shouldUpdateState({
|
|
62
|
-
stateUpdateQueueId: 'test-id',
|
|
63
|
-
stateUpdateQueue,
|
|
64
|
-
watch: true,
|
|
65
|
-
isTriggeredByConnectedUser: true,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
expect(result).toBe(false);
|
|
69
|
-
expect(stateUpdateQueue).toEqual(new Set(['http-other-id']));
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should handle empty queue when conditions are met', () => {
|
|
73
|
-
const result = shouldUpdateState({
|
|
74
|
-
stateUpdateQueueId: 'test-id',
|
|
75
|
-
stateUpdateQueue: new Set(),
|
|
76
|
-
watch: true,
|
|
77
|
-
isTriggeredByConnectedUser: true,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
expect(result).toBe(true);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should not clear the queue state if 2 equal HTTP response updates arrive', () => {
|
|
84
|
-
const stateUpdateQueue = new Set<string>();
|
|
85
|
-
|
|
86
|
-
const result1 = shouldUpdateState({
|
|
87
|
-
stateUpdateQueueId: 'test-id',
|
|
88
|
-
stateUpdateQueue,
|
|
89
|
-
watch: true,
|
|
90
|
-
fromWs: false,
|
|
91
|
-
isTriggeredByConnectedUser: true,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const result2 = shouldUpdateState({
|
|
95
|
-
stateUpdateQueueId: 'test-id',
|
|
96
|
-
stateUpdateQueue,
|
|
97
|
-
watch: true,
|
|
98
|
-
fromWs: false,
|
|
99
|
-
isTriggeredByConnectedUser: true,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
expect(result1).toBe(true);
|
|
103
|
-
expect(result2).toBe(true);
|
|
104
|
-
expect(stateUpdateQueue).toEqual(new Set(['http-test-id']))
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('should not clear the queue state if 2 equal WS event updates arrive', () => {
|
|
108
|
-
const stateUpdateQueue = new Set<string>();
|
|
109
|
-
|
|
110
|
-
const result1 = shouldUpdateState({
|
|
111
|
-
stateUpdateQueueId: 'test-id',
|
|
112
|
-
stateUpdateQueue,
|
|
113
|
-
watch: true,
|
|
114
|
-
isTriggeredByConnectedUser: true,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const result2 = shouldUpdateState({
|
|
118
|
-
stateUpdateQueueId: 'test-id',
|
|
119
|
-
stateUpdateQueue,
|
|
120
|
-
watch: true,
|
|
121
|
-
isTriggeredByConnectedUser: true,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
expect(result1).toBe(true);
|
|
125
|
-
expect(result2).toBe(true);
|
|
126
|
-
expect(stateUpdateQueue).toEqual(new Set(['ws-test-id']))
|
|
127
|
-
})
|
|
128
|
-
});
|
|
129
|
-
});
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { uniqueArrayMerge } from './unique-array-merge';
|
|
4
|
-
|
|
5
|
-
describe('utils', () => {
|
|
6
|
-
describe(uniqueArrayMerge.name, () => {
|
|
7
|
-
it('should merge arrays with unique objects based on key', () => {
|
|
8
|
-
const existingArray = [
|
|
9
|
-
{ id: '1', name: 'Alice' },
|
|
10
|
-
{ id: '2', name: 'Bob' },
|
|
11
|
-
];
|
|
12
|
-
const arrayToMerge = [
|
|
13
|
-
{ id: '2', name: 'Bob Updated' },
|
|
14
|
-
{ id: '3', name: 'Charlie' },
|
|
15
|
-
];
|
|
16
|
-
const getKey = (item: { id: string; name: string }) => item.id;
|
|
17
|
-
|
|
18
|
-
const result = uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
19
|
-
|
|
20
|
-
expect(result).toEqual([
|
|
21
|
-
{ id: '1', name: 'Alice' },
|
|
22
|
-
{ id: '2', name: 'Bob' },
|
|
23
|
-
{ id: '3', name: 'Charlie' },
|
|
24
|
-
]);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should preserve order of existing array and append new items', () => {
|
|
28
|
-
const existingArray = [
|
|
29
|
-
{ id: '1', name: 'Alice' },
|
|
30
|
-
{ id: '2', name: 'Bob' },
|
|
31
|
-
];
|
|
32
|
-
const arrayToMerge = [
|
|
33
|
-
{ id: '3', name: 'Charlie' },
|
|
34
|
-
{ id: '4', name: 'David' },
|
|
35
|
-
];
|
|
36
|
-
const getKey = (item: { id: string; name: string }) => item.id;
|
|
37
|
-
|
|
38
|
-
const result = uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
39
|
-
|
|
40
|
-
expect(result).toEqual([
|
|
41
|
-
{ id: '1', name: 'Alice' },
|
|
42
|
-
{ id: '2', name: 'Bob' },
|
|
43
|
-
{ id: '3', name: 'Charlie' },
|
|
44
|
-
{ id: '4', name: 'David' },
|
|
45
|
-
]);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('should filter out duplicate keys from array to merge', () => {
|
|
49
|
-
const existingArray = [
|
|
50
|
-
{ id: '1', name: 'Alice' },
|
|
51
|
-
{ id: '2', name: 'Bob' },
|
|
52
|
-
];
|
|
53
|
-
const arrayToMerge = [
|
|
54
|
-
{ id: '1', name: 'Alice Updated' },
|
|
55
|
-
{ id: '2', name: 'Bob Updated' },
|
|
56
|
-
{ id: '3', name: 'Charlie' },
|
|
57
|
-
];
|
|
58
|
-
const getKey = (item: { id: string; name: string }) => item.id;
|
|
59
|
-
|
|
60
|
-
const result = uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
61
|
-
|
|
62
|
-
expect(result).toEqual([
|
|
63
|
-
{ id: '1', name: 'Alice' },
|
|
64
|
-
{ id: '2', name: 'Bob' },
|
|
65
|
-
{ id: '3', name: 'Charlie' },
|
|
66
|
-
]);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should handle empty existing array', () => {
|
|
70
|
-
const existingArray: Array<{ id: string; name: string }> = [];
|
|
71
|
-
const arrayToMerge = [
|
|
72
|
-
{ id: '1', name: 'Alice' },
|
|
73
|
-
{ id: '2', name: 'Bob' },
|
|
74
|
-
];
|
|
75
|
-
const getKey = (item: { id: string; name: string }) => item.id;
|
|
76
|
-
|
|
77
|
-
const result = uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
78
|
-
|
|
79
|
-
expect(result).toEqual([
|
|
80
|
-
{ id: '1', name: 'Alice' },
|
|
81
|
-
{ id: '2', name: 'Bob' },
|
|
82
|
-
]);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should handle empty array to merge', () => {
|
|
86
|
-
const existingArray = [
|
|
87
|
-
{ id: '1', name: 'Alice' },
|
|
88
|
-
{ id: '2', name: 'Bob' },
|
|
89
|
-
];
|
|
90
|
-
const arrayToMerge: Array<{ id: string; name: string }> = [];
|
|
91
|
-
const getKey = (item: { id: string; name: string }) => item.id;
|
|
92
|
-
|
|
93
|
-
const result = uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
94
|
-
|
|
95
|
-
expect(result).toEqual([
|
|
96
|
-
{ id: '1', name: 'Alice' },
|
|
97
|
-
{ id: '2', name: 'Bob' },
|
|
98
|
-
]);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should handle both arrays being empty', () => {
|
|
102
|
-
const existingArray: Array<{ id: string; name: string }> = [];
|
|
103
|
-
const arrayToMerge: Array<{ id: string; name: string }> = [];
|
|
104
|
-
const getKey = (item: { id: string; name: string }) => item.id;
|
|
105
|
-
|
|
106
|
-
const result = uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
107
|
-
|
|
108
|
-
expect(result).toEqual([]);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('should work with different key functions', () => {
|
|
112
|
-
const existingArray = [
|
|
113
|
-
{ id: '1', name: 'Alice', email: 'alice@example.com' },
|
|
114
|
-
{ id: '2', name: 'Bob', email: 'bob@example.com' },
|
|
115
|
-
];
|
|
116
|
-
const arrayToMerge = [
|
|
117
|
-
{ id: '3', name: 'Charlie', email: 'alice@example.com' },
|
|
118
|
-
{ id: '4', name: 'David', email: 'david@example.com' },
|
|
119
|
-
];
|
|
120
|
-
const getKeyByEmail = (item: {
|
|
121
|
-
id: string;
|
|
122
|
-
name: string;
|
|
123
|
-
email: string;
|
|
124
|
-
}) => item.email;
|
|
125
|
-
|
|
126
|
-
const result = uniqueArrayMerge(
|
|
127
|
-
existingArray,
|
|
128
|
-
arrayToMerge,
|
|
129
|
-
getKeyByEmail,
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
expect(result).toEqual([
|
|
133
|
-
{ id: '1', name: 'Alice', email: 'alice@example.com' },
|
|
134
|
-
{ id: '2', name: 'Bob', email: 'bob@example.com' },
|
|
135
|
-
{ id: '4', name: 'David', email: 'david@example.com' },
|
|
136
|
-
]);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('should handle complex nested objects', () => {
|
|
140
|
-
const existingArray = [
|
|
141
|
-
{ id: '1', data: { nested: { value: 'a' } } },
|
|
142
|
-
{ id: '2', data: { nested: { value: 'b' } } },
|
|
143
|
-
];
|
|
144
|
-
const arrayToMerge = [
|
|
145
|
-
{ id: '2', data: { nested: { value: 'b_updated' } } },
|
|
146
|
-
{ id: '3', data: { nested: { value: 'c' } } },
|
|
147
|
-
];
|
|
148
|
-
const getKey = (item: {
|
|
149
|
-
id: string;
|
|
150
|
-
data: { nested: { value: string } };
|
|
151
|
-
}) => item.id;
|
|
152
|
-
|
|
153
|
-
const result = uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
154
|
-
|
|
155
|
-
expect(result).toEqual([
|
|
156
|
-
{ id: '1', data: { nested: { value: 'a' } } },
|
|
157
|
-
{ id: '2', data: { nested: { value: 'b' } } },
|
|
158
|
-
{ id: '3', data: { nested: { value: 'c' } } },
|
|
159
|
-
]);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('should preserve original arrays (immutability)', () => {
|
|
163
|
-
const existingArray = [
|
|
164
|
-
{ id: '1', name: 'Alice' },
|
|
165
|
-
{ id: '2', name: 'Bob' },
|
|
166
|
-
];
|
|
167
|
-
const arrayToMerge = [{ id: '3', name: 'Charlie' }];
|
|
168
|
-
const getKey = (item: { id: string; name: string }) => item.id;
|
|
169
|
-
|
|
170
|
-
const originalExisting = [...existingArray];
|
|
171
|
-
const originalToMerge = [...arrayToMerge];
|
|
172
|
-
|
|
173
|
-
uniqueArrayMerge(existingArray, arrayToMerge, getKey);
|
|
174
|
-
|
|
175
|
-
expect(existingArray).toEqual(originalExisting);
|
|
176
|
-
expect(arrayToMerge).toEqual(originalToMerge);
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
});
|