mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 22:35:51 +00:00
Squashed 5 commits: Features (from 5 feature branches): - MCP fix, pipe mute, stub recovery - KAIROS activation, openclaw autonomy - Daemon/job command hierarchy + cross-platform bg engine Upstream fixes: - fix: Bun.hash compatibility - chore: chrome dependency update - docs: browser support guide MIME detection fix: - Screenshot detectMimeFromBase64(): decode raw bytes from base64 instead of broken charCodeAt comparison - Fixes API 400 on Windows (JPEG) and macOS (PNG) screenshots
92 lines
3.2 KiB
TypeScript
92 lines
3.2 KiB
TypeScript
/**
|
|
* Tests for src/jobs/state.ts
|
|
*
|
|
* Uses real temp directories and CLAUDE_CONFIG_DIR env var
|
|
* instead of mocking fs, to avoid cross-test mock pollution.
|
|
*/
|
|
import { describe, expect, test, beforeEach, afterAll } from 'bun:test'
|
|
import { mkdtempSync, rmSync, readFileSync, existsSync } from 'fs'
|
|
import { join } from 'path'
|
|
import { tmpdir } from 'os'
|
|
|
|
// ─── setup: real temp dir via env var ──────────────────────────────────────
|
|
|
|
const tempBase = mkdtempSync(join(tmpdir(), 'jobs-state-test-'))
|
|
|
|
beforeEach(() => {
|
|
// Each test gets a fresh config dir
|
|
const tempHome = mkdtempSync(join(tempBase, 'home-'))
|
|
process.env.CLAUDE_CONFIG_DIR = tempHome
|
|
})
|
|
|
|
afterAll(() => {
|
|
delete process.env.CLAUDE_CONFIG_DIR
|
|
try {
|
|
rmSync(tempBase, { recursive: true, force: true })
|
|
} catch {
|
|
// best-effort cleanup
|
|
}
|
|
})
|
|
|
|
// ─── import ─────────────────────────────────────────────────────────────────
|
|
|
|
const { createJob, readJobState, appendJobReply, getJobDir } = await import(
|
|
'../state.js'
|
|
)
|
|
|
|
// ─── tests ──────────────────────────────────────────────────────────────────
|
|
|
|
describe('createJob', () => {
|
|
test('creates job directory and writes state, template, and input files', () => {
|
|
const dir = createJob('job-1', 'my-template', '# Template', 'hello', [
|
|
'--flag',
|
|
])
|
|
expect(dir).toContain('job-1')
|
|
expect(existsSync(dir)).toBe(true)
|
|
|
|
const stateFile = join(dir, 'state.json')
|
|
expect(existsSync(stateFile)).toBe(true)
|
|
const state = JSON.parse(readFileSync(stateFile, 'utf-8'))
|
|
expect(state.jobId).toBe('job-1')
|
|
expect(state.templateName).toBe('my-template')
|
|
expect(state.status).toBe('created')
|
|
expect(state.args).toEqual(['--flag'])
|
|
|
|
expect(readFileSync(join(dir, 'template.md'), 'utf-8')).toBe('# Template')
|
|
expect(readFileSync(join(dir, 'input.txt'), 'utf-8')).toBe('hello')
|
|
})
|
|
})
|
|
|
|
describe('readJobState', () => {
|
|
test('returns null when job does not exist', () => {
|
|
expect(readJobState('nonexistent')).toBeNull()
|
|
})
|
|
|
|
test('returns parsed state when job exists', () => {
|
|
createJob('job-2', 'tpl', 'content', 'input', [])
|
|
const result = readJobState('job-2')
|
|
expect(result).not.toBeNull()
|
|
expect(result!.jobId).toBe('job-2')
|
|
expect(result!.status).toBe('created')
|
|
})
|
|
})
|
|
|
|
describe('appendJobReply', () => {
|
|
test('returns false when job does not exist', () => {
|
|
expect(appendJobReply('no-job', 'hello')).toBe(false)
|
|
})
|
|
|
|
test('appends reply and updates state', () => {
|
|
createJob('job-3', 'tpl', 'content', 'input', [])
|
|
|
|
const result = appendJobReply('job-3', 'my reply')
|
|
expect(result).toBe(true)
|
|
|
|
const dir = getJobDir('job-3')
|
|
const repliesPath = join(dir, 'replies.jsonl')
|
|
expect(existsSync(repliesPath)).toBe(true)
|
|
const replyLine = JSON.parse(readFileSync(repliesPath, 'utf-8').trim())
|
|
expect(replyLine.text).toBe('my reply')
|
|
})
|
|
})
|