import { describe, it, expect } from 'vitest'; import { isShippable, isErroneous, isInPreparation, isInProductionQueue, isPrinting, isSent, isCanceled, isTerminal, isCancelable, getErrors, getWarnings, getInfoMessages, hasErrors, hasWarnings, getStatusDescription, pollUntil, } from '../src/helpers.js'; import { DocumentStatus } from '../src/types.js'; import type { Document, ValidationMessage } from '../src/types.js'; // Helper to create mock documents with specific status function createMockDocument(status: DocumentStatus, validationMessages?: ValidationMessage[]): Document { return { id: 12345, filename: 'test-doc.pdf', numberOfPages: 1, status: { code: status, text: 'Test status', }, documentType: 'LETTER', letter: { letterType: 'LETTERDATA', letterData: { options: { simplex: false, color: false, franking: 'STANDARD_FRANKING', productionCountry: 'DE', envelope: 'DINLANG', }, }, errors: validationMessages ?? [], }, }; } describe('Status Predicates', () => { describe('isShippable', () => { it('returns true for status SHIPPABLE', () => { const doc = createMockDocument(DocumentStatus.SHIPPABLE); expect(isShippable(doc)).toBe(true); }); it('returns false for other statuses', () => { expect(isShippable(createMockDocument(DocumentStatus.IN_PREPARATION))).toBe(false); expect(isShippable(createMockDocument(DocumentStatus.ERRONEOUS))).toBe(false); expect(isShippable(createMockDocument(DocumentStatus.SENT))).toBe(false); }); }); describe('isErroneous', () => { it('returns true for status ERRONEOUS', () => { const doc = createMockDocument(DocumentStatus.ERRONEOUS); expect(isErroneous(doc)).toBe(true); }); it('returns false for other statuses', () => { expect(isErroneous(createMockDocument(DocumentStatus.SHIPPABLE))).toBe(false); }); }); describe('isInPreparation', () => { it('returns true for status IN_PREPARATION', () => { const doc = createMockDocument(DocumentStatus.IN_PREPARATION); expect(isInPreparation(doc)).toBe(true); }); }); describe('isInProductionQueue', () => { it('returns true for status PRODUCTION_QUEUE', () => { const doc = createMockDocument(DocumentStatus.PRODUCTION_QUEUE); expect(isInProductionQueue(doc)).toBe(true); }); }); describe('isPrinting', () => { it('returns true for status PRINTING', () => { const doc = createMockDocument(DocumentStatus.PRINTING); expect(isPrinting(doc)).toBe(true); }); }); describe('isSent', () => { it('returns true for status SENT', () => { const doc = createMockDocument(DocumentStatus.SENT); expect(isSent(doc)).toBe(true); }); }); describe('isCanceled', () => { it('returns true for status CANCELED', () => { const doc = createMockDocument(DocumentStatus.CANCELED); expect(isCanceled(doc)).toBe(true); }); }); describe('isTerminal', () => { it('returns true for SENT, CANCELED, and ERRONEOUS', () => { expect(isTerminal(createMockDocument(DocumentStatus.SENT))).toBe(true); expect(isTerminal(createMockDocument(DocumentStatus.CANCELED))).toBe(true); expect(isTerminal(createMockDocument(DocumentStatus.ERRONEOUS))).toBe(true); }); it('returns false for non-terminal statuses', () => { expect(isTerminal(createMockDocument(DocumentStatus.IN_PREPARATION))).toBe(false); expect(isTerminal(createMockDocument(DocumentStatus.SHIPPABLE))).toBe(false); expect(isTerminal(createMockDocument(DocumentStatus.PRODUCTION_QUEUE))).toBe(false); expect(isTerminal(createMockDocument(DocumentStatus.PRINTING))).toBe(false); }); }); describe('isCancelable', () => { it('returns true for PRODUCTION_QUEUE and PRINTING', () => { expect(isCancelable(createMockDocument(DocumentStatus.PRODUCTION_QUEUE))).toBe(true); expect(isCancelable(createMockDocument(DocumentStatus.PRINTING))).toBe(true); }); it('returns false for non-cancelable statuses', () => { expect(isCancelable(createMockDocument(DocumentStatus.IN_PREPARATION))).toBe(false); expect(isCancelable(createMockDocument(DocumentStatus.SENT))).toBe(false); expect(isCancelable(createMockDocument(DocumentStatus.CANCELED))).toBe(false); }); }); }); describe('Validation Helpers', () => { const mockMessages: ValidationMessage[] = [ { type: 'ERROR', code: 'ERR001', message: 'Error 1' }, { type: 'ERROR', code: 'ERR002', message: 'Error 2' }, { type: 'WARNING', code: 'WARN001', message: 'Warning 1' }, { type: 'INFO', code: 'INFO001', message: 'Info 1' }, ]; describe('getErrors', () => { it('returns only error messages', () => { const doc = createMockDocument(DocumentStatus.ERRONEOUS, mockMessages); const errors = getErrors(doc); expect(errors).toHaveLength(2); expect(errors.every(m => m.type === 'ERROR')).toBe(true); }); it('returns empty array when no validation messages', () => { const doc = createMockDocument(DocumentStatus.SHIPPABLE); expect(getErrors(doc)).toEqual([]); }); }); describe('getWarnings', () => { it('returns only warning messages', () => { const doc = createMockDocument(DocumentStatus.SHIPPABLE, mockMessages); const warnings = getWarnings(doc); expect(warnings).toHaveLength(1); expect(warnings[0]?.type).toBe('WARNING'); }); }); describe('getInfoMessages', () => { it('returns only info messages', () => { const doc = createMockDocument(DocumentStatus.SHIPPABLE, mockMessages); const info = getInfoMessages(doc); expect(info).toHaveLength(1); expect(info[0]?.type).toBe('INFO'); }); }); describe('hasErrors', () => { it('returns true when document has errors', () => { const doc = createMockDocument(DocumentStatus.ERRONEOUS, mockMessages); expect(hasErrors(doc)).toBe(true); }); it('returns false when document has no errors', () => { const doc = createMockDocument(DocumentStatus.SHIPPABLE, [ { type: 'WARNING', code: 'WARN001', message: 'Warning' }, ]); expect(hasErrors(doc)).toBe(false); }); }); describe('hasWarnings', () => { it('returns true when document has warnings', () => { const doc = createMockDocument(DocumentStatus.SHIPPABLE, mockMessages); expect(hasWarnings(doc)).toBe(true); }); it('returns false when document has no warnings', () => { const doc = createMockDocument(DocumentStatus.SHIPPABLE, [ { type: 'INFO', code: 'INFO001', message: 'Info' }, ]); expect(hasWarnings(doc)).toBe(false); }); }); }); describe('getStatusDescription', () => { it('returns correct descriptions for all statuses', () => { expect(getStatusDescription(DocumentStatus.IN_PREPARATION)).toBe('In preparation'); expect(getStatusDescription(DocumentStatus.SHIPPABLE)).toBe('Ready to ship'); expect(getStatusDescription(DocumentStatus.PRODUCTION_QUEUE)).toBe('In production queue'); expect(getStatusDescription(DocumentStatus.PRINTING)).toBe('Printing'); expect(getStatusDescription(DocumentStatus.SENT)).toBe('Sent'); expect(getStatusDescription(DocumentStatus.CANCELED)).toBe('Canceled'); expect(getStatusDescription(DocumentStatus.ERRONEOUS)).toBe('Has errors'); }); it('returns "Unknown status" for invalid status', () => { expect(getStatusDescription(999 as DocumentStatus)).toBe('Unknown status'); }); }); describe('Polling Utilities', () => { describe('pollUntil', () => { it('returns immediately when condition is met', async () => { let callCount = 0; const result = await pollUntil( async () => { callCount++; return { value: 42 }; }, (r) => r.value === 42, { intervalMs: 10 } ); expect(result.value).toBe(42); expect(callCount).toBe(1); }); it('polls until condition is met', async () => { let callCount = 0; const result = await pollUntil( async () => { callCount++; return { value: callCount }; }, (r) => r.value >= 3, { intervalMs: 10 } ); expect(result.value).toBe(3); expect(callCount).toBe(3); }); it('throws when max attempts exceeded', async () => { await expect( pollUntil( async () => ({ value: 1 }), (r) => r.value > 100, { intervalMs: 10, maxAttempts: 3 } ) ).rejects.toThrow('Polling exceeded maximum attempts (3)'); }); it('respects abort signal', async () => { const controller = new AbortController(); // Abort immediately controller.abort(); await expect( pollUntil( async () => ({ value: 1 }), () => false, { intervalMs: 10, signal: controller.signal } ) ).rejects.toThrow('Polling aborted'); }); }); });