| import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' |
|
|
| type HoistedVi = typeof vi & { |
| hoisted?: <T>(factory: () => T) => T |
| } |
|
|
| if (typeof (vi as HoistedVi).hoisted !== 'function') { |
| ;(vi as HoistedVi).hoisted = <T>(factory: () => T) => factory() |
| } |
|
|
| const mocks = vi.hoisted(() => ({ |
| getWorkspaceStatusMock: vi.fn(), |
| getWorkspaceTreeMock: vi.fn(), |
| getWorkspaceFileMock: vi.fn(), |
| getWorkspaceDiffMock: vi.fn(), |
| })) |
|
|
| vi.mock('../api/sessions', () => ({ |
| sessionsApi: { |
| getWorkspaceStatus: mocks.getWorkspaceStatusMock, |
| getWorkspaceTree: mocks.getWorkspaceTreeMock, |
| getWorkspaceFile: mocks.getWorkspaceFileMock, |
| getWorkspaceDiff: mocks.getWorkspaceDiffMock, |
| }, |
| })) |
|
|
| import { sessionsApi } from '../api/sessions' |
| import { |
| WORKSPACE_PANEL_DEFAULT_WIDTH, |
| WORKSPACE_PANEL_MAX_WIDTH, |
| WORKSPACE_PANEL_MIN_WIDTH, |
| getWorkspacePreviewTabId, |
| useWorkspacePanelStore, |
| } from './workspacePanelStore' |
|
|
| function deferred<T>() { |
| let resolve!: (value: T) => void |
| let reject!: (reason?: unknown) => void |
| const promise = new Promise<T>((res, rej) => { |
| resolve = res |
| reject = rej |
| }) |
| return { promise, resolve, reject } |
| } |
|
|
| describe('workspacePanelStore', () => { |
| const initialState = useWorkspacePanelStore.getInitialState() |
|
|
| beforeEach(() => { |
| vi.clearAllMocks() |
| useWorkspacePanelStore.setState(initialState, true) |
| }) |
|
|
| afterEach(() => { |
| useWorkspacePanelStore.setState(initialState, true) |
| vi.restoreAllMocks() |
| }) |
|
|
| it('uses hoisted session api mocks', () => { |
| expect(sessionsApi.getWorkspaceStatus).toBe(mocks.getWorkspaceStatusMock) |
| expect(sessionsApi.getWorkspaceTree).toBe(mocks.getWorkspaceTreeMock) |
| expect(sessionsApi.getWorkspaceFile).toBe(mocks.getWorkspaceFileMock) |
| expect(sessionsApi.getWorkspaceDiff).toBe(mocks.getWorkspaceDiffMock) |
| }) |
|
|
| it('keeps panel open state and active view isolated per session', () => { |
| const store = useWorkspacePanelStore.getState() |
|
|
| expect(store.isPanelOpen('session-a')).toBe(false) |
| expect(store.getActiveView('session-a')).toBe('changed') |
| expect(store.width).toBe(WORKSPACE_PANEL_DEFAULT_WIDTH) |
|
|
| store.openPanel('session-a') |
| store.setActiveView('session-a', 'all') |
|
|
| expect(useWorkspacePanelStore.getState().isPanelOpen('session-a')).toBe(true) |
| expect(useWorkspacePanelStore.getState().getActiveView('session-a')).toBe('all') |
| expect(useWorkspacePanelStore.getState().isPanelOpen('session-b')).toBe(false) |
| expect(useWorkspacePanelStore.getState().getActiveView('session-b')).toBe('changed') |
|
|
| store.togglePanel('session-b') |
| expect(useWorkspacePanelStore.getState().isPanelOpen('session-b')).toBe(true) |
| expect(useWorkspacePanelStore.getState().isPanelOpen('session-a')).toBe(true) |
|
|
| store.closePanel('session-a') |
| expect(useWorkspacePanelStore.getState().isPanelOpen('session-a')).toBe(false) |
| expect(useWorkspacePanelStore.getState().getActiveView('session-a')).toBe('all') |
|
|
| store.setWidth(120) |
| expect(useWorkspacePanelStore.getState().width).toBe(WORKSPACE_PANEL_MIN_WIDTH) |
| store.setWidth(1200) |
| expect(useWorkspacePanelStore.getState().width).toBe(WORKSPACE_PANEL_MAX_WIDTH) |
| }) |
|
|
| it('loads workspace status successfully', async () => { |
| mocks.getWorkspaceStatusMock.mockResolvedValue({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [ |
| { |
| path: 'src/a.ts', |
| status: 'modified', |
| additions: 3, |
| deletions: 1, |
| }, |
| ], |
| }) |
|
|
| await useWorkspacePanelStore.getState().loadStatus('session-1') |
|
|
| expect(mocks.getWorkspaceStatusMock).toHaveBeenCalledWith('session-1') |
| expect(useWorkspacePanelStore.getState().statusBySession['session-1']).toMatchObject({ |
| branch: 'main', |
| changedFiles: [{ path: 'src/a.ts' }], |
| }) |
| expect(useWorkspacePanelStore.getState().loading.statusBySession['session-1']).toBe(false) |
| expect(useWorkspacePanelStore.getState().errors.statusBySession['session-1']).toBeNull() |
| }) |
|
|
| it('defaults an empty changed-files status to the all-files view', async () => { |
| mocks.getWorkspaceStatusMock.mockResolvedValue({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [], |
| }) |
|
|
| useWorkspacePanelStore.getState().openPanel('session-empty-changes') |
| expect(useWorkspacePanelStore.getState().getActiveView('session-empty-changes')).toBe('changed') |
|
|
| await useWorkspacePanelStore.getState().loadStatus('session-empty-changes') |
|
|
| expect(useWorkspacePanelStore.getState().statusBySession['session-empty-changes']?.changedFiles).toEqual([]) |
| expect(useWorkspacePanelStore.getState().getActiveView('session-empty-changes')).toBe('all') |
| }) |
|
|
| it('keeps the changed-files view when status contains changes', async () => { |
| mocks.getWorkspaceStatusMock.mockResolvedValue({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [ |
| { |
| path: 'src/app.ts', |
| status: 'modified', |
| additions: 2, |
| deletions: 1, |
| }, |
| ], |
| }) |
|
|
| useWorkspacePanelStore.getState().openPanel('session-has-changes') |
| await useWorkspacePanelStore.getState().loadStatus('session-has-changes') |
|
|
| expect(useWorkspacePanelStore.getState().getActiveView('session-has-changes')).toBe('changed') |
| }) |
|
|
| it('returns to changed-files when a refreshed default all-files view now has changes', async () => { |
| mocks.getWorkspaceStatusMock |
| .mockResolvedValueOnce({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [], |
| }) |
| .mockResolvedValueOnce({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [ |
| { |
| path: 'src/app.ts', |
| status: 'modified', |
| additions: 2, |
| deletions: 1, |
| }, |
| ], |
| }) |
|
|
| useWorkspacePanelStore.getState().openPanel('session-refresh-changes') |
| await useWorkspacePanelStore.getState().loadStatus('session-refresh-changes') |
| expect(useWorkspacePanelStore.getState().getActiveView('session-refresh-changes')).toBe('all') |
|
|
| await useWorkspacePanelStore.getState().loadStatus('session-refresh-changes') |
|
|
| expect(useWorkspacePanelStore.getState().getActiveView('session-refresh-changes')).toBe('changed') |
| }) |
|
|
| it('does not override an explicit all-files selection when refreshed status has changes', async () => { |
| mocks.getWorkspaceStatusMock.mockResolvedValue({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [ |
| { |
| path: 'src/app.ts', |
| status: 'modified', |
| additions: 2, |
| deletions: 1, |
| }, |
| ], |
| }) |
|
|
| useWorkspacePanelStore.getState().openPanel('session-explicit-all') |
| useWorkspacePanelStore.getState().setActiveView('session-explicit-all', 'all') |
| await useWorkspacePanelStore.getState().loadStatus('session-explicit-all') |
|
|
| expect(useWorkspacePanelStore.getState().getActiveView('session-explicit-all')).toBe('all') |
| }) |
|
|
| it('does not override an explicit changed-files selection when status is empty', async () => { |
| mocks.getWorkspaceStatusMock.mockResolvedValue({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [], |
| }) |
|
|
| useWorkspacePanelStore.getState().openPanel('session-explicit-changed') |
| useWorkspacePanelStore.getState().setActiveView('session-explicit-changed', 'changed') |
| await useWorkspacePanelStore.getState().loadStatus('session-explicit-changed') |
|
|
| expect(useWorkspacePanelStore.getState().getActiveView('session-explicit-changed')).toBe('changed') |
| }) |
|
|
| it('captures workspace status request errors', async () => { |
| mocks.getWorkspaceStatusMock.mockRejectedValue(new Error('status failed')) |
|
|
| await useWorkspacePanelStore.getState().loadStatus('session-err') |
|
|
| expect(useWorkspacePanelStore.getState().statusBySession['session-err']).toBeUndefined() |
| expect(useWorkspacePanelStore.getState().loading.statusBySession['session-err']).toBe(false) |
| expect(useWorkspacePanelStore.getState().errors.statusBySession['session-err']).toBe('status failed') |
| }) |
|
|
| it('lazily loads tree nodes when expanding and reuses cached results', async () => { |
| mocks.getWorkspaceTreeMock.mockResolvedValue({ |
| state: 'ok', |
| path: '', |
| entries: [ |
| { name: 'src', path: 'src', isDirectory: true }, |
| { name: 'README.md', path: 'README.md', isDirectory: false }, |
| ], |
| }) |
|
|
| await useWorkspacePanelStore.getState().toggleTreeNode('session-tree', '') |
|
|
| expect(mocks.getWorkspaceTreeMock).toHaveBeenCalledTimes(1) |
| expect(mocks.getWorkspaceTreeMock).toHaveBeenCalledWith('session-tree', '') |
| expect(useWorkspacePanelStore.getState().expandedPathsBySession['session-tree']).toEqual(['']) |
| expect(useWorkspacePanelStore.getState().treeBySessionPath['session-tree']?.['']).toMatchObject({ |
| entries: [{ path: 'src' }, { path: 'README.md' }], |
| }) |
|
|
| await useWorkspacePanelStore.getState().toggleTreeNode('session-tree', '') |
| expect(useWorkspacePanelStore.getState().expandedPathsBySession['session-tree']).toEqual([]) |
|
|
| await useWorkspacePanelStore.getState().toggleTreeNode('session-tree', '') |
| expect(mocks.getWorkspaceTreeMock).toHaveBeenCalledTimes(1) |
| expect(useWorkspacePanelStore.getState().expandedPathsBySession['session-tree']).toEqual(['']) |
| }) |
|
|
| it('ignores stale tree responses for the same session path', async () => { |
| const first = deferred<{ state: 'ok'; path: string; entries: Array<{ name: string; path: string; isDirectory: boolean }> }>() |
| const second = deferred<{ state: 'ok'; path: string; entries: Array<{ name: string; path: string; isDirectory: boolean }> }>() |
|
|
| mocks.getWorkspaceTreeMock |
| .mockReturnValueOnce(first.promise) |
| .mockReturnValueOnce(second.promise) |
|
|
| const firstLoad = useWorkspacePanelStore.getState().loadTree('session-tree-race', 'src') |
| const secondLoad = useWorkspacePanelStore.getState().loadTree('session-tree-race', 'src') |
|
|
| second.resolve({ |
| state: 'ok', |
| path: 'src', |
| entries: [{ name: 'new.ts', path: 'src/new.ts', isDirectory: false }], |
| }) |
| await secondLoad |
|
|
| first.resolve({ |
| state: 'ok', |
| path: 'src', |
| entries: [{ name: 'old.ts', path: 'src/old.ts', isDirectory: false }], |
| }) |
| await firstLoad |
|
|
| expect(useWorkspacePanelStore.getState().treeBySessionPath['session-tree-race']?.src?.entries).toEqual([ |
| { name: 'new.ts', path: 'src/new.ts', isDirectory: false }, |
| ]) |
| }) |
|
|
| it('opens preview tabs, supports multiple kinds, and reuses duplicates without persistence', async () => { |
| const storage = typeof globalThis.localStorage === 'undefined' ? null : globalThis.localStorage |
| const setItemSpy = storage ? vi.spyOn(storage, 'setItem') : null |
|
|
| mocks.getWorkspaceFileMock.mockResolvedValue({ |
| state: 'ok', |
| path: 'src/a.ts', |
| content: 'export const a = 1', |
| language: 'typescript', |
| size: 18, |
| }) |
| mocks.getWorkspaceDiffMock.mockResolvedValue({ |
| state: 'ok', |
| path: 'src/a.ts', |
| diff: '@@ -1 +1 @@', |
| }) |
|
|
| useWorkspacePanelStore.getState().openPanel('session-preview') |
| await useWorkspacePanelStore.getState().openPreview('session-preview', 'src/a.ts', 'file') |
| await useWorkspacePanelStore.getState().openPreview('session-preview', 'src/a.ts', 'diff') |
| await useWorkspacePanelStore.getState().openPreview('session-preview', 'src/a.ts', 'file') |
|
|
| expect(mocks.getWorkspaceFileMock).toHaveBeenCalledTimes(1) |
| expect(mocks.getWorkspaceDiffMock).toHaveBeenCalledTimes(1) |
|
|
| const tabs = useWorkspacePanelStore.getState().previewTabsBySession['session-preview'] |
| expect(tabs).toBeDefined() |
| expect(tabs).toHaveLength(2) |
| expect(tabs![0]).toMatchObject({ |
| id: 'file:src/a.ts', |
| kind: 'file', |
| path: 'src/a.ts', |
| content: 'export const a = 1', |
| language: 'typescript', |
| }) |
| expect(tabs![1]).toMatchObject({ |
| id: 'diff:src/a.ts', |
| kind: 'diff', |
| path: 'src/a.ts', |
| diff: '@@ -1 +1 @@', |
| }) |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-preview']).toBe('file:src/a.ts') |
| if (setItemSpy) { |
| expect(setItemSpy).not.toHaveBeenCalled() |
| } else { |
| expect(storage).toBeNull() |
| } |
| }) |
|
|
| it('closes exact tab id and preserves sibling preview for the same path', async () => { |
| mocks.getWorkspaceFileMock.mockResolvedValue({ |
| state: 'ok', |
| path: 'src/a.ts', |
| content: 'export const a = 1', |
| language: 'typescript', |
| size: 18, |
| }) |
| mocks.getWorkspaceDiffMock.mockResolvedValue({ |
| state: 'ok', |
| path: 'src/a.ts', |
| diff: '@@ -1 +1 @@', |
| }) |
|
|
| await useWorkspacePanelStore.getState().openPreview('session-close-path', 'src/a.ts', 'file') |
| await useWorkspacePanelStore.getState().openPreview('session-close-path', 'src/a.ts', 'diff') |
|
|
| useWorkspacePanelStore.getState().closePreview('session-close-path', 'diff:src/a.ts') |
|
|
| expect(useWorkspacePanelStore.getState().previewTabsBySession['session-close-path']).toEqual([ |
| expect.objectContaining({ id: 'file:src/a.ts' }), |
| ]) |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-close-path']).toBe('file:src/a.ts') |
| }) |
|
|
| it('chooses the next sensible active preview when closing the current tab', async () => { |
| mocks.getWorkspaceFileMock |
| .mockResolvedValueOnce({ |
| state: 'ok', |
| path: 'src/a.ts', |
| content: 'a', |
| language: 'typescript', |
| size: 1, |
| }) |
| .mockResolvedValueOnce({ |
| state: 'ok', |
| path: 'src/b.ts', |
| content: 'b', |
| language: 'typescript', |
| size: 1, |
| }) |
| .mockResolvedValueOnce({ |
| state: 'ok', |
| path: 'src/c.ts', |
| content: 'c', |
| language: 'typescript', |
| size: 1, |
| }) |
|
|
| await useWorkspacePanelStore.getState().openPreview('session-close', 'src/a.ts', 'file') |
| await useWorkspacePanelStore.getState().openPreview('session-close', 'src/b.ts', 'file') |
| await useWorkspacePanelStore.getState().openPreview('session-close', 'src/c.ts', 'file') |
|
|
| useWorkspacePanelStore.getState().closePreview('session-close', 'file:src/b.ts') |
|
|
| expect(useWorkspacePanelStore.getState().previewTabsBySession['session-close']).toMatchObject([ |
| { id: 'file:src/a.ts' }, |
| { id: 'file:src/c.ts' }, |
| ]) |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-close']).toBe('file:src/c.ts') |
|
|
| useWorkspacePanelStore.getState().closePreview('session-close', 'file:src/c.ts') |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-close']).toBe('file:src/a.ts') |
| }) |
|
|
| it('closes preview tabs by context-menu scope', () => { |
| useWorkspacePanelStore.setState((state) => ({ |
| ...state, |
| previewTabsBySession: { |
| ...state.previewTabsBySession, |
| 'session-preview-scope': [ |
| { id: 'file:a.ts', path: 'a.ts', kind: 'file', title: 'a.ts', state: 'ok', language: 'typescript', size: 1 }, |
| { id: 'file:b.ts', path: 'b.ts', kind: 'file', title: 'b.ts', state: 'ok', language: 'typescript', size: 1 }, |
| { id: 'file:c.ts', path: 'c.ts', kind: 'file', title: 'c.ts', state: 'ok', language: 'typescript', size: 1 }, |
| { id: 'file:d.ts', path: 'd.ts', kind: 'file', title: 'd.ts', state: 'ok', language: 'typescript', size: 1 }, |
| ], |
| }, |
| activePreviewTabIdBySession: { |
| ...state.activePreviewTabIdBySession, |
| 'session-preview-scope': 'file:d.ts', |
| }, |
| loading: { |
| ...state.loading, |
| previewByTabId: { |
| ...state.loading.previewByTabId, |
| 'session-preview-scope::file:c.ts': true, |
| 'session-preview-scope::file:d.ts': true, |
| }, |
| }, |
| errors: { |
| ...state.errors, |
| previewByTabId: { |
| ...state.errors.previewByTabId, |
| 'session-preview-scope::file:c.ts': 'loading', |
| 'session-preview-scope::file:d.ts': 'loading', |
| }, |
| }, |
| })) |
|
|
| useWorkspacePanelStore.getState().closePreviewTabs('session-preview-scope', 'file:b.ts', 'right') |
|
|
| expect(useWorkspacePanelStore.getState().previewTabsBySession['session-preview-scope']).toMatchObject([ |
| { id: 'file:a.ts' }, |
| { id: 'file:b.ts' }, |
| ]) |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-preview-scope']).toBe('file:b.ts') |
| expect(useWorkspacePanelStore.getState().loading.previewByTabId['session-preview-scope::file:c.ts']).toBeUndefined() |
| expect(useWorkspacePanelStore.getState().errors.previewByTabId['session-preview-scope::file:d.ts']).toBeUndefined() |
|
|
| useWorkspacePanelStore.getState().closePreviewTabs('session-preview-scope', 'file:b.ts', 'others') |
|
|
| expect(useWorkspacePanelStore.getState().previewTabsBySession['session-preview-scope']).toMatchObject([ |
| { id: 'file:b.ts' }, |
| ]) |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-preview-scope']).toBe('file:b.ts') |
|
|
| useWorkspacePanelStore.getState().closePreviewTabs('session-preview-scope', 'file:b.ts', 'all') |
|
|
| expect(useWorkspacePanelStore.getState().previewTabsBySession['session-preview-scope']).toBeUndefined() |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-preview-scope']).toBeNull() |
| }) |
|
|
| it('ignores stale status responses for the same session', async () => { |
| const first = deferred<{ |
| state: 'ok' |
| workDir: string |
| repoName: string | null |
| branch: string | null |
| isGitRepo: boolean |
| changedFiles: [] |
| error?: string |
| }>() |
| const second = deferred<{ |
| state: 'ok' |
| workDir: string |
| repoName: string | null |
| branch: string | null |
| isGitRepo: boolean |
| changedFiles: [] |
| error?: string |
| }>() |
|
|
| mocks.getWorkspaceStatusMock |
| .mockReturnValueOnce(first.promise) |
| .mockReturnValueOnce(second.promise) |
|
|
| const firstLoad = useWorkspacePanelStore.getState().loadStatus('session-race') |
| const secondLoad = useWorkspacePanelStore.getState().loadStatus('session-race') |
|
|
| second.resolve({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'new', |
| isGitRepo: true, |
| changedFiles: [], |
| }) |
| await secondLoad |
|
|
| first.resolve({ |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'old', |
| isGitRepo: true, |
| changedFiles: [], |
| }) |
| await firstLoad |
|
|
| expect(useWorkspacePanelStore.getState().statusBySession['session-race']?.branch).toBe('new') |
| }) |
|
|
| it('ignores stale preview responses after close and reopen', async () => { |
| const first = deferred<{ state: 'ok'; path: string; content: string; language: string; size: number }>() |
| const second = deferred<{ state: 'ok'; path: string; content: string; language: string; size: number }>() |
|
|
| mocks.getWorkspaceFileMock |
| .mockReturnValueOnce(first.promise) |
| .mockReturnValueOnce(second.promise) |
|
|
| const firstOpen = useWorkspacePanelStore.getState().openPreview('session-preview-race', 'src/a.ts', 'file') |
| useWorkspacePanelStore.getState().closePreview('session-preview-race', 'file:src/a.ts') |
| const secondOpen = useWorkspacePanelStore.getState().openPreview('session-preview-race', 'src/a.ts', 'file') |
|
|
| second.resolve({ |
| state: 'ok', |
| path: 'src/a.ts', |
| content: 'new', |
| language: 'typescript', |
| size: 3, |
| }) |
| await secondOpen |
|
|
| first.resolve({ |
| state: 'ok', |
| path: 'src/a.ts', |
| content: 'old', |
| language: 'typescript', |
| size: 3, |
| }) |
| await firstOpen |
|
|
| expect(useWorkspacePanelStore.getState().previewTabsBySession['session-preview-race']).toEqual([ |
| expect.objectContaining({ id: 'file:src/a.ts', content: 'new' }), |
| ]) |
| }) |
|
|
| it('does not recreate loading or error state when a loading preview is closed before completion', async () => { |
| const pending = deferred<{ state: 'ok'; path: string; diff: string }>() |
| const tabId = getWorkspacePreviewTabId('src/a.ts', 'diff') |
| const previewKey = `session-preview-close::${tabId}` |
|
|
| mocks.getWorkspaceDiffMock.mockReturnValueOnce(pending.promise) |
|
|
| const openPromise = useWorkspacePanelStore.getState().openPreview('session-preview-close', 'src/a.ts', 'diff') |
| useWorkspacePanelStore.getState().closePreview('session-preview-close', tabId) |
|
|
| pending.resolve({ |
| state: 'ok', |
| path: 'src/a.ts', |
| diff: '@@ -1 +1 @@', |
| }) |
| await openPromise |
|
|
| expect(useWorkspacePanelStore.getState().previewTabsBySession['session-preview-close']).toBeUndefined() |
| expect(useWorkspacePanelStore.getState().activePreviewTabIdBySession['session-preview-close']).toBeNull() |
| expect(useWorkspacePanelStore.getState().loading.previewByTabId[previewKey]).toBeUndefined() |
| expect(useWorkspacePanelStore.getState().errors.previewByTabId[previewKey]).toBeUndefined() |
| }) |
|
|
| it('clears session UI and cached data for clearSession and resetSessionUi', () => { |
| useWorkspacePanelStore.setState((state) => ({ |
| ...state, |
| panelBySession: { |
| 'session-clear': { isOpen: true, activeView: 'all' }, |
| 'session-reset': { isOpen: true, activeView: 'all' }, |
| }, |
| statusBySession: { |
| 'session-clear': { |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [], |
| }, |
| 'session-reset': { |
| state: 'ok', |
| workDir: '/repo', |
| repoName: 'repo', |
| branch: 'main', |
| isGitRepo: true, |
| changedFiles: [], |
| }, |
| }, |
| expandedPathsBySession: { |
| 'session-clear': ['src'], |
| 'session-reset': ['src'], |
| }, |
| treeBySessionPath: { |
| 'session-clear': { |
| src: { state: 'ok', path: 'src', entries: [] }, |
| }, |
| 'session-reset': { |
| src: { state: 'ok', path: 'src', entries: [] }, |
| }, |
| }, |
| previewTabsBySession: { |
| 'session-clear': [ |
| { id: 'file:src/a.ts', path: 'src/a.ts', kind: 'file', title: 'a.ts' }, |
| ], |
| 'session-reset': [ |
| { id: 'file:src/b.ts', path: 'src/b.ts', kind: 'file', title: 'b.ts' }, |
| ], |
| }, |
| activePreviewTabIdBySession: { |
| 'session-clear': 'file:src/a.ts', |
| 'session-reset': 'file:src/b.ts', |
| }, |
| loading: { |
| statusBySession: { |
| 'session-clear': true, |
| 'session-reset': true, |
| }, |
| treeBySessionPath: { |
| 'session-clear::src': true, |
| 'session-reset::src': true, |
| }, |
| previewByTabId: { |
| 'session-clear::file:src/a.ts': true, |
| 'session-reset::file:src/b.ts': true, |
| }, |
| }, |
| errors: { |
| statusBySession: { |
| 'session-clear': 'bad', |
| 'session-reset': 'bad', |
| }, |
| treeBySessionPath: { |
| 'session-clear::src': 'bad', |
| 'session-reset::src': 'bad', |
| }, |
| previewByTabId: { |
| 'session-clear::file:src/a.ts': 'bad', |
| 'session-reset::file:src/b.ts': 'bad', |
| }, |
| }, |
| })) |
|
|
| useWorkspacePanelStore.getState().clearSession('session-clear') |
| useWorkspacePanelStore.getState().resetSessionUi('session-reset') |
|
|
| const state = useWorkspacePanelStore.getState() |
| expect(state.panelBySession['session-clear']).toBeUndefined() |
| expect(state.panelBySession['session-reset']).toBeUndefined() |
| expect(state.statusBySession['session-clear']).toBeUndefined() |
| expect(state.statusBySession['session-reset']).toBeUndefined() |
| expect(state.expandedPathsBySession['session-clear']).toBeUndefined() |
| expect(state.expandedPathsBySession['session-reset']).toBeUndefined() |
| expect(state.treeBySessionPath['session-clear']).toBeUndefined() |
| expect(state.treeBySessionPath['session-reset']).toBeUndefined() |
| expect(state.previewTabsBySession['session-clear']).toBeUndefined() |
| expect(state.previewTabsBySession['session-reset']).toBeUndefined() |
| expect(state.activePreviewTabIdBySession['session-clear']).toBeUndefined() |
| expect(state.activePreviewTabIdBySession['session-reset']).toBeUndefined() |
| expect(state.loading.statusBySession['session-clear']).toBeUndefined() |
| expect(state.loading.statusBySession['session-reset']).toBeUndefined() |
| expect(state.loading.treeBySessionPath['session-clear::src']).toBeUndefined() |
| expect(state.loading.treeBySessionPath['session-reset::src']).toBeUndefined() |
| expect(state.loading.previewByTabId['session-clear::file:src/a.ts']).toBeUndefined() |
| expect(state.loading.previewByTabId['session-reset::file:src/b.ts']).toBeUndefined() |
| expect(state.errors.statusBySession['session-clear']).toBeUndefined() |
| expect(state.errors.statusBySession['session-reset']).toBeUndefined() |
| expect(state.errors.treeBySessionPath['session-clear::src']).toBeUndefined() |
| expect(state.errors.treeBySessionPath['session-reset::src']).toBeUndefined() |
| expect(state.errors.previewByTabId['session-clear::file:src/a.ts']).toBeUndefined() |
| expect(state.errors.previewByTabId['session-reset::file:src/b.ts']).toBeUndefined() |
| }) |
| }) |
|
|