@lobehub/chat 1.37.0 → 1.37.2

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 (50) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/en-US/common.json +2 -2
  4. package/package.json +1 -1
  5. package/src/services/file/_deprecated.test.ts +119 -0
  6. package/src/services/file/{pglite.ts → _deprecated.ts} +28 -32
  7. package/src/services/file/client.test.ts +153 -74
  8. package/src/services/file/client.ts +32 -28
  9. package/src/services/file/index.ts +2 -2
  10. package/src/services/import/_deprecated.ts +74 -0
  11. package/src/services/import/{pglite.test.ts → client.test.ts} +1 -1
  12. package/src/services/import/client.ts +21 -61
  13. package/src/services/import/index.ts +2 -2
  14. package/src/services/message/_deprecated.test.ts +398 -0
  15. package/src/services/message/_deprecated.ts +121 -0
  16. package/src/services/message/client.test.ts +191 -159
  17. package/src/services/message/client.ts +47 -50
  18. package/src/services/message/index.ts +2 -2
  19. package/src/services/plugin/_deprecated.test.ts +162 -0
  20. package/src/services/plugin/_deprecated.ts +42 -0
  21. package/src/services/plugin/client.test.ts +68 -55
  22. package/src/services/plugin/client.ts +20 -11
  23. package/src/services/plugin/index.ts +2 -2
  24. package/src/services/session/_deprecated.test.ts +440 -0
  25. package/src/services/session/_deprecated.ts +183 -0
  26. package/src/services/session/client.test.ts +212 -241
  27. package/src/services/session/client.ts +61 -60
  28. package/src/services/session/index.ts +2 -2
  29. package/src/services/topic/{client.test.ts → _deprecated.test.ts} +1 -1
  30. package/src/services/topic/_deprecated.ts +70 -0
  31. package/src/services/topic/client.ts +40 -25
  32. package/src/services/topic/index.ts +2 -2
  33. package/src/services/topic/pglite.test.ts +1 -1
  34. package/src/services/user/{pglite.test.ts → _deprecated.test.ts} +32 -29
  35. package/src/services/user/_deprecated.ts +57 -0
  36. package/src/services/user/client.test.ts +28 -31
  37. package/src/services/user/client.ts +51 -16
  38. package/src/services/user/index.ts +2 -2
  39. package/src/store/chat/slices/builtinTool/action.test.ts +1 -1
  40. package/src/store/user/slices/common/action.test.ts +1 -1
  41. package/src/services/file/pglite.test.ts +0 -198
  42. package/src/services/import/pglite.ts +0 -34
  43. package/src/services/message/pglite.test.ts +0 -430
  44. package/src/services/message/pglite.ts +0 -118
  45. package/src/services/plugin/pglite.test.ts +0 -175
  46. package/src/services/plugin/pglite.ts +0 -51
  47. package/src/services/session/pglite.test.ts +0 -411
  48. package/src/services/session/pglite.ts +0 -184
  49. package/src/services/topic/pglite.ts +0 -85
  50. package/src/services/user/pglite.ts +0 -92
@@ -1,194 +1,119 @@
1
+ import { eq, not } from 'drizzle-orm/expressions';
1
2
  import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
2
3
 
3
- import { SessionModel } from '@/database/_deprecated/models/session';
4
- import { SessionGroupModel } from '@/database/_deprecated/models/sessionGroup';
5
- import { LobeAgentConfig } from '@/types/agent';
4
+ import { INBOX_SESSION_ID } from '@/const/session';
5
+ import { clientDB, initializeDB } from '@/database/client/db';
6
+ import {
7
+ NewSession,
8
+ SessionItem,
9
+ agents,
10
+ agentsToSessions,
11
+ sessionGroups,
12
+ sessions,
13
+ users,
14
+ } from '@/database/schemas';
15
+ import { LobeAgentChatConfig, LobeAgentConfig } from '@/types/agent';
6
16
  import { LobeAgentSession, LobeSessionType, SessionGroups } from '@/types/session';
7
17
 
8
18
  import { ClientService } from './client';
9
19
 
