import { INQUIRY_DEADLINE_MS, createAttemptTrail, runWithProviderResilience, toAttemptErrorFields, } from '../../src/common/helpers/provider-resilience.helper'; import { ProviderExecutionContext } from '../../src/common/interfaces/inquiry-provider.interface'; describe('timeout / deadline resilience bugs', () => { it('maps withTimeout ETIMEDOUT errors to PROVIDER_TIMEOUT (not PROVIDER_ERROR)', () => { const error = new Error('PARSIAN request timed out after 20000ms'); (error as NodeJS.ErrnoException).code = 'ETIMEDOUT'; expect(toAttemptErrorFields(error)).toMatchObject({ code: 'PROVIDER_TIMEOUT', messageFa: expect.stringMatching(/زمان/), }); }); it('caps attempt timeout by inquiry deadline even when provider timeout is higher', async () => { const context: ProviderExecutionContext = { requestId: 'req', trackingCode: 'trk', deadlineAt: Date.now() + 80, attemptTrail: createAttemptTrail(), }; const started = Date.now(); await expect( runWithProviderResilience( () => new Promise((resolve) => setTimeout(() => resolve('late'), 500)), { providerName: 'PARSIAN', maxAttempts: 1, timeoutMs: 30_000, context, label: 'PARSIAN request', }, ), ).rejects.toMatchObject({ code: 'ETIMEDOUT' }); expect(Date.now() - started).toBeLessThan(250); }); it('default inquiry deadline must exceed a single slow CentInsur SOAP (~30s)', () => { // thirdPartyCar may need two SOAP calls over a proxy; 20s was killing successful ~28s responses expect(INQUIRY_DEADLINE_MS).toBeGreaterThanOrEqual(60_000); }); });