All files / repo-tools/src/test-utils abort-signal.ts

100% Statements 14/14
50% Branches 3/6
100% Functions 5/5
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59                                      10x 10x   10x   2x       10x 10x       10x 10x 10x 10x                 6x   6x 6x               10x    
import { vi } from 'vitest';
 
/**
 * Create a mock AbortSignal that can be manually aborted.
 *
 * This utility was created because Vitest cannot mock `AbortSignal.timeout()`.
 * Vitest relies on @sinonjs/fake-timers for timer mocking, but fake-timers does
 * not implement the AbortSignal.timeout API, so we cannot use Vitest's timer
 * mocking to test timeout behavior. This mock allows us to manually trigger
 * abort events in tests to simulate timeout scenarios.
 * https://github.com/vitest-dev/vitest/issues/3088
 *
 * @param timeoutMs - The timeout value (stored for verification).
 * @returns A mock AbortSignal.
 */
export function makeAbortSignalMock(timeoutMs: number): AbortSignal & {
  abort: () => void;
  timeoutMs: number;
} {
  const handlers: (() => void)[] = [];
  let aborted = false;
 
  const signal = {
    get aborted() {
      return aborted;
    },
    timeoutMs,
    addEventListener: vi.fn((event: string, handler: () => void) => {
      Eif (event === 'abort') {
        handlers.push(handler);
      }
    }),
    removeEventListener: vi.fn((event: string, handler: () => void) => {
      Eif (event === 'abort') {
        const index = handlers.indexOf(handler);
        Eif (index > -1) {
          handlers.splice(index, 1);
        }
      }
    }),
    dispatchEvent: vi.fn(),
    onabort: null,
    reason: undefined,
    throwIfAborted: vi.fn(),
    abort() {
      aborted = true;
      // Call all handlers synchronously
      for (const handler of handlers) {
        handler();
      }
    },
  } as AbortSignal & {
    abort: () => void;
    timeoutMs: number;
  };
 
  return signal;
}