CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jest-canvas-mock

Mock canvas when run unit test cases with jest.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

test-utilities.mddocs/

Test Utilities

Special testing methods added to CanvasRenderingContext2D for Jest testing. These methods track canvas operations and provide utilities for snapshot testing, assertions, and debugging canvas behavior in tests. All tracking methods record operations with transformation state and relevant properties.

Capabilities

Event Tracking

Methods for tracking all canvas context operations including property changes and method calls.

/**
 * Get all the events associated with this CanvasRenderingContext2D object
 * Records every property set and method call with transformation state
 * @returns Array of all canvas context events since creation or last clear
 */
__getEvents(): CanvasRenderingContext2DEvent[];

/**
 * Clear all the events associated with this CanvasRenderingContext2D object
 * Resets the event tracking array to empty state
 */
__clearEvents(): void;

Usage Examples:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// Perform some canvas operations
ctx.fillStyle = '#ff0000';
ctx.fillRect(10, 10, 100, 100);
ctx.strokeStyle = '#00ff00';
ctx.lineWidth = 2;
ctx.strokeRect(20, 20, 80, 80);

// Get all events for snapshot testing
const events = ctx.__getEvents();
expect(events).toMatchSnapshot();

// Clear events for next test phase
ctx.__clearEvents();
expect(ctx.__getEvents()).toHaveLength(0);

Draw Call Tracking

Methods for tracking actual drawing operations (operations that modify pixels on the canvas).

/**
 * Get all the successful draw calls associated with this CanvasRenderingContext2D object
 * Only includes operations that actually draw pixels: fill, stroke, fillText, strokeText, drawImage
 * @returns Array of draw call events with transformation state and properties
 */
__getDrawCalls(): CanvasRenderingContext2DEvent[];

/**
 * Clear all the successful draw calls associated with this CanvasRenderingContext2D object
 * Resets the draw calls tracking array to empty state
 */
__clearDrawCalls(): void;

Usage Examples:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// Non-drawing operations (not tracked in draw calls)
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(100, 100);
ctx.fillStyle = '#ff0000';

// Drawing operations (tracked in draw calls)
ctx.fill();
ctx.fillText('Hello', 50, 50);

// Get only the actual draw operations
const drawCalls = ctx.__getDrawCalls();
expect(drawCalls).toHaveLength(2);
expect(drawCalls[0].type).toBe('fill');
expect(drawCalls[1].type).toBe('fillText');

// Clear draw calls
ctx.__clearDrawCalls();
expect(ctx.__getDrawCalls()).toHaveLength(0);

Path Tracking

Methods for tracking the current path construction and modification.

/**
 * Get the current path associated with this CanvasRenderingContext2D object
 * Returns all path construction commands since the last beginPath call
 * @returns Array of path events representing the current path state
 */
__getPath(): CanvasRenderingContext2DEvent[];

/**
 * Clears the current path associated with this CanvasRenderingContext2D object
 * Resets path to a single beginPath event and updates clipping index
 */
__clearPath(): void;

Usage Examples:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// Build a complex path
ctx.beginPath();
ctx.arc(50, 50, 20, 0, Math.PI * 2);
ctx.moveTo(100, 50);
ctx.lineTo(150, 100);
ctx.quadraticCurveTo(175, 75, 200, 100);
ctx.closePath();

// Get the path for testing
const path = ctx.__getPath();
expect(path).toMatchSnapshot();
expect(path[0].type).toBe('beginPath');
expect(path[1].type).toBe('arc');
expect(path[2].type).toBe('moveTo');

// Clear path (resets to beginPath)
ctx.__clearPath();
const clearedPath = ctx.__getPath();
expect(clearedPath).toHaveLength(1);
expect(clearedPath[0].type).toBe('beginPath');

Clipping Region Tracking

Method for tracking clipping operations and the current clipping region.

/**
 * Obtains the current clipping path
 * Returns the portion of the current path that represents the clipping region
 * @returns Array of path events representing the current clipping region
 */
