All files / qr-scanner/src/__testing__ dom.ts

100% Statements 16/16
100% Branches 0/0
100% Functions 11/11
100% Lines 16/16

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 60 61 62 63 64 65 66 67 68 69 70 71                                                    46x 46x           22x 22x               19x 19x     19x       46x 46x 7x 7x       7x         46x 2x 2x   1x        
import { vi } from "vitest";
 
/**
 * Doubles for the browser APIs that turn a source into pixels.
 *
 * jsdom ships no image decoder and no canvas, so `createImageBitmap`,
 * `OffscreenCanvas` and `getContext("2d")` are all missing or inert. Rather
 * than skipping the source-normalization path in tests — it is the one place
 * the decoder touches the DOM, so skipping it would leave the whole file
 * unexercised — these doubles replay a known `ImageData` through the real code.
 */
 
export interface ImageSourceDoubles {
  /** How many times pixels were read back. */
  readonly reads: () => number;
  /** How many bitmaps were created but never closed. */
  readonly leakedBitmaps: () => number;
  restore(): void;
}
 
/**
 * Install doubles that make every drawable source resolve to `pixels`.
 *
 * @param pixels - The image every read returns.
 */
export function installImageSourceDoubles(pixels: ImageData): ImageSourceDoubles {
  let reads = 0;
  let open = 0;
 
  class FakeContext {
    clearRect(): void {}
    drawImage(): void {}
    getImageData(): ImageData {
      reads++;
      return pixels;
    }
  }
 
  class FakeOffscreenCanvas {
    width: number;
    height: number;
    constructor(width: number, height: number) {
      this.width = width;
      this.height = height;
    }
    getContext(): FakeContext {
      return new FakeContext();
    }
  }
 
  vi.stubGlobal("OffscreenCanvas", FakeOffscreenCanvas);
  vi.stubGlobal("createImageBitmap", async () => {
    open++;
    return {
      width: pixels.width,
      height: pixels.height,
      close(): void {
        open--;
      },
    };
  });
 
  return {
    reads: () => reads,
    leakedBitmaps: () => open,
    restore: () => {
      vi.unstubAllGlobals();
    },
  };
}