test(08.1-02): update tests to use schema-aligned scenarios

- Update MockAgentManager tests to use status-based scenarios
- Change outcome:'crash' to status:'unrecoverable_error' with error field
- Change outcome:'waiting_for_input' to status:'question' with question field
- Change outcome:'success' to status:'done' with result field
- Add tests for structured question data (options, multiSelect)
- Add tests for getPendingQuestion and resume clearing pending question
- Update E2E edge-cases tests with new scenario format
- Update harness tests with new scenario format
This commit is contained in:
Lukas May
2026-01-31 15:31:56 +01:00
parent 8e38bd298b
commit 565f9fdae9
3 changed files with 122 additions and 41 deletions

View File

@@ -129,9 +129,9 @@ describe('MockAgentManager', () => {
describe('spawn with configured delay', () => {
it('should not complete before delay expires', async () => {
manager.setScenario('delayed-agent', {
outcome: 'success',
status: 'done',
delay: 100,
message: 'Delayed completion',
result: 'Delayed completion',
});
const agent = await manager.spawn({
@@ -149,9 +149,9 @@ describe('MockAgentManager', () => {
it('should complete after delay expires', async () => {
manager.setScenario('delayed-agent', {
outcome: 'success',
status: 'done',
delay: 100,
message: 'Delayed completion',
result: 'Delayed completion',
});
const agent = await manager.spawn({
@@ -175,12 +175,12 @@ describe('MockAgentManager', () => {
// spawn() with crash scenario
// ===========================================================================
describe('spawn with crash scenario', () => {
describe('spawn with unrecoverable_error scenario', () => {
it('should emit agent:crashed and set result.success=false', async () => {
manager.setScenario('crash-agent', {
outcome: 'crash',
status: 'unrecoverable_error',
delay: 0,
message: 'Something went terribly wrong',
error: 'Something went terribly wrong',
});
const agent = await manager.spawn({
@@ -208,13 +208,13 @@ describe('MockAgentManager', () => {
});
// ===========================================================================
// spawn() with waiting_for_input scenario
// spawn() with question scenario
// ===========================================================================
describe('spawn with waiting_for_input scenario', () => {
describe('spawn with question scenario', () => {
it('should emit agent:waiting and set status to waiting_for_input', async () => {
manager.setScenario('waiting-agent', {
outcome: 'waiting_for_input',
status: 'question',
delay: 0,
question: 'Should I continue?',
});
@@ -242,10 +242,10 @@ describe('MockAgentManager', () => {
// resume() after waiting_for_input
// ===========================================================================
describe('resume after waiting_for_input', () => {
describe('resume after question', () => {
it('should emit agent:resumed and continue with scenario', async () => {
manager.setScenario('resume-agent', {
outcome: 'waiting_for_input',
status: 'question',
delay: 0,
question: 'Need your input',
});
@@ -311,9 +311,9 @@ describe('MockAgentManager', () => {
describe('stop', () => {
it('should cancel scheduled completion and emit agent:stopped', async () => {
manager.setScenario('stoppable-agent', {
outcome: 'success',
status: 'done',
delay: 1000,
message: 'Should not see this',
result: 'Should not see this',
});
const agent = await manager.spawn({
@@ -411,11 +411,11 @@ describe('MockAgentManager', () => {
describe('setScenario overrides', () => {
it('should use scenario override for specific agent name', async () => {
// Set crash scenario for one agent
// Set unrecoverable_error scenario for one agent
manager.setScenario('crasher', {
outcome: 'crash',
status: 'unrecoverable_error',
delay: 0,
message: 'Intentional crash',
error: 'Intentional crash',
});
// Spawn two agents - one with override, one with default
@@ -443,8 +443,9 @@ describe('MockAgentManager', () => {
it('should allow clearing scenario override', async () => {
manager.setScenario('flip-flop', {
outcome: 'crash',
status: 'unrecoverable_error',
delay: 0,
error: 'Crash for test',
});
// First spawn crashes
@@ -489,7 +490,7 @@ describe('MockAgentManager', () => {
});
it('should emit spawned before crashed', async () => {
manager.setScenario('crash-order', { outcome: 'crash', delay: 0 });
manager.setScenario('crash-order', { status: 'unrecoverable_error', delay: 0, error: 'Crash' });
await manager.spawn({ name: 'crash-order', taskId: 't1', prompt: 'p1' });
await vi.advanceTimersByTimeAsync(0);
@@ -503,8 +504,9 @@ describe('MockAgentManager', () => {
it('should emit spawned before waiting', async () => {
manager.setScenario('wait-order', {
outcome: 'waiting_for_input',
status: 'question',
delay: 0,
question: 'Test question',
});
await manager.spawn({ name: 'wait-order', taskId: 't1', prompt: 'p1' });
await vi.advanceTimersByTimeAsync(0);
@@ -551,9 +553,9 @@ describe('MockAgentManager', () => {
it('should use provided default scenario', async () => {
const customDefault: MockAgentScenario = {
outcome: 'crash',
status: 'unrecoverable_error',
delay: 0,
message: 'Default crash',
error: 'Default crash',
};
const customManager = new MockAgentManager({
@@ -580,7 +582,7 @@ describe('MockAgentManager', () => {
describe('clear', () => {
it('should remove all agents and cancel pending timers', async () => {
manager.setScenario('pending', { outcome: 'success', delay: 1000 });
manager.setScenario('pending', { status: 'done', delay: 1000 });
await manager.spawn({ name: 'pending', taskId: 't1', prompt: 'p1' });
await manager.spawn({ name: 'another', taskId: 't2', prompt: 'p2' });
@@ -592,4 +594,83 @@ describe('MockAgentManager', () => {
expect((await manager.list()).length).toBe(0);
});
});
// ===========================================================================
// Structured question data (new schema tests)
// ===========================================================================
describe('structured question data', () => {
it('emits agent:waiting with structured question data', async () => {
manager.setScenario('test-agent', {
status: 'question',
question: 'Which database?',
options: [
{ label: 'PostgreSQL', description: 'Full-featured' },
{ label: 'SQLite', description: 'Lightweight' },
],
multiSelect: false,
});
await manager.spawn({ name: 'test-agent', taskId: 'task-1', prompt: 'test' });
await vi.runAllTimersAsync();
const events = eventBus.emittedEvents.filter((e) => e.type === 'agent:waiting');
expect(events.length).toBe(1);
expect((events[0] as any).payload.options).toHaveLength(2);
expect((events[0] as any).payload.options[0].label).toBe('PostgreSQL');
expect((events[0] as any).payload.multiSelect).toBe(false);
});
it('stores pending question for retrieval', async () => {
manager.setScenario('test-agent', {
status: 'question',
question: 'Which database?',
options: [{ label: 'PostgreSQL' }],
});
const agent = await manager.spawn({ name: 'test-agent', taskId: 'task-1', prompt: 'test' });
await vi.runAllTimersAsync();
const pending = await manager.getPendingQuestion(agent.id);
expect(pending?.question).toBe('Which database?');
expect(pending?.options).toHaveLength(1);
expect(pending?.options?.[0].label).toBe('PostgreSQL');
});
it('clears pending question after resume', async () => {
manager.setScenario('resume-test', {
status: 'question',
question: 'Need your input',
options: [{ label: 'Option A' }, { label: 'Option B' }],
});
const agent = await manager.spawn({ name: 'resume-test', taskId: 'task-1', prompt: 'test' });
await vi.runAllTimersAsync();
// Verify question is pending
const pendingBefore = await manager.getPendingQuestion(agent.id);
expect(pendingBefore).not.toBeNull();
expect(pendingBefore?.question).toBe('Need your input');
// Resume the agent
await manager.resume(agent.id, 'Option A');
// Pending question should be cleared
const pendingAfter = await manager.getPendingQuestion(agent.id);
expect(pendingAfter).toBeNull();
});
it('returns null for non-existent agent pending question', async () => {
const pending = await manager.getPendingQuestion('non-existent-id');
expect(pending).toBeNull();
});
it('returns null for agent not in waiting state', async () => {
const agent = await manager.spawn({ name: 'running-agent', taskId: 'task-1', prompt: 'test' });
// Agent is running, not waiting
const pending = await manager.getPendingQuestion(agent.id);
expect(pending).toBeNull();
});
});
});