__getClippingRegion(): CanvasRenderingContext2DEvent[];

Usage Examples:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// Create a clipping path
ctx.beginPath();
ctx.rect(25, 25, 100, 100);
ctx.clip();

// Add more to the path after clipping
ctx.rect(0, 0, 50, 50);

// Get only the clipping region
const clippingRegion = ctx.__getClippingRegion();
expect(clippingRegion).toMatchSnapshot();

// The clipping region cannot be cleared as it's based on stack values
// and when the clip() function is called

Event Object Structure

All tracking methods return arrays of CanvasRenderingContext2DEvent objects:

interface CanvasRenderingContext2DEvent {
  /**
   * The type of canvas event that occurred (method name or property name)
   */
  type: string;
  
  /**
   * Six-element array containing the current transformation matrix state
   * Format: [a, b, c, d, e, f] representing the transform matrix
   */
  transform: [number, number, number, number, number, number];
  
  /**
   * Relevant properties and parameters related to this canvas event
   * Contains method arguments, property values, and other contextual data
   */
  props: { [key: string]: any };
}

Event Type Examples:

  • Method calls: "fillRect", "arc", "drawImage", "save", "restore"
  • Property sets: "fillStyle", "lineWidth", "font", "globalAlpha"
  • Path operations: "beginPath", "moveTo", "lineTo", "closePath"

Transform Array:

The transform array represents the current transformation matrix as [a, b, c, d, e, f] where:

  • a (m11): Horizontal scaling
  • b (m12): Horizontal skewing
  • c (m21): Vertical skewing
  • d (m22): Vertical scaling
  • e (m41): Horizontal translation
  • f (m42): Vertical translation

Props Object:

Contains relevant data for the operation:

  • Method arguments: { x: 10, y: 20, width: 100, height: 50 }
  • Property values: { fillStyle: "#ff0000" }
  • Additional context: { anticlockwise: false, radius: 25 }

Advanced Testing Patterns

Snapshot Testing Workflow

describe('Canvas drawing operations', () => {
  let canvas, ctx;
  
  beforeEach(() => {
    canvas = document.createElement('canvas');
    ctx = canvas.getContext('2d');
  });
  
  test('complex drawing sequence', () => {
    // Setup
    ctx.fillStyle = '#ff0000';
    ctx.strokeStyle = '#00ff00';
    ctx.lineWidth = 3;
    
    // Drawing operations
    ctx.fillRect(10, 10, 100, 100);
    ctx.strokeRect(15, 15, 90, 90);
    
    // Test complete operation sequence
    expect(ctx.__getEvents()).toMatchSnapshot();
    
    // Test only actual drawing calls
    expect(ctx.__getDrawCalls()).toMatchSnapshot();
  });
});

Incremental Testing

test('incremental canvas operations', () => {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  // Phase 1: Setup
  ctx.fillStyle = '#ff0000';
  ctx.beginPath();
  expect(ctx.__getEvents()).toHaveLength(2);
  
  // Phase 2: Path construction
  ctx.arc(50, 50, 25, 0, Math.PI * 2);
  ctx.closePath();
  expect(ctx.__getPath()).toHaveLength(3); // beginPath, arc, closePath
  
  // Phase 3: Drawing
  ctx.__clearEvents(); // Clear setup events
  ctx.fill();
  
  const drawCalls = ctx.__getDrawCalls();
  expect(drawCalls).toHaveLength(1);
  expect(drawCalls[0].type).toBe('fill');
});

Error Validation Testing

test('canvas error behavior', () => {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  // Test parameter validation
  expect(() => ctx.arc(0, 0, -5, 0, Math.PI)).toThrow(DOMException);
  expect(() => ctx.arc(0, 0)).toThrow(TypeError);
  
  // Verify error operations are still tracked
  const events = ctx.__getEvents();
  expect(events.some(e => e.type === 'arc')).toBe(true);
});

docs

browser-apis.md

canvas-context.md

index.md

setup.md

test-utilities.md

tile.json