import { describe, expect, it } from 'vitest'; import { heuristicPlan } from './lib/fallback'; import { parsePlanExported } from './lib/openrouter'; import { buildSystemPrompt } from './lib/prompts'; describe('heuristicPlan', () => { it('kitchen hard sums correctly', () => { const p = heuristicPlan('The kitchen has descended into chaos', 'hard'); expect(p.steps.length).toBeGreaterThanOrEqual(8); expect(p.totalMin).toBe(p.steps.reduce((a, s) => a + s.minutes, 0)); }); it('generic easy is short', () => { const p = heuristicPlan('do something vague', 'easy'); expect(p.steps.length).toBeLessThanOrEqual(4); }); }); describe('prompts', () => { it('embeds difficulty + context', () => { const s = buildSystemPrompt('hard', 'small studio, low energy'); expect(s).toMatch(/hyper-granular/i); expect(s).toMatch(/small studio/); }); }); describe('parsePlan', () => { it('parses fenced json', () => { const raw = '```json\n{"steps":[{"emoji":"🧽","text":"Wipe counters","minutes":4}],"totalMin":4}\n```'; const p = parsePlanExported(raw); expect(p?.steps[0].text).toMatch(/Wipe/); expect(p?.totalMin).toBe(4); }); it('rejects garbage', () => { expect(parsePlanExported('hello world')).toBeNull(); }); it('reconciles mismatched totalMin to sum of steps', () => { const raw = '{"steps":[{"emoji":"a","text":"one","minutes":10},{"emoji":"b","text":"two","minutes":30}],"totalMin":5}'; const p = parsePlanExported(raw); expect(p?.totalMin).toBe(40); }); it('clamps minutes to 1..60 and caps 20 steps', () => { const steps = Array.from({ length: 25 }, (_, i) => ({ emoji: 'x', text: `s${i}`, minutes: 999 })); const p = parsePlanExported(JSON.stringify({ steps, totalMin: 1 })); expect(p?.steps.length).toBe(20); expect(p?.steps[0].minutes).toBe(60); expect(p?.totalMin).toBe(20 * 60); }); });