Skip to content

Commit 8a2f4bc

Browse files
committed
refactor replay helpers
1 parent 61b30f0 commit 8a2f4bc

File tree

6 files changed

+75
-24
lines changed

6 files changed

+75
-24
lines changed

packages/integration-tests/suites/replay/captureReplay/test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { expect } from '@playwright/test';
22
import { SDK_VERSION } from '@sentry/browser';
3+
import type { ReplayEvent } from '@sentry/types';
34

45
import { sentryTest } from '../../../utils/fixtures';
56
import { envelopeRequestParser } from '../../../utils/helpers';
6-
import { waitForReplayRequest } from '../../../utils/replay';
7+
import { waitForReplayRequest } from '../../../utils/replayHelpers';
78

8-
sentryTest('captureReplay', async ({ getLocalTestPath, page }) => {
9+
sentryTest('should capture replays', async ({ getLocalTestPath, page }) => {
910
// Replay bundles are es6 only
1011
if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) {
1112
sentryTest.skip();
@@ -25,10 +26,10 @@ sentryTest('captureReplay', async ({ getLocalTestPath, page }) => {
2526
const url = await getLocalTestPath({ testDir: __dirname });
2627

2728
await page.goto(url);
28-
const replayEvent0 = envelopeRequestParser(await reqPromise0);
29+
const replayEvent0 = envelopeRequestParser(await reqPromise0) as ReplayEvent;
2930

3031
await page.click('button');
31-
const replayEvent1 = envelopeRequestParser(await reqPromise1);
32+
const replayEvent1 = envelopeRequestParser(await reqPromise1) as ReplayEvent;
3233

3334
expect(replayEvent0).toBeDefined();
3435
expect(replayEvent0).toEqual({

packages/integration-tests/suites/replay/captureReplayViaBrowser/test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { expect } from '@playwright/test';
22
import { SDK_VERSION } from '@sentry/browser';
3+
import type { ReplayEvent } from '@sentry/types';
34

45
import { sentryTest } from '../../../utils/fixtures';
56
import { envelopeRequestParser } from '../../../utils/helpers';
6-
import { waitForReplayRequest } from '../../../utils/replay';
7+
import { waitForReplayRequest } from '../../../utils/replayHelpers';
78

8-
sentryTest('captureReplay', async ({ getLocalTestPath, page }) => {
9+
sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalTestPath, page }) => {
910
// For this test, we skip all bundle tests, as we're only interested in Replay being correctly
1011
// exported from the `@sentry/browser` npm package.
1112
if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_')) {
@@ -26,10 +27,10 @@ sentryTest('captureReplay', async ({ getLocalTestPath, page }) => {
2627
const url = await getLocalTestPath({ testDir: __dirname });
2728

2829
await page.goto(url);
29-
const replayEvent0 = envelopeRequestParser(await reqPromise0);
30+
const replayEvent0 = envelopeRequestParser(await reqPromise0) as ReplayEvent;
3031

3132
await page.click('button');
32-
const replayEvent1 = envelopeRequestParser(await reqPromise1);
33+
const replayEvent1 = envelopeRequestParser(await reqPromise1) as ReplayEvent;
3334

3435
expect(replayEvent0).toBeDefined();
3536
expect(replayEvent0).toEqual({

packages/integration-tests/suites/replay/errorResponse/test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../utils/fixtures';
4-
import { getReplaySnapshot } from '../../../utils/helpers';
4+
import { getReplaySnapshot, waitForReplayRequest } from '../../../utils/replayHelpers';
55

6-
sentryTest('errorResponse', async ({ getLocalTestPath, page }) => {
6+
sentryTest('should stop recording after receiving an error response', async ({ getLocalTestPath, page }) => {
77
// Currently bundle tests are not supported for replay
88
if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) {
99
sentryTest.skip();
@@ -22,12 +22,14 @@ sentryTest('errorResponse', async ({ getLocalTestPath, page }) => {
2222
const url = await getLocalTestPath({ testDir: __dirname });
2323
await page.goto(url);
2424

25-
await page.waitForRequest('https://dsn.ingest.sentry.io/**/*');
25+
await waitForReplayRequest(page);
2626
await page.click('button');
2727

2828
expect(called).toBe(1);
2929

3030
// Should immediately skip retrying and just cancel, no backoff
31+
// This waitForTimeout call should be okay, as we're not checking for any
32+
// further network requests afterwards.
3133
await page.waitForTimeout(5001);
3234

3335
expect(called).toBe(1);

packages/integration-tests/suites/replay/sampling/test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../utils/fixtures';
4-
import { getReplaySnapshot } from '../../../utils/helpers';
4+
import { getReplaySnapshot } from '../../../utils/replayHelpers';
55

6-
sentryTest('sampling', async ({ getLocalTestPath, page }) => {
6+
sentryTest('should not send replays if both sample rates are 0', async ({ getLocalTestPath, page }) => {
77
// Replay bundles are es6 only
88
if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) {
99
sentryTest.skip();
@@ -24,6 +24,8 @@ sentryTest('sampling', async ({ getLocalTestPath, page }) => {
2424
await page.goto(url);
2525

2626
await page.click('button');
27+
28+
// This waitForTimeout call should be okay, as we're not checking for any requests after it
2729
await page.waitForTimeout(500);
2830

2931
const replay = await getReplaySnapshot(page);

packages/integration-tests/utils/helpers.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { Page, Request } from '@playwright/test';
2-
import type { ReplayContainer } from '@sentry/replay/build/npm/types/types';
32
import type { EnvelopeItemType, Event, EventEnvelopeHeaders } from '@sentry/types';
43

54
const envelopeUrlRegex = /\.sentry\.io\/api\/\d+\/envelope\//;
@@ -105,16 +104,6 @@ async function getSentryEvents(page: Page, url?: string): Promise<Array<Event>>
105104
return eventsHandle.jsonValue();
106105
}
107106

108-
/**
109-
* This returns the replay container (assuming it exists).
110-
* Note that due to how this works with playwright, this is a POJO copy of replay.
111-
* This means that we cannot access any methods on it, and also not mutate it in any way.
112-
*/
113-
export async function getReplaySnapshot(page: Page): Promise<ReplayContainer> {
114-
const replayIntegration = await page.evaluate<{ _replay: ReplayContainer }>('window.Replay');
115-
return replayIntegration._replay;
116-
}
117-
118107
/**
119108
* Waits until a number of requests matching urlRgx at the given URL arrive.
120109
* If the timout option is configured, this function will abort waiting, even if it hasn't reveived the configured
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import type { ReplayContainer } from '@sentry/replay/build/npm/types/types';
2+
import type { Event, ReplayEvent } from '@sentry/types';
3+
import type { Page, Request } from 'playwright';
4+
5+
import { envelopeRequestParser } from './helpers';
6+
7+
/**
8+
* Waits for a replay request to be sent by the page and returns it.
9+
*
10+
* Optionally, you can specify a segmentId to wait for a specific replay request, containing
11+
* the segment_id in the replay envelope.
12+
* This is useful for tests where you want to wait on multiple replay requests or check
13+
* segment order.
14+
*
15+
* @param page the playwright page object
16+
* @param segmentId the segment_id of the replay event
17+
* @returns
18+
*/
19+
export function waitForReplayRequest(page: Page, segmentId?: number): Promise<Request> {
20+
return page.waitForRequest(req => {
21+
const postData = req.postData();
22+
if (!postData) {
23+
return false;
24+
}
25+
26+
try {
27+
const event = envelopeRequestParser(req);
28+
29+
if (!isReplayEvent(event)) {
30+
return false;
31+
}
32+
33+
if (segmentId !== undefined) {
34+
return event.segment_id === segmentId;
35+
}
36+
37+
return true;
38+
} catch {
39+
return false;
40+
}
41+
});
42+
}
43+
44+
function isReplayEvent(event: Event): event is ReplayEvent {
45+
return event.type === 'replay_event';
46+
}
47+
48+
/**
49+
* This returns the replay container (assuming it exists).
50+
* Note that due to how this works with playwright, this is a POJO copy of replay.
51+
* This means that we cannot access any methods on it, and also not mutate it in any way.
52+
*/
53+
export async function getReplaySnapshot(page: Page): Promise<ReplayContainer> {
54+
const replayIntegration = await page.evaluate<{ _replay: ReplayContainer }>('window.Replay');
55+
return replayIntegration._replay;
56+
}

0 commit comments

Comments
 (0)