From 9ae00029d8d52fc5ad05c48ec4d4b2272157d2d9 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 5 Dec 2022 18:35:06 +0100 Subject: [PATCH] ref(replay): Enable `naming-convention` EsLint rule --- packages/replay/.eslintrc.js | 16 -- packages/replay/src/eventBuffer.ts | 42 ++--- packages/replay/src/index.ts | 173 +++++++++--------- .../test/unit/index-handleGlobalEvent.test.ts | 8 +- .../replay/test/unit/index-sampling.test.ts | 2 +- packages/replay/test/unit/index.test.ts | 12 +- 6 files changed, 120 insertions(+), 133 deletions(-) diff --git a/packages/replay/.eslintrc.js b/packages/replay/.eslintrc.js index 908f9e17120e..9df1f4dffa5f 100644 --- a/packages/replay/.eslintrc.js +++ b/packages/replay/.eslintrc.js @@ -25,22 +25,6 @@ module.exports = { rules: { // TODO (high-prio): Re-enable this after migration '@typescript-eslint/explicit-member-accessibility': 'off', - // TODO (high-prio): Remove this exception from naming convention after migration - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'memberLike', - modifiers: ['private'], - format: ['camelCase'], - leadingUnderscore: 'allow', - }, - { - selector: 'memberLike', - modifiers: ['protected'], - format: ['camelCase'], - leadingUnderscore: 'allow', - }, - ], // TODO (high-prio): Re-enable this after migration '@sentry-internal/sdk/no-async-await': 'off', // TODO (medium-prio): Re-enable this after migration diff --git a/packages/replay/src/eventBuffer.ts b/packages/replay/src/eventBuffer.ts index a42a6ab2a2f7..3ebf87229668 100644 --- a/packages/replay/src/eventBuffer.ts +++ b/packages/replay/src/eventBuffer.ts @@ -43,27 +43,27 @@ export interface EventBuffer { } class EventBufferArray implements EventBuffer { - private events: RecordingEvent[]; + private _events: RecordingEvent[]; public constructor() { - this.events = []; + this._events = []; } public destroy(): void { - this.events = []; + this._events = []; } public get length(): number { - return this.events.length; + return this._events.length; } public addEvent(event: RecordingEvent, isCheckout?: boolean): void { if (isCheckout) { - this.events = [event]; + this._events = [event]; return; } - this.events.push(event); + this._events.push(event); } public finish(): Promise { @@ -71,8 +71,8 @@ class EventBufferArray implements EventBuffer { // Make a copy of the events array reference and immediately clear the // events member so that we do not lose new events while uploading // attachment. - const eventsRet = this.events; - this.events = []; + const eventsRet = this._events; + this._events = []; resolve(JSON.stringify(eventsRet)); }); } @@ -80,18 +80,18 @@ class EventBufferArray implements EventBuffer { // exporting for testing export class EventBufferCompressionWorker implements EventBuffer { - private worker: null | Worker; - private eventBufferItemLength: number = 0; - private id: number = 0; + private _worker: null | Worker; + private _eventBufferItemLength: number = 0; + private _id: number = 0; public constructor(worker: Worker) { - this.worker = worker; + this._worker = worker; } public destroy(): void { __DEBUG_BUILD__ && logger.log('[Replay] Destroying compression worker'); - this.worker?.terminate(); - this.worker = null; + this._worker?.terminate(); + this._worker = null; } /** @@ -99,7 +99,7 @@ export class EventBufferCompressionWorker implements EventBuffer { * is only a local count of the buffer size since `addEvent` is async. */ public get length(): number { - return this.eventBufferItemLength; + return this._eventBufferItemLength; } public async addEvent(event: RecordingEvent, isCheckout?: boolean): Promise { @@ -138,7 +138,7 @@ export class EventBufferCompressionWorker implements EventBuffer { } // At this point, we'll always want to remove listener regardless of result status - this.worker?.removeEventListener('message', listener); + this._worker?.removeEventListener('message', listener); if (!data.success) { // TODO: Do some error handling, not sure what @@ -161,8 +161,8 @@ export class EventBufferCompressionWorker implements EventBuffer { // Note: we can't use `once` option because it's possible it needs to // listen to multiple messages - this.worker?.addEventListener('message', listener); - this.worker?.postMessage({ id, method, args: stringifiedArgs }); + this._worker?.addEventListener('message', listener); + this._worker?.postMessage({ id, method, args: stringifiedArgs }); }); } @@ -174,7 +174,7 @@ export class EventBufferCompressionWorker implements EventBuffer { }); // XXX: See note in `get length()` - this.eventBufferItemLength++; + this._eventBufferItemLength++; return promise; } @@ -183,12 +183,12 @@ export class EventBufferCompressionWorker implements EventBuffer { const promise = this._postMessage({ id, method: 'finish', args: [] }); // XXX: See note in `get length()` - this.eventBufferItemLength = 0; + this._eventBufferItemLength = 0; return promise as Promise; } private _getAndIncrementId(): number { - return this.id++; + return this._id++; } } diff --git a/packages/replay/src/index.ts b/packages/replay/src/index.ts index 745930e14544..d0fed45263ec 100644 --- a/packages/replay/src/index.ts +++ b/packages/replay/src/index.ts @@ -84,54 +84,54 @@ export class Replay implements Integration { readonly options: ReplayPluginOptions; - private performanceObserver: PerformanceObserver | null = null; + private _performanceObserver: PerformanceObserver | null = null; - private retryCount: number = 0; - private retryInterval: number = BASE_RETRY_INTERVAL; + private _retryCount: number = 0; + private _retryInterval: number = BASE_RETRY_INTERVAL; - private debouncedFlush: ReturnType; - private flushLock: Promise | null = null; + private _debouncedFlush: ReturnType; + private _flushLock: Promise | null = null; /** * Timestamp of the last user activity. This lives across sessions. */ - private lastActivity: number = new Date().getTime(); + private _lastActivity: number = new Date().getTime(); /** * Is the integration currently active? */ - private isEnabled: boolean = false; + private _isEnabled: boolean = false; /** * Paused is a state where: * - DOM Recording is not listening at all * - Nothing will be added to event buffer (e.g. core SDK events) */ - private isPaused: boolean = false; + private _isPaused: boolean = false; /** * Integration will wait until an error occurs before creating and sending a * replay. */ - private waitForError: boolean = false; + private _waitForError: boolean = false; /** * Have we attached listeners to the core SDK? * Note we have to track this as there is no way to remove instrumentation handlers. */ - private hasInitializedCoreListeners: boolean = false; + private _hasInitializedCoreListeners: boolean = false; /** * Function to stop recording */ - private stopRecording: ReturnType | null = null; + private _stopRecording: ReturnType | null = null; /** * We overwrite `client.recordDroppedEvent`, but store the original method here so we can restore it. */ private _originalRecordDroppedEvent?: Client['recordDroppedEvent']; - private context: InternalEventContext = { + private _context: InternalEventContext = { errorIds: new Set(), traceIds: new Set(), urls: [], @@ -193,7 +193,7 @@ export class Replay implements Integration { : `${this.recordingOptions.blockSelector},${MEDIA_SELECTORS}`; } - this.debouncedFlush = debounce(() => this.flush(), this.options.flushMinDelay, { + this._debouncedFlush = debounce(() => this.flush(), this.options.flushMinDelay, { maxWait: this.options.flushMaxDelay, }); @@ -260,7 +260,7 @@ export class Replay implements Integration { if (this.session.sampled === 'error') { // Checkout every minute, meaning we only get up-to one minute of events before the error happens this.recordingOptions.checkoutEveryNms = 60000; - this.waitForError = true; + this._waitForError = true; } // setup() is generally called on page load or manually - in both cases we @@ -275,7 +275,7 @@ export class Replay implements Integration { this.startRecording(); - this.isEnabled = true; + this._isEnabled = true; } /** @@ -285,7 +285,7 @@ export class Replay implements Integration { */ startRecording(): void { try { - this.stopRecording = record({ + this._stopRecording = record({ ...this.recordingOptions, emit: this.handleRecordingEmit, }); @@ -306,9 +306,9 @@ export class Replay implements Integration { try { __DEBUG_BUILD__ && logger.log('[Replay] Stopping Replays'); - this.isEnabled = false; + this._isEnabled = false; this.removeListeners(); - this.stopRecording?.(); + this._stopRecording?.(); this.eventBuffer?.destroy(); this.eventBuffer = null; } catch (err) { @@ -323,11 +323,11 @@ export class Replay implements Integration { * not as thorough of a shutdown as `stop()`. */ pause(): void { - this.isPaused = true; + this._isPaused = true; try { - if (this.stopRecording) { - this.stopRecording(); - this.stopRecording = undefined; + if (this._stopRecording) { + this._stopRecording(); + this._stopRecording = undefined; } } catch (err) { __DEBUG_BUILD__ && logger.error('[Replay]', err); @@ -342,7 +342,7 @@ export class Replay implements Integration { * new DOM checkout.` */ resume(): void { - this.isPaused = false; + this._isPaused = false; this.startRecording(); } @@ -396,9 +396,9 @@ export class Replay implements Integration { // Reset context as well this.clearContext(); - this.context.initialUrl = url; - this.context.initialTimestamp = new Date().getTime(); - this.context.urls.push(url); + this._context.initialUrl = url; + this._context.initialTimestamp = new Date().getTime(); + this._context.urls.push(url); } /** @@ -414,7 +414,7 @@ export class Replay implements Integration { this._overwriteRecordDroppedEvent(); // There is no way to remove these listeners, so ensure they are only added once - if (!this.hasInitializedCoreListeners) { + if (!this._hasInitializedCoreListeners) { // Listeners from core SDK // const scope = getCurrentHub().getScope(); scope?.addScopeListener(this.handleCoreBreadcrumbListener('scope')); @@ -427,7 +427,7 @@ export class Replay implements Integration { // replay ID so that we can reference them later in the UI addGlobalEventProcessor(this.handleGlobalEvent); - this.hasInitializedCoreListeners = true; + this._hasInitializedCoreListeners = true; } } catch (err) { __DEBUG_BUILD__ && logger.error('[Replay]', err); @@ -439,7 +439,7 @@ export class Replay implements Integration { return; } - this.performanceObserver = new PerformanceObserver(this.handlePerformanceObserver); + this._performanceObserver = new PerformanceObserver(this.handlePerformanceObserver); // Observe almost everything for now (no mark/measure) [ @@ -454,7 +454,7 @@ export class Replay implements Integration { 'resource', ].forEach(type => { try { - this.performanceObserver?.observe({ + this._performanceObserver?.observe({ type, buffered: true, }); @@ -477,9 +477,9 @@ export class Replay implements Integration { this._restoreRecordDroppedEvent(); - if (this.performanceObserver) { - this.performanceObserver.disconnect(); - this.performanceObserver = null; + if (this._performanceObserver) { + this._performanceObserver.disconnect(); + this._performanceObserver = null; } } catch (err) { __DEBUG_BUILD__ && logger.error('[Replay]', err); @@ -501,7 +501,7 @@ export class Replay implements Integration { // If this option is turned on then we will only want to call `flush` // explicitly - if (this.waitForError) { + if (this._waitForError) { return; } @@ -513,7 +513,7 @@ export class Replay implements Integration { // addUpdate is called quite frequently - use debouncedFlush so that it // respects the flush delays and does not flush immediately - this.debouncedFlush(); + this._debouncedFlush(); } /** @@ -534,20 +534,20 @@ export class Replay implements Integration { } // Only tag transactions with replayId if not waiting for an error - if (event.type !== 'transaction' || !this.waitForError) { + if (event.type !== 'transaction' || !this._waitForError) { event.tags = { ...event.tags, replayId: this.session?.id }; } // Collect traceIds in context regardless of `waitForError` - if it's true, // context gets cleared on every checkout if (event.type === 'transaction') { - this.context.traceIds.add(String(event.contexts?.trace?.trace_id || '')); + this._context.traceIds.add(String(event.contexts?.trace?.trace_id || '')); return event; } // XXX: Is it safe to assume that all other events are error events? // @ts-ignore: Type 'undefined' is not assignable to type 'string'.ts(2345) - this.context.errorIds.add(event.event_id); + this._context.errorIds.add(event.event_id); const exc = event.exception?.values?.[0]; addInternalBreadcrumb({ @@ -558,7 +558,7 @@ export class Replay implements Integration { // Need to be very careful that this does not cause an infinite loop if ( - this.waitForError && + this._waitForError && event.exception && event.message !== UNABLE_TO_SEND_REPLAY // ignore this error because otherwise we could loop indefinitely with trying to capture replay and failing ) { @@ -569,12 +569,12 @@ export class Replay implements Integration { // than the session replay. await this.flushImmediate(); - if (this.stopRecording) { - this.stopRecording(); + if (this._stopRecording) { + this._stopRecording(); // Reset all "capture on error" configuration before // starting a new recording delete this.recordingOptions.checkoutEveryNms; - this.waitForError = false; + this._waitForError = false; this.startRecording(); } }); @@ -605,7 +605,7 @@ export class Replay implements Integration { // when an error occurs. Clear any state that happens before this current // checkout. This needs to happen before `addEvent()` which updates state // dependent on this reset. - if (this.waitForError && event.type === 2) { + if (this._waitForError && event.type === 2) { this.setInitialState(); } @@ -631,8 +631,8 @@ export class Replay implements Integration { // See note above re: session start needs to reflect the most recent // checkout. - if (this.waitForError && this.session && this.context.earliestEvent) { - this.session.started = this.context.earliestEvent; + if (this._waitForError && this.session && this._context.earliestEvent) { + this.session.started = this._context.earliestEvent; this._maybeSaveSession(); } @@ -650,7 +650,7 @@ export class Replay implements Integration { // This can happen because there's no guarantee that a recording event // happens first. e.g. a mouse click can happen and trigger a debounced // flush before the checkout. - this.debouncedFlush?.cancel(); + this._debouncedFlush?.cancel(); return true; }); @@ -704,7 +704,7 @@ export class Replay implements Integration { handleCoreSpanListener: (type: InstrumentationTypeSpan) => (handlerData: unknown) => void = (type: InstrumentationTypeSpan) => (handlerData: unknown): void => { - if (!this.isEnabled) { + if (!this._isEnabled) { return; } @@ -716,7 +716,7 @@ export class Replay implements Integration { if (type === 'history') { // Need to collect visited URLs - this.context.urls.push(result.name); + this._context.urls.push(result.name); this.triggerUserActivity(); } @@ -737,7 +737,7 @@ export class Replay implements Integration { handleCoreBreadcrumbListener: (type: InstrumentationTypeBreadcrumb) => (handlerData: unknown) => void = (type: InstrumentationTypeBreadcrumb) => (handlerData: unknown): void => { - if (!this.isEnabled) { + if (!this._isEnabled) { return; } @@ -850,7 +850,7 @@ export class Replay implements Integration { return; } - if (this.isPaused) { + if (this._isPaused) { // Do not add to event buffer when recording is paused return; } @@ -870,8 +870,11 @@ export class Replay implements Integration { // Only record earliest event if a new session was created, otherwise it // shouldn't be relevant - if (this.session?.segmentId === 0 && (!this.context.earliestEvent || timestampInMs < this.context.earliestEvent)) { - this.context.earliestEvent = timestampInMs; + if ( + this.session?.segmentId === 0 && + (!this._context.earliestEvent || timestampInMs < this._context.earliestEvent) + ) { + this._context.earliestEvent = timestampInMs; } this.eventBuffer.addEvent(event, isCheckout); @@ -881,7 +884,7 @@ export class Replay implements Integration { * Update user activity (across session lifespans) */ updateUserActivity(lastActivity: number = new Date().getTime()): void { - this.lastActivity = lastActivity; + this._lastActivity = lastActivity; } /** @@ -904,7 +907,7 @@ export class Replay implements Integration { // This case means that recording was once stopped due to inactivity. // Ensure that recording is resumed. - if (!this.stopRecording) { + if (!this._stopRecording) { // Create a new session, otherwise when the user action is flushed, it // will get rejected due to an expired session. this.loadSession({ expiry: SESSION_IDLE_DURATION }); @@ -1003,7 +1006,7 @@ export class Replay implements Integration { // MAX_SESSION_LIFE. Otherwise non-user activity can trigger a new // session+recording. This creates noisy replays that do not have much // content in them. - if (this.lastActivity && isExpired(this.lastActivity, MAX_SESSION_LIFE)) { + if (this._lastActivity && isExpired(this._lastActivity, MAX_SESSION_LIFE)) { // Pause recording this.pause(); return; @@ -1030,7 +1033,7 @@ export class Replay implements Integration { * Only flush if `this.waitForError` is false. */ conditionalFlush(): void { - if (this.waitForError) { + if (this._waitForError) { return; } @@ -1042,26 +1045,26 @@ export class Replay implements Integration { */ clearContext(): void { // XXX: `initialTimestamp` and `initialUrl` do not get cleared - this.context.errorIds.clear(); - this.context.traceIds.clear(); - this.context.urls = []; - this.context.earliestEvent = null; + this._context.errorIds.clear(); + this._context.traceIds.clear(); + this._context.urls = []; + this._context.earliestEvent = null; } /** * Return and clear context */ popEventContext(): PopEventContext { - if (this.context.earliestEvent && this.context.earliestEvent < this.context.initialTimestamp) { - this.context.initialTimestamp = this.context.earliestEvent; + if (this._context.earliestEvent && this._context.earliestEvent < this._context.initialTimestamp) { + this._context.initialTimestamp = this._context.earliestEvent; } const context = { - initialTimestamp: this.context.initialTimestamp, - initialUrl: this.context.initialUrl, - errorIds: Array.from(this.context.errorIds).filter(Boolean), - traceIds: Array.from(this.context.traceIds).filter(Boolean), - urls: this.context.urls, + initialTimestamp: this._context.initialTimestamp, + initialUrl: this._context.initialUrl, + errorIds: Array.from(this._context.errorIds).filter(Boolean), + traceIds: Array.from(this._context.traceIds).filter(Boolean), + urls: this._context.urls, }; this.clearContext(); @@ -1122,7 +1125,7 @@ export class Replay implements Integration { * can be active at a time. Do not call this directly. */ flush: () => Promise = async () => { - if (!this.isEnabled) { + if (!this._isEnabled) { // This is just a precaution, there should be no listeners that would // cause a flush. return; @@ -1139,15 +1142,15 @@ export class Replay implements Integration { } // A flush is about to happen, cancel any queued flushes - this.debouncedFlush?.cancel(); + this._debouncedFlush?.cancel(); // No existing flush in progress, proceed with flushing. // this.flushLock acts as a lock so that future calls to `flush()` // will be blocked until this promise resolves - if (!this.flushLock) { - this.flushLock = this.runFlush(); - await this.flushLock; - this.flushLock = null; + if (!this._flushLock) { + this._flushLock = this.runFlush(); + await this._flushLock; + this._flushLock = null; return; } @@ -1158,11 +1161,11 @@ export class Replay implements Integration { // completing) into a single flush. try { - await this.flushLock; + await this._flushLock; } catch (err) { __DEBUG_BUILD__ && logger.error(err); } finally { - this.debouncedFlush(); + this._debouncedFlush(); } }; @@ -1173,9 +1176,9 @@ export class Replay implements Integration { * cases of mulitple flushes happening closely together. */ flushImmediate(): Promise { - this.debouncedFlush(); + this._debouncedFlush(); // `.flush` is provided by lodash.debounce - return this.debouncedFlush.flush(); + return this._debouncedFlush.flush(); } /** @@ -1276,8 +1279,8 @@ export class Replay implements Integration { } resetRetries(): void { - this.retryCount = 0; - this.retryInterval = BASE_RETRY_INTERVAL; + this._retryCount = 0; + this._retryInterval = BASE_RETRY_INTERVAL; } /** @@ -1309,19 +1312,19 @@ export class Replay implements Integration { __DEBUG_BUILD__ && logger.error(err); // Capture error for every failed replay setContext('Replays', { - retryCount: this.retryCount, + retryCount: this._retryCount, }); captureInternalException(err); // If an error happened here, it's likely that uploading the attachment // failed, we'll can retry with the same events payload - if (this.retryCount >= MAX_RETRY_COUNT) { + if (this._retryCount >= MAX_RETRY_COUNT) { throw new Error(`${UNABLE_TO_SEND_REPLAY} - max retries exceeded`); } - this.retryCount = this.retryCount + 1; + this._retryCount = this._retryCount + 1; // will retry in intervals of 5, 10, 30 - this.retryInterval = this.retryCount * this.retryInterval; + this._retryInterval = this._retryCount * this._retryInterval; return await new Promise((resolve, reject) => { setTimeout(async () => { @@ -1337,7 +1340,7 @@ export class Replay implements Integration { } catch (err) { reject(err); } - }, this.retryInterval); + }, this._retryInterval); }); } } @@ -1378,7 +1381,7 @@ export class Replay implements Integration { event?: Event, ): void => { if (event && event.event_id) { - this.context.errorIds.delete(event.event_id); + this._context.errorIds.delete(event.event_id); } return _originalCallback(reason, category, event); diff --git a/packages/replay/test/unit/index-handleGlobalEvent.test.ts b/packages/replay/test/unit/index-handleGlobalEvent.test.ts index 0d5a05f6c602..37efda9eb674 100644 --- a/packages/replay/test/unit/index-handleGlobalEvent.test.ts +++ b/packages/replay/test/unit/index-handleGlobalEvent.test.ts @@ -72,16 +72,16 @@ it('only tags errors with replay id, adds trace and error id to context for erro ); // @ts-ignore private - expect(replay.context.traceIds).toContain('trace_id'); + expect(replay._context.traceIds).toContain('trace_id'); // @ts-ignore private - expect(replay.context.errorIds).toContain('event_id'); + expect(replay._context.errorIds).toContain('event_id'); jest.runAllTimers(); await new Promise(process.nextTick); // wait for flush // Turns off `waitForError` mode // @ts-ignore private - expect(replay.waitForError).toBe(false); + expect(replay._waitForError).toBe(false); }); it('strips out dropped events from errorIds', async () => { @@ -100,7 +100,7 @@ it('strips out dropped events from errorIds', async () => { client.recordDroppedEvent('before_send', 'error', { event_id: 'err2' }); // @ts-ignore private - expect(Array.from(replay.context.errorIds)).toEqual(['err1', 'err3']); + expect(Array.from(replay._context.errorIds)).toEqual(['err1', 'err3']); replay['_restoreRecordDroppedEvent'](); }); diff --git a/packages/replay/test/unit/index-sampling.test.ts b/packages/replay/test/unit/index-sampling.test.ts index 55f42b88bbfc..911bc97dc4ec 100644 --- a/packages/replay/test/unit/index-sampling.test.ts +++ b/packages/replay/test/unit/index-sampling.test.ts @@ -25,7 +25,7 @@ describe('Replay (sampling)', () => { expect(replay.session?.sampled).toBe(false); // @ts-ignore private - expect(replay.context).toEqual( + expect(replay._context).toEqual( expect.objectContaining({ initialTimestamp: expect.any(Number), initialUrl: 'http://localhost/', diff --git a/packages/replay/test/unit/index.test.ts b/packages/replay/test/unit/index.test.ts index 9f3b48a3fc73..4d33b3f70cb9 100644 --- a/packages/replay/test/unit/index.test.ts +++ b/packages/replay/test/unit/index.test.ts @@ -349,7 +349,7 @@ describe('Replay', () => { expect(initialSession?.id).toBeDefined(); // @ts-ignore private member - expect(replay.context).toEqual( + expect(replay._context).toEqual( expect.objectContaining({ initialUrl: 'http://localhost/', initialTimestamp: BASE_TIMESTAMP, @@ -423,7 +423,7 @@ describe('Replay', () => { // `context` should be reset when a new session is created // @ts-ignore private member - expect(replay.context).toEqual( + expect(replay._context).toEqual( expect.objectContaining({ initialUrl: 'http://dummy/', initialTimestamp: newTimestamp, @@ -437,7 +437,7 @@ describe('Replay', () => { expect(initialSession?.id).toBeDefined(); // @ts-ignore private member - expect(replay.context).toEqual( + expect(replay._context).toEqual( expect.objectContaining({ initialUrl: 'http://localhost/', initialTimestamp: BASE_TIMESTAMP, @@ -536,7 +536,7 @@ describe('Replay', () => { // `context` should be reset when a new session is created // @ts-ignore private member - expect(replay.context).toEqual( + expect(replay._context).toEqual( expect.objectContaining({ initialUrl: 'http://dummy/', initialTimestamp: newTimestamp, @@ -855,7 +855,7 @@ describe('Replay', () => { // This should be null because `addEvent` has not been called yet // @ts-ignore private member - expect(replay.context.earliestEvent).toBe(null); + expect(replay._context.earliestEvent).toBe(null); expect(mockTransportSend).toHaveBeenCalledTimes(0); // A new checkout occurs (i.e. a new session was started) @@ -896,7 +896,7 @@ describe('Replay', () => { // This gets reset after sending replay // @ts-ignore private member - expect(replay.context.earliestEvent).toBe(null); + expect(replay._context.earliestEvent).toBe(null); }); it('has single flush when checkout flush and debounce flush happen near simultaneously', async () => {