Files
DashDescomplicar/api/tests/sessions-parser.test.ts
T

101 lines
3.8 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { parseSessionFile } from '../services/sessions/parser.js'
import { mkdtempSync, writeFileSync } from 'fs'
import { tmpdir } from 'os'
import { join } from 'path'
function writeJsonl(lines: object[]): string {
const dir = mkdtempSync(join(tmpdir(), 'obs-test-'))
const path = join(dir, 'session-test.jsonl')
writeFileSync(path, lines.map((l) => JSON.stringify(l)).join('\n'))
return path
}
describe('parseSessionFile', () => {
it('extrai metadata básica de sessão mínima', async () => {
const path = writeJsonl([
{ type: 'permission-mode', permissionMode: 'default', sessionId: 's1' },
{
type: 'user',
timestamp: '2026-04-23T10:00:00Z',
message: { role: 'user', content: [{ type: 'text', text: 'olá mundo' }] },
},
{
type: 'assistant',
timestamp: '2026-04-23T10:00:30Z',
message: { role: 'assistant', content: [{ type: 'text', text: 'olá' }] },
},
])
const result = await parseSessionFile(path)
expect(result.meta.session_id).toBe('s1')
expect(result.meta.user_messages).toBe(1)
expect(result.meta.assistant_msgs).toBe(1)
expect(result.meta.tool_calls).toBe(0)
expect(result.meta.first_prompt).toBe('olá mundo')
expect(result.meta.permission_mode).toBe('default')
expect(result.meta.outcome).toBe('completed')
})
it('conta tool_calls e recolhe tools_used', async () => {
const path = writeJsonl([
{
type: 'assistant',
timestamp: '2026-04-23T10:00:00Z',
message: {
role: 'assistant',
content: [
{ type: 'tool_use', name: 'Bash', input: { command: 'ls' } },
{ type: 'tool_use', name: 'Read', input: { file_path: '/tmp/x' } },
],
},
},
])
const result = await parseSessionFile(path)
expect(result.meta.tool_calls).toBe(2)
expect(result.meta.tools_used).toEqual(expect.arrayContaining(['Bash', 'Read']))
})
it('detecta skill invocation em system-reminder', async () => {
const path = writeJsonl([
{
type: 'system',
timestamp: '2026-04-23T10:00:00Z',
message: { role: 'system', content: [{ type: 'text', text: 'Launching skill: superpowers:brainstorming' }] },
},
])
const result = await parseSessionFile(path)
expect(result.meta.skills_invoked).toContain('superpowers:brainstorming')
})
it('ignora linhas JSON inválidas silenciosamente', async () => {
const path = writeJsonl([
{ type: 'user', message: { role: 'user', content: [{ type: 'text', text: 'válido' }] } },
])
const { writeFileSync } = await import('fs')
writeFileSync(path, 'linha inválida\n' + JSON.stringify({ type: 'user', message: { role: 'user', content: [{ type: 'text', text: 'válido' }] } }))
const result = await parseSessionFile(path)
expect(result.meta.user_messages).toBe(1)
})
it('devolve duration_sec null quando timestamps são inválidos', async () => {
const path = writeJsonl([
{ type: 'user', timestamp: 'not-a-date', message: { role: 'user', content: [{ type: 'text', text: 'a' }] } },
{ type: 'assistant', timestamp: 'also-not-a-date', message: { role: 'assistant', content: [{ type: 'text', text: 'b' }] } },
])
const result = await parseSessionFile(path)
expect(result.meta.duration_sec).toBeNull()
})
it('classifica max_tokens como interrupted', async () => {
const path = writeJsonl([
{
type: 'assistant',
timestamp: '2026-04-23T10:00:00Z',
message: { role: 'assistant', content: [{ type: 'text', text: 'resposta cortada' }], stop_reason: 'max_tokens' },
},
])
const result = await parseSessionFile(path)
expect(result.meta.outcome).toBe('interrupted')
})
})