import { RetryStrategy } from '../src/index.js'; describe('RetryStrategy', () => { it('uses exponential backoff for recoverable errors', async () => { const strategy = new RetryStrategy({ maxAttempts: 4, baseDelayMs: 100, classifyError: async () => 'recoverable', }); const decision = await strategy.shouldRetry(new Error('boom'), { id: 'job-1', status: 'active', data: {}, currentPhase: 'run', phases: [], phaseResults: {}, progress: 0, progressMessage: null, error: null, retryCount: 1, maxAttempts: 4, webhookUrl: null, webhookSent: false, createdAt: new Date().toISOString(), startedAt: null, completedAt: null, updatedAt: new Date().toISOString(), scheduledAt: null, cancelledAt: null, }); expect(decision.retry).toBe(true); expect(decision.delayMs).toBe(200); expect(decision.disposition).toBe('recoverable'); }); it('does not retry fatal errors', async () => { const strategy = new RetryStrategy({ maxAttempts: 4, classifyError: async () => 'fatal', }); const decision = await strategy.shouldRetry(new Error('fatal'), { id: 'job-1', status: 'active', data: {}, currentPhase: 'run', phases: [], phaseResults: {}, progress: 0, progressMessage: null, error: null, retryCount: 0, maxAttempts: 4, webhookUrl: null, webhookSent: false, createdAt: new Date().toISOString(), startedAt: null, completedAt: null, updatedAt: new Date().toISOString(), scheduledAt: null, cancelledAt: null, }); expect(decision).toEqual({ retry: false, delayMs: 0, disposition: 'fatal', }); }); });