Download desktop/src/stores/sessionStore.test.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 8.84 kB
-
https://huggingface.co/chenbhao/codev/resolve/e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/stores/sessionStore.test.ts
- Command line
-
hf download hf://chenbhao/codev@e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/stores/sessionStore.test.ts
-
curl -L -o sessionStore.test.ts https://huggingface.co/chenbhao/codev/resolve/e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/stores/sessionStore.test.ts
8.84 kB
| import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' | |
| const { branchMock, createMock, listMock } = vi.hoisted(() => ({ | |
| branchMock: vi.fn(), | |
| createMock: vi.fn(), | |
| listMock: vi.fn(), | |
| })) | |
| vi.mock('../api/sessions', () => ({ | |
| sessionsApi: { | |
| branch: branchMock, | |
| create: createMock, | |
| list: listMock, | |
| delete: vi.fn(), | |
| rename: vi.fn(), | |
| }, | |
| })) | |
| import { useSessionStore } from './sessionStore' | |
| import { useTabStore } from './tabStore' | |
| const initialState = useSessionStore.getState() | |
| function delay(ms: number) { | |
| return new Promise((resolve) => setTimeout(resolve, ms)) | |
| } | |
| function createDeferred<T>() { | |
| let resolve!: (value: T) => void | |
| const promise = new Promise<T>((res) => { | |
| resolve = res | |
| }) | |
| return { promise, resolve } | |
| } | |
| describe('sessionStore', () => { | |
| beforeEach(() => { | |
| branchMock.mockReset() | |
| createMock.mockReset() | |
| listMock.mockReset() | |
| useSessionStore.setState({ | |
| ...initialState, | |
| sessions: [], | |
| activeSessionId: null, | |
| isLoading: false, | |
| error: null, | |
| }) | |
| useTabStore.setState({ tabs: [], activeTabId: null }) | |
| }) | |
| afterEach(() => { | |
| useSessionStore.setState(initialState) | |
| useTabStore.setState({ tabs: [], activeTabId: null }) | |
| }) | |
| it('returns a new session id before the background refresh completes', async () => { | |
| createMock.mockResolvedValue({ sessionId: 'session-optimistic-1' }) | |
| listMock.mockImplementation(() => new Promise(() => {})) | |
| const result = await Promise.race([ | |
| useSessionStore.getState().createSession('D:/workspace/code/myself_code/cc-haha'), | |
| delay(100).then(() => 'timed-out'), | |
| ]) | |
| expect(result).toBe('session-optimistic-1') | |
| expect(useSessionStore.getState().activeSessionId).toBe('session-optimistic-1') | |
| expect(useSessionStore.getState().sessions[0]).toMatchObject({ | |
| id: 'session-optimistic-1', | |
| title: 'New Session', | |
| workDir: 'D:/workspace/code/myself_code/cc-haha', | |
| workDirExists: true, | |
| }) | |
| expect(createMock).toHaveBeenCalledWith({ | |
| workDir: 'D:/workspace/code/myself_code/cc-haha', | |
| }) | |
| expect(listMock).toHaveBeenCalledOnce() | |
| }) | |
| it('keeps an optimistic local title when a background refresh still returns a placeholder', async () => { | |
| const refresh = createDeferred<{ | |
| sessions: Array<{ | |
| id: string | |
| title: string | |
| createdAt: string | |
| modifiedAt: string | |
| messageCount: number | |
| projectPath: string | |
| workDir: string | null | |
| workDirExists: boolean | |
| }> | |
| total: number | |
| }>() | |
| createMock.mockResolvedValue({ sessionId: 'session-title-1', workDir: '/workspace/project' }) | |
| listMock.mockReturnValue(refresh.promise) | |
| await useSessionStore.getState().createSession('/workspace/project') | |
| useSessionStore.getState().updateSessionTitle('session-title-1', '开始优化UI') | |
| refresh.resolve({ | |
| sessions: [{ | |
| id: 'session-title-1', | |
| title: 'Untitled Session', | |
| createdAt: '2026-05-07T00:00:00.000Z', | |
| modifiedAt: '2026-05-07T00:00:01.000Z', | |
| messageCount: 0, | |
| projectPath: '', | |
| workDir: '/workspace/project', | |
| workDirExists: true, | |
| }], | |
| total: 1, | |
| }) | |
| await refresh.promise | |
| await delay(0) | |
| expect(useSessionStore.getState().sessions[0]?.title).toBe('开始优化UI') | |
| }) | |
| it('syncs refreshed session titles into already-open tabs', async () => { | |
| useTabStore.getState().openTab('session-title-2', '```json {"title":') | |
| listMock.mockResolvedValue({ | |
| sessions: [{ | |
| id: 'session-title-2', | |
| title: '使用bash写一个shell,随便写点什么东西', | |
| createdAt: '2026-05-07T00:00:00.000Z', | |
| modifiedAt: '2026-05-07T00:00:01.000Z', | |
| messageCount: 3, | |
| projectPath: '', | |
| workDir: '/workspace/project', | |
| workDirExists: true, | |
| }], | |
| total: 1, | |
| }) | |
| await useSessionStore.getState().fetchSessions() | |
| expect(useTabStore.getState().tabs[0]?.title).toBe('使用bash写一个shell,随便写点什么东西') | |
| }) | |
| it('forwards direct branch switch repository options when creating a session', async () => { | |
| createMock.mockResolvedValue({ sessionId: 'session-branch-switch', workDir: '/workspace/repo' }) | |
| listMock.mockImplementation(() => new Promise(() => {})) | |
| await useSessionStore.getState().createSession('/workspace/repo', { | |
| repository: { branch: 'feature/rail', worktree: false }, | |
| }) | |
| expect(createMock).toHaveBeenCalledWith({ | |
| workDir: '/workspace/repo', | |
| repository: { branch: 'feature/rail', worktree: false }, | |
| }) | |
| }) | |
| it('forwards isolated worktree repository options when creating a session', async () => { | |
| createMock.mockResolvedValue({ | |
| sessionId: 'session-worktree-launch', | |
| workDir: '/workspace/repo/.claude/worktrees/desktop-feature-rail-12345678', | |
| }) | |
| listMock.mockImplementation(() => new Promise(() => {})) | |
| await useSessionStore.getState().createSession('/workspace/repo', { | |
| repository: { branch: 'feature/rail', worktree: true }, | |
| }) | |
| expect(createMock).toHaveBeenCalledWith({ | |
| workDir: '/workspace/repo', | |
| repository: { branch: 'feature/rail', worktree: true }, | |
| }) | |
| expect(useSessionStore.getState().sessions[0]?.workDir) | |
| .toBe('/workspace/repo/.claude/worktrees/desktop-feature-rail-12345678') | |
| }) | |
| it('returns the branched session before the background refresh completes', async () => { | |
| branchMock.mockResolvedValue({ | |
| sessionId: 'session-branch-1', | |
| title: 'Branch from here', | |
| workDir: '/workspace/repo/branches/session-branch-1', | |
| sourceSessionId: 'session-source-1', | |
| targetMessageId: 'transcript-message-1', | |
| }) | |
| listMock.mockImplementation(() => new Promise(() => {})) | |
| useSessionStore.setState({ | |
| sessions: [{ | |
| id: 'session-source-1', | |
| title: 'Source session', | |
| createdAt: '2026-05-19T00:00:00.000Z', | |
| modifiedAt: '2026-05-19T00:00:00.000Z', | |
| messageCount: 4, | |
| projectPath: '/workspace/repo', | |
| projectRoot: '/workspace/repo', | |
| workDir: '/workspace/repo', | |
| workDirExists: true, | |
| }], | |
| }) | |
| const result = await Promise.race([ | |
| useSessionStore.getState().branchSession('session-source-1', 'transcript-message-1'), | |
| delay(100).then(() => 'timed-out'), | |
| ]) | |
| expect(result).toMatchObject({ | |
| sessionId: 'session-branch-1', | |
| title: 'Branch from here', | |
| workDir: '/workspace/repo/branches/session-branch-1', | |
| }) | |
| expect(branchMock).toHaveBeenCalledWith('session-source-1', { | |
| targetMessageId: 'transcript-message-1', | |
| }) | |
| expect(useSessionStore.getState().activeSessionId).toBe('session-branch-1') | |
| expect(useSessionStore.getState().sessions[0]).toMatchObject({ | |
| id: 'session-branch-1', | |
| title: 'Branch from here', | |
| projectPath: '/workspace/repo', | |
| workDir: '/workspace/repo/branches/session-branch-1', | |
| projectRoot: '/workspace/repo', | |
| workDirExists: true, | |
| }) | |
| expect(listMock).toHaveBeenCalledOnce() | |
| }) | |
| it('updates an existing optimistic branch row when the branch session id is already present', async () => { | |
| branchMock.mockResolvedValue({ | |
| sessionId: 'session-branch-existing', | |
| title: 'Updated branch', | |
| workDir: '/workspace/repo/branches/session-branch-existing', | |
| sourceSessionId: 'session-source-1', | |
| targetMessageId: 'transcript-message-2', | |
| }) | |
| listMock.mockImplementation(() => new Promise(() => {})) | |
| useSessionStore.setState({ | |
| sessions: [ | |
| { | |
| id: 'session-branch-existing', | |
| title: 'Old branch title', | |
| createdAt: '2026-05-18T00:00:00.000Z', | |
| modifiedAt: '2026-05-18T00:00:00.000Z', | |
| messageCount: 3, | |
| projectPath: '/workspace/old', | |
| projectRoot: '/workspace/old', | |
| workDir: '/workspace/old', | |
| workDirExists: true, | |
| }, | |
| { | |
| id: 'session-source-1', | |
| title: 'Source session', | |
| createdAt: '2026-05-19T00:00:00.000Z', | |
| modifiedAt: '2026-05-19T00:00:00.000Z', | |
| messageCount: 4, | |
| projectPath: '/workspace/repo', | |
| projectRoot: '/workspace/repo', | |
| workDir: '/workspace/repo', | |
| workDirExists: true, | |
| }, | |
| ], | |
| }) | |
| await useSessionStore.getState().branchSession('session-source-1', 'transcript-message-2') | |
| expect(useSessionStore.getState().sessions).toHaveLength(2) | |
| expect(useSessionStore.getState().sessions[0]).toMatchObject({ | |
| id: 'session-branch-existing', | |
| title: 'Updated branch', | |
| projectPath: '/workspace/repo', | |
| projectRoot: '/workspace/repo', | |
| workDir: '/workspace/repo/branches/session-branch-existing', | |
| }) | |
| }) | |
| }) | |