Skip to content

Commit fc9a8de

Browse files
committed
update tests
1 parent e2b692c commit fc9a8de

File tree

6 files changed

+54
-53
lines changed

6 files changed

+54
-53
lines changed

packages/replay/src/util/handleRecordingEmit.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function getHandleRecordingEmit(replay: ReplayContainer): RecordingEmitCa
4141

4242
// We need to clear existing events on a checkout, otherwise they are
4343
// incremental event updates and should be appended
44-
void addEvent(replay, event, isCheckout);
44+
addEvent(replay, event, isCheckout);
4545

4646
// Different behavior for full snapshots (type=2), ignore other event types
4747
// See https://github.com/rrweb-io/rrweb/blob/d8f9290ca496712aa1e7d472549480c4e7876594/packages/rrweb/src/types.ts#L16
@@ -94,18 +94,13 @@ export function getHandleRecordingEmit(replay: ReplayContainer): RecordingEmitCa
9494
};
9595
}
9696

97-
/**
98-
* Add an event to the event buffer.
99-
* `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
100-
*/
101-
export async function addSettingsEvent(replay: ReplayContainer, isCheckout?: boolean): Promise<void | null> {
102-
// Only need to add this event when sending the first segment
103-
if (!isCheckout || !replay.session || replay.session.segmentId !== 0) {
104-
return null;
105-
}
10697

98+
/**
99+
* Exported for tests
100+
*/
101+
export function createOptionsEvent(replay: ReplayContainer): RecordingEvent {
107102
const options = replay.getOptions();
108-
const event = {
103+
return {
109104
type: EventType.Custom,
110105
timestamp: new Date().getTime(),
111106
data: {
@@ -125,6 +120,17 @@ export async function addSettingsEvent(replay: ReplayContainer, isCheckout?: boo
125120
},
126121
},
127122
};
123+
}
124+
125+
/**
126+
* Add a "meta" event that contains a simplified view on current configuration
127+
* options. This should only be included on the first segment of a recording.
128+
*/
129+
function addSettingsEvent(replay: ReplayContainer, isCheckout?: boolean): Promise<void | null> {
130+
// Only need to add this event when sending the first segment
131+
if (!isCheckout || !replay.session || replay.session.segmentId !== 0) {
132+
return Promise.resolve(null);
133+
}
128134

129-
return addEvent(replay, event, true);
135+
return addEvent(replay, createOptionsEvent(replay), false);
130136
}

packages/replay/test/integration/errorSampleRate.test.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import type { ReplayContainer } from '../../src/replay';
1212
import { clearSession } from '../../src/session/clearSession';
1313
import { addEvent } from '../../src/util/addEvent';
14+
import { createOptionsEvent } from '../../src/util/handleRecordingEmit';
1415
import { PerformanceEntryResource } from '../fixtures/performanceEntry/resource';
1516
import type { RecordMock } from '../index';
1617
import { BASE_TIMESTAMP } from '../index';
@@ -50,6 +51,7 @@ describe('Integration | errorSampleRate', () => {
5051
it('uploads a replay when `Sentry.captureException` is called and continues recording', async () => {
5152
const TEST_EVENT = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 };
5253
mockRecord._emitter(TEST_EVENT);
54+
const optionsEvent = createOptionsEvent(replay)
5355

5456
expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled();
5557
expect(replay).not.toHaveLastSentReplay();
@@ -72,15 +74,10 @@ describe('Integration | errorSampleRate', () => {
7274
recordingPayloadHeader: { segment_id: 0 },
7375
replayEventPayload: expect.objectContaining({
7476
replay_type: 'buffer',
75-
contexts: {
76-
replay: {
77-
error_sample_rate: 1,
78-
session_sample_rate: 0,
79-
},
80-
},
8177
}),
8278
recordingData: JSON.stringify([
8379
{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 },
80+
optionsEvent,
8481
TEST_EVENT,
8582
{
8683
type: 5,
@@ -104,12 +101,6 @@ describe('Integration | errorSampleRate', () => {
104101
recordingPayloadHeader: { segment_id: 1 },
105102
replayEventPayload: expect.objectContaining({
106103
replay_type: 'buffer',
107-
contexts: {
108-
replay: {
109-
error_sample_rate: 1,
110-
session_sample_rate: 0,
111-
},
112-
},
113104
}),
114105
recordingData: JSON.stringify([
115106
{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY + 40, type: 2 },
@@ -161,6 +152,7 @@ describe('Integration | errorSampleRate', () => {
161152
it('manually flushes replay and does not continue to record', async () => {
162153
const TEST_EVENT = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 };
163154
mockRecord._emitter(TEST_EVENT);
155+
const optionsEvent = createOptionsEvent(replay);
164156

165157
expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled();
166158
expect(replay).not.toHaveLastSentReplay();
@@ -186,6 +178,7 @@ describe('Integration | errorSampleRate', () => {
186178
}),
187179
recordingData: JSON.stringify([
188180
{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 },
181+
optionsEvent,
189182
TEST_EVENT,
190183
{
191184
type: 5,
@@ -218,15 +211,10 @@ describe('Integration | errorSampleRate', () => {
218211
recordingPayloadHeader: { segment_id: 0 },
219212
replayEventPayload: expect.objectContaining({
220213
replay_type: 'buffer',
221-
contexts: {
222-
replay: {
223-
error_sample_rate: 1,
224-
session_sample_rate: 0,
225-
},
226-
},
227214
}),
228215
recordingData: JSON.stringify([
229216
{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 },
217+
optionsEvent,
230218
TEST_EVENT,
231219
{
232220
type: 5,
@@ -532,6 +520,7 @@ describe('Integration | errorSampleRate', () => {
532520
it('has the correct timestamps with deferred root event and last replay update', async () => {
533521
const TEST_EVENT = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 };
534522
mockRecord._emitter(TEST_EVENT);
523+
const optionsEvent = createOptionsEvent(replay);
535524

536525
expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled();
537526
expect(replay).not.toHaveLastSentReplay();
@@ -548,7 +537,7 @@ describe('Integration | errorSampleRate', () => {
548537
await new Promise(process.nextTick);
549538

550539
expect(replay).toHaveSentReplay({
551-
recordingData: JSON.stringify([{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 }, TEST_EVENT]),
540+
recordingData: JSON.stringify([{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 }, optionsEvent, TEST_EVENT]),
552541
replayEventPayload: expect.objectContaining({
553542
replay_start_timestamp: BASE_TIMESTAMP / 1000,
554543
// the exception happens roughly 10 seconds after BASE_TIMESTAMP
@@ -584,6 +573,7 @@ describe('Integration | errorSampleRate', () => {
584573
// in production, this happens at a time interval
585574
// session started time should be updated to this current timestamp
586575
mockRecord.takeFullSnapshot(true);
576+
const optionsEvent = createOptionsEvent(replay);
587577

588578
jest.runAllTimers();
589579
jest.advanceTimersByTime(20);
@@ -611,6 +601,7 @@ describe('Integration | errorSampleRate', () => {
611601
timestamp: BASE_TIMESTAMP + ELAPSED + 20,
612602
type: 2,
613603
},
604+
optionsEvent,
614605
]),
615606
});
616607
});
@@ -726,8 +717,9 @@ it('sends a replay after loading the session multiple times', async () => {
726717
},
727718
autoStart: false,
728719
});
729-
// @ts-ignore this is protected, but we want to call it for this test
730-
integration._initialize();
720+
integration['_initialize']();
721+
722+
const optionsEvent = createOptionsEvent(replay)
731723

732724
jest.runAllTimers();
733725

@@ -744,12 +736,14 @@ it('sends a replay after loading the session multiple times', async () => {
744736
await new Promise(process.nextTick);
745737

746738
expect(replay).toHaveSentReplay({
747-
recordingData: JSON.stringify([{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 }, TEST_EVENT]),
739+
recordingPayloadHeader: { segment_id: 0 },
740+
recordingData: JSON.stringify([{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 }, optionsEvent, TEST_EVENT]),
748741
});
749742

750743
// Latest checkout when we call `startRecording` again after uploading segment
751744
// after an error occurs (e.g. when we switch to session replay recording)
752745
expect(replay).toHaveLastSentReplay({
746+
recordingPayloadHeader: { segment_id: 1 },
753747
recordingData: JSON.stringify([{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP + 5040, type: 2 }]),
754748
});
755749
});

packages/replay/test/integration/events.test.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,6 @@ describe('Integration | events', () => {
130130
expect(replay).toHaveLastSentReplay({
131131
replayEventPayload: expect.objectContaining({
132132
replay_start_timestamp: (BASE_TIMESTAMP - 10000) / 1000,
133-
contexts: {
134-
replay: {
135-
error_sample_rate: 0,
136-
session_sample_rate: 1,
137-
},
138-
},
139133
urls: ['http://localhost/'], // this doesn't truly test if we are capturing the right URL as we don't change URLs, but good enough
140134
}),
141135
});

packages/replay/test/integration/session.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { clearSession } from '../../src/session/clearSession';
1414
import type { Session } from '../../src/types';
1515
import { addEvent } from '../../src/util/addEvent';
1616
import { createPerformanceSpans } from '../../src/util/createPerformanceSpans';
17+
import { createOptionsEvent } from '../../src/util/handleRecordingEmit';
1718
import { BASE_TIMESTAMP } from '../index';
1819
import type { RecordMock } from '../mocks/mockRrweb';
1920
import { resetSdkMock } from '../mocks/resetSdkMock';
@@ -197,6 +198,8 @@ describe('Integration | session', () => {
197198
// Replay does not send immediately because checkout was due to expired session
198199
expect(replay).not.toHaveLastSentReplay();
199200

201+
const optionsEvent = createOptionsEvent(replay);
202+
200203
await advanceTimers(DEFAULT_FLUSH_MIN_DELAY);
201204

202205
const newTimestamp = BASE_TIMESTAMP + ELAPSED + 20;
@@ -205,6 +208,7 @@ describe('Integration | session', () => {
205208
recordingPayloadHeader: { segment_id: 0 },
206209
recordingData: JSON.stringify([
207210
{ data: { isCheckout: true }, timestamp: newTimestamp, type: 2 },
211+
optionsEvent,
208212
{
209213
type: 5,
210214
timestamp: newTimestamp,
@@ -382,14 +386,16 @@ describe('Integration | session', () => {
382386
type: 3,
383387
};
384388
mockRecord._emitter(NEW_TEST_EVENT);
389+
const optionsEvent = createOptionsEvent(replay)
385390

386391
jest.runAllTimers();
387392
await advanceTimers(DEFAULT_FLUSH_MIN_DELAY);
388393

389394
expect(replay).toHaveLastSentReplay({
390395
recordingPayloadHeader: { segment_id: 0 },
391396
recordingData: JSON.stringify([
392-
{ type: 5, timestamp: newTimestamp, data: { tag: 'options', payload: DEFAULT_OPTIONS_EVENT_PAYLOAD } },
397+
{data: {isCheckout: true}, timestamp: BASE_TIMESTAMP + ELAPSED, type: 2},
398+
optionsEvent,
393399
{
394400
type: 5,
395401
timestamp: newTimestamp,

packages/replay/test/integration/stop.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { WINDOW } from '../../src/constants';
55
import type { ReplayContainer } from '../../src/replay';
66
import { clearSession } from '../../src/session/clearSession';
77
import { addEvent } from '../../src/util/addEvent';
8+
import { createOptionsEvent } from '../../src/util/handleRecordingEmit';
89
// mock functions need to be imported first
910
import { BASE_TIMESTAMP, mockRrweb, mockSdk } from '../index';
1011
import { useFakeTimers } from '../utils/use-fake-timers';
@@ -95,6 +96,7 @@ describe('Integration | stop', () => {
9596

9697
// re-enable replay
9798
integration.start();
99+
const optionsEvent = createOptionsEvent(replay);
98100

99101
// will be different session
100102
expect(replay.session?.id).not.toEqual(previousSessionId);
@@ -121,17 +123,20 @@ describe('Integration | stop', () => {
121123
jest.runAllTimers();
122124
await new Promise(process.nextTick);
123125
expect(replay).toHaveLastSentReplay({
126+
recordingPayloadHeader: { segment_id: 0 },
124127
recordingData: JSON.stringify([
125128
// This event happens when we call `replay.start`
126129
{
127130
data: { isCheckout: true },
128131
timestamp: BASE_TIMESTAMP + ELAPSED + EXTRA_TICKS,
129132
type: 2,
130133
},
134+
optionsEvent,
131135
TEST_EVENT,
132136
hiddenBreadcrumb,
133137
]),
134138
});
139+
135140
// Session's last activity is last updated when we call `setup()` and *NOT*
136141
// when tab is blurred
137142
expect(replay.session?.lastActivity).toBe(BASE_TIMESTAMP + ELAPSED + 20);

packages/replay/test/unit/util/handleRecordingEmit.test.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
11
import { EventType } from '@sentry-internal/rrweb';
22

33
import { BASE_TIMESTAMP } from '../..';
4+
import type { RecordingEvent } from '../../../src/types';
45
import * as SentryAddEvent from '../../../src/util/addEvent';
5-
import { getHandleRecordingEmit } from '../../../src/util/handleRecordingEmit';
6+
import { createOptionsEvent,getHandleRecordingEmit } from '../../../src/util/handleRecordingEmit';
67
import { DEFAULT_OPTIONS_EVENT_PAYLOAD, setupReplayContainer } from '../../utils/setupReplayContainer';
78
import { useFakeTimers } from '../../utils/use-fake-timers';
89

910
useFakeTimers();
1011

11-
const optionsEvent = {
12-
type: 5,
13-
data: {
14-
tag: 'options',
15-
payload: DEFAULT_OPTIONS_EVENT_PAYLOAD,
16-
},
17-
timestamp: BASE_TIMESTAMP,
18-
};
12+
let optionsEvent: RecordingEvent;
1913

2014
describe('Unit | util | handleRecordingEmit', () => {
2115
let addEventMock: jest.SpyInstance;
@@ -38,6 +32,7 @@ describe('Unit | util | handleRecordingEmit', () => {
3832
sessionSampleRate: 1,
3933
},
4034
});
35+
optionsEvent = createOptionsEvent(replay)
4136

4237
const handler = getHandleRecordingEmit(replay);
4338

@@ -54,7 +49,7 @@ describe('Unit | util | handleRecordingEmit', () => {
5449

5550
expect(addEventMock).toBeCalledTimes(2);
5651
expect(addEventMock).toHaveBeenNthCalledWith(1, replay, event, true);
57-
expect(addEventMock).toHaveBeenLastCalledWith(replay, optionsEvent, true);
52+
expect(addEventMock).toHaveBeenLastCalledWith(replay, optionsEvent, false);
5853

5954
handler(event);
6055
await new Promise(process.nextTick);
@@ -70,6 +65,7 @@ describe('Unit | util | handleRecordingEmit', () => {
7065
sessionSampleRate: 1,
7166
},
7267
});
68+
optionsEvent = createOptionsEvent(replay)
7369

7470
const handler = getHandleRecordingEmit(replay);
7571

@@ -87,13 +83,13 @@ describe('Unit | util | handleRecordingEmit', () => {
8783
// Called twice, once for event and once for settings on checkout only
8884
expect(addEventMock).toBeCalledTimes(2);
8985
expect(addEventMock).toHaveBeenNthCalledWith(1, replay, event, true);
90-
expect(addEventMock).toHaveBeenLastCalledWith(replay, optionsEvent, true);
86+
expect(addEventMock).toHaveBeenLastCalledWith(replay, optionsEvent, false);
9187

9288
handler(event, true);
9389
await new Promise(process.nextTick);
9490

9591
expect(addEventMock).toBeCalledTimes(4);
9692
expect(addEventMock).toHaveBeenNthCalledWith(3, replay, event, true);
97-
expect(addEventMock).toHaveBeenLastCalledWith(replay, { ...optionsEvent, timestamp: BASE_TIMESTAMP + 20 }, true);
93+
expect(addEventMock).toHaveBeenLastCalledWith(replay, { ...optionsEvent, timestamp: BASE_TIMESTAMP + 20 }, false);
9894
});
9995
});

0 commit comments

Comments
 (0)