From 9deb4520664a81b33fa7d831dc15c235b376f24f Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 11 Jan 2023 15:48:10 -0500 Subject: [PATCH 1/8] fix(replay): Fix recording size incorrect due to encoding For uncompressed payloads, we were potentially sending the incorrect size due to encoding issues. Instead encode to UTF8 when determining the payload size. Note that `TextEncoder` mostly overlaps with `MutationObserver` support *except* for IE11. So we will not be supporting IE11. --- packages/replay/src/util/createReplayEnvelope.ts | 7 +++++-- packages/utils/src/envelope.ts | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/replay/src/util/createReplayEnvelope.ts b/packages/replay/src/util/createReplayEnvelope.ts index afc445e83d71..76fa9a4f4982 100644 --- a/packages/replay/src/util/createReplayEnvelope.ts +++ b/packages/replay/src/util/createReplayEnvelope.ts @@ -1,5 +1,5 @@ import type { DsnComponents, ReplayEnvelope, ReplayEvent, ReplayRecordingData } from '@sentry/types'; -import { createEnvelope, createEventEnvelopeHeaders, getSdkMetadataForEnvelopeHeader } from '@sentry/utils'; +import { createEnvelope, createEventEnvelopeHeaders, encodeUTF8, getSdkMetadataForEnvelopeHeader } from '@sentry/utils'; /** * Create a replay envelope ready to be sent. @@ -18,7 +18,10 @@ export function createReplayEnvelope( [ { type: 'replay_recording', - length: recordingData.length, + // If string then we need to encode to UTF8, otherwise will have + // wrong size. TextEncoder has similar browser support to + // MutationObserver, although it does not accept IE11. + length: typeof recordingData === 'string' ? encodeUTF8(recordingData).length : recordingData.length, }, recordingData, ], diff --git a/packages/utils/src/envelope.ts b/packages/utils/src/envelope.ts index 8dcb7c492fed..0bfb43462674 100644 --- a/packages/utils/src/envelope.ts +++ b/packages/utils/src/envelope.ts @@ -53,7 +53,7 @@ export function forEachEnvelopeItem( }); } -function encodeUTF8(input: string, textEncoder?: TextEncoderInternal): Uint8Array { +export function encodeUTF8(input: string, textEncoder?: TextEncoderInternal): Uint8Array { const utf8 = textEncoder || new TextEncoder(); return utf8.encode(input); } From 2e546e2a6f61d166c49f8bfa4ba4d58013e380d8 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 11 Jan 2023 16:11:12 -0500 Subject: [PATCH 2/8] lint --- packages/utils/src/envelope.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/utils/src/envelope.ts b/packages/utils/src/envelope.ts index 0bfb43462674..2a5d9f469a24 100644 --- a/packages/utils/src/envelope.ts +++ b/packages/utils/src/envelope.ts @@ -53,6 +53,9 @@ export function forEachEnvelopeItem( }); } +/** + * Encode a string to UTF8. + */ export function encodeUTF8(input: string, textEncoder?: TextEncoderInternal): Uint8Array { const utf8 = textEncoder || new TextEncoder(); return utf8.encode(input); From ad97179ddfb94ce0f6d5099a8cecb7913719105e Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 11 Jan 2023 16:55:52 -0500 Subject: [PATCH 3/8] fix integration tests, need to provide TextEncoder in global --- packages/replay/test/integration/autoSaveSession.test.ts | 5 +++++ .../test/integration/coreHandlers/handleGlobalEvent.test.ts | 5 +++++ packages/replay/test/integration/errorSampleRate.test.ts | 5 +++++ packages/replay/test/integration/eventProcessors.test.ts | 5 +++++ packages/replay/test/integration/events.test.ts | 2 ++ packages/replay/test/integration/sendReplayEvent.test.ts | 2 ++ packages/replay/test/integration/session.test.ts | 5 +++++ packages/replay/test/integration/stop.test.ts | 2 ++ packages/replay/test/unit/util/createReplayEnvelope.test.ts | 5 +++++ 9 files changed, 36 insertions(+) diff --git a/packages/replay/test/integration/autoSaveSession.test.ts b/packages/replay/test/integration/autoSaveSession.test.ts index fb047e07bcc8..280f59d7c17e 100644 --- a/packages/replay/test/integration/autoSaveSession.test.ts +++ b/packages/replay/test/integration/autoSaveSession.test.ts @@ -1,4 +1,5 @@ import { EventType } from 'rrweb'; +import { TextEncoder } from 'util'; import type { RecordingEvent } from '../../src/types'; import { addEvent } from '../../src/util/addEvent'; @@ -8,6 +9,10 @@ import { useFakeTimers } from '../utils/use-fake-timers'; useFakeTimers(); describe('Integration | autoSaveSession', () => { + beforeAll(() => { + (global as any).TextEncoder = TextEncoder; + }); + afterEach(() => { jest.clearAllMocks(); }); diff --git a/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts b/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts index a59dfe838051..0ab7fbf641c0 100644 --- a/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts +++ b/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts @@ -1,5 +1,6 @@ import { getCurrentHub } from '@sentry/core'; import type { Event } from '@sentry/types'; +import { TextEncoder } from 'util'; import { REPLAY_EVENT_NAME } from '../../../src/constants'; import { handleGlobalEventListener } from '../../../src/coreHandlers/handleGlobalEvent'; @@ -17,6 +18,10 @@ useFakeTimers(); let replay: ReplayContainer; describe('Integration | coreHandlers | handleGlobalEvent', () => { + beforeAll(() => { + (global as any).TextEncoder = TextEncoder; + }); + beforeEach(async () => { ({ replay } = await resetSdkMock({ replayOptions: { diff --git a/packages/replay/test/integration/errorSampleRate.test.ts b/packages/replay/test/integration/errorSampleRate.test.ts index 2b52e6c7d96c..f6edd6fb6a38 100644 --- a/packages/replay/test/integration/errorSampleRate.test.ts +++ b/packages/replay/test/integration/errorSampleRate.test.ts @@ -1,4 +1,5 @@ import { captureException } from '@sentry/core'; +import { TextEncoder } from 'util'; import { DEFAULT_FLUSH_MIN_DELAY, REPLAY_SESSION_KEY, VISIBILITY_CHANGE_TIMEOUT, WINDOW } from '../../src/constants'; import type { ReplayContainer } from '../../src/replay'; @@ -23,6 +24,10 @@ describe('Integration | errorSampleRate', () => { let mockRecord: RecordMock; let domHandler: DomHandler; + beforeAll(() => { + (global as any).TextEncoder = TextEncoder; + }); + beforeEach(async () => { ({ mockRecord, domHandler, replay } = await resetSdkMock({ replayOptions: { diff --git a/packages/replay/test/integration/eventProcessors.test.ts b/packages/replay/test/integration/eventProcessors.test.ts index 363c5f2d5a74..ef2a7c5cbdf3 100644 --- a/packages/replay/test/integration/eventProcessors.test.ts +++ b/packages/replay/test/integration/eventProcessors.test.ts @@ -1,5 +1,6 @@ import { getCurrentHub } from '@sentry/core'; import type { Event, Hub, Scope } from '@sentry/types'; +import { TextEncoder } from 'util'; import { BASE_TIMESTAMP } from '..'; import { resetSdkMock } from '../mocks/resetSdkMock'; @@ -11,6 +12,10 @@ describe('Integration | eventProcessors', () => { let hub: Hub; let scope: Scope; + beforeAll(() => { + (global as any).TextEncoder = TextEncoder; + }); + beforeEach(() => { hub = getCurrentHub(); scope = hub.pushScope(); diff --git a/packages/replay/test/integration/events.test.ts b/packages/replay/test/integration/events.test.ts index 5168426dfd79..51f8eaa646ea 100644 --- a/packages/replay/test/integration/events.test.ts +++ b/packages/replay/test/integration/events.test.ts @@ -1,4 +1,5 @@ import { getCurrentHub } from '@sentry/core'; +import { TextEncoder } from 'util'; import { WINDOW } from '../../src/constants'; import type { ReplayContainer } from '../../src/replay'; @@ -24,6 +25,7 @@ describe('Integration | events', () => { const prevLocation = WINDOW.location; beforeAll(async () => { + (global as any).TextEncoder = TextEncoder; jest.setSystemTime(new Date(BASE_TIMESTAMP)); jest.runAllTimers(); }); diff --git a/packages/replay/test/integration/sendReplayEvent.test.ts b/packages/replay/test/integration/sendReplayEvent.test.ts index ec0106c1b946..3796a8c954a7 100644 --- a/packages/replay/test/integration/sendReplayEvent.test.ts +++ b/packages/replay/test/integration/sendReplayEvent.test.ts @@ -1,6 +1,7 @@ import * as SentryCore from '@sentry/core'; import type { Transport } from '@sentry/types'; import * as SentryUtils from '@sentry/utils'; +import { TextEncoder } from 'util'; import { DEFAULT_FLUSH_MIN_DELAY, SESSION_IDLE_DURATION, WINDOW } from '../../src/constants'; import type { ReplayContainer } from '../../src/replay'; @@ -27,6 +28,7 @@ describe('Integration | sendReplayEvent', () => { const { record: mockRecord } = mockRrweb(); beforeAll(async () => { + (global as any).TextEncoder = TextEncoder; jest.setSystemTime(new Date(BASE_TIMESTAMP)); jest.spyOn(SentryUtils, 'addInstrumentationHandler').mockImplementation((type, handler: (args: any) => any) => { if (type === 'dom') { diff --git a/packages/replay/test/integration/session.test.ts b/packages/replay/test/integration/session.test.ts index 0a8a79dc5467..b82ec443c4e2 100644 --- a/packages/replay/test/integration/session.test.ts +++ b/packages/replay/test/integration/session.test.ts @@ -1,5 +1,6 @@ import { getCurrentHub } from '@sentry/core'; import type { Transport } from '@sentry/types'; +import { TextEncoder } from 'util'; import { DEFAULT_FLUSH_MIN_DELAY, @@ -31,6 +32,10 @@ describe('Integration | session', () => { let domHandler: (args: any) => any; let mockRecord: RecordMock; + beforeAll(() => { + (global as any).TextEncoder = TextEncoder; + }); + beforeEach(async () => { ({ mockRecord, domHandler, replay } = await resetSdkMock({ replayOptions: { diff --git a/packages/replay/test/integration/stop.test.ts b/packages/replay/test/integration/stop.test.ts index 55f8dafd9289..adf82d18e8dd 100644 --- a/packages/replay/test/integration/stop.test.ts +++ b/packages/replay/test/integration/stop.test.ts @@ -1,4 +1,5 @@ import * as SentryUtils from '@sentry/utils'; +import { TextEncoder } from 'util'; import type { Replay } from '../../src'; import { SESSION_IDLE_DURATION, WINDOW } from '../../src/constants'; @@ -22,6 +23,7 @@ describe('Integration | stop', () => { let mockAddInstrumentationHandler: MockAddInstrumentationHandler; beforeAll(async () => { + (global as any).TextEncoder = TextEncoder; jest.setSystemTime(new Date(BASE_TIMESTAMP)); mockAddInstrumentationHandler = jest.spyOn( SentryUtils, diff --git a/packages/replay/test/unit/util/createReplayEnvelope.test.ts b/packages/replay/test/unit/util/createReplayEnvelope.test.ts index d0245d0d2f5f..687c65e5ca63 100644 --- a/packages/replay/test/unit/util/createReplayEnvelope.test.ts +++ b/packages/replay/test/unit/util/createReplayEnvelope.test.ts @@ -1,5 +1,6 @@ import type { ReplayEvent } from '@sentry/types'; import { makeDsn } from '@sentry/utils'; +import { TextEncoder } from 'util'; import { createReplayEnvelope } from '../../../src/util/createReplayEnvelope'; @@ -41,6 +42,10 @@ describe('Unit | util | createReplayEnvelope', () => { publicKey: 'abc', }); + beforeAll(() => { + (global as any).TextEncoder = TextEncoder; + }); + it('creates an envelope for a given Replay event', () => { const envelope = createReplayEnvelope(replayEvent, payloadWithSequence, dsn); From 65d5f888d103d6a3a50d09a7c46597de0ca1de0c Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 11 Jan 2023 17:25:00 -0500 Subject: [PATCH 4/8] ok just use textencoder directly --- packages/replay/src/util/createReplayEnvelope.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/replay/src/util/createReplayEnvelope.ts b/packages/replay/src/util/createReplayEnvelope.ts index 76fa9a4f4982..b897cec3ea18 100644 --- a/packages/replay/src/util/createReplayEnvelope.ts +++ b/packages/replay/src/util/createReplayEnvelope.ts @@ -1,5 +1,5 @@ import type { DsnComponents, ReplayEnvelope, ReplayEvent, ReplayRecordingData } from '@sentry/types'; -import { createEnvelope, createEventEnvelopeHeaders, encodeUTF8, getSdkMetadataForEnvelopeHeader } from '@sentry/utils'; +import { createEnvelope, createEventEnvelopeHeaders, getSdkMetadataForEnvelopeHeader } from '@sentry/utils'; /** * Create a replay envelope ready to be sent. @@ -21,7 +21,7 @@ export function createReplayEnvelope( // If string then we need to encode to UTF8, otherwise will have // wrong size. TextEncoder has similar browser support to // MutationObserver, although it does not accept IE11. - length: typeof recordingData === 'string' ? encodeUTF8(recordingData).length : recordingData.length, + length: typeof recordingData === 'string' ? new TextEncoder().encode(recordingData).length : recordingData.length, }, recordingData, ], From 97aa77c0f392701208885e0c2b531f9e3454a366 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 11 Jan 2023 17:25:29 -0500 Subject: [PATCH 5/8] revert export --- packages/utils/src/envelope.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/envelope.ts b/packages/utils/src/envelope.ts index 2a5d9f469a24..b5d315e1cd81 100644 --- a/packages/utils/src/envelope.ts +++ b/packages/utils/src/envelope.ts @@ -56,7 +56,7 @@ export function forEachEnvelopeItem( /** * Encode a string to UTF8. */ -export function encodeUTF8(input: string, textEncoder?: TextEncoderInternal): Uint8Array { +function encodeUTF8(input: string, textEncoder?: TextEncoderInternal): Uint8Array { const utf8 = textEncoder || new TextEncoder(); return utf8.encode(input); } From e9a8d98a35a97530cf9a6f93d25a595d0233c546 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 11 Jan 2023 17:43:53 -0500 Subject: [PATCH 6/8] prettier --- packages/replay/src/util/createReplayEnvelope.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/replay/src/util/createReplayEnvelope.ts b/packages/replay/src/util/createReplayEnvelope.ts index b897cec3ea18..de269fdf9905 100644 --- a/packages/replay/src/util/createReplayEnvelope.ts +++ b/packages/replay/src/util/createReplayEnvelope.ts @@ -21,7 +21,8 @@ export function createReplayEnvelope( // If string then we need to encode to UTF8, otherwise will have // wrong size. TextEncoder has similar browser support to // MutationObserver, although it does not accept IE11. - length: typeof recordingData === 'string' ? new TextEncoder().encode(recordingData).length : recordingData.length, + length: + typeof recordingData === 'string' ? new TextEncoder().encode(recordingData).length : recordingData.length, }, recordingData, ], From 9a76788c21abe2a264a6cdb021300a750f5b4b75 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 12 Jan 2023 11:12:11 -0500 Subject: [PATCH 7/8] Revert "fix integration tests, need to provide TextEncoder in global" This reverts commit 7157ef2797be3e6b22bcd75c55db67294fb65024. --- packages/replay/test/integration/autoSaveSession.test.ts | 5 ----- .../test/integration/coreHandlers/handleGlobalEvent.test.ts | 5 ----- packages/replay/test/integration/errorSampleRate.test.ts | 5 ----- packages/replay/test/integration/eventProcessors.test.ts | 5 ----- packages/replay/test/integration/events.test.ts | 2 -- packages/replay/test/integration/sendReplayEvent.test.ts | 2 -- packages/replay/test/integration/session.test.ts | 5 ----- packages/replay/test/integration/stop.test.ts | 2 -- packages/replay/test/unit/util/createReplayEnvelope.test.ts | 5 ----- 9 files changed, 36 deletions(-) diff --git a/packages/replay/test/integration/autoSaveSession.test.ts b/packages/replay/test/integration/autoSaveSession.test.ts index 280f59d7c17e..fb047e07bcc8 100644 --- a/packages/replay/test/integration/autoSaveSession.test.ts +++ b/packages/replay/test/integration/autoSaveSession.test.ts @@ -1,5 +1,4 @@ import { EventType } from 'rrweb'; -import { TextEncoder } from 'util'; import type { RecordingEvent } from '../../src/types'; import { addEvent } from '../../src/util/addEvent'; @@ -9,10 +8,6 @@ import { useFakeTimers } from '../utils/use-fake-timers'; useFakeTimers(); describe('Integration | autoSaveSession', () => { - beforeAll(() => { - (global as any).TextEncoder = TextEncoder; - }); - afterEach(() => { jest.clearAllMocks(); }); diff --git a/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts b/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts index 0ab7fbf641c0..a59dfe838051 100644 --- a/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts +++ b/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts @@ -1,6 +1,5 @@ import { getCurrentHub } from '@sentry/core'; import type { Event } from '@sentry/types'; -import { TextEncoder } from 'util'; import { REPLAY_EVENT_NAME } from '../../../src/constants'; import { handleGlobalEventListener } from '../../../src/coreHandlers/handleGlobalEvent'; @@ -18,10 +17,6 @@ useFakeTimers(); let replay: ReplayContainer; describe('Integration | coreHandlers | handleGlobalEvent', () => { - beforeAll(() => { - (global as any).TextEncoder = TextEncoder; - }); - beforeEach(async () => { ({ replay } = await resetSdkMock({ replayOptions: { diff --git a/packages/replay/test/integration/errorSampleRate.test.ts b/packages/replay/test/integration/errorSampleRate.test.ts index f6edd6fb6a38..2b52e6c7d96c 100644 --- a/packages/replay/test/integration/errorSampleRate.test.ts +++ b/packages/replay/test/integration/errorSampleRate.test.ts @@ -1,5 +1,4 @@ import { captureException } from '@sentry/core'; -import { TextEncoder } from 'util'; import { DEFAULT_FLUSH_MIN_DELAY, REPLAY_SESSION_KEY, VISIBILITY_CHANGE_TIMEOUT, WINDOW } from '../../src/constants'; import type { ReplayContainer } from '../../src/replay'; @@ -24,10 +23,6 @@ describe('Integration | errorSampleRate', () => { let mockRecord: RecordMock; let domHandler: DomHandler; - beforeAll(() => { - (global as any).TextEncoder = TextEncoder; - }); - beforeEach(async () => { ({ mockRecord, domHandler, replay } = await resetSdkMock({ replayOptions: { diff --git a/packages/replay/test/integration/eventProcessors.test.ts b/packages/replay/test/integration/eventProcessors.test.ts index ef2a7c5cbdf3..363c5f2d5a74 100644 --- a/packages/replay/test/integration/eventProcessors.test.ts +++ b/packages/replay/test/integration/eventProcessors.test.ts @@ -1,6 +1,5 @@ import { getCurrentHub } from '@sentry/core'; import type { Event, Hub, Scope } from '@sentry/types'; -import { TextEncoder } from 'util'; import { BASE_TIMESTAMP } from '..'; import { resetSdkMock } from '../mocks/resetSdkMock'; @@ -12,10 +11,6 @@ describe('Integration | eventProcessors', () => { let hub: Hub; let scope: Scope; - beforeAll(() => { - (global as any).TextEncoder = TextEncoder; - }); - beforeEach(() => { hub = getCurrentHub(); scope = hub.pushScope(); diff --git a/packages/replay/test/integration/events.test.ts b/packages/replay/test/integration/events.test.ts index 51f8eaa646ea..5168426dfd79 100644 --- a/packages/replay/test/integration/events.test.ts +++ b/packages/replay/test/integration/events.test.ts @@ -1,5 +1,4 @@ import { getCurrentHub } from '@sentry/core'; -import { TextEncoder } from 'util'; import { WINDOW } from '../../src/constants'; import type { ReplayContainer } from '../../src/replay'; @@ -25,7 +24,6 @@ describe('Integration | events', () => { const prevLocation = WINDOW.location; beforeAll(async () => { - (global as any).TextEncoder = TextEncoder; jest.setSystemTime(new Date(BASE_TIMESTAMP)); jest.runAllTimers(); }); diff --git a/packages/replay/test/integration/sendReplayEvent.test.ts b/packages/replay/test/integration/sendReplayEvent.test.ts index 3796a8c954a7..ec0106c1b946 100644 --- a/packages/replay/test/integration/sendReplayEvent.test.ts +++ b/packages/replay/test/integration/sendReplayEvent.test.ts @@ -1,7 +1,6 @@ import * as SentryCore from '@sentry/core'; import type { Transport } from '@sentry/types'; import * as SentryUtils from '@sentry/utils'; -import { TextEncoder } from 'util'; import { DEFAULT_FLUSH_MIN_DELAY, SESSION_IDLE_DURATION, WINDOW } from '../../src/constants'; import type { ReplayContainer } from '../../src/replay'; @@ -28,7 +27,6 @@ describe('Integration | sendReplayEvent', () => { const { record: mockRecord } = mockRrweb(); beforeAll(async () => { - (global as any).TextEncoder = TextEncoder; jest.setSystemTime(new Date(BASE_TIMESTAMP)); jest.spyOn(SentryUtils, 'addInstrumentationHandler').mockImplementation((type, handler: (args: any) => any) => { if (type === 'dom') { diff --git a/packages/replay/test/integration/session.test.ts b/packages/replay/test/integration/session.test.ts index b82ec443c4e2..0a8a79dc5467 100644 --- a/packages/replay/test/integration/session.test.ts +++ b/packages/replay/test/integration/session.test.ts @@ -1,6 +1,5 @@ import { getCurrentHub } from '@sentry/core'; import type { Transport } from '@sentry/types'; -import { TextEncoder } from 'util'; import { DEFAULT_FLUSH_MIN_DELAY, @@ -32,10 +31,6 @@ describe('Integration | session', () => { let domHandler: (args: any) => any; let mockRecord: RecordMock; - beforeAll(() => { - (global as any).TextEncoder = TextEncoder; - }); - beforeEach(async () => { ({ mockRecord, domHandler, replay } = await resetSdkMock({ replayOptions: { diff --git a/packages/replay/test/integration/stop.test.ts b/packages/replay/test/integration/stop.test.ts index adf82d18e8dd..55f8dafd9289 100644 --- a/packages/replay/test/integration/stop.test.ts +++ b/packages/replay/test/integration/stop.test.ts @@ -1,5 +1,4 @@ import * as SentryUtils from '@sentry/utils'; -import { TextEncoder } from 'util'; import type { Replay } from '../../src'; import { SESSION_IDLE_DURATION, WINDOW } from '../../src/constants'; @@ -23,7 +22,6 @@ describe('Integration | stop', () => { let mockAddInstrumentationHandler: MockAddInstrumentationHandler; beforeAll(async () => { - (global as any).TextEncoder = TextEncoder; jest.setSystemTime(new Date(BASE_TIMESTAMP)); mockAddInstrumentationHandler = jest.spyOn( SentryUtils, diff --git a/packages/replay/test/unit/util/createReplayEnvelope.test.ts b/packages/replay/test/unit/util/createReplayEnvelope.test.ts index 687c65e5ca63..d0245d0d2f5f 100644 --- a/packages/replay/test/unit/util/createReplayEnvelope.test.ts +++ b/packages/replay/test/unit/util/createReplayEnvelope.test.ts @@ -1,6 +1,5 @@ import type { ReplayEvent } from '@sentry/types'; import { makeDsn } from '@sentry/utils'; -import { TextEncoder } from 'util'; import { createReplayEnvelope } from '../../../src/util/createReplayEnvelope'; @@ -42,10 +41,6 @@ describe('Unit | util | createReplayEnvelope', () => { publicKey: 'abc', }); - beforeAll(() => { - (global as any).TextEncoder = TextEncoder; - }); - it('creates an envelope for a given Replay event', () => { const envelope = createReplayEnvelope(replayEvent, payloadWithSequence, dsn); From 129820f8ebbc5c3fa58ca4a429f0678caa0196de Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 12 Jan 2023 11:25:26 -0500 Subject: [PATCH 8/8] TextEncoder in global in jest setup --- packages/replay/jest.setup.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/replay/jest.setup.ts b/packages/replay/jest.setup.ts index 26f9ea346a0d..640deeccf777 100644 --- a/packages/replay/jest.setup.ts +++ b/packages/replay/jest.setup.ts @@ -1,12 +1,15 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { getCurrentHub } from '@sentry/core'; import type { ReplayRecordingData, Transport } from '@sentry/types'; +import {TextEncoder} from 'util'; import type { ReplayContainer, Session } from './src/types'; // @ts-ignore TS error, this is replaced in prod builds bc of rollup global.__SENTRY_REPLAY_VERSION__ = 'version:Test'; +(global as any).TextEncoder = TextEncoder; + type MockTransport = jest.MockedFunction; jest.mock('./src/util/isBrowser', () => {