mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
Remove jest-canvas-mock (#66854)
This commit is contained in:
@@ -52,5 +52,6 @@ module.exports = {
|
||||
setupFilesAfterEnv: [
|
||||
'<rootDir>/web/packages/build/jest/setupTests.ts',
|
||||
'<rootDir>/web/packages/build/jest/customMatchers.ts',
|
||||
'<rootDir>/web/packages/build/jest/canvasMock.ts',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
"eslint-plugin-testing-library": "7.16.2",
|
||||
"eslint-plugin-unused-imports": "^4.4.1",
|
||||
"jest": "^30.3.0",
|
||||
"jest-canvas-mock": "^2.5.2",
|
||||
"jsdom-testing-mocks": "^1.16.0",
|
||||
"msw": "2.14.2",
|
||||
"msw-storybook-addon": "^2.0.7",
|
||||
|
||||
Generated
-28
@@ -6,11 +6,6 @@ settings:
|
||||
|
||||
pnpmfileChecksum: sha256-TR6zTaL3sXZMyu+QoRdd27aSUTH6sH0gp+M2XjxgTUI=
|
||||
|
||||
patchedDependencies:
|
||||
[email protected]:
|
||||
hash: 8329a68f6b8f930f6204c405a071859893962d4a6641b6c2c2bb33122c0441b1
|
||||
path: web/patches/[email protected]
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -184,9 +179,6 @@ importers:
|
||||
jest:
|
||||
specifier: ^30.3.0
|
||||
version: 30.3.0(@types/[email protected])([email protected])
|
||||
jest-canvas-mock:
|
||||
specifier: ^2.5.2
|
||||
version: 2.5.2(patch_hash=8329a68f6b8f930f6204c405a071859893962d4a6641b6c2c2bb33122c0441b1)
|
||||
jsdom-testing-mocks:
|
||||
specifier: ^1.16.0
|
||||
version: 1.16.0
|
||||
@@ -4166,9 +4158,6 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
||||
@@ -5088,9 +5077,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==}
|
||||
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
|
||||
@@ -5600,9 +5586,6 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-5iXz5n9LWQzx/C2WesGFfpE6RLamzdHwsn3KpfzShwbfIqs7stnoEpaNErf/7+3mbxwZ4s8Foq7I0tPxw7BWHg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
@@ -10814,8 +10797,6 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
css-tree: 2.2.1
|
||||
@@ -11835,11 +11816,6 @@ snapshots:
|
||||
filelist: 1.0.4
|
||||
minimatch: 3.1.5
|
||||
|
||||
[email protected](patch_hash=8329a68f6b8f930f6204c405a071859893962d4a6641b6c2c2bb33122c0441b1):
|
||||
dependencies:
|
||||
cssfontparser: 1.2.1
|
||||
moo-color: 1.0.2
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
execa: 5.1.1
|
||||
@@ -12518,10 +12494,6 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]([email protected](@types/[email protected])([email protected])):
|
||||
|
||||
@@ -39,8 +39,5 @@ shellEmulator: true
|
||||
# affect performance outside of docker.
|
||||
# https://github.com/gravitational/teleport/issues/46019
|
||||
packageImportMethod: clone-or-copy
|
||||
patchedDependencies:
|
||||
# Needed for roundRect support which was merged to jest-canvas-mock but not released.
|
||||
[email protected]: web/patches/[email protected]
|
||||
# Do not install packages released less than 2 days (2880 minutes) ago
|
||||
minimumReleaseAge: 2880
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
/**
|
||||
* Teleport
|
||||
* Copyright (C) 2026 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Minimal in-repo replacement for jest-canvas-mock. jsdom does not implement
|
||||
// HTMLCanvasElement.getContext('2d'), and a handful of tests inspect the
|
||||
// recorded canvas events to assert what was drawn (see SessionRecordings
|
||||
// timeline renderers). This file mocks just enough of CanvasRenderingContext2D
|
||||
// for those tests, exposing the same __getEvents/__getDrawCalls/__getPath
|
||||
// helpers that jest-canvas-mock used to provide.
|
||||
|
||||
type Transform = [number, number, number, number, number, number];
|
||||
|
||||
type CanvasStyle = string | CanvasGradient | CanvasPattern;
|
||||
|
||||
type EventProps = { [key: string]: any };
|
||||
|
||||
export interface CanvasRenderingContext2DEvent {
|
||||
type: string;
|
||||
transform: Transform;
|
||||
props: EventProps;
|
||||
}
|
||||
|
||||
const IDENTITY: Transform = [1, 0, 0, 1, 0, 0];
|
||||
|
||||
class MockTextMetrics implements TextMetrics {
|
||||
readonly width: number;
|
||||
readonly actualBoundingBoxLeft = 0;
|
||||
readonly actualBoundingBoxRight = 0;
|
||||
readonly fontBoundingBoxAscent = 0;
|
||||
readonly fontBoundingBoxDescent = 0;
|
||||
readonly actualBoundingBoxAscent = 0;
|
||||
readonly actualBoundingBoxDescent = 0;
|
||||
readonly emHeightAscent = 0;
|
||||
readonly emHeightDescent = 0;
|
||||
readonly hangingBaseline = 0;
|
||||
readonly alphabeticBaseline = 0;
|
||||
readonly ideographicBaseline = 0;
|
||||
|
||||
constructor(text: string) {
|
||||
this.width = text.length;
|
||||
}
|
||||
}
|
||||
|
||||
class MockCanvasGradient implements CanvasGradient {
|
||||
addColorStop(_offset: number, _color: string) {}
|
||||
}
|
||||
|
||||
class MockCanvasPattern implements CanvasPattern {
|
||||
setTransform(_transform?: DOMMatrix2DInit) {}
|
||||
}
|
||||
|
||||
function createEvent(
|
||||
type: string,
|
||||
props: EventProps
|
||||
): CanvasRenderingContext2DEvent {
|
||||
return { type, transform: IDENTITY.slice() as Transform, props };
|
||||
}
|
||||
|
||||
class MockCanvasRenderingContext2D {
|
||||
private _events: CanvasRenderingContext2DEvent[] = [];
|
||||
private _drawCalls: CanvasRenderingContext2DEvent[] = [];
|
||||
private _path: CanvasRenderingContext2DEvent[] = [
|
||||
createEvent('beginPath', {}),
|
||||
];
|
||||
private _clip: CanvasRenderingContext2DEvent[] = [];
|
||||
|
||||
fillStyle: CanvasStyle = '#000000';
|
||||
strokeStyle: CanvasStyle = '#000000';
|
||||
font = '10px sans-serif';
|
||||
textAlign: CanvasTextAlign = 'start';
|
||||
textBaseline: CanvasTextBaseline = 'alphabetic';
|
||||
direction: CanvasDirection = 'inherit';
|
||||
lineWidth = 1;
|
||||
lineCap: CanvasLineCap = 'butt';
|
||||
lineJoin: CanvasLineJoin = 'miter';
|
||||
miterLimit = 10;
|
||||
lineDashOffset = 0;
|
||||
globalAlpha = 1;
|
||||
globalCompositeOperation: GlobalCompositeOperation = 'source-over';
|
||||
shadowBlur = 0;
|
||||
shadowColor = 'rgba(0, 0, 0, 0)';
|
||||
shadowOffsetX = 0;
|
||||
shadowOffsetY = 0;
|
||||
imageSmoothingEnabled = true;
|
||||
imageSmoothingQuality: ImageSmoothingQuality = 'low';
|
||||
filter = 'none';
|
||||
fontKerning: CanvasFontKerning = 'auto';
|
||||
fontStretch: CanvasFontStretch = 'normal';
|
||||
fontVariantCaps: CanvasFontVariantCaps = 'normal';
|
||||
letterSpacing = '0px';
|
||||
wordSpacing = '0px';
|
||||
textRendering: CanvasTextRendering = 'auto';
|
||||
|
||||
readonly canvas: HTMLCanvasElement;
|
||||
|
||||
constructor(canvas: HTMLCanvasElement) {
|
||||
this.canvas = canvas;
|
||||
}
|
||||
|
||||
private push(
|
||||
type: string,
|
||||
props: EventProps = {}
|
||||
): CanvasRenderingContext2DEvent {
|
||||
const event = createEvent(type, props);
|
||||
this._events.push(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
private pushDraw(
|
||||
type: string,
|
||||
props: EventProps = {}
|
||||
): CanvasRenderingContext2DEvent {
|
||||
const event = this.push(type, props);
|
||||
this._drawCalls.push(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
private pushPath(
|
||||
type: string,
|
||||
props: EventProps = {}
|
||||
): CanvasRenderingContext2DEvent {
|
||||
const event = this.push(type, props);
|
||||
this._path.push(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
__getEvents(): CanvasRenderingContext2DEvent[] {
|
||||
return this._events.slice();
|
||||
}
|
||||
|
||||
__clearEvents() {
|
||||
this._events = [];
|
||||
}
|
||||
|
||||
__getDrawCalls(): CanvasRenderingContext2DEvent[] {
|
||||
return this._drawCalls.slice();
|
||||
}
|
||||
|
||||
__clearDrawCalls() {
|
||||
this._drawCalls = [];
|
||||
}
|
||||
|
||||
__getPath(): CanvasRenderingContext2DEvent[] {
|
||||
return this._path.slice();
|
||||
}
|
||||
|
||||
__clearPath() {
|
||||
this._path = [createEvent('beginPath', {})];
|
||||
}
|
||||
|
||||
__getClippingRegion(): CanvasRenderingContext2DEvent[] {
|
||||
return this._clip.slice();
|
||||
}
|
||||
|
||||
save() {
|
||||
this.push('save');
|
||||
}
|
||||
|
||||
restore() {
|
||||
this.push('restore');
|
||||
}
|
||||
|
||||
scale(x: number, y: number) {
|
||||
this.push('scale', { x, y });
|
||||
}
|
||||
|
||||
rotate(angle: number) {
|
||||
this.push('rotate', { angle });
|
||||
}
|
||||
|
||||
translate(x: number, y: number) {
|
||||
this.push('translate', { x, y });
|
||||
}
|
||||
|
||||
transform(a: number, b: number, c: number, d: number, e: number, f: number) {
|
||||
this.push('transform', { a, b, c, d, e, f });
|
||||
}
|
||||
|
||||
setTransform(
|
||||
a?: number | DOMMatrix2DInit,
|
||||
b?: number,
|
||||
c?: number,
|
||||
d?: number,
|
||||
e?: number,
|
||||
f?: number
|
||||
) {
|
||||
this.push('setTransform', { a, b, c, d, e, f });
|
||||
}
|
||||
|
||||
resetTransform() {
|
||||
this.push('resetTransform');
|
||||
}
|
||||
|
||||
getTransform(): DOMMatrix {
|
||||
return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 } as DOMMatrix;
|
||||
}
|
||||
|
||||
beginPath() {
|
||||
this.__clearPath();
|
||||
this._events.push(this._path[0]);
|
||||
}
|
||||
|
||||
closePath() {
|
||||
this.pushPath('closePath');
|
||||
}
|
||||
|
||||
moveTo(x: number, y: number) {
|
||||
this.pushPath('moveTo', { x, y });
|
||||
}
|
||||
|
||||
lineTo(x: number, y: number) {
|
||||
this.pushPath('lineTo', { x, y });
|
||||
}
|
||||
|
||||
bezierCurveTo(
|
||||
cp1x: number,
|
||||
cp1y: number,
|
||||
cp2x: number,
|
||||
cp2y: number,
|
||||
x: number,
|
||||
y: number
|
||||
) {
|
||||
this.pushPath('bezierCurveTo', { cp1x, cp1y, cp2x, cp2y, x, y });
|
||||
}
|
||||
|
||||
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number) {
|
||||
this.pushPath('quadraticCurveTo', { cpx, cpy, x, y });
|
||||
}
|
||||
|
||||
arc(
|
||||
x: number,
|
||||
y: number,
|
||||
radius: number,
|
||||
startAngle: number,
|
||||
endAngle: number,
|
||||
anticlockwise = false
|
||||
) {
|
||||
this.pushPath('arc', {
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
startAngle,
|
||||
endAngle,
|
||||
anticlockwise,
|
||||
});
|
||||
}
|
||||
|
||||
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number) {
|
||||
this.pushPath('arcTo', { x1, y1, x2, y2, radius });
|
||||
}
|
||||
|
||||
ellipse(
|
||||
x: number,
|
||||
y: number,
|
||||
radiusX: number,
|
||||
radiusY: number,
|
||||
rotation: number,
|
||||
startAngle: number,
|
||||
endAngle: number,
|
||||
anticlockwise = false
|
||||
) {
|
||||
this.pushPath('ellipse', {
|
||||
x,
|
||||
y,
|
||||
radiusX,
|
||||
radiusY,
|
||||
rotation,
|
||||
startAngle,
|
||||
endAngle,
|
||||
anticlockwise,
|
||||
});
|
||||
}
|
||||
|
||||
rect(x: number, y: number, width: number, height: number) {
|
||||
this.pushPath('rect', { x, y, width, height });
|
||||
}
|
||||
|
||||
roundRect(
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
radii?: number | DOMPointInit | (number | DOMPointInit)[]
|
||||
) {
|
||||
this.pushPath('roundRect', { x, y, width, height, radii });
|
||||
}
|
||||
|
||||
fill() {
|
||||
this.pushDraw('fill');
|
||||
}
|
||||
|
||||
stroke() {
|
||||
this.pushDraw('stroke');
|
||||
}
|
||||
|
||||
clip() {
|
||||
const event = this.push('clip');
|
||||
this._clip.push(event);
|
||||
}
|
||||
|
||||
fillRect(x: number, y: number, width: number, height: number) {
|
||||
this.pushDraw('fillRect', { x, y, width, height });
|
||||
}
|
||||
|
||||
strokeRect(x: number, y: number, width: number, height: number) {
|
||||
this.pushDraw('strokeRect', { x, y, width, height });
|
||||
}
|
||||
|
||||
clearRect(x: number, y: number, width: number, height: number) {
|
||||
this.pushDraw('clearRect', { x, y, width, height });
|
||||
}
|
||||
|
||||
fillText(text: string, x: number, y: number, maxWidth?: number) {
|
||||
this.pushDraw('fillText', { text, x, y, maxWidth });
|
||||
}
|
||||
|
||||
strokeText(text: string, x: number, y: number, maxWidth?: number) {
|
||||
this.pushDraw('strokeText', { text, x, y, maxWidth });
|
||||
}
|
||||
|
||||
drawImage(
|
||||
image: CanvasImageSource,
|
||||
sxOrDx: number,
|
||||
syOrDy: number,
|
||||
sWidthOrDWidth?: number,
|
||||
sHeightOrDHeight?: number,
|
||||
dx?: number,
|
||||
dy?: number,
|
||||
dWidth?: number,
|
||||
dHeight?: number
|
||||
) {
|
||||
if (dx === undefined) {
|
||||
this.pushDraw('drawImage', {
|
||||
img: image,
|
||||
dx: sxOrDx,
|
||||
dy: syOrDy,
|
||||
dWidth: sWidthOrDWidth,
|
||||
dHeight: sHeightOrDHeight,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.pushDraw('drawImage', {
|
||||
img: image,
|
||||
sx: sxOrDx,
|
||||
sy: syOrDy,
|
||||
sWidth: sWidthOrDWidth,
|
||||
sHeight: sHeightOrDHeight,
|
||||
dx,
|
||||
dy,
|
||||
dWidth,
|
||||
dHeight,
|
||||
});
|
||||
}
|
||||
|
||||
measureText(text: string): TextMetrics {
|
||||
const normalized = text == null ? '' : String(text);
|
||||
this.push('measureText', { text: normalized });
|
||||
return new MockTextMetrics(normalized);
|
||||
}
|
||||
|
||||
createLinearGradient(
|
||||
x0: number,
|
||||
y0: number,
|
||||
x1: number,
|
||||
y1: number
|
||||
): CanvasGradient {
|
||||
this.push('createLinearGradient', { x0, y0, x1, y1 });
|
||||
return new MockCanvasGradient();
|
||||
}
|
||||
|
||||
createRadialGradient(
|
||||
x0: number,
|
||||
y0: number,
|
||||
r0: number,
|
||||
x1: number,
|
||||
y1: number,
|
||||
r1: number
|
||||
): CanvasGradient {
|
||||
this.push('createRadialGradient', { x0, y0, r0, x1, y1, r1 });
|
||||
return new MockCanvasGradient();
|
||||
}
|
||||
|
||||
createConicGradient(
|
||||
startAngle: number,
|
||||
x: number,
|
||||
y: number
|
||||
): CanvasGradient {
|
||||
this.push('createConicGradient', { startAngle, x, y });
|
||||
return new MockCanvasGradient();
|
||||
}
|
||||
|
||||
createPattern(
|
||||
_image: CanvasImageSource,
|
||||
_repetition: string | null
|
||||
): CanvasPattern | null {
|
||||
return new MockCanvasPattern();
|
||||
}
|
||||
|
||||
createImageData(
|
||||
widthOrImageData: number | ImageData,
|
||||
height?: number
|
||||
): ImageData {
|
||||
const isImageData = typeof widthOrImageData !== 'number';
|
||||
const w = isImageData ? widthOrImageData.width : widthOrImageData;
|
||||
const h = isImageData ? widthOrImageData.height : (height ?? 0);
|
||||
return {
|
||||
data: new Uint8ClampedArray(w * h * 4),
|
||||
width: w,
|
||||
height: h,
|
||||
colorSpace: 'srgb',
|
||||
} as ImageData;
|
||||
}
|
||||
|
||||
getImageData(_sx: number, _sy: number, sw: number, sh: number): ImageData {
|
||||
return {
|
||||
data: new Uint8ClampedArray(sw * sh * 4),
|
||||
width: sw,
|
||||
height: sh,
|
||||
colorSpace: 'srgb',
|
||||
} as ImageData;
|
||||
}
|
||||
|
||||
putImageData() {}
|
||||
|
||||
setLineDash(_segments: number[]) {}
|
||||
|
||||
getLineDash(): number[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
isPointInPath(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
isPointInStroke(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
drawFocusIfNeeded() {}
|
||||
|
||||
scrollPathIntoView() {}
|
||||
|
||||
getContextAttributes(): CanvasRenderingContext2DSettings {
|
||||
return {};
|
||||
}
|
||||
|
||||
isContextLost(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.__clearEvents();
|
||||
this.__clearDrawCalls();
|
||||
this.__clearPath();
|
||||
this._clip = [];
|
||||
}
|
||||
}
|
||||
|
||||
const contexts = new WeakMap<HTMLCanvasElement, MockCanvasRenderingContext2D>();
|
||||
|
||||
function installCanvasMock() {
|
||||
if (typeof window === 'undefined') return;
|
||||
const proto = window.HTMLCanvasElement?.prototype;
|
||||
if (!proto) return;
|
||||
|
||||
// The DOM `getContext` has many context-specific overloads we can't
|
||||
// express in a single signature. Define it via Object.defineProperty so the
|
||||
// value slot doesn't have to satisfy every overload simultaneously.
|
||||
Object.defineProperty(proto, 'getContext', {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function getContext(
|
||||
this: HTMLCanvasElement,
|
||||
type: string
|
||||
): MockCanvasRenderingContext2D | null {
|
||||
if (type !== '2d') return null;
|
||||
let ctx = contexts.get(this);
|
||||
if (!ctx) {
|
||||
ctx = new MockCanvasRenderingContext2D(this);
|
||||
contexts.set(this, ctx);
|
||||
}
|
||||
return ctx;
|
||||
},
|
||||
});
|
||||
|
||||
proto.toDataURL = function toDataURL(type?: string): string {
|
||||
const mime =
|
||||
type === 'image/jpeg' || type === 'image/webp' ? type : 'image/png';
|
||||
return `data:${mime};base64,00`;
|
||||
};
|
||||
|
||||
proto.toBlob = function toBlob(callback: BlobCallback, type?: string) {
|
||||
const mime =
|
||||
type === 'image/jpeg' || type === 'image/webp' ? type : 'image/png';
|
||||
const length = (this.width || 1) * (this.height || 1) * 4;
|
||||
const blob = new window.Blob([new Uint8Array(length)], { type: mime });
|
||||
setTimeout(() => callback(blob), 0);
|
||||
};
|
||||
}
|
||||
|
||||
installCanvasMock();
|
||||
|
||||
declare global {
|
||||
interface CanvasRenderingContext2D {
|
||||
__getEvents(): CanvasRenderingContext2DEvent[];
|
||||
|
||||
__clearEvents(): void;
|
||||
|
||||
__getDrawCalls(): CanvasRenderingContext2DEvent[];
|
||||
|
||||
__clearDrawCalls(): void;
|
||||
|
||||
__getPath(): CanvasRenderingContext2DEvent[];
|
||||
|
||||
__clearPath(): void;
|
||||
|
||||
__getClippingRegion(): CanvasRenderingContext2DEvent[];
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import { EventEmitter } from 'events';
|
||||
|
||||
import { screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import 'jest-canvas-mock';
|
||||
import { act } from 'react';
|
||||
|
||||
import { render } from 'design/utils/testing';
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
import '@testing-library/jest-dom';
|
||||
import { screen } from '@testing-library/react';
|
||||
import 'jest-canvas-mock';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
|
||||
import { act, CurrentPath, render } from 'design/utils/testing';
|
||||
|
||||
@@ -17,7 +17,6 @@ import '@testing-library/jest-dom';
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { screen } from '@testing-library/react';
|
||||
import 'jest-canvas-mock';
|
||||
|
||||
import { act, render } from 'design/utils/testing';
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
|
||||
import { render, screen } from 'design/utils/testing';
|
||||
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { darkTheme } from 'design/theme';
|
||||
|
||||
import {
|
||||
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { darkTheme } from 'design/theme';
|
||||
|
||||
import { SessionRecordingThumbnail } from 'teleport/services/recordings';
|
||||
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { darkTheme } from 'design/theme';
|
||||
|
||||
import { SessionRecordingMetadata } from 'teleport/services/recordings';
|
||||
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { darkTheme } from 'design/theme';
|
||||
|
||||
import { SessionRecordingMetadata } from 'teleport/services/recordings';
|
||||
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { darkTheme } from 'design/theme';
|
||||
|
||||
import {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import TtyTerminal from './terminal';
|
||||
import Tty from './tty';
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
import { act, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import 'jest-canvas-mock';
|
||||
import { mockIntersectionObserver } from 'jsdom-testing-mocks';
|
||||
|
||||
import { render } from 'design/utils/testing';
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { render, screen } from 'design/utils/testing';
|
||||
import { makeDeepLinkWithSafeInput } from 'shared/deepLinks';
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'jest-canvas-mock';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { render, screen } from 'design/utils/testing';
|
||||
|
||||
@@ -20,7 +20,6 @@ import { EventEmitter } from 'node:events';
|
||||
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import 'jest-canvas-mock';
|
||||
|
||||
import { render } from 'design/utils/testing';
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import Logger, { NullService } from 'teleterm/logger';
|
||||
import { createMockConfigService } from 'teleterm/services/config/fixtures/mocks';
|
||||
import { MockPtyProcess } from 'teleterm/services/pty/fixtures/mocks';
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import 'jest-canvas-mock';
|
||||
|
||||
import Logger, { NullService } from 'teleterm/logger';
|
||||
import {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
import { createRef } from 'react';
|
||||
|
||||
import { act, fireEvent, render, screen } from 'design/utils/testing';
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'jest-canvas-mock';
|
||||
import { within } from '@testing-library/react';
|
||||
import { mockIntersectionObserver } from 'jsdom-testing-mocks';
|
||||
|
||||
|
||||
-1
@@ -18,7 +18,6 @@
|
||||
|
||||
import { within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import 'jest-canvas-mock';
|
||||
import { act, ComponentType, createRef } from 'react';
|
||||
|
||||
import { render, screen } from 'design/utils/testing';
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
diff --git a/lib/classes/CanvasRenderingContext2D.js b/lib/classes/CanvasRenderingContext2D.js
|
||||
index e1e4b8fe31826baadbdce3f48ee2a68455de8910..46dad56798ddc7fa094f911a7a7e0c97fb2a3770 100644
|
||||
--- a/lib/classes/CanvasRenderingContext2D.js
|
||||
+++ b/lib/classes/CanvasRenderingContext2D.js
|
||||
@@ -15,7 +15,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
||||
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
||||
-const testFuncs = ['setLineDash', 'getLineDash', 'setTransform', 'getTransform', 'getImageData', 'save', 'restore', 'createPattern', 'createRadialGradient', 'addHitRegion', 'arc', 'arcTo', 'beginPath', 'clip', 'closePath', 'scale', 'stroke', 'clearHitRegions', 'clearRect', 'fillRect', 'strokeRect', 'rect', 'resetTransform', 'translate', 'moveTo', 'lineTo', 'bezierCurveTo', 'createLinearGradient', 'ellipse', 'measureText', 'rotate', 'drawImage', 'drawFocusIfNeeded', 'isPointInPath', 'isPointInStroke', 'putImageData', 'strokeText', 'fillText', 'quadraticCurveTo', 'removeHitRegion', 'fill', 'transform', 'scrollPathIntoView', 'createImageData'];
|
||||
+const testFuncs = ['setLineDash', 'getLineDash', 'setTransform', 'getTransform', 'getImageData', 'save', 'restore', 'createPattern', 'createRadialGradient', 'addHitRegion', 'arc', 'arcTo', 'beginPath', 'clip', 'closePath', 'scale', 'stroke', 'clearHitRegions', 'clearRect', 'fillRect', 'strokeRect', 'rect', 'roundRect', 'resetTransform', 'translate', 'moveTo', 'lineTo', 'bezierCurveTo', 'createLinearGradient', 'ellipse', 'measureText', 'rotate', 'drawImage', 'drawFocusIfNeeded', 'isPointInPath', 'isPointInStroke', 'putImageData', 'strokeText', 'fillText', 'quadraticCurveTo', 'removeHitRegion', 'fill', 'transform', 'scrollPathIntoView', 'createImageData'];
|
||||
const compositeOperations = ['source-over', 'source-in', 'source-out', 'source-atop', 'destination-over', 'destination-in', 'destination-out', 'destination-atop', 'lighter', 'copy', 'xor', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity'];
|
||||
function getTransformSlice(ctx) {
|
||||
return ctx._transformStack[ctx._stackIndex].slice();
|
||||
@@ -909,6 +909,40 @@ class CanvasRenderingContext2D {
|
||||
const event = (0, _createCanvasEvent.default)('restore', getTransformSlice(this), {});
|
||||
this._events.push(event);
|
||||
}
|
||||
+ roundRect(x, y, width, height, radii) {
|
||||
+ if (arguments.length < 4)
|
||||
+ throw new TypeError(
|
||||
+ "Failed to execute 'roundRect' on '" +
|
||||
+ this.constructor.name +
|
||||
+ "': 4 arguments required, but only " +
|
||||
+ arguments.length +
|
||||
+ ' present.'
|
||||
+ );
|
||||
+ if (radii.constructor === Array && (radii.length === 0 || radii.length > 4))
|
||||
+ throw new TypeError(
|
||||
+ "Failed to execute 'roundRect' on '" +
|
||||
+ this.constructor.name +
|
||||
+ "': " +
|
||||
+ radii.length +
|
||||
+ ' radii provided. Between one and four radii are necessary.'
|
||||
+ );
|
||||
+ if (!Number.isFinite(x + y + width + height)) return;
|
||||
+
|
||||
+ const xResult = Number(x);
|
||||
+ const yResult = Number(y);
|
||||
+ const widthResult = Number(width);
|
||||
+ const heightResult = Number(height);
|
||||
+ const event = (0, _createCanvasEvent.default)('roundRect', getTransformSlice(this), {
|
||||
+ x: xResult,
|
||||
+ y: yResult,
|
||||
+ width: widthResult,
|
||||
+ height: heightResult,
|
||||
+ radii: radii,
|
||||
+ });
|
||||
+
|
||||
+ this._events.push(event);
|
||||
+ this._path.push(event);
|
||||
+ }
|
||||
rotate(angle) {
|
||||
if (arguments.length < 1) throw new TypeError("Failed to execute 'rotate' on '" + this.constructor.name + "': 1 argument required, but only 0 present.");
|
||||
angle = Number(angle);
|
||||
Reference in New Issue
Block a user