Back to Repositories

Testing Canvas Factory Implementation in Mozilla PDF.js

This test suite validates the DOMCanvasFactory implementation in Mozilla’s PDF.js, focusing on canvas creation, manipulation, and cleanup operations. The tests ensure proper handling of canvas dimensions, context management, and error conditions in the PDF rendering pipeline.

Test Coverage Overview

The test suite provides comprehensive coverage of the DOMCanvasFactory class functionality, including canvas creation, resetting, and destruction operations. Key test cases focus on:

  • Canvas dimension validation
  • Canvas and context object creation
  • Canvas reset operations
  • Resource cleanup procedures
  • Error handling for invalid inputs

Implementation Analysis

The testing approach utilizes Jasmine’s BDD framework with describe/it blocks for structured test organization. The implementation validates both positive and negative test cases, employing beforeAll/afterAll hooks for proper test setup and teardown. Node.js environment detection ensures browser-specific tests are properly handled.

Technical Details

Testing tools and configuration include:

  • Jasmine test framework
  • DOM canvas API integration
  • Environment-specific conditional testing
  • HTMLCanvasElement and CanvasRenderingContext2D validation
  • Dimension validation checks

Best Practices Demonstrated

The test suite exemplifies several testing best practices including:

  • Proper test isolation and setup/teardown
  • Comprehensive error case coverage
  • Environment-aware conditional testing
  • Clear test case organization
  • Explicit expectation statements

mozilla/pdfJs

test/unit/canvas_factory_spec.js

            
/* Copyright 2017 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { DOMCanvasFactory } from "../../src/display/canvas_factory.js";
import { isNodeJS } from "../../src/shared/util.js";

describe("canvas_factory", function () {
  describe("DOMCanvasFactory", function () {
    let canvasFactory;

    beforeAll(function () {
      canvasFactory = new DOMCanvasFactory({});
    });

    afterAll(function () {
      canvasFactory = null;
    });

    it("`create` should throw an error if the dimensions are invalid", function () {
      // Invalid width.
      expect(function () {
        return canvasFactory.create(-1, 1);
      }).toThrow(new Error("Invalid canvas size"));

      // Invalid height.
      expect(function () {
        return canvasFactory.create(1, -1);
      }).toThrow(new Error("Invalid canvas size"));
    });

    it("`create` should return a canvas if the dimensions are valid", function () {
      if (isNodeJS) {
        pending("Document is not supported in Node.js.");
      }

      const { canvas, context } = canvasFactory.create(20, 40);
      expect(canvas instanceof HTMLCanvasElement).toBe(true);
      expect(context instanceof CanvasRenderingContext2D).toBe(true);
      expect(canvas.width).toBe(20);
      expect(canvas.height).toBe(40);
    });

    it("`reset` should throw an error if no canvas is provided", function () {
      const canvasAndContext = { canvas: null, context: null };

      expect(function () {
        return canvasFactory.reset(canvasAndContext, 20, 40);
      }).toThrow(new Error("Canvas is not specified"));
    });

    it("`reset` should throw an error if the dimensions are invalid", function () {
      const canvasAndContext = { canvas: "foo", context: "bar" };

      // Invalid width.
      expect(function () {
        return canvasFactory.reset(canvasAndContext, -1, 1);
      }).toThrow(new Error("Invalid canvas size"));

      // Invalid height.
      expect(function () {
        return canvasFactory.reset(canvasAndContext, 1, -1);
      }).toThrow(new Error("Invalid canvas size"));
    });

    it("`reset` should alter the canvas/context if the dimensions are valid", function () {
      if (isNodeJS) {
        pending("Document is not supported in Node.js.");
      }

      const canvasAndContext = canvasFactory.create(20, 40);
      canvasFactory.reset(canvasAndContext, 60, 80);

      const { canvas, context } = canvasAndContext;
      expect(canvas instanceof HTMLCanvasElement).toBe(true);
      expect(context instanceof CanvasRenderingContext2D).toBe(true);
      expect(canvas.width).toBe(60);
      expect(canvas.height).toBe(80);
    });

    it("`destroy` should throw an error if no canvas is provided", function () {
      expect(function () {
        return canvasFactory.destroy({});
      }).toThrow(new Error("Canvas is not specified"));
    });

    it("`destroy` should clear the canvas/context", function () {
      if (isNodeJS) {
        pending("Document is not supported in Node.js.");
      }

      const canvasAndContext = canvasFactory.create(20, 40);
      canvasFactory.destroy(canvasAndContext);

      const { canvas, context } = canvasAndContext;
      expect(canvas).toBe(null);
      expect(context).toBe(null);
    });
  });
});