Skip to content

Commit 301dbf4

Browse files
committed
test and snapshot
1 parent 155715f commit 301dbf4

File tree

5 files changed

+132
-9
lines changed

5 files changed

+132
-9
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window.Replay = new Sentry.Replay({
5+
flushMinDelay: 50,
6+
flushMaxDelay: 50,
7+
minReplayDuration: 0,
8+
});
9+
10+
Sentry.init({
11+
dsn: 'https://[email protected]/1337',
12+
sampleRate: 0,
13+
replaysSessionSampleRate: 1.0,
14+
replaysOnErrorSampleRate: 0.0,
15+
debug: true,
16+
17+
integrations: [window.Replay, new Sentry.ReplayCanvas({ enableManualSnapshot: true })],
18+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<canvas id="canvas" width="150" height="150"></canvas>
8+
<button id="draw">Draw</button>
9+
</body>
10+
11+
12+
<script>
13+
function draw() {
14+
const canvas = document.getElementById("canvas");
15+
if (canvas.getContext) {
16+
console.log('has canvas')
17+
const ctx = canvas.getContext("2d");
18+
19+
ctx.fillRect(25, 25, 100, 100);
20+
ctx.clearRect(45, 45, 60, 60);
21+
ctx.strokeRect(50, 50, 50, 50);
22+
}
23+
}
24+
document.getElementById('draw').addEventListener('click', draw);
25+
</script>
26+
</html>
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import { getReplayRecordingContent, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers';
5+
6+
sentryTest('can manually snapshot canvas', async ({ getLocalTestUrl, page, browserName }) => {
7+
if (shouldSkipReplayTest() || browserName === 'webkit') {
8+
sentryTest.skip();
9+
}
10+
11+
const reqPromise0 = waitForReplayRequest(page, 0);
12+
const reqPromise1 = waitForReplayRequest(page, 1);
13+
const reqPromise2 = waitForReplayRequest(page, 2);
14+
const reqPromise3 = waitForReplayRequest(page, 3);
15+
16+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
17+
return route.fulfill({
18+
status: 200,
19+
contentType: 'application/json',
20+
body: JSON.stringify({ id: 'test-id' }),
21+
});
22+
});
23+
24+
const url = await getLocalTestUrl({ testDir: __dirname });
25+
26+
await page.goto(url);
27+
await reqPromise0;
28+
await Promise.all([page.click('#draw'), reqPromise1]);
29+
30+
const { incrementalSnapshots } = getReplayRecordingContent(await reqPromise2);
31+
expect(incrementalSnapshots).toEqual([]);
32+
33+
await page.evaluate(() => {
34+
(window as any).Sentry.getClient().getIntegrationById('ReplayCanvas').snapshot();
35+
});
36+
37+
const { incrementalSnapshots:incrementalSnapshotsManual } = getReplayRecordingContent(await reqPromise3);
38+
expect(incrementalSnapshotsManual).toEqual(
39+
expect.arrayContaining([
40+
{
41+
data: {
42+
commands: [
43+
{
44+
args: [0, 0, 150, 150],
45+
property: 'clearRect',
46+
},
47+
{
48+
args: [
49+
{
50+
args: [
51+
{
52+
data: [
53+
{
54+
base64: expect.any(String),
55+
rr_type: 'ArrayBuffer',
56+
},
57+
],
58+
rr_type: 'Blob',
59+
type: 'image/webp',
60+
},
61+
],
62+
rr_type: 'ImageBitmap',
63+
},
64+
0,
65+
0,
66+
],
67+
property: 'drawImage',
68+
},
69+
],
70+
id: 9,
71+
source: 9,
72+
type: 0,
73+
},
74+
timestamp: 0,
75+
type: 3,
76+
},
77+
]),
78+
);
79+
});

packages/replay-canvas/src/canvas.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { CanvasManager } from '@sentry-internal/rrweb';
22
import { convertIntegrationFnToClass } from '@sentry/core';
3-
import type { CanvasManagerInterface, CanvasManagerOptions } from '@sentry/replay';
3+
import type { CanvasManagerOptions } from '@sentry/replay';
44
import type { IntegrationFn } from '@sentry/types';
55

66
interface ReplayCanvasOptions {
77
enableManualSnapshot?: boolean;
88
quality: 'low' | 'medium' | 'high';
99
}
1010

11-
type GetCanvasManager = (options: CanvasManagerOptions) => CanvasManagerInterface;
11+
type GetCanvasManager = (options: CanvasManagerOptions) => void;
1212
export interface ReplayCanvasIntegrationOptions {
1313
enableManualSnapshot?: boolean;
1414
recordCanvas: true;
@@ -60,27 +60,28 @@ const INTEGRATION_NAME = 'ReplayCanvas';
6060
const replayCanvasIntegration = ((options: Partial<ReplayCanvasOptions> = {}) => {
6161
const _canvasOptions = {
6262
quality: options.quality || 'medium',
63+
enableManualSnapshot: options.enableManualSnapshot,
6364
};
6465

65-
let _canvasManager: CanvasManager;
66+
let canvasManagerResolve: (value: CanvasManager) => void;
67+
const _canvasManager: Promise<CanvasManager> = new Promise((resolve) => canvasManagerResolve = resolve);
6668

6769
return {
6870
name: INTEGRATION_NAME,
6971
// eslint-disable-next-line @typescript-eslint/no-empty-function
7072
setupOnce() {},
7173
getOptions(): ReplayCanvasIntegrationOptions {
72-
const { quality } = _canvasOptions;
74+
const { quality, enableManualSnapshot } = _canvasOptions;
7375

7476
return {
75-
enableManualSnapshot: options.enableManualSnapshot,
7677
recordCanvas: true,
77-
getCanvasManager: (options: CanvasManagerOptions) => (_canvasManager = new CanvasManager(options)),
78+
getCanvasManager: (options: CanvasManagerOptions) => (canvasManagerResolve(new CanvasManager({ ...options, isManualSnapshot: enableManualSnapshot } ))),
7879
...(CANVAS_QUALITY[quality || 'medium'] || CANVAS_QUALITY.medium),
7980
};
8081
},
8182
async snapshot(canvasElement?: HTMLCanvasElement) {
82-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
83-
_canvasManager.snapshot(canvasElement);
83+
const canvasManager = await _canvasManager;
84+
canvasManager.snapshot(canvasElement);
8485
},
8586
};
8687
}) satisfies IntegrationFn;

packages/replay/src/replay.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,6 @@ export class ReplayContainer implements ReplayContainerInterface {
355355
onMutation: this._onMutationHandler,
356356
...(canvasOptions
357357
? {
358-
isManualSnapshot: canvasOptions.enableManualSnapshot,
359358
recordCanvas: canvasOptions.recordCanvas,
360359
getCanvasManager: canvasOptions.getCanvasManager,
361360
sampling: canvasOptions.sampling,

0 commit comments

Comments
 (0)