10
- const sessionService = new ClientService();
11
-
12
- // Mock the SessionModel
13
- vi.mock('@/database/_deprecated/models/session', () => {
14
- return {
15
- SessionModel: {
16
- create: vi.fn(),
17
- query: vi.fn(),
18
- delete: vi.fn(),
19
- clearTable: vi.fn(),
20
- update: vi.fn(),
21
- count: vi.fn(),
22
- batchCreate: vi.fn(),
23
- findById: vi.fn(),
24
- isEmpty: vi.fn(),
25
- queryByKeyword: vi.fn(),
26
- updateConfig: vi.fn(),
27
- queryByGroupIds: vi.fn(),
28
- updatePinned: vi.fn(),
29
- duplicate: vi.fn(),
30
- queryWithGroups: vi.fn(),
31
- },
32
- };
20
+ const userId = 'message-db';
21
+ const sessionService = new ClientService(userId);
22
+
23
+ const mockSessionId = 'mock-session-id';
24
+ const mockAgentId = 'agent-id';
25
+
26
+ // Mock data
27
+ beforeEach(async () => {
28
+ await initializeDB();
29
+
30
+ // 在每个测试用例之前,清空表
31
+ await clientDB.transaction(async (trx) => {
32
+ await trx.insert(users).values([{ id: userId }, { id: '456' }]);
33
+ await trx.insert(sessions).values([{ id: mockSessionId, userId }]);
34
+ await trx.insert(agents).values([{ id: mockAgentId, userId }]);
35
+ await trx.insert(agentsToSessions).values([{ agentId: mockAgentId, sessionId: mockSessionId }]);
36
+ await trx.insert(sessionGroups).values([
37
+ { id: 'group-1', name: 'group-A', sort: 2, userId },
38
+ { id: 'group-2', name: 'group-B', sort: 1, userId },
39
+ { id: 'group-4', name: 'group-C', sort: 1, userId: '456' },
40
+ ]);
41
+ });
33
42
  });
34
43
 
35
- // Mock the SessionGroupModel
36
- vi.mock('@/database/_deprecated/models/sessionGroup', () => {
37
- return {
38
- SessionGroupModel: {
39
- create: vi.fn(),
40
- query: vi.fn(),
41
- delete: vi.fn(),
42
- clear: vi.fn(),
43
- update: vi.fn(),
44
- batchCreate: vi.fn(),
45
- isEmpty: vi.fn(),
46
- updateOrder: vi.fn(),
47
- queryByKeyword: vi.fn(),
48
- updateConfig: vi.fn(),
49
- queryByGroupIds: vi.fn(),
50
- },
51
- };
44
+ afterEach(async () => {
45
+ // 在每个测试用例之后,清空表
46
+ await clientDB.delete(users);
52
47
  });
53
48
 
54
49
  describe('SessionService', () => {
55
- const mockSessionId = 'mock-session-id';
56
50
  const mockSession = {
57
51
  id: mockSessionId,
58
52
  type: 'agent',
59
53
  meta: { title: 'Mock Session' },
60
54
  } as LobeAgentSession;
61
- const mockSessions = [mockSession];
62
-
63
- beforeEach(() => {
64
- // Reset all mocks before running each test case
65
- vi.resetAllMocks();
66
- });
67
55
 
68
56
  describe('createSession', () => {
69
57
  it('should create a new session and return its id', async () => {
70
58
  // Setup
71
59
  const sessionType = LobeSessionType.Agent;
72
60
  const defaultValue = { meta: { title: 'New Session' } } as Partial<LobeAgentSession>;
73
- (SessionModel.create as Mock).mockResolvedValue(mockSession);
74
61
 
75
62
  // Execute
76
63
  const sessionId = await sessionService.createSession(sessionType, defaultValue);
77
64
 
78
65
  // Assert
79
- expect(SessionModel.create).toHaveBeenCalledWith(sessionType, defaultValue);
80
- expect(sessionId).toBe(mockSessionId);
81
- });
82
-
83
- it('should throw an error if session creation fails', async () => {
84
- // Setup
85
- const sessionType = LobeSessionType.Agent;
86
- const defaultValue = { meta: { title: 'New Session' } } as Partial<LobeAgentSession>;
87
- (SessionModel.create as Mock).mockResolvedValue(null);
88
-
89
- // Execute & Assert
90
- await expect(sessionService.createSession(sessionType, defaultValue)).rejects.toThrow(
91
- 'session create Error',
92
- );
93
- });
94
- });
95
-
96
- describe('batchCreateSessions', () => {
97
- it('should batch create sessions', async () => {
98
- // Setup
99
- (SessionModel.batchCreate as Mock).mockResolvedValue(mockSessions);
100
-
101
- // Execute
102
- const result = await sessionService.batchCreateSessions(mockSessions);
103
-
104
- // Assert
105
- expect(SessionModel.batchCreate).toHaveBeenCalledWith(mockSessions);
106
- expect(result).toBe(mockSessions);
107
- });
108
- });
109
-
110
- describe('getSessionsByType', () => {
111
- it('should retrieve sessions with their group ids', async () => {
112
- // Setup
113
- (SessionModel.query as Mock).mockResolvedValue(mockSessions);
114
-
115
- // Execute
116
- const sessions = await sessionService.getSessionsByType();
117
-
118
- // Assert
119
- expect(SessionModel.query).toHaveBeenCalled();
120
- expect(sessions).toBe(mockSessions);
121
- });
122
-
123
- it('should retrieve all agent sessions', async () => {
124
- // Setup
125
- // Assuming that SessionModel.query has been modified to accept filters
126
- const agentSessions = mockSessions.filter((session) => session.type === 'agent');
127
- (SessionModel.query as Mock).mockResolvedValue(agentSessions);
128
-
129
- // Execute
130
- const result = await sessionService.getSessionsByType('agent');
131
-
132
- // Assert
133
- // Assuming that SessionModel.query would be called with a filter for agents
134
- expect(SessionModel.query).toHaveBeenCalled(); // Add filter argument if applicable
135
- expect(result).toBe(agentSessions);
66
+ expect(sessionId).toMatch(/^ssn_/);
136
67
  });
137
68
  });
138
69
 
139
70
  describe('removeSession', () => {
140
71
  it('should remove a session by its id', async () => {
141
- // Setup
142
- (SessionModel.delete as Mock).mockResolvedValue(true);
143
-
144
72
  // Execute
145
- const result = await sessionService.removeSession(mockSessionId);
73
+ await sessionService.removeSession(mockSessionId);
146
74
 
147
75
  // Assert
148
- expect(SessionModel.delete).toHaveBeenCalledWith(mockSessionId);
149
- expect(result).toBe(true);
76
+
77
+ const result = await clientDB.query.sessions.findFirst({
78
+ where: eq(sessions.id, mockSessionId),
79
+ });
80
+ // Assert
81
+ expect(result).toBeUndefined();
150
82
  });
151
83
  });
152
84
 
153
85
  describe('removeAllSessions', () => {
154
86
  it('should clear all sessions from the table', async () => {
155
87
  // Setup
156
- (SessionModel.clearTable as Mock).mockResolvedValue(true);
88
+ await clientDB
89
+ .insert(sessions)
90
+ .values([{ userId: userId }, { userId: userId }, { userId: userId }]);
157
91
 
158
92
  // Execute
159
- const result = await sessionService.removeAllSessions();
93
+ await sessionService.removeAllSessions();
160
94
 
161
95
  // Assert
162
- expect(SessionModel.clearTable).toHaveBeenCalled();
163
- expect(result).toBe(true);
96
+ const result = await clientDB.query.sessions.findMany({
97
+ where: eq(sessionGroups.userId, userId),
98
+ });
99
+
100
+ expect(result.length).toBe(0);
164
101
  });
165
102
  });
166
103
 
167
104
  describe('updateSession', () => {
168
105
  it('should update the group of a session', async () => {
169
106
  // Setup
170
- const groupId = 'new-group';
171
- (SessionModel.update as Mock).mockResolvedValue({ ...mockSession, group: groupId });
172
-
173
- // Execute
174
- const result = await sessionService.updateSession(mockSessionId, { group: groupId });
175
-
176
- // Assert
177
- expect(SessionModel.update).toHaveBeenCalledWith(mockSessionId, { group: groupId });
178
- expect(result).toEqual({ ...mockSession, group: groupId });
179
- });
180
-
181
- it('should update the meta of a session', async () => {
182
- // Setup
183
- const newMeta = { description: 'Updated description' };
184
- (SessionModel.update as Mock).mockResolvedValue({ ...mockSession, meta: newMeta });
107
+ const groupId = 'group-1';
185
108
 
186
109
  // Execute
187
- const result = await sessionService.updateSession(mockSessionId, { meta: newMeta });
110
+ await sessionService.updateSession(mockSessionId, { group: groupId });
188
111
 
189
112
  // Assert
190
- expect(SessionModel.update).toHaveBeenCalledWith(mockSessionId, { meta: newMeta });
191
- expect(result).toEqual({ ...mockSession, meta: newMeta });
113
+ const result = await clientDB.query.sessions.findFirst({
114
+ where: eq(sessions.id, mockSessionId),
115
+ });
116
+ expect(result).toMatchObject({ groupId });
192
117
  });
193
118
 
194
119
  it('should update the pinned status of a session', async () => {
@@ -199,7 +124,11 @@ describe('SessionService', () => {
199
124
  await sessionService.updateSession(mockSessionId, { pinned });
200
125
 
201
126
  // Assert
202
- expect(SessionModel.update).toHaveBeenCalledWith(mockSessionId, { pinned: 1 });
127
+ const result = await clientDB.query.sessions.findFirst({
128
+ where: eq(sessions.id, mockSessionId),
129
+ });
130
+
131
+ expect(result!.pinned).toBeTruthy();
203
132
  });
204
133
  });
205
134
 
@@ -207,81 +136,55 @@ describe('SessionService', () => {
207
136
  it('should update the config of a session', async () => {
208
137
  // Setup
209
138
  const newConfig = { model: 'abc' } as LobeAgentConfig;
210
- (SessionModel.updateConfig as Mock).mockResolvedValue({ ...mockSession, config: newConfig });
211
139
 
212
140
  // Execute
213
- const result = await sessionService.updateSessionConfig(mockSessionId, newConfig);
141
+ await sessionService.updateSessionConfig(mockSessionId, newConfig);
214
142
 
215
143
  // Assert
216
- expect(SessionModel.updateConfig).toHaveBeenCalledWith(mockSessionId, newConfig);
217
- expect(result).toEqual({ ...mockSession, config: newConfig });
144
+ const result = await sessionService.getSessionConfig(mockSessionId);
145
+ expect(result).toMatchObject(newConfig);
218
146
  });
219
147
  });
220
148
 
221
149
  describe('countSessions', () => {
222
150
  it('should return false if no sessions exist', async () => {
223
- // Setup
224
- (SessionModel.count as Mock).mockResolvedValue(0);
151
+ await clientDB.delete(sessions);
225
152
 
226
153
  // Execute
227
154
  const result = await sessionService.countSessions();
228
155
 
229
156
  // Assert
230
- expect(SessionModel.count).toHaveBeenCalled();
231
157
  expect(result).toBe(0);
232
158
  });
233
159
 
234
160
  it('should return true if sessions exist', async () => {
235
161
  // Setup
236
- (SessionModel.count as Mock).mockResolvedValue(1);
162
+ await clientDB.delete(sessions);
163
+ await clientDB.insert(sessions).values([{ userId }]);
237
164
 
238
165
  // Execute
239
166
  const result = await sessionService.countSessions();
240
167
 
241
168
  // Assert
242
- expect(SessionModel.count).toHaveBeenCalled();
243
169
  expect(result).toBe(1);
244
170
  });
245
171
  });
246
172
 
247
- describe('hasSessions', () => {
248
- it('should return false if no sessions exist', async () => {
249
- // Setup
250
- (SessionModel.count as Mock).mockResolvedValue(0);
251
-
252
- // Execute
253
- const result = await sessionService.hasSessions();
254
-
255
- // Assert
256
- expect(SessionModel.count).toHaveBeenCalled();
257
- expect(result).toBe(false);
258
- });
259
-
260
- it('should return true if sessions exist', async () => {
261
- // Setup
262
- (SessionModel.count as Mock).mockResolvedValue(1);
263
-
264
- // Execute
265
- const result = await sessionService.hasSessions();
266
-
267
- // Assert
268
- expect(SessionModel.count).toHaveBeenCalled();
269
- expect(result).toBe(true);
270
- });
271
- });
272
-
273
173
  describe('searchSessions', () => {
274
174
  it('should return sessions that match the keyword', async () => {
275
175
  // Setup
276
- const keyword = 'search';
277
- (SessionModel.queryByKeyword as Mock).mockResolvedValue(mockSessions);
176
+ await clientDB.insert(agents).values({ userId, id: 'agent-1', title: 'Session Name' });
177
+ await clientDB
178
+ .insert(agentsToSessions)
179
+ .values({ agentId: 'agent-1', sessionId: mockSessionId });
278
180
 
279
181
  // Execute
182
+ const keyword = 'Name';
280
183
  const result = await sessionService.searchSessions(keyword);
281
184
 
282
185
  // Assert
283
- expect(SessionModel.queryByKeyword).toHaveBeenCalledWith(keyword);
284
- expect(result).toBe(mockSessions);
186
+ // TODO: 后续需要把这个搜索的标题和描述都加上,现在这个 client 搜索会有问题
187
+ expect(result).toMatchObject([{ id: mockSessionId }]);
285
188
  });
286
189
  });
287
190
 
@@ -289,31 +192,112 @@ describe('SessionService', () => {
289
192
  it('should duplicate a session and return its id', async () => {
290
193
  // Setup
291
194
  const newTitle = 'Duplicated Session';
292
- (SessionModel.duplicate as Mock).mockResolvedValue({
293
- ...mockSession,
195
+ const session: NewSession = {
294
196
  id: 'duplicated-session-id',
295
- });
197
+ title: '123',
198
+ userId,
199
+ };
200
+ await clientDB.insert(sessions).values([session]);
201
+ await clientDB.insert(agents).values({ userId, id: 'agent-1' });
202
+ await clientDB
203
+ .insert(agentsToSessions)
204
+ .values({ agentId: 'agent-1', sessionId: 'duplicated-session-id' });
296
205
 
297
206
  // Execute
298
207
  const duplicatedSessionId = await sessionService.cloneSession(mockSessionId, newTitle);
299
208
 
300
209
  // Assert
301
- expect(SessionModel.duplicate).toHaveBeenCalledWith(mockSessionId, newTitle);
302
- expect(duplicatedSessionId).toBe('duplicated-session-id');
210
+
211
+ const result = await clientDB.query.sessions.findFirst({
212
+ where: eq(sessions.id, duplicatedSessionId!),
213
+ });
214
+ expect(result).toMatchObject({ title: 'Duplicated Session' });
303
215
  });
304
216
  });
305
217
 
306
218
  describe('getGroupedSessions', () => {
307
219
  it('should retrieve sessions with their group', async () => {
308
- // Setup
309
- (SessionModel.queryWithGroups as Mock).mockResolvedValue(mockSessions);
310
-
311
220
  // Execute
312
221
  const sessionsWithGroup = await sessionService.getGroupedSessions();
313
222
 
314
- // Assert
315
- expect(SessionModel.queryWithGroups).toHaveBeenCalled();
316
- expect(sessionsWithGroup).toBe(mockSessions);
223
+ expect(sessionsWithGroup).toMatchObject({
224
+ sessionGroups: [
225
+ { id: 'group-2', name: 'group-B', sort: 1 },
226
+ { id: 'group-1', name: 'group-A', sort: 2 },
227
+ ],
228
+ sessions: [{ id: 'mock-session-id', type: 'agent' }],
229
+ });
230
+ });
231
+ });
232
+
233
+ describe('getSessionsByType', () => {
234
+ it('should get sessions by type "all"', async () => {
235
+ const sessions = await sessionService.getSessionsByType('all');
236
+ expect(sessions).toBeDefined();
237
+ });
238
+
239
+ it('should get sessions by type "agent"', async () => {
240
+ const sessions = await sessionService.getSessionsByType('agent');
241
+ expect(sessions).toBeDefined();
242
+ });
243
+
244
+ it('should get sessions by type "group"', async () => {
245
+ const sessions = await sessionService.getSessionsByType('group');
246
+ expect(sessions).toBeDefined();
247
+ });
248
+ });
249
+
250
+ describe('getSessionConfig', () => {
251
+ it.skip('should get default config for INBOX_SESSION_ID', async () => {
252
+ const config = await sessionService.getSessionConfig(INBOX_SESSION_ID);
253
+ expect(config).toBeDefined();
254
+ });
255
+
256
+ it('should throw error for non-existent session', async () => {
257
+ await expect(sessionService.getSessionConfig('non-existent')).rejects.toThrow(
258
+ 'Session not found',
259
+ );
260
+ });
261
+ });
262
+
263
+ describe('updateSessionMeta', () => {
264
+ it('should not update meta for INBOX_SESSION_ID', async () => {
265
+ const result = await sessionService.updateSessionMeta(INBOX_SESSION_ID, {
266
+ title: 'New Title',
267
+ });
268
+ expect(result).toBeUndefined();
269
+ });
270
+
271
+ it('should update meta for normal session', async () => {
272
+ const meta = { title: 'Updated Title' };
273
+ await sessionService.updateSessionMeta(mockSessionId, meta);
274
+
275
+ const session = await clientDB.query.sessions.findFirst({
276
+ where: eq(sessions.id, mockSessionId),
277
+ });
278
+ expect(session).toBeDefined();
279
+ });
280
+ });
281
+
282
+ describe('updateSessionChatConfig', () => {
283
+ it('should update chat config', async () => {
284
+ const chatConfig = { temperature: 0.8 } as Partial<LobeAgentChatConfig>;
285
+ const result = await sessionService.updateSessionChatConfig(mockSessionId, chatConfig);
286
+ expect(result).toBeDefined();
287
+ });
288
+ });
289
+
290
+ describe('model getters', () => {
291
+ it('should return session model instance', () => {
292
+ // @ts-ignore - accessing private getter
293
+ const model = sessionService.sessionModel;
294
+ expect(model).toBeDefined();
295
+ });
296
+
297
+ it('should return session group model instance', () => {
298
+ // @ts-ignore - accessing private getter
299
+ const model = sessionService.sessionGroupModel;
300
+ expect(model).toBeDefined();
317
301
  });
318
302
  });
319
303
 
@@ -323,84 +307,66 @@ describe('SessionService', () => {
323
307
  // Setup
324
308
  const groupName = 'New Group';
325
309
  const sort = 1;
326
- (SessionGroupModel.create as Mock).mockResolvedValue({
327
- id: 'new-group-id',
328
- name: groupName,
329
- sort,
330
- });
331
310
 
332
311
  // Execute
333
312
  const groupId = await sessionService.createSessionGroup(groupName, sort);
334
313
 
335
314
  // Assert
336
- expect(SessionGroupModel.create).toHaveBeenCalledWith(groupName, sort);
337
- expect(groupId).toBe('new-group-id');
338
- });
339
- });
340
-
341
- describe('batchCreateSessionGroups', () => {
342
- it('should batch create session groups', async () => {
343
- // Setup
344
- const groups = [
345
- { id: 'group-1', name: 'Group 1', sort: 1 },
346
- { id: 'group-2', name: 'Group 2', sort: 2 },
347
- ] as SessionGroups;
315
+ expect(groupId).toMatch(/^sg_/);
348
316
 
349
- (SessionGroupModel.batchCreate as Mock).mockResolvedValue(groups);
350
-
351
- // Execute
352
- const result = await sessionService.batchCreateSessionGroups(groups);
317
+ const result = await clientDB.query.sessionGroups.findFirst({
318
+ where: eq(sessionGroups.id, groupId),
319
+ });
353
320
 
354
- // Assert
355
- expect(SessionGroupModel.batchCreate).toHaveBeenCalledWith(groups);
356
- expect(result).toBe(groups);
321
+ expect(result).toMatchObject({ id: groupId, name: groupName, sort });
357
322
  });
358
323
  });
359
324
 
360
325
  describe('removeSessionGroup', () => {
361
326
  it('should remove a session group by its id', async () => {
362
- // Setup
363
- const removeChildren = true;
364
- (SessionGroupModel.delete as Mock).mockResolvedValue(true);
365
-
327
+ const groupId = 'group-1';
366
328
  // Execute
367
- const result = await sessionService.removeSessionGroup('group-id', removeChildren);
329
+ await sessionService.removeSessionGroup(groupId);
368
330
 
331
+ const result = await clientDB.query.sessionGroups.findFirst({
332
+ where: eq(sessionGroups.id, groupId),
333
+ });
369
334
  // Assert
370
- expect(SessionGroupModel.delete).toHaveBeenCalledWith('group-id', removeChildren);
371
- expect(result).toBe(true);
335
+ expect(result).toBeUndefined();
372
336
  });
373
337
  });
374
338
 
375
339
  describe('clearSessionGroups', () => {
376
340
  it('should clear all session groups', async () => {
377
- // Setup
378
- (SessionGroupModel.clear as Mock).mockResolvedValue(true);
379
-
380
341
  // Execute
381
- const result = await sessionService.removeSessionGroups();
342
+ await sessionService.removeSessionGroups();
382
343
 
383
344
  // Assert
384
- expect(SessionGroupModel.clear).toHaveBeenCalled();
385
- expect(result).toBe(true);
345
+ const result = await clientDB.query.sessionGroups.findMany({
346
+ where: eq(sessionGroups.userId, userId),
347
+ });
348
+
349
+ expect(result.length).toBe(0);
350
+
351
+ const result2 = await clientDB.query.sessionGroups.findMany({
352
+ where: not(eq(sessionGroups.userId, userId)),
353
+ });
354
+
355
+ expect(result2.length).toBeGreaterThan(0);
386
356
  });
387
357
  });
388
358
 
389
359
  describe('getSessionGroups', () => {
390
360
  it('should retrieve all session groups', async () => {
391
- // Setup
392
- const groups = [
393
- { id: 'group-1', name: 'Group 1', sort: 1 },
394
- { id: 'group-2', name: 'Group 2', sort: 2 },
395
- ];
396
- (SessionGroupModel.query as Mock).mockResolvedValue(groups);
397
-
398
361
  // Execute
399
362
  const result = await sessionService.getSessionGroups();
400
363
 
401
364
  // Assert
402
- expect(SessionGroupModel.query).toHaveBeenCalled();
403
- expect(result).toBe(groups);
365
+ const groups = [
366
+ { id: 'group-2', name: 'group-B', sort: 1 },
367
+ { id: 'group-1', name: 'group-A', sort: 2 },
368
+ ];
369
+ expect(result).toMatchObject(groups);
404
370
  });
405
371
  });
406
372
 
@@ -409,14 +375,15 @@ describe('SessionService', () => {
409
375
  // Setup
410
376
  const groupId = 'group-1';
411
377
  const data = { name: 'Updated Group', sort: 2 };
412
- (SessionGroupModel.update as Mock).mockResolvedValue({ id: groupId, ...data });
413
378
 
414
379
  // Execute
415
- const result = await sessionService.updateSessionGroup(groupId, data);
380
+ await sessionService.updateSessionGroup(groupId, data);
416
381
 
417
382
  // Assert
418
- expect(SessionGroupModel.update).toHaveBeenCalledWith(groupId, data);
419
- expect(result).toEqual({ id: groupId, ...data });
383
+ const result = await clientDB.query.sessionGroups.findFirst({
384
+ where: eq(sessionGroups.id, groupId),
385
+ });
386
+ expect(result).toMatchObject({ id: groupId, ...data });
420
387
  });
421
388
  });
422
389
 
@@ -427,14 +394,18 @@ describe('SessionService', () => {
427
394
  { id: 'group-1', sort: 2 },
428
395
  { id: 'group-2', sort: 1 },
429
396
  ];
430
- (SessionGroupModel.updateOrder as Mock).mockResolvedValue(true);
431
397
 
432
398
  // Execute
433
- const result = await sessionService.updateSessionGroupOrder(sortMap);
399
+ await sessionService.updateSessionGroupOrder(sortMap);
434
400
 
435
401
  // Assert
436
- expect(SessionGroupModel.updateOrder).toHaveBeenCalledWith(sortMap);
437
- expect(result).toBe(true);
402
+ const data = await clientDB.query.sessionGroups.findMany({
403
+ where: eq(sessionGroups.userId, userId),
404
+ });
405
+ expect(data).toMatchObject([
406
+ { id: 'group-1', sort: 2 },
407
+ { id: 'group-2', sort: 1 },
408
+ ]);
438
409
  });
439
410
  });
440
411
  });