Files
zeekay 6c65e3e941 @hanzo/app 0.2.0: the app SDK, renamed from @hanzo/rooms
Every import, the catalog pin and the docs name @hanzo/app and
github.com/hanzoai/app. lib/rooms.ts is lib/app.ts and
components/rooms.tsx is components/app.tsx.
2026-10-22 19:07:20 -07:00

116 lines
3.7 KiB
TypeScript

import { test, expect } from '@playwright/test'
import {
CodingRefusal,
dispatchable,
startCoding,
startRun,
listTargets,
type Target,
} from '@hanzo/app/lib/coding'
test.describe('hanzo coding client unit tests', () => {
test('CodingRefusal stores status and message', () => {
const refusal = new CodingRefusal(401, 'Sign in or use Free AI')
expect(refusal.status).toBe(401)
expect(refusal.message).toBe('Sign in or use Free AI')
expect(refusal).toBeInstanceOf(Error)
})
test('dispatchable reports true only for online machines', () => {
const onlineTgt: Target = { id: 'tgt_1', label: 'Box 1', kind: 'cloud', status: 'online' }
const offlineTgt: Target = { id: 'tgt_2', label: 'Box 2', kind: 'cloud', status: 'offline' }
const drainingTgt: Target = { id: 'tgt_3', label: 'Box 3', kind: 'cloud', status: 'draining' }
expect(dispatchable(onlineTgt)).toBe(true)
expect(dispatchable(offlineTgt)).toBe(false)
expect(dispatchable(drainingTgt)).toBe(false)
})
test('startRun aliases startCoding', () => {
expect(startRun).toBe(startCoding)
})
test('startCoding handles valid 202 session responses', async () => {
const origFetch = globalThis.fetch
try {
globalThis.fetch = async (url: string | URL | Request, init?: RequestInit) => {
return new Response(
JSON.stringify({
sessionId: 'ses_12345',
repo: 'hanzo/ai',
branch: 'feat/cool',
routed: true,
targetId: 'tgt_99',
}),
{ status: 202, headers: { 'Content-Type': 'application/json' } }
)
}
const run = await startCoding({ prompt: 'Build a widget', repo: 'hanzo/ai' })
expect(run.sessionId).toBe('ses_12345')
expect(run.repo).toBe('hanzo/ai')
expect(run.branch).toBe('feat/cool')
expect(run.routed).toBe(true)
expect(run.targetId).toBe('tgt_99')
} finally {
globalThis.fetch = origFetch
}
})
test('startCoding throws 502 CodingRefusal if accepted with no session', async () => {
const origFetch = globalThis.fetch
try {
globalThis.fetch = async () => {
return new Response(JSON.stringify({ repo: 'hanzo/ai' }), {
status: 202,
headers: { 'Content-Type': 'application/json' },
})
}
await expect(startCoding({ prompt: 'Test missing session' })).rejects.toThrow(CodingRefusal)
} finally {
globalThis.fetch = origFetch
}
})
test('startCoding propagates 401 unauthenticated refusal', async () => {
const origFetch = globalThis.fetch
try {
globalThis.fetch = async () => {
return new Response(JSON.stringify({ error: { message: 'Unauthorized' } }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
})
}
await expect(startCoding({ prompt: 'Test 401' })).rejects.toThrow(CodingRefusal)
} finally {
globalThis.fetch = origFetch
}
})
test('listTargets returns array of claimed targets', async () => {
const origFetch = globalThis.fetch
try {
globalThis.fetch = async () => {
return new Response(
JSON.stringify({
targets: [
{ id: 'tgt_1', label: 'Rig 1', kind: 'laptop', status: 'online' },
{ id: 'tgt_2', label: 'Rig 2', kind: 'cloud', status: 'offline' },
],
}),
{ status: 200, headers: { 'Content-Type': 'application/json' } }
)
}
const targets = await listTargets()
expect(targets.length).toBe(2)
expect(targets[0].label).toBe('Rig 1')
expect(targets[1].status).toBe('offline')
} finally {
globalThis.fetch = origFetch
}
})
})