Files
rrweb/packages/rrweb/test/replay/2d-mutation.test.ts
Justin Halsall 7d1a278688 Canvas recording: Preserve drawing buffer (#1273)
* Upgrade jest to 29 and puppeteer to 16 in rrweb

* Apply formatting changes

* Upgrade rrweb's puppeteer to v20

* Apply formatting changes

* Canvas: Reduce flickering and capturing of empty canvas elements

Turn on `preserveDrawingBuffer` by default for canvas FPS recording.
Has some negative performance implications, but really helps when capturing canvas.

* Apply formatting changes

* Include all test image snapshots in ci

* Apply formatting changes

* Allow more flexibility when capturing hover

* Apply formatting changes

* Create tiny-chairs-build.md

* Apply formatting changes

* Update hover.test.ts

* Apply formatting changes

* Document snapshotFormat jest config

* Freeze `yarn.lock` in ci for reproducible dependencies

* Apply formatting changes

* Apply formatting changes

* Revert to old style of puppeteer evaluation script notation

* Apply formatting changes

* Make test less flaky

* Apply formatting changes

* Apply formatting changes

* Make tests less flaky

* Apply formatting changes

* Make test more robust

* Apply formatting changes

* Apply formatting changes

* Add debugging code for test

* Apply formatting changes

* Also test not ignored input

* Apply formatting changes

* Apply formatting changes

* Apply formatting changes

* escape ignoreSelector

* Apply formatting changes

* Apply formatting changes
2026-04-01 12:00:00 +08:00

82 lines
1.9 KiB
TypeScript

/**
* @jest-environment jsdom
*/
import { polyfillWebGLGlobals } from '../utils';
polyfillWebGLGlobals();
import canvas2DMutation from '../../src/replay/canvas/2d';
import type { Replayer } from '../../src/replay';
let canvas: HTMLCanvasElement;
describe('canvas2DMutation', () => {
beforeEach(() => {
jest.useFakeTimers();
canvas = document.createElement('canvas');
});
afterEach(() => {
jest.clearAllMocks();
jest.useRealTimers();
});
it('should execute all mutations after args are parsed', async () => {
let resolve: (value: unknown) => void;
const promise = new Promise((r) => {
resolve = r;
});
const context = {
clearRect: jest.fn(),
drawImage: jest.fn(),
} as unknown as CanvasRenderingContext2D;
jest.spyOn(canvas, 'getContext').mockImplementation(() => {
return context;
});
const createImageBitmapMock = jest.fn(() => {
return new Promise((r) => {
setTimeout(r, 1000);
});
});
(global as any).createImageBitmap = createImageBitmapMock;
const mutation = canvas2DMutation({
event: {} as Parameters<Replayer['applyIncremental']>[0],
mutations: [
{
property: 'clearRect',
args: [0, 0, 1000, 1000],
},
{
property: 'drawImage',
args: [
{
rr_type: 'ImageBitmap',
args: [],
},
0,
0,
],
},
],
target: canvas,
imageMap: new Map(),
errorHandler: () => {},
});
await jest.advanceTimersByTimeAsync(100);
await expect(createImageBitmapMock).toHaveBeenCalled();
expect(context.clearRect).not.toBeCalled();
expect(context.drawImage).not.toBeCalled();
await jest.advanceTimersByTimeAsync(1000);
await mutation;
expect(context.clearRect).toHaveBeenCalledWith(0, 0, 1000, 1000);
expect(context.drawImage).toHaveBeenCalled();
});
});