profileShare

rasmusjy / voicetask

Read-only snapshot

No repository description.

main default branch 105 files Expires Sep 13, 2026, 9:06 AM
sessionStore.test.ts 3,625 bytes
1 import { mkdtemp, rm } from 'node:fs/promises'
2 import { tmpdir } from 'node:os'
3 import path from 'node:path'
4 import { afterEach, beforeEach, describe, expect, it } from 'vitest'
5 import { initialCoverage } from '../../shared/types'
6 import { SessionStore } from './sessionStore'
7
8 describe('SessionStore', () => {
9 let baseDir: string
10 let store: SessionStore
11
12 beforeEach(async () => {
13 baseDir = await mkdtemp(path.join(tmpdir(), 'voicetask-store-'))
14 store = new SessionStore(baseDir)
15 })
16
17 afterEach(async () => {
18 await rm(baseDir, { recursive: true, force: true })
19 })
20
21 it('creates a session and reloads it with matching data', async () => {
22 const created = await store.createSession('my project', '/tmp/target')
23 expect(created.name).toBe('my project')
24 expect(created.targetDir).toBe('/tmp/target')
25 expect(created.status).toBe('interviewing')
26 expect(created.coverage).toEqual(initialCoverage())
27
28 const reloaded = await store.getSession(created.id)
29 expect(reloaded).toEqual(created)
30 })
31
32 it('returns null for an unknown session id', async () => {
33 expect(await store.getSession('does-not-exist')).toBeNull()
34 })
35
36 it('assigns sequential segment ids S1..Sn', async () => {
37 const session = await store.createSession('proj', '/tmp/target')
38 const first = await store.appendSegment(session.id, 'user', 'hello')
39 expect(first.segment.id).toBe('S1')
40 const second = await store.appendSegment(session.id, 'interviewer', 'what next?')
41 expect(second.segment.id).toBe('S2')
42 const third = await store.appendSegment(session.id, 'user', 'more')
43 expect(third.segment.id).toBe('S3')
44
45 const reloaded = await store.getSession(session.id)
46 expect(reloaded?.segments.map((s) => s.id)).toEqual(['S1', 'S2', 'S3'])
47 expect(reloaded?.segments.map((s) => s.text)).toEqual(['hello', 'what next?', 'more'])
48 })
49
50 it('updates coverage, summary, and status', async () => {
51 const session = await store.createSession('proj', '/tmp/target')
52 const coverage = { ...initialCoverage(), goal: 'clear' as const }
53 const updated = await store.updateTurn(session.id, {
54 coverage,
55 summary: 'a running summary',
56 status: 'done',
57 })
58 expect(updated.coverage).toEqual(coverage)
59 expect(updated.summary).toBe('a running summary')
60 expect(updated.status).toBe('done')
61 })
62
63 it('lists sessions as summaries, newest first', async () => {
64 const a = await store.createSession('alpha', '/tmp/a')
65 const b = await store.createSession('beta', '/tmp/b')
66 await store.updateTurn(b.id, { status: 'done' })
67
68 const list = await store.listSessions()
69 expect(list).toHaveLength(2)
70 expect(list).toEqual(
71 expect.arrayContaining([
72 { id: a.id, name: 'alpha', status: 'interviewing', createdAt: a.createdAt },
73 { id: b.id, name: 'beta', status: 'done', createdAt: b.createdAt },
74 ]),
75 )
76 const sorted = [...list].sort((x, y) => y.createdAt.localeCompare(x.createdAt))
77 expect(list).toEqual(sorted)
78 })
79
80 it('deletes a session and reports missing ones', async () => {
81 const session = await store.createSession('gone soon', '/tmp/g')
82 expect(await store.deleteSession(session.id)).toBe(true)
83 expect(await store.getSession(session.id)).toBeNull()
84 expect(await store.listSessions()).toEqual([])
85 expect(await store.deleteSession(session.id)).toBe(false)
86 })
87
88 it('lists no sessions when the base directory does not exist yet', async () => {
89 const emptyStore = new SessionStore(path.join(baseDir, 'nonexistent'))
90 expect(await emptyStore.listSessions()).toEqual([])
91 })
92 })
93