vitest-canvas-mock

A drop-in HTML canvas mock for Vitest that emulates spec-accurate CanvasRenderingContext2D behavior in jsdom test environments.

Library
npm
v1.2.0
70stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
64/100Good
Development Activity76
Maintenance68
Community36
Maturity56
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture75
Code Quality82
Innovation68
Learning Curve85

vitest-canvas-mock lets you run unit tests that touch the HTML canvas API without a real browser or a native canvas binding. jsdom does not implement getContext('2d'), so any test that renders to a <canvas> element normally crashes or has to skip canvas assertions entirely. This package patches window with full implementations of CanvasRenderingContext2D, Path2D, CanvasGradient, CanvasPattern, DOMMatrix, ImageData, TextMetrics, and ImageBitmap, wiring each drawing method through vi.fn() so calls are spy-able and assertable.

It is a fork of the popular jest-canvas-mock project, retargeted at Vitest’s vi mocking APIs instead of Jest’s jest global, so teams migrating from Jest to Vitest can keep the same canvas-testing behavior. Rather than returning stub values for everything, the mock validates arguments the way a real browser would: calling arc() with too few arguments throws a TypeError, a negative radius throws a DOMException, and numeric arguments go through the same Number() coercion the spec requires. This makes it possible to write tests that assert on canvas API misuse, not just on successful draw calls.

The library also exposes introspection helpers on the mocked context — __getEvents(), __getPath(), __getDrawCalls(), and __getClippingRegion() — so tests can snapshot exactly what a component drew to the canvas without needing pixel-level rendering. A setupVitestCanvasMock() export lets the mock be re-applied after vi.resetAllMocks() clears the spies, which matters for test suites that reset mocks between test cases.

What You Get

  • A full mock of CanvasRenderingContext2D covering path construction (arc, bezierCurveTo, rect, roundRect), drawing (fillRect, strokeText, drawImage), and state (fillStyle, globalAlpha, lineWidth) with vi.fn()-wrapped spies on every method
  • Companion mock classes for Path2D, CanvasGradient, CanvasPattern, DOMMatrix, ImageData, TextMetrics, and ImageBitmap so code that constructs these types in a canvas workflow keeps working under test
  • Browser-accurate argument validation — wrong arity throws TypeError, invalid enum values (like an unrecognized fillRule) throw TypeError, and negative radii throw DOMException, matching real canvas error behavior
  • Snapshot-friendly introspection via __getEvents(), __getPath(), __getDrawCalls(), and __getClippingRegion() for asserting on what a component actually drew
  • A setupVitestCanvasMock() export to re-install the mock after vi.resetAllMocks() clears the spy state between tests

Common Use Cases

  • Unit-testing chart or data-visualization components (canvas-based charting libraries) in a jsdom environment without spinning up a real browser
  • Testing canvas-drawing utility functions and verifying the exact sequence of draw calls via __getDrawCalls() snapshots
  • Migrating a test suite from jest-canvas-mock to Vitest while keeping the same canvas-mocking behavior and assertions
  • Validating that application code handles canvas API errors (invalid arguments, negative radii) the same way a real browser would
  • CI pipelines that run component tests headlessly and need canvas APIs to exist on window without a native canvas npm package build step

Under The Hood

Architecture The package has a small, single-purpose architecture: src/index.js is the entry point that, on import, calls mockWindow(globalThis.window) from src/window.js to patch the global window object, and also exports setupVitestCanvasMock() for manual re-invocation. src/window.js conditionally assigns each canvas-related global (Path2D, CanvasGradient, CanvasPattern, CanvasRenderingContext2D, DOMMatrix, ImageData, TextMetrics, ImageBitmap, createImageBitmap) only if it is not already defined, then delegates prototype patching to src/mock/prototype.js. Each mocked type lives in its own file under src/classes/, keeping CanvasRenderingContext2D (by far the largest file, implementing dozens of canvas methods) isolated from the smaller supporting classes like Path2D and TextMetrics. This one-way patch-on-import flow with no external state means the whole library is a side-effecting shim layer rather than a runtime with its own control flow.

Tech Stack Written in plain JavaScript (not TypeScript) with hand-written type declarations shipped separately under types/. It depends on cssfontparser for CSS font string parsing (used by the font setter) and moo-color for CSS color parsing (used by fillStyle/strokeStyle/shadowColor setters), and declares vitest as a peer dependency spanning versions 3 through 5. The project builds with vite-plus (vp pack), a unified toolchain wrapping Vite, Rolldown, and Vitest, publishing both ESM (dist/index.js) and CJS (dist/index.cjs) builds from a single src/index.js entry with platform: neutral.

Code Quality The test suite is extensive: __tests__/classes/ contains one dedicated test file per CanvasRenderingContext2D method (arity checks, type coercion, thrown-error assertions), plus dedicated files for the other mocked classes, run via two separate test tasks — one against the bundled Vitest runner and one (test:compat) against the vitest version pinned in devDependencies — specifically to prove compatibility across the supported peer range. Linting runs with type-aware checking enabled (lint.options.typeAware/typeCheck) even though the source is JavaScript, and CI enforces both vp lint and vp test run. Error handling throughout mirrors the DOM spec closely, throwing typed TypeError/DOMException errors with browser-matching messages rather than silently no-op-ing on invalid input.

What Makes It Unique Unlike mocks that simply stub every canvas method to return undefined, this library reimplements enough of the canvas 2D context’s actual semantics — transform stacks, path tracking, clip regions, save/restore state stacks — to let tests assert on real drawing behavior and catch spec-violating calls the same way a browser would. Being a Vitest-native fork of jest-canvas-mock also means teams get a maintained migration path for canvas-testing behavior that would otherwise need to be hand-ported when moving test runners.

Used by 7 apps in this directory

TypeScript
50%
Other

Dify

No Code Platforms · AI Development · Developer Tools

154,649

Visual LLM workflow platform with RAG pipelines, agent capabilities, and model management for building production AI applications.

View details
92
Repo Health
85
Technical
67
Dependency
Built with
TypeScript50%
Python46%
Updated yesterday
TypeScript
94%
AGPL 3.0

Element Web

Team Chat · Collaboration

13,437

A polished, self-hostable Matrix client for secure, decentralized messaging and collaboration that puts your organization in full control of its data.

View details
96
Repo Health
83
Technical
65
Dependency
Built with
TypeScript94%
Updated yesterday
TypeScript
71%
Other

highlight.io

Developer Tools · Analytics · Monitoring

9,372

Open-source full-stack monitoring that unifies session replay, error tracking, logging, and distributed tracing so you can stop context-switching between tools.

View details
69
Repo Health
78
Technical
65
Dependency
Built with
TypeScript71%
Go16%
Updated 2 weeks ago
TypeScript
99%
Other

LobeHub

AI Assistants · Productivity · Automation

82,273

Your Chief Agent Operator — build, schedule, and collaborate with an entire AI team in one self-hostable workspace.

View details
92
Repo Health
81
Technical
69
Dependency
Built with
TypeScript99%
Updated today
TypeScript
38%
AGPL 3.0

OpenObserve

Monitoring · Analytics · Devops

21,666

Open source observability platform for logs, metrics, traces, and real user monitoring — delivering 140x lower storage costs than Elasticsearch with a single binary you can run in under 2 minutes.

View details
89
Repo Health
9
Technical
71
Dependency
Built with
TypeScript38%
Rust30%
Vue18%
Updated today
Python
48%
Other

Arize Phoenix

Devops · Analytics · Monitoring

11,346

Open-source AI observability platform for tracing, evaluating, and debugging LLM applications with built-in intelligence and MCP support.

View details
90
Repo Health
88
Technical
67
Dependency
Built with
Python48%
TypeScript41%
Updated yesterday
Go
93%
MIT

Traefik

Devops · Automation · Security

64,764

A cloud-native reverse proxy and load balancer that auto-configures itself from Docker, Kubernetes, and other orchestrators — zero manual routing required.

View details
92
Repo Health
85
Technical
64
Dependency
Built with
Go93%
Updated 3 days ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search