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:
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user