diff --git a/packages/replay/jest.setup.ts b/packages/replay/jest.setup.ts index 481221831f73..f7d2a1248c0c 100644 --- a/packages/replay/jest.setup.ts +++ b/packages/replay/jest.setup.ts @@ -36,19 +36,25 @@ afterEach(() => { (client.getTransport()?.send as MockTransport).mockClear(); }); -type SentReplayExpected = { - envelopeHeader?: { - event_id: string; - sent_at: string; - sdk: { - name: string; - version?: string; - }; +type EnvelopeHeader = { + event_id: string; + sent_at: string; + sdk: { + name: string; + version?: string; }; - replayEventHeader?: { type: 'replay_event' }; - replayEventPayload?: Record; - recordingHeader?: { type: 'replay_recording'; length: number }; - recordingPayloadHeader?: Record; +}; + +type ReplayEventHeader = { type: 'replay_event' }; +type ReplayEventPayload = Record; +type RecordingHeader = { type: 'replay_recording'; length: number }; +type RecordingPayloadHeader = Record; +type SentReplayExpected = { + envelopeHeader?: EnvelopeHeader; + replayEventHeader?: ReplayEventHeader; + replayEventPayload?: ReplayEventPayload; + recordingHeader?: RecordingHeader; + recordingPayloadHeader?: RecordingPayloadHeader; events?: string | Uint8Array; }; @@ -70,20 +76,27 @@ const toHaveSameSession = function (received: jest.Mocked, expe }; }; -/** - * Checks the last call to `fetch` and ensures a replay was uploaded by - * checking the `fetch()` request's body. - */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -const toHaveSentReplay = function ( - _received: jest.Mocked, +type Result = { + passed: boolean; + key: string; + expectedVal: SentReplayExpected[keyof SentReplayExpected]; + actualVal: SentReplayExpected[keyof SentReplayExpected]; +}; +type Call = [ + EnvelopeHeader, + [ + [ReplayEventHeader | undefined, ReplayEventPayload | undefined], + [RecordingHeader | undefined, RecordingPayloadHeader | undefined], + ], +]; +type CheckCallForSentReplayResult = { pass: boolean; call: Call | undefined; results: Result[] }; + +function checkCallForSentReplay( + call: Call | undefined, expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, -) { - const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock; - const lastCall = calls[calls.length - 1]?.[0]; - - const envelopeHeader = lastCall?.[0]; - const envelopeItems = lastCall?.[1] || [[], []]; +): CheckCallForSentReplayResult { + const envelopeHeader = call?.[0]; + const envelopeItems = call?.[1] || [[], []]; const [[replayEventHeader, replayEventPayload], [recordingHeader, recordingPayload] = []] = envelopeItems; // @ts-ignore recordingPayload is always a string in our tests @@ -116,34 +129,98 @@ const toHaveSentReplay = function ( .map(key => { const actualVal = actualObj[key as keyof SentReplayExpected]; const expectedVal = expectedObj[key as keyof SentReplayExpected]; - const matches = !expectedVal || this.equals(actualVal, expectedVal); + const passed = !expectedVal || this.equals(actualVal, expectedVal); - return [matches, key, expectedVal, actualVal]; + return { passed, key, expectedVal, actualVal }; }) - .filter(([passed]) => !passed) + .filter(({ passed }) => !passed) : []; - const payloadPassed = Boolean(lastCall && (!expected || results.length === 0)); + const pass = Boolean(call && (!expected || results.length === 0)); + + return { + pass, + call, + results, + }; +} + +/** + * Checks all calls to `fetch` and ensures a replay was uploaded by + * checking the `fetch()` request's body. + */ +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +const toHaveSentReplay = function ( + _received: jest.Mocked, + expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, +) { + const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock; + + let result: CheckCallForSentReplayResult; + + for (const currentCall of calls) { + result = checkCallForSentReplay.call(this, currentCall[0], expected); + if (result.pass) { + break; + } + } + + // @ts-ignore use before assigned + const { results, call, pass } = result; const options = { isNot: this.isNot, promise: this.promise, }; - const allPass = payloadPassed; - return { - pass: allPass, + pass, message: () => - !lastCall - ? allPass + !call + ? pass ? 'Expected Replay to not have been sent, but a request was attempted' : 'Expected Replay to have been sent, but a request was not attempted' : `${this.utils.matcherHint('toHaveSentReplay', undefined, undefined, options)}\n\n${results .map( - ([, key, expected, actual]) => - `Expected (key: ${key}): ${payloadPassed ? 'not ' : ''}${this.utils.printExpected(expected)}\n` + - `Received (key: ${key}): ${this.utils.printReceived(actual)}`, + ({ key, expectedVal, actualVal }: Result) => + `Expected (key: ${key}): ${pass ? 'not ' : ''}${this.utils.printExpected(expectedVal)}\n` + + `Received (key: ${key}): ${this.utils.printReceived(actualVal)}`, + ) + .join('\n')}`, + }; +}; + +/** + * Checks the last call to `fetch` and ensures a replay was uploaded by + * checking the `fetch()` request's body. + */ +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +const toHaveLastSentReplay = function ( + _received: jest.Mocked, + expected?: SentReplayExpected | { sample: SentReplayExpected; inverse: boolean }, +) { + const { calls } = (getCurrentHub().getClient()?.getTransport()?.send as MockTransport).mock; + const lastCall = calls[calls.length - 1]?.[0]; + + const { results, call, pass } = checkCallForSentReplay.call(this, lastCall, expected); + + const options = { + isNot: this.isNot, + promise: this.promise, + }; + + return { + pass, + message: () => + !call + ? pass + ? 'Expected Replay to not have been sent, but a request was attempted' + : 'Expected Replay to have last been sent, but a request was not attempted' + : `${this.utils.matcherHint('toHaveSentReplay', undefined, undefined, options)}\n\n${results + .map( + ({ key, expectedVal, actualVal }: Result) => + `Expected (key: ${key}): ${pass ? 'not ' : ''}${this.utils.printExpected(expectedVal)}\n` + + `Received (key: ${key}): ${this.utils.printReceived(actualVal)}`, ) .join('\n')}`, }; @@ -152,6 +229,7 @@ const toHaveSentReplay = function ( expect.extend({ toHaveSameSession, toHaveSentReplay, + toHaveLastSentReplay, }); declare global { @@ -159,10 +237,12 @@ declare global { namespace jest { interface AsymmetricMatchers { toHaveSentReplay(expected?: SentReplayExpected): void; + toHaveLastSentReplay(expected?: SentReplayExpected): void; toHaveSameSession(expected: undefined | Session): void; } interface Matchers { toHaveSentReplay(expected?: SentReplayExpected): R; + toHaveLastSentReplay(expected?: SentReplayExpected): R; toHaveSameSession(expected: undefined | Session): R; } } diff --git a/packages/replay/test/unit/index-errorSampleRate.test.ts b/packages/replay/test/unit/index-errorSampleRate.test.ts index 82517267fd8f..867bf229ee1d 100644 --- a/packages/replay/test/unit/index-errorSampleRate.test.ts +++ b/packages/replay/test/unit/index-errorSampleRate.test.ts @@ -44,7 +44,7 @@ describe('Replay (errorSampleRate)', () => { mockRecord._emitter(TEST_EVENT); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Does not capture mouse click domHandler({ @@ -52,7 +52,7 @@ describe('Replay (errorSampleRate)', () => { }); jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); captureException(new Error('testing')); jest.runAllTimers(); @@ -86,14 +86,12 @@ describe('Replay (errorSampleRate)', () => { ]), }); - jest.runAllTimers(); - await new Promise(process.nextTick); jest.runAllTimers(); await new Promise(process.nextTick); // New checkout when we call `startRecording` again after uploading segment // after an error occurs - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([ { data: { isCheckout: true }, @@ -109,15 +107,15 @@ describe('Replay (errorSampleRate)', () => { }); jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([ { type: 5, - timestamp: BASE_TIMESTAMP + 15000 + 60, + timestamp: BASE_TIMESTAMP + 15000 + 40, data: { tag: 'breadcrumb', payload: { - timestamp: (BASE_TIMESTAMP + 15000 + 60) / 1000, + timestamp: (BASE_TIMESTAMP + 15000 + 40) / 1000, type: 'default', category: 'ui.click', message: '', @@ -144,7 +142,7 @@ describe('Replay (errorSampleRate)', () => { jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); }); it('does not send a replay if user hides the tab and comes back within 60 seconds', async () => { @@ -159,7 +157,7 @@ describe('Replay (errorSampleRate)', () => { jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // User comes back before `VISIBILITY_CHANGE_TIMEOUT` elapses jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT - 100); @@ -175,7 +173,7 @@ describe('Replay (errorSampleRate)', () => { await new Promise(process.nextTick); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); }); it('does not upload a replay event when document becomes hidden', async () => { @@ -199,7 +197,7 @@ describe('Replay (errorSampleRate)', () => { await new Promise(process.nextTick); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); }); it('does not upload a replay event if 5 seconds have elapsed since the last replay event occurred', async () => { @@ -214,7 +212,7 @@ describe('Replay (errorSampleRate)', () => { jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); }); it('does not upload a replay event if 15 seconds have elapsed since the last replay upload', async () => { @@ -230,18 +228,18 @@ describe('Replay (errorSampleRate)', () => { mockRecord._emitter(TEST_EVENT); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // There should also not be another attempt at an upload 5 seconds after the last replay event await advanceTimers(5000); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Let's make sure it continues to work mockRecord._emitter(TEST_EVENT); await advanceTimers(5000); jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); }); it('does not upload if user has been idle for more than 15 minutes and comes back to move their mouse', async () => { @@ -256,7 +254,7 @@ describe('Replay (errorSampleRate)', () => { type: 3, }; mockRecord._emitter(TEST_EVENT); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); jest.runAllTimers(); await new Promise(process.nextTick); @@ -268,7 +266,7 @@ describe('Replay (errorSampleRate)', () => { // replay the event on top. Or maybe replay the event on top of a refresh // snapshot. - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); expect(mockRecord.takeFullSnapshot).toHaveBeenCalledWith(true); }); @@ -277,7 +275,7 @@ describe('Replay (errorSampleRate)', () => { mockRecord._emitter(TEST_EVENT); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); jest.runAllTimers(); await new Promise(process.nextTick); @@ -289,7 +287,7 @@ describe('Replay (errorSampleRate)', () => { jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 }, TEST_EVENT]), replayEventPayload: expect.objectContaining({ replay_start_timestamp: BASE_TIMESTAMP / 1000, @@ -319,7 +317,7 @@ describe('Replay (errorSampleRate)', () => { await new Promise(process.nextTick); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); jest.advanceTimersByTime(ELAPSED); @@ -340,7 +338,7 @@ describe('Replay (errorSampleRate)', () => { expect(replay.session?.started).toBe(BASE_TIMESTAMP + ELAPSED + 20); // Does not capture mouse click - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ replayEventPayload: expect.objectContaining({ // Make sure the old performance event is thrown out replay_start_timestamp: (BASE_TIMESTAMP + ELAPSED + 20) / 1000, @@ -389,18 +387,18 @@ it('sends a replay after loading the session multiple times', async () => { const TEST_EVENT = { data: {}, timestamp: BASE_TIMESTAMP, type: 3 }; mockRecord._emitter(TEST_EVENT); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); captureException(new Error('testing')); jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([{ data: { isCheckout: true }, timestamp: BASE_TIMESTAMP, type: 2 }, TEST_EVENT]), }); mockTransportSend.mockClear(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); jest.runAllTimers(); await new Promise(process.nextTick); @@ -409,7 +407,7 @@ it('sends a replay after loading the session multiple times', async () => { // New checkout when we call `startRecording` again after uploading segment // after an error occurs - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([ { data: { isCheckout: true }, diff --git a/packages/replay/test/unit/index-noSticky.test.ts b/packages/replay/test/unit/index-noSticky.test.ts index fa69f34b8e02..a1ca7b0fd7bf 100644 --- a/packages/replay/test/unit/index-noSticky.test.ts +++ b/packages/replay/test/unit/index-noSticky.test.ts @@ -128,7 +128,7 @@ describe('Replay (no sticky)', () => { expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).toHaveSentReplay({ events: JSON.stringify([TEST_EVENT]) }); + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([TEST_EVENT]) }); // Session's last activity is not updated because we do not consider // visibilitystate as user being active @@ -168,7 +168,7 @@ describe('Replay (no sticky)', () => { expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).toHaveSentReplay({ events: JSON.stringify([TEST_EVENT]) }); + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([TEST_EVENT]) }); // No user activity to trigger an update expect(replay.session?.lastActivity).toBe(BASE_TIMESTAMP); @@ -191,14 +191,14 @@ describe('Replay (no sticky)', () => { mockRecord._emitter(TEST_EVENT); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([...Array(5)].map(() => TEST_EVENT)), }); // There should also not be another attempt at an upload 5 seconds after the last replay event mockTransport.mockClear(); await advanceTimers(5000); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); expect(replay.session?.lastActivity).toBe(BASE_TIMESTAMP); expect(replay.session?.segmentId).toBe(1); @@ -209,7 +209,7 @@ describe('Replay (no sticky)', () => { mockTransport.mockClear(); mockRecord._emitter(TEST_EVENT); await advanceTimers(5000); - expect(replay).toHaveSentReplay({ events: JSON.stringify([TEST_EVENT]) }); + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([TEST_EVENT]) }); }); it('creates a new session if user has been idle for more than 15 minutes and comes back to move their mouse', async () => { @@ -229,7 +229,7 @@ describe('Replay (no sticky)', () => { type: 3, }; mockRecord._emitter(TEST_EVENT); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); await new Promise(process.nextTick); @@ -245,7 +245,7 @@ describe('Replay (no sticky)', () => { expect(replay).not.toHaveSameSession(initialSession); // Replay does not send immediately because checkout was due to expired session - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Now do a click domHandler({ @@ -257,7 +257,7 @@ describe('Replay (no sticky)', () => { const newTimestamp = BASE_TIMESTAMP + FIFTEEN_MINUTES; const breadcrumbTimestamp = newTimestamp + 20; // I don't know where this 20ms comes from - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([ { data: { isCheckout: true }, timestamp: newTimestamp, type: 2 }, { diff --git a/packages/replay/test/unit/index.test.ts b/packages/replay/test/unit/index.test.ts index d41e587380a9..eda6e10c3b1f 100644 --- a/packages/replay/test/unit/index.test.ts +++ b/packages/replay/test/unit/index.test.ts @@ -254,7 +254,7 @@ describe('Replay', () => { WINDOW.dispatchEvent(new Event('blur')); await new Promise(process.nextTick); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([TEST_EVENT, hiddenBreadcrumb]), }); // Session's last activity should not be updated @@ -282,7 +282,7 @@ describe('Replay', () => { await new Promise(process.nextTick); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).toHaveSentReplay({ events: JSON.stringify([TEST_EVENT]) }); + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([TEST_EVENT]) }); // Session's last activity is not updated because we do not consider // visibilitystate as user being active @@ -300,7 +300,7 @@ describe('Replay', () => { expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); expect(mockTransportSend).toHaveBeenCalledTimes(1); - expect(replay).toHaveSentReplay({ events: JSON.stringify([TEST_EVENT]) }); + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([TEST_EVENT]) }); // No user activity to trigger an update expect(replay.session?.lastActivity).toBe(BASE_TIMESTAMP); @@ -323,7 +323,7 @@ describe('Replay', () => { mockRecord._emitter(TEST_EVENT); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([...Array(5)].map(() => TEST_EVENT)), }); @@ -331,7 +331,7 @@ describe('Replay', () => { mockTransportSend.mockClear(); await advanceTimers(5000); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); expect(replay.session?.lastActivity).toBe(BASE_TIMESTAMP); expect(replay.session?.segmentId).toBe(1); @@ -342,7 +342,7 @@ describe('Replay', () => { mockTransportSend.mockClear(); mockRecord._emitter(TEST_EVENT); await advanceTimers(5000); - expect(replay).toHaveSentReplay({ events: JSON.stringify([TEST_EVENT]) }); + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([TEST_EVENT]) }); }); it('creates a new session if user has been idle for 15 minutes and comes back to click their mouse', async () => { @@ -373,7 +373,7 @@ describe('Replay', () => { type: 3, }; mockRecord._emitter(TEST_EVENT); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); await new Promise(process.nextTick); @@ -385,7 +385,7 @@ describe('Replay', () => { // snapshot. expect(mockRecord.takeFullSnapshot).toHaveBeenCalledWith(true); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Should be a new session expect(replay).not.toHaveSameSession(initialSession); @@ -400,7 +400,7 @@ describe('Replay', () => { const newTimestamp = BASE_TIMESTAMP + FIFTEEN_MINUTES; const breadcrumbTimestamp = newTimestamp + 20; // I don't know where this 20ms comes from - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ recordingPayloadHeader: { segment_id: 0 }, events: JSON.stringify([ { data: { isCheckout: true }, timestamp: newTimestamp, type: 2 }, @@ -475,7 +475,7 @@ describe('Replay', () => { await advanceTimers(5000); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Should be the same session because user has been idle and no events have caused a new session to be created expect(replay).toHaveSameSession(initialSession); @@ -510,7 +510,7 @@ describe('Replay', () => { jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ recordingPayloadHeader: { segment_id: 0 }, events: JSON.stringify([ { data: { isCheckout: true }, timestamp: newTimestamp, type: 2 }, @@ -550,7 +550,7 @@ describe('Replay', () => { const ELAPSED = 5000; await advanceTimers(ELAPSED); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([ { type: 5, @@ -598,7 +598,7 @@ describe('Replay', () => { await advanceTimers(8000); await advanceTimers(2000); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ replayEventPayload: expect.objectContaining({ error_ids: [], replay_id: expect.any(String), @@ -619,7 +619,7 @@ describe('Replay', () => { // next tick should do nothing await advanceTimers(5000); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); }); it('fails to upload data and hits retry max and stops', async () => { @@ -692,7 +692,7 @@ describe('Replay', () => { addEvent(replay, TEST_EVENT); WINDOW.dispatchEvent(new Event('blur')); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ recordingPayloadHeader: { segment_id: 0 }, }); expect(replay.session?.segmentId).toBe(1); @@ -702,7 +702,7 @@ describe('Replay', () => { jest.runAllTimers(); await new Promise(process.nextTick); expect(replay.session?.segmentId).toBe(2); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ recordingPayloadHeader: { segment_id: 1 }, }); }); @@ -717,7 +717,7 @@ describe('Replay', () => { document.dispatchEvent(new Event('visibilitychange')); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Pretend 5 seconds have passed const ELAPSED = 5000; @@ -733,7 +733,7 @@ describe('Replay', () => { WINDOW.dispatchEvent(new Event('blur')); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ replayEventPayload: expect.objectContaining({ replay_start_timestamp: BASE_TIMESTAMP / 1000, urls: ['http://localhost/'], // this doesn't truly test if we are capturing the right URL as we don't change URLs, but good enough @@ -802,7 +802,7 @@ describe('Replay', () => { document.dispatchEvent(new Event('visibilitychange')); await new Promise(process.nextTick); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Pretend 5 seconds have passed const ELAPSED = 5000; @@ -825,7 +825,7 @@ describe('Replay', () => { WINDOW.dispatchEvent(new Event('blur')); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ replayEventPayload: expect.objectContaining({ replay_start_timestamp: (BASE_TIMESTAMP - 10000) / 1000, urls: ['http://localhost/'], // this doesn't truly test if we are capturing the right URL as we don't change URLs, but good enough @@ -870,7 +870,7 @@ describe('Replay', () => { await new Promise(process.nextTick); expect(mockTransportSend).toHaveBeenCalledTimes(1); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ replayEventPayload: expect.objectContaining({ // Make sure the old performance event is thrown out replay_start_timestamp: BASE_TIMESTAMP / 1000, diff --git a/packages/replay/test/unit/stop.test.ts b/packages/replay/test/unit/stop.test.ts index 543f7e512a3f..1adbde5a11d3 100644 --- a/packages/replay/test/unit/stop.test.ts +++ b/packages/replay/test/unit/stop.test.ts @@ -78,7 +78,7 @@ describe('Replay - stop', () => { WINDOW.dispatchEvent(new Event('blur')); await new Promise(process.nextTick); expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled(); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); // Session's last activity should not be updated expect(replay.session?.lastActivity).toEqual(BASE_TIMESTAMP); // eventBuffer is destroyed @@ -108,7 +108,7 @@ describe('Replay - stop', () => { WINDOW.dispatchEvent(new Event('blur')); jest.runAllTimers(); await new Promise(process.nextTick); - expect(replay).toHaveSentReplay({ + expect(replay).toHaveLastSentReplay({ events: JSON.stringify([ // This event happens when we call `replay.start` { @@ -138,7 +138,7 @@ describe('Replay - stop', () => { await new Promise(process.nextTick); expect(replay.eventBuffer?.length).toBe(undefined); - expect(replay).not.toHaveSentReplay(); + expect(replay).not.toHaveLastSentReplay(); }); it('does not call core SDK `addInstrumentationHandler` after initial setup', async function () {