diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a5f73684e0ff..9716113ce134 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -533,6 +533,8 @@ jobs: - bundle_es5_min - bundle_es6 - bundle_es6_min + - bundle_replay_es6 + - bundle_replay_es6_min tracing_only: - true - false diff --git a/CHANGELOG.md b/CHANGELOG.md index 451b3c828e26..56c5223e65e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +## 7.37.2 + +This release includes changes and fixes around text masking and blocking in Replay's `rrweb` dependency. See versions [1.102.0](https://github.com/getsentry/rrweb/releases/tag/1.102.0) and [1.103.0](https://github.com/getsentry/rrweb/releases/tag/1.103.0). + +- feat: Check `blockSelector` for blocking elements as well +- feat: With maskAllText, mask the attributes: placeholder, title, `aria-label` +- feat: fix masking on `textarea` +- feat: Add `maskAllText` option + +SDK Changes: + +- fix(replay): Fix svgs not getting unblocked (#7132) + ## 7.37.1 - fix(browser): Support `async` in stack frame urls (#7131) diff --git a/MIGRATION.md b/MIGRATION.md index 55987041e698..860cf9d38022 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -254,7 +254,7 @@ export function makeMyCustomTransport(options: BaseTransportOptions): Transport } // `createTransport` takes care of rate limiting and flushing - return createTransport({ bufferSize: options.bufferSize }, makeRequest); + return createTransport(options, makeRequest); } Sentry.init({ diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index e1e550e4b5c6..2c6aa55c6552 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -23,6 +23,8 @@ "test:bundle:es5:min": "PW_BUNDLE=bundle_es5_min yarn test", "test:bundle:es6": "PW_BUNDLE=bundle_es6 yarn test", "test:bundle:es6:min": "PW_BUNDLE=bundle_es6_min yarn test", + "test:bundle:replay:es6": "PW_BUNDLE=bundle_replay_es6 yarn test", + "test:bundle:replay:es6:min": "PW_BUNDLE=bundle_replay_es6_min yarn test", "test:cjs": "PW_BUNDLE=cjs yarn test", "test:esm": "PW_BUNDLE=esm yarn test", "test:ci": "playwright test ./suites --browser='all' --reporter='line'" diff --git a/packages/integration-tests/suites/replay/captureReplay/test.ts b/packages/integration-tests/suites/replay/captureReplay/test.ts index e1319c3d0d6b..0801f13101c4 100644 --- a/packages/integration-tests/suites/replay/captureReplay/test.ts +++ b/packages/integration-tests/suites/replay/captureReplay/test.ts @@ -4,11 +4,10 @@ import type { ReplayEvent } from '@sentry/types'; import { sentryTest } from '../../../utils/fixtures'; import { envelopeRequestParser } from '../../../utils/helpers'; -import { waitForReplayRequest } from '../../../utils/replayHelpers'; +import { shouldSkipReplayTest, waitForReplayRequest } from '../../../utils/replayHelpers'; sentryTest('should capture replays', async ({ getLocalTestPath, page }) => { - // Replay bundles are es6 only - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { + if (shouldSkipReplayTest()) { sentryTest.skip(); } diff --git a/packages/integration-tests/suites/replay/compression/init.js b/packages/integration-tests/suites/replay/compression/init.js index f20e4054e34f..639cf05628e4 100644 --- a/packages/integration-tests/suites/replay/compression/init.js +++ b/packages/integration-tests/suites/replay/compression/init.js @@ -1,8 +1,7 @@ import * as Sentry from '@sentry/browser'; -import { Replay } from '@sentry/replay'; window.Sentry = Sentry; -window.Replay = new Replay({ +window.Replay = new Sentry.Replay({ flushMinDelay: 500, flushMaxDelay: 500, useCompression: true, diff --git a/packages/integration-tests/suites/replay/compression/test.ts b/packages/integration-tests/suites/replay/compression/test.ts index e92d7f2dde40..d9a88a91a995 100644 --- a/packages/integration-tests/suites/replay/compression/test.ts +++ b/packages/integration-tests/suites/replay/compression/test.ts @@ -2,11 +2,15 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../utils/fixtures'; import { getExpectedReplayEvent } from '../../../utils/replayEventTemplates'; -import { getFullRecordingSnapshots, getReplayEvent, waitForReplayRequest } from '../../../utils/replayHelpers'; +import { + getFullRecordingSnapshots, + getReplayEvent, + shouldSkipReplayTest, + waitForReplayRequest, +} from '../../../utils/replayHelpers'; sentryTest('replay recording should be compressed by default', async ({ getLocalTestPath, page }) => { - // Replay bundles are es6 only - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { + if (shouldSkipReplayTest()) { sentryTest.skip(); } diff --git a/packages/integration-tests/suites/replay/customEvents/init.js b/packages/integration-tests/suites/replay/customEvents/init.js index f02e43c7235c..db6a0aa21821 100644 --- a/packages/integration-tests/suites/replay/customEvents/init.js +++ b/packages/integration-tests/suites/replay/customEvents/init.js @@ -1,8 +1,7 @@ import * as Sentry from '@sentry/browser'; -import { Replay } from '@sentry/replay'; window.Sentry = Sentry; -window.Replay = new Replay({ +window.Replay = new Sentry.Replay({ flushMinDelay: 500, flushMaxDelay: 500, useCompression: false, diff --git a/packages/integration-tests/suites/replay/customEvents/test.ts b/packages/integration-tests/suites/replay/customEvents/test.ts index ac900cfe0961..a317ea281e9b 100644 --- a/packages/integration-tests/suites/replay/customEvents/test.ts +++ b/packages/integration-tests/suites/replay/customEvents/test.ts @@ -10,13 +10,19 @@ import { expectedNavigationPerformanceSpan, getExpectedReplayEvent, } from '../../../utils/replayEventTemplates'; -import { getCustomRecordingEvents, getReplayEvent, waitForReplayRequest } from '../../../utils/replayHelpers'; +import { + getCustomRecordingEvents, + getReplayEvent, + shouldSkipReplayTest, + waitForReplayRequest, +} from '../../../utils/replayHelpers'; sentryTest( 'replay recording should contain default performance spans', async ({ getLocalTestPath, page, browserName }) => { - // Replay bundles are es6 only and most performance entries are only available in chromium - if ((process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) || browserName !== 'chromium') { + // We only test this against the NPM package and replay bundles + // and only on chromium as most performance entries are only available in chromium + if (shouldSkipReplayTest() || browserName !== 'chromium') { sentryTest.skip(); } @@ -68,8 +74,7 @@ sentryTest( sentryTest( 'replay recording should contain a click breadcrumb when a button is clicked', async ({ getLocalTestPath, page }) => { - // Replay bundles are es6 only - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { + if (shouldSkipReplayTest()) { sentryTest.skip(); } diff --git a/packages/integration-tests/suites/replay/errorResponse/test.ts b/packages/integration-tests/suites/replay/errorResponse/test.ts index 68b90697410c..d81d16196b8e 100644 --- a/packages/integration-tests/suites/replay/errorResponse/test.ts +++ b/packages/integration-tests/suites/replay/errorResponse/test.ts @@ -1,14 +1,17 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../utils/fixtures'; -import { getReplaySnapshot, REPLAY_DEFAULT_FLUSH_MAX_DELAY, waitForReplayRequest } from '../../../utils/replayHelpers'; +import { + getReplaySnapshot, + REPLAY_DEFAULT_FLUSH_MAX_DELAY, + shouldSkipReplayTest, + waitForReplayRequest, +} from '../../../utils/replayHelpers'; sentryTest('should stop recording after receiving an error response', async ({ getLocalTestPath, page }) => { - // Currently bundle tests are not supported for replay - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { + if (shouldSkipReplayTest()) { sentryTest.skip(); } - let called = 0; await page.route('https://dsn.ingest.sentry.io/**/*', route => { diff --git a/packages/integration-tests/suites/replay/init.js b/packages/integration-tests/suites/replay/init.js index 16b46e3adc54..7a0337445768 100644 --- a/packages/integration-tests/suites/replay/init.js +++ b/packages/integration-tests/suites/replay/init.js @@ -1,8 +1,7 @@ import * as Sentry from '@sentry/browser'; -import { Replay } from '@sentry/replay'; window.Sentry = Sentry; -window.Replay = new Replay({ +window.Replay = new Sentry.Replay({ flushMinDelay: 200, flushMaxDelay: 200, }); diff --git a/packages/integration-tests/suites/replay/privacy/template.html b/packages/integration-tests/suites/replay/privacy/template.html index aa916d3f116e..a61532e6ae68 100644 --- a/packages/integration-tests/suites/replay/privacy/template.html +++ b/packages/integration-tests/suites/replay/privacy/template.html @@ -7,8 +7,8 @@
This should be unmasked due to data attribute
Title should be masked
- - + + diff --git a/packages/integration-tests/suites/replay/privacy/test.ts b/packages/integration-tests/suites/replay/privacy/test.ts index 3ad8ee5684fb..2c2b1f9b8070 100644 --- a/packages/integration-tests/suites/replay/privacy/test.ts +++ b/packages/integration-tests/suites/replay/privacy/test.ts @@ -4,11 +4,10 @@ import type { RecordingEvent } from '@sentry/replay/build/npm/types/types'; import { sentryTest } from '../../../utils/fixtures'; import { envelopeRequestParser } from '../../../utils/helpers'; -import { waitForReplayRequest } from '../../../utils/replayHelpers'; +import { shouldSkipReplayTest, waitForReplayRequest } from '../../../utils/replayHelpers'; sentryTest('should have the correct default privacy settings', async ({ getLocalTestPath, page }) => { - // Replay bundles are es6 only - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { + if (shouldSkipReplayTest()) { sentryTest.skip(); } @@ -80,7 +79,7 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal type: 2, tagName: 'button', attributes: { - 'aria-label': 'Click me', + 'aria-label': '***** **', onclick: "console.log('Test log')", }, childNodes: [ @@ -139,7 +138,7 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal type: 2, tagName: 'input', attributes: { - placeholder: 'Placeholder should be masked', + placeholder: '*********** ****** ** ******', }, childNodes: [], id: 18, @@ -153,7 +152,7 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal type: 2, tagName: 'div', attributes: { - title: 'Title should be masked', + title: '***** ****** ** ******', }, childNodes: [ { @@ -190,7 +189,6 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal tagName: 'svg', attributes: { style: 'width:200px;height:200px', - class: 'sentry-unblock', viewBox: '0 0 80 80', 'data-sentry-unblock': '', }, @@ -199,13 +197,28 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal type: 2, tagName: 'path', attributes: { - rr_width: '0px', - rr_height: '0px', + d: '', }, childNodes: [], isSVG: true, id: 26, }, + { + type: 2, + tagName: 'area', + attributes: {}, + childNodes: [], + isSVG: true, + id: 27, + }, + { + type: 2, + tagName: 'rect', + attributes: {}, + childNodes: [], + isSVG: true, + id: 28, + }, ], isSVG: true, id: 25, @@ -213,7 +226,7 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal { type: 3, textContent: '\n ', - id: 27, + id: 29, }, { type: 2, @@ -223,12 +236,12 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal rr_height: '100px', }, childNodes: [], - id: 28, + id: 30, }, { type: 3, textContent: '\n ', - id: 29, + id: 31, }, { type: 2, @@ -239,17 +252,17 @@ sentryTest('should have the correct default privacy settings', async ({ getLocal src: 'file:///none.png', }, childNodes: [], - id: 30, + id: 32, }, { type: 3, textContent: '\n ', - id: 31, + id: 33, }, { type: 3, textContent: '\n\n', - id: 32, + id: 34, }, ], id: 7, diff --git a/packages/integration-tests/suites/replay/sampling/init.js b/packages/integration-tests/suites/replay/sampling/init.js index 92a9fb51b959..9e99c3536d05 100644 --- a/packages/integration-tests/suites/replay/sampling/init.js +++ b/packages/integration-tests/suites/replay/sampling/init.js @@ -1,8 +1,7 @@ import * as Sentry from '@sentry/browser'; -import { Replay } from '@sentry/replay'; window.Sentry = Sentry; -window.Replay = new Replay({ +window.Replay = new Sentry.Replay({ flushMinDelay: 200, flushMaxDelay: 200, }); diff --git a/packages/integration-tests/suites/replay/sampling/test.ts b/packages/integration-tests/suites/replay/sampling/test.ts index f1afa573551a..3475669a2a00 100644 --- a/packages/integration-tests/suites/replay/sampling/test.ts +++ b/packages/integration-tests/suites/replay/sampling/test.ts @@ -1,11 +1,10 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../utils/fixtures'; -import { getReplaySnapshot } from '../../../utils/replayHelpers'; +import { getReplaySnapshot, shouldSkipReplayTest } from '../../../utils/replayHelpers'; sentryTest('should not send replays if both sample rates are 0', async ({ getLocalTestPath, page }) => { - // Replay bundles are es6 only - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { + if (shouldSkipReplayTest()) { sentryTest.skip(); } diff --git a/packages/integration-tests/utils/generatePlugin.ts b/packages/integration-tests/utils/generatePlugin.ts index 4c8d4bd9471e..d7f57007d5c8 100644 --- a/packages/integration-tests/utils/generatePlugin.ts +++ b/packages/integration-tests/utils/generatePlugin.ts @@ -7,6 +7,7 @@ import type { Compiler } from 'webpack'; const PACKAGES_DIR = '../../packages'; const tracingOnly = process.env.PW_TRACING_ONLY === 'true'; + const bundleKey = process.env.PW_BUNDLE; // `esm` and `cjs` builds are modules that can be imported / aliased by webpack @@ -23,6 +24,8 @@ const BUNDLE_PATHS: Record> = { bundle_es5_min: 'build/bundles/bundle.es5.min.js', bundle_es6: 'build/bundles/bundle.js', bundle_es6_min: 'build/bundles/bundle.min.js', + bundle_replay_es6: 'build/bundles/bundle.replay.js', + bundle_replay_es6_min: 'build/bundles/bundle.replay.min.js', }, tracing: { cjs: 'build/npm/cjs/index.js', @@ -31,6 +34,8 @@ const BUNDLE_PATHS: Record> = { bundle_es5_min: 'build/bundles/bundle.tracing.es5.min.js', bundle_es6: 'build/bundles/bundle.tracing.js', bundle_es6_min: 'build/bundles/bundle.tracing.min.js', + bundle_replay_es6: 'build/bundles/bundle.tracing.replay.js', + bundle_replay_es6_min: 'build/bundles/bundle.tracing.replay.min.js', }, integrations: { cjs: 'build/npm/cjs/index.js', @@ -39,12 +44,8 @@ const BUNDLE_PATHS: Record> = { bundle_es5_min: 'build/bundles/[INTEGRATION_NAME].es5.min.js', bundle_es6: 'build/bundles/[INTEGRATION_NAME].js', bundle_es6_min: 'build/bundles/[INTEGRATION_NAME].min.js', - }, - replay: { - cjs: 'build/npm/cjs/index.js', - esm: 'build/npm/esm/index.js', - bundle_es6: 'build/bundles/replay.js', - bundle_es6_min: 'build/bundles/replay.min.js', + bundle_replay_es6: 'build/bundles/[INTEGRATION_NAME].js', + bundle_replay_es6_min: 'build/bundles/[INTEGRATION_NAME].min.js', }, }; @@ -93,7 +94,6 @@ function generateSentryAlias(): Record { class SentryScenarioGenerationPlugin { public requiresTracing: boolean = false; public requiredIntegrations: string[] = []; - public requiresReplay = false; private _name: string = 'SentryScenarioGenerationPlugin'; @@ -106,7 +106,7 @@ class SentryScenarioGenerationPlugin { '@sentry/browser': 'Sentry', '@sentry/tracing': 'Sentry', '@sentry/integrations': 'Sentry.Integrations', - '@sentry/replay': 'Sentry.Integrations', + '@sentry/replay': 'Sentry', } : {}; @@ -121,8 +121,6 @@ class SentryScenarioGenerationPlugin { this.requiresTracing = true; } else if (source === '@sentry/integrations') { this.requiredIntegrations.push(statement.specifiers[0].imported.name.toLowerCase()); - } else if (source === '@sentry/replay') { - this.requiresReplay = true; } }, ); @@ -150,14 +148,6 @@ class SentryScenarioGenerationPlugin { data.assetTags.scripts.unshift(integrationObject); }); - if (this.requiresReplay && BUNDLE_PATHS['replay'][bundleKey]) { - const replayObject = createHtmlTagObject('script', { - src: path.resolve(PACKAGES_DIR, 'replay', BUNDLE_PATHS['replay'][bundleKey]), - }); - - data.assetTags.scripts.unshift(replayObject); - } - data.assetTags.scripts.unshift(bundleObject); } diff --git a/packages/integration-tests/utils/replayHelpers.ts b/packages/integration-tests/utils/replayHelpers.ts index b133ee1a3fe7..11a4131e6753 100644 --- a/packages/integration-tests/utils/replayHelpers.ts +++ b/packages/integration-tests/utils/replayHelpers.ts @@ -177,3 +177,15 @@ const replayEnvelopeParser = (request: Request | null): unknown[] => { return lines; }; + +/** + * We can only test replay tests in certain bundles/packages: + * - NPM (ESM, CJS) + * - CDN bundles that contain the Replay integration + * + * @returns `true` if we should skip the replay test + */ +export function shouldSkipReplayTest(): boolean { + const bundle = process.env.PW_BUNDLE as string | undefined; + return bundle != null && !bundle.includes('replay') && !bundle.includes('esm') && !bundle.includes('cjs'); +} diff --git a/packages/replay/package.json b/packages/replay/package.json index ed46cd620849..49b46a6055e2 100644 --- a/packages/replay/package.json +++ b/packages/replay/package.json @@ -46,7 +46,7 @@ "homepage": "https://docs.sentry.io/platforms/javascript/session-replay/", "devDependencies": { "@babel/core": "^7.17.5", - "@sentry-internal/rrweb": "1.101.2", + "@sentry-internal/rrweb": "1.103.0", "@types/pako": "^2.0.0", "jsdom-worker": "^0.2.1", "pako": "^2.0.4", diff --git a/packages/replay/src/constants.ts b/packages/replay/src/constants.ts index 434c64158cb4..87bf1823b056 100644 --- a/packages/replay/src/constants.ts +++ b/packages/replay/src/constants.ts @@ -20,9 +20,6 @@ export const VISIBILITY_CHANGE_TIMEOUT = SESSION_IDLE_DURATION; // The maximum length of a session export const MAX_SESSION_LIFE = 3_600_000; // 60 minutes -/** The select to use for the `maskAllText` option */ -export const MASK_ALL_TEXT_SELECTOR = 'body *:not(style), body *:not(script)'; - /** Default flush delays */ export const DEFAULT_FLUSH_MIN_DELAY = 5_000; export const DEFAULT_FLUSH_MAX_DELAY = 5_000; diff --git a/packages/replay/src/integration.ts b/packages/replay/src/integration.ts index d7c67b403f77..7d55c555042a 100644 --- a/packages/replay/src/integration.ts +++ b/packages/replay/src/integration.ts @@ -2,13 +2,13 @@ import { getCurrentHub } from '@sentry/core'; import type { BrowserClientReplayOptions, Integration } from '@sentry/types'; import { dropUndefinedKeys } from '@sentry/utils'; -import { DEFAULT_FLUSH_MAX_DELAY, DEFAULT_FLUSH_MIN_DELAY, MASK_ALL_TEXT_SELECTOR } from './constants'; +import { DEFAULT_FLUSH_MAX_DELAY, DEFAULT_FLUSH_MIN_DELAY } from './constants'; import { ReplayContainer } from './replay'; import type { RecordingOptions, ReplayConfiguration, ReplayPluginOptions } from './types'; import { getPrivacyOptions } from './util/getPrivacyOptions'; import { isBrowser } from './util/isBrowser'; -const MEDIA_SELECTORS = 'img,image,svg,path,rect,area,video,object,picture,embed,map,audio'; +const MEDIA_SELECTORS = 'img,image,svg,video,object,picture,embed,map,audio'; let _initialized = false; @@ -53,7 +53,7 @@ export class Replay implements Integration { _experiments = {}, sessionSampleRate, errorSampleRate, - maskAllText, + maskAllText = true, maskAllInputs = true, blockAllMedia = true, @@ -79,6 +79,7 @@ export class Replay implements Integration { }: ReplayConfiguration = {}) { this._recordingOptions = { maskAllInputs, + maskAllText, maskInputOptions: { ...(maskInputOptions || {}), password: true }, maskTextFn: maskFn, maskInputFn: maskFn, @@ -113,7 +114,6 @@ export class Replay implements Integration { sessionSampleRate, errorSampleRate, useCompression, - maskAllText: typeof maskAllText === 'boolean' ? maskAllText : !maskTextSelector, blockAllMedia, _experiments, }; @@ -142,13 +142,6 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`, this._initialOptions.errorSampleRate = errorSampleRate; } - if (this._initialOptions.maskAllText) { - // `maskAllText` is a more user friendly option to configure - // `maskTextSelector`. This means that all nodes will have their text - // content masked. - this._recordingOptions.maskTextSelector = MASK_ALL_TEXT_SELECTOR; - } - if (this._initialOptions.blockAllMedia) { // `blockAllMedia` is a more user friendly option to configure blocking // embedded media elements diff --git a/packages/replay/src/types.ts b/packages/replay/src/types.ts index 136ce1e526a3..27c878a3edba 100644 --- a/packages/replay/src/types.ts +++ b/packages/replay/src/types.ts @@ -90,11 +90,6 @@ export interface ReplayPluginOptions extends SessionOptions { */ useCompression: boolean; - /** - * Mask all text in recordings. All text will be replaced with asterisks by default. - */ - maskAllText: boolean; - /** * Block all media (e.g. images, svg, video) in recordings. */ @@ -180,7 +175,7 @@ export interface ReplayConfiguration extends ReplayIntegrationPrivacyOptions, OptionalReplayPluginOptions, DeprecatedPrivacyOptions, - Pick {} + Pick {} interface CommonEventContext { /** diff --git a/packages/replay/src/types/rrweb.ts b/packages/replay/src/types/rrweb.ts index 3628d45ef9ab..7a794face4cb 100644 --- a/packages/replay/src/types/rrweb.ts +++ b/packages/replay/src/types/rrweb.ts @@ -30,6 +30,7 @@ export type eventWithTime = { * Record union type. */ export type recordOptions = { + maskAllText?: boolean; maskAllInputs?: boolean; blockClass?: blockClass; ignoreClass?: string; diff --git a/packages/replay/test/integration/integrationSettings.test.ts b/packages/replay/test/integration/integrationSettings.test.ts index dd23b1a4cfdb..d0f75afdb285 100644 --- a/packages/replay/test/integration/integrationSettings.test.ts +++ b/packages/replay/test/integration/integrationSettings.test.ts @@ -1,4 +1,3 @@ -import { MASK_ALL_TEXT_SELECTOR } from '../../src/constants'; import { mockSdk } from '../index'; describe('Integration | integrationSettings', () => { @@ -17,7 +16,7 @@ describe('Integration | integrationSettings', () => { const { replay } = await mockSdk({ replayOptions: { blockSelector: '' } }); expect(replay['_recordingOptions'].blockSelector).toMatchInlineSnapshot( - '",.sentry-block,[data-sentry-block],img,image,svg,path,rect,area,video,object,picture,embed,map,audio"', + '",.sentry-block,[data-sentry-block],img,image,svg,video,object,picture,embed,map,audio"', ); }); @@ -27,7 +26,7 @@ describe('Integration | integrationSettings', () => { }); expect(replay['_recordingOptions'].blockSelector).toMatchInlineSnapshot( - '"[data-test-blockSelector],.sentry-block,[data-sentry-block],img,image,svg,path,rect,area,video,object,picture,embed,map,audio"', + '"[data-test-blockSelector],.sentry-block,[data-sentry-block],img,image,svg,video,object,picture,embed,map,audio"', ); }); }); @@ -191,33 +190,28 @@ describe('Integration | integrationSettings', () => { it('works with default value', async () => { const { replay } = await mockSdk({ replayOptions: {} }); - // Default is true - expect(replay['_recordingOptions'].maskTextSelector).toBe(MASK_ALL_TEXT_SELECTOR); + expect(replay['_recordingOptions'].maskAllText).toBe(true); }); it('works with true', async () => { const { replay } = await mockSdk({ replayOptions: { maskAllText: true } }); - expect(replay['_recordingOptions'].maskTextSelector).toBe(MASK_ALL_TEXT_SELECTOR); + expect(replay['_recordingOptions'].maskAllText).toBe(true); }); it('works with false', async () => { const { replay } = await mockSdk({ replayOptions: { maskAllText: false } }); - expect(replay['_recordingOptions'].maskTextSelector).toBe('.sentry-mask,[data-sentry-mask]'); + expect(replay['_recordingOptions'].maskAllText).toBe(false); }); + }); - it('maskTextSelector takes precedence over maskAllText when not specifiying maskAllText:true', async () => { + describe('maskTextSelector', () => { + it('can have custom mask selector', async () => { const { replay } = await mockSdk({ replayOptions: { maskTextSelector: '[custom]' } }); expect(replay['_recordingOptions'].maskTextSelector).toBe('[custom],.sentry-mask,[data-sentry-mask]'); }); - - it('maskAllText takes precedence over maskTextSelector when specifiying maskAllText:true', async () => { - const { replay } = await mockSdk({ replayOptions: { maskAllText: true, maskTextSelector: '[custom]' } }); - - expect(replay['_recordingOptions'].maskTextSelector).toBe(MASK_ALL_TEXT_SELECTOR); - }); }); describe('_experiments', () => { diff --git a/packages/replay/test/integration/rrweb.test.ts b/packages/replay/test/integration/rrweb.test.ts index 00e1fb09af97..05d46c93193e 100644 --- a/packages/replay/test/integration/rrweb.test.ts +++ b/packages/replay/test/integration/rrweb.test.ts @@ -17,20 +17,21 @@ describe('Integration | rrweb', () => { }); expect(mockRecord.mock.calls[0][0]).toMatchInlineSnapshot(` Object { - "blockSelector": ".sentry-block,[data-sentry-block],img,image,svg,path,rect,area,video,object,picture,embed,map,audio", + "blockSelector": ".sentry-block,[data-sentry-block],img,image,svg,video,object,picture,embed,map,audio", "collectFonts": true, "emit": [Function], "ignoreSelector": ".sentry-test-ignore,.sentry-ignore,[data-sentry-ignore]", "inlineImages": false, "inlineStylesheet": true, "maskAllInputs": true, + "maskAllText": true, "maskInputFn": undefined, "maskInputOptions": Object { "password": true, }, "maskInputSelector": ".sentry-mask,[data-sentry-mask]", "maskTextFn": undefined, - "maskTextSelector": "body *:not(style), body *:not(script)", + "maskTextSelector": ".sentry-mask,[data-sentry-mask]", "slimDOMOptions": "all", "unblockSelector": ".sentry-unblock,[data-sentry-unblock]", "unmaskInputSelector": ".sentry-unmask,[data-sentry-unmask]", diff --git a/packages/replay/test/utils/setupReplayContainer.ts b/packages/replay/test/utils/setupReplayContainer.ts index fd6a5baa40e0..15eaa47d5736 100644 --- a/packages/replay/test/utils/setupReplayContainer.ts +++ b/packages/replay/test/utils/setupReplayContainer.ts @@ -16,12 +16,12 @@ export function setupReplayContainer({ sessionSampleRate: 0, errorSampleRate: 1, useCompression: false, - maskAllText: true, blockAllMedia: true, _experiments: {}, ...options, }, recordingOptions: { + maskAllText: true, ...recordingOptions, }, }); diff --git a/yarn.lock b/yarn.lock index 8fb259ed02e0..38ba0892b21e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3158,17 +3158,17 @@ semver "7.3.2" semver-intersect "1.4.0" -"@sentry-internal/rrweb-snapshot@1.101.2": - version "1.101.2" - resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-snapshot/-/rrweb-snapshot-1.101.2.tgz#cf73629374812f110ab7271f9da65f1afc6c08c3" - integrity sha512-wbc/lQ4ta7zXZGFU3sFfTz8PVcfOTeI2H2l2bo4BehZiQEEDTrqhGSFe5Nzq6Noi38CZyPT0kweGI4fUk1u0KQ== +"@sentry-internal/rrweb-snapshot@1.103.0": + version "1.103.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb-snapshot/-/rrweb-snapshot-1.103.0.tgz#afabe3d5c729a82a65b896e45018d50ee896fd74" + integrity sha512-YE0RlQh/bvVr3LcYgMhs5FJ4VUMpVZPUT/IqDVN+rZ4be2ARAn9z50skA26RyO/z6IXiIi8i6YacP8gGTOyFJg== -"@sentry-internal/rrweb@1.101.2": - version "1.101.2" - resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb/-/rrweb-1.101.2.tgz#65e5d80745e1c01c2f66031fb807b36837283944" - integrity sha512-IaDgoo9kxnwC6xn25yLU0ymKLVBAWGEH90iMdweTC7Izhza6k4oTy01t4/wy7ORCnfCeHZYJ4gkNJJyi4J1XHQ== +"@sentry-internal/rrweb@1.103.0": + version "1.103.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/rrweb/-/rrweb-1.103.0.tgz#c702be1616e9391e1dde2b0549a6038438e7bbf7" + integrity sha512-F9RfDbbjM1oddUX6jcfuv4n8jpZG5fsHvzIjT4z+KxBa8V09G9Nz/8wuDrIg0Cgb54wTRAbyyAKOexvzoZ8SKA== dependencies: - "@sentry-internal/rrweb-snapshot" "1.101.2" + "@sentry-internal/rrweb-snapshot" "1.103.0" "@types/css-font-loading-module" "0.0.7" "@xstate/fsm" "^1.4.0" base64-arraybuffer "^1.0.1"