mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Prevent stale same-version update metadata from surfacing another install prompt, avoid showing a fake desktop version fallback, and configure the Windows NSIS installer to expose install directory selection. Fixes #801 Tested: bun run verify Confidence: high Scope-risk: moderate
117 lines
3.9 KiB
TypeScript
117 lines
3.9 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from 'bun:test'
|
|
import * as fs from 'node:fs'
|
|
import * as path from 'node:path'
|
|
import * as os from 'node:os'
|
|
import { SessionStore } from '../session-store.js'
|
|
|
|
describe('SessionStore', () => {
|
|
let tmpDir: string
|
|
let store: SessionStore
|
|
|
|
beforeEach(() => {
|
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'session-store-'))
|
|
store = new SessionStore(path.join(tmpDir, 'sessions.json'))
|
|
})
|
|
|
|
afterEach(() => {
|
|
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
})
|
|
|
|
it('returns null for unknown chatId', () => {
|
|
expect(store.get('unknown')).toBeNull()
|
|
})
|
|
|
|
it('stores and retrieves a session', () => {
|
|
store.set('chat-1', 'uuid-aaa', '/path/to/project')
|
|
const entry = store.get('chat-1')
|
|
expect(entry).not.toBeNull()
|
|
expect(entry!.sessionId).toBe('uuid-aaa')
|
|
expect(entry!.workDir).toBe('/path/to/project')
|
|
})
|
|
|
|
it('overwrites existing entry on set', () => {
|
|
store.set('chat-1', 'uuid-aaa', '/old')
|
|
store.set('chat-1', 'uuid-bbb', '/new')
|
|
expect(store.get('chat-1')!.sessionId).toBe('uuid-bbb')
|
|
})
|
|
|
|
it('deletes an entry', () => {
|
|
store.set('chat-1', 'uuid-aaa', '/path')
|
|
store.delete('chat-1')
|
|
expect(store.get('chat-1')).toBeNull()
|
|
})
|
|
|
|
it('deletes every chat entry bound to a sessionId', () => {
|
|
store.set('chat-1', 'uuid-shared', '/project-a')
|
|
store.set('chat-2', 'uuid-other', '/project-b')
|
|
store.set('chat-3', 'uuid-shared', '/project-c')
|
|
|
|
const removed = store.deleteBySessionId('uuid-shared')
|
|
|
|
expect(removed.sort()).toEqual(['chat-1', 'chat-3'])
|
|
expect(store.get('chat-1')).toBeNull()
|
|
expect(store.get('chat-3')).toBeNull()
|
|
expect(store.get('chat-2')!.sessionId).toBe('uuid-other')
|
|
|
|
const reloaded = new SessionStore(path.join(tmpDir, 'sessions.json'))
|
|
expect(reloaded.get('chat-1')).toBeNull()
|
|
expect(reloaded.get('chat-3')).toBeNull()
|
|
expect(reloaded.get('chat-2')!.sessionId).toBe('uuid-other')
|
|
})
|
|
|
|
it('refreshes from disk before reading so running adapters do not reuse deleted mappings', () => {
|
|
store.set('chat-1', 'uuid-stale', '/project')
|
|
const serverSideStore = new SessionStore(path.join(tmpDir, 'sessions.json'))
|
|
|
|
expect(serverSideStore.deleteBySessionId('uuid-stale')).toEqual(['chat-1'])
|
|
|
|
expect(store.get('chat-1')).toBeNull()
|
|
expect(store.listAll()).toEqual([])
|
|
})
|
|
|
|
it('returns an empty list when deleting an unknown sessionId', () => {
|
|
store.set('chat-1', 'uuid-aaa', '/project')
|
|
|
|
expect(store.deleteBySessionId('uuid-missing')).toEqual([])
|
|
expect(store.get('chat-1')!.sessionId).toBe('uuid-aaa')
|
|
})
|
|
|
|
it('persists to disk and reloads', () => {
|
|
store.set('chat-1', 'uuid-aaa', '/path')
|
|
|
|
const store2 = new SessionStore(path.join(tmpDir, 'sessions.json'))
|
|
expect(store2.get('chat-1')!.sessionId).toBe('uuid-aaa')
|
|
})
|
|
|
|
it('handles missing file gracefully', () => {
|
|
const store2 = new SessionStore(path.join(tmpDir, 'nonexistent.json'))
|
|
expect(store2.get('anything')).toBeNull()
|
|
})
|
|
|
|
it('uses CLAUDE_CONFIG_DIR for the default session store path', () => {
|
|
const previousConfigDir = process.env.CLAUDE_CONFIG_DIR
|
|
process.env.CLAUDE_CONFIG_DIR = tmpDir
|
|
try {
|
|
const defaultStore = new SessionStore()
|
|
defaultStore.set('chat-default', 'uuid-default', '/default-project')
|
|
|
|
const savedPath = path.join(tmpDir, 'adapter-sessions.json')
|
|
expect(fs.existsSync(savedPath)).toBe(true)
|
|
expect(JSON.parse(fs.readFileSync(savedPath, 'utf8'))['chat-default'].sessionId).toBe('uuid-default')
|
|
} finally {
|
|
if (previousConfigDir === undefined) {
|
|
delete process.env.CLAUDE_CONFIG_DIR
|
|
} else {
|
|
process.env.CLAUDE_CONFIG_DIR = previousConfigDir
|
|
}
|
|
}
|
|
})
|
|
|
|
it('lists all entries', () => {
|
|
store.set('chat-1', 'uuid-1', '/a')
|
|
store.set('chat-2', 'uuid-2', '/b')
|
|
const all = store.listAll()
|
|
expect(all).toHaveLength(2)
|
|
})
|
|
})
|