~bigbes/lethe

ref: 346e6a81d673e2daf06604b9a838b08ba9dbdbef lethe/web/src/api/adapters.test.ts -rw-r--r-- 3.5 KiB
346e6a81 — Eugene Blikh web: project detail route scoped via ?cwd= sessions filter a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { describe, it, expect } from 'vitest'
import { adaptSession, adaptProject } from './adapters'
import type { SessionDTO, ProjectDTO } from './adapters'

function makeDTO(overrides: Partial<SessionDTO> = {}): SessionDTO {
  return {
    owner: 'bigbes',
    tool: 'claude-code',
    host: 'laptop',
    session_id: 'abc123',
    started_at: 1_000_000,
    ended_at: 1_001_000,
    source_file: '/path/to/session.jsonl',
    summary: 'A test session',
    turn_count: 5,
    tokens_in_total: 1234,
    tokens_out_total: 5678,
    ...overrides,
  }
}

describe('adaptSession', () => {
  it('started_at=0 → started="1970-01-01T00:00:00.000Z"', () => {
    const s = adaptSession(makeDTO({ started_at: 0, ended_at: 0 }))
    expect(s.started).toBe('1970-01-01T00:00:00.000Z')
  })

  it('working_dir absent → cwd === ""', () => {
    const s = adaptSession(makeDTO({ working_dir: undefined }))
    expect(s.cwd).toBe('')
  })

  it('model absent → model === undefined (not null)', () => {
    const s = adaptSession(makeDTO({ model: undefined }))
    expect(s.model).toBeUndefined()
  })

  it('id is composite ${tool}/${host}/${session_id}', () => {
    const s = adaptSession(makeDTO({ tool: 'opencode', host: 'workpc', session_id: 'xyz789' }))
    expect(s.id).toBe('opencode/workpc/xyz789')
    const parts = s.id.split('/')
    expect(parts[0]).toBe('opencode')
    expect(parts[1]).toBe('workpc')
    expect(parts[2]).toBe('xyz789')
  })

  it('ended_at === started_at → ended === null', () => {
    const ts = 1_000_000
    const s = adaptSession(makeDTO({ started_at: ts, ended_at: ts }))
    expect(s.ended).toBeNull()
  })

  it('ended_at > started_at → ended is the ISO of ended_at', () => {
    const startedAt = 1_000_000
    const endedAt = 1_001_000
    const s = adaptSession(makeDTO({ started_at: startedAt, ended_at: endedAt }))
    expect(s.ended).toBe(new Date(endedAt * 1000).toISOString())
  })
})

function makeProjectDTO(overrides: Partial<ProjectDTO> = {}): ProjectDTO {
  return {
    cwd: '/home/user/code/project',
    sessions: 3,
    turn_count: 12,
    tokens_in_total: 5000,
    tokens_out_total: 8000,
    last_active: 1_700_000_000,
    hosts: ['laptop', 'workpc'],
    tools: ['claude-code', 'opencode'],
    top_tool: 'claude-code',
    ...overrides,
  }
}

describe('adaptProject', () => {
  it('passes through empty arrays unchanged', () => {
    const p = adaptProject(makeProjectDTO({ hosts: [], tools: [] }))
    expect(p.hosts).toEqual([])
    expect(p.tools).toEqual([])
  })

  it('last_active=0 → lastActive === ""', () => {
    const p = adaptProject(makeProjectDTO({ last_active: 0 }))
    expect(p.lastActive).toBe('')
  })

  it('last_active=1700000000 → ISO string "2023-11-14T22:13:20.000Z"', () => {
    const p = adaptProject(makeProjectDTO({ last_active: 1_700_000_000 }))
    expect(p.lastActive).toBe(new Date(1_700_000_000 * 1000).toISOString())
    // Verify the concrete value for determinism
    expect(p.lastActive).toBe('2023-11-14T22:13:20.000Z')
  })

  it('maps snake_case fields to camelCase', () => {
    const p = adaptProject(makeProjectDTO())
    expect(p.turns).toBe(12)
    expect(p.tokensIn).toBe(5000)
    expect(p.tokensOut).toBe(8000)
    expect(p.topTool).toBe('claude-code')
    expect(p.sessions).toBe(3)
    expect(p.cwd).toBe('/home/user/code/project')
  })

  it('passes through hosts and tools arrays', () => {
    const p = adaptProject(makeProjectDTO({ hosts: ['laptop'], tools: ['claude-code', 'opencode'] }))
    expect(p.hosts).toEqual(['laptop'])
    expect(p.tools).toEqual(['claude-code', 'opencode'])
  })
})