UNPKG

vi-canvas-mock

Version:
108 lines (102 loc) 4.05 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = mockPrototype; function mockPrototype() { /** * This weakmap is designed to contain all of the generated canvas contexts. It's keys are the * jsdom canvases obtained by using the `this` keyword inside the `#getContext('2d')` function * call. It's values are the generated `CanvasRenderingContext2D` objects. */ const generatedContexts = new WeakMap(); /** * Overrides getContext. Every test run will create a new function that overrides the current * value of getContext. It attempts to preserve the original getContext function by storing it on * the callback as a property. */ const getContext2D = vi.fn(function getContext2d(type) { if (type === '2d') { /** * Contexts must be idempotent. Once they are generated, they should be returned when * getContext() is called on the same canvas object multiple times. */ if (generatedContexts.has(this)) return generatedContexts.get(this); const ctx = new CanvasRenderingContext2D(this); generatedContexts.set(this, ctx); return ctx; } try { if (!this.dataset.internalRequireTest) require('canvas'); } catch (_unused) { return null; } return getContext2D.internal.call(this, type); }); if (!vi.isMockFunction(HTMLCanvasElement.prototype.getContext)) { getContext2D.internal = HTMLCanvasElement.prototype.getContext; } else { getContext2D.internal = HTMLCanvasElement.prototype.getContext.internal; } HTMLCanvasElement.prototype.getContext = getContext2D; /** * This function technically throws SecurityError at runtime, but it cannot be mocked, because * we don't know if the canvas is tainted. These kinds of errors will be silent. */ const toBlobOverride = vi.fn(function toBlobOverride(callback, mimetype) { if (arguments.length < 1) throw new TypeError("Failed to execute 'toBlob' on 'HTMLCanvasElement': 1 argument required, but only 0 present."); if (typeof callback !== 'function') throw new TypeError("Failed to execute 'toBlob' on 'HTMLCanvasElement': The callback provided as parameter 1 is not a function."); /** * Mime type must be image/jpeg or image/webp exactly for the browser to accept it, otherwise * it's image/png. */ switch (mimetype) { case 'image/webp': break; case 'image/jpeg': break; default: mimetype = 'image/png'; } /** * This section creates a blob of size width * height * 4. This is not actually valid, because * jpeg size is variable, and so is png. TODO: Is there a better way to do this? */ const length = this.width * this.height * 4; const data = new Uint8Array(length); const blob = new window.Blob([data], { type: mimetype }); setTimeout(() => callback(blob), 0); }); if (!vi.isMockFunction(HTMLCanvasElement.prototype.toBlob)) { toBlobOverride.internal = HTMLCanvasElement.prototype.toBlob; } else { toBlobOverride.internal = HTMLCanvasElement.prototype.toBlob.internal; } HTMLCanvasElement.prototype.toBlob = toBlobOverride; /** * This section creates a dataurl with a validated mime type. This is not actually valid, because * jpeg size is variable, and so is png. TODO: Is there a better way to do this? */ const toDataURLOverride = vi.fn(function toDataURLOverride(type, encoderOptions) { switch (type) { case 'image/jpeg': break; case 'image/webp': break; default: type = 'image/png'; } /** * This is the smallest valid data url I could generate. */ return 'data:' + type + ';base64,00'; }); if (!vi.isMockFunction(HTMLCanvasElement.prototype.toDataURL)) { toDataURLOverride.internal = HTMLCanvasElement.prototype.toDataURL; } else { toDataURLOverride.internal = HTMLCanvasElement.prototype.toDataURL.internal; } HTMLCanvasElement.prototype.toDataURL = toDataURLOverride; }