From 88f98fd7f7dba8191f53c381d765525b76bdbf60 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 16 Mar 2023 14:11:43 +0100 Subject: [PATCH 1/2] fix(replay): Never capture file input changes --- .../suites/replay/fileInput/init.js | 19 +++++++ .../suites/replay/fileInput/template.html | 9 ++++ .../suites/replay/fileInput/test.ts | 54 +++++++++++++++++++ packages/replay/src/util/getPrivacyOptions.ts | 2 +- .../replay/test/integration/rrweb.test.ts | 2 +- .../test/unit/util/getPrivacyOptions.test.ts | 6 +-- 6 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 packages/browser-integration-tests/suites/replay/fileInput/init.js create mode 100644 packages/browser-integration-tests/suites/replay/fileInput/template.html create mode 100644 packages/browser-integration-tests/suites/replay/fileInput/test.ts diff --git a/packages/browser-integration-tests/suites/replay/fileInput/init.js b/packages/browser-integration-tests/suites/replay/fileInput/init.js new file mode 100644 index 000000000000..a09c517b6a92 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/fileInput/init.js @@ -0,0 +1,19 @@ +import * as Sentry from '@sentry/browser'; +import { Replay } from '@sentry/replay'; + +window.Sentry = Sentry; +window.Replay = new Replay({ + flushMinDelay: 200, + flushMaxDelay: 200, + useCompression: false, + maskAllInputs: false, +}); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 0, + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + + integrations: [window.Replay], +}); diff --git a/packages/browser-integration-tests/suites/replay/fileInput/template.html b/packages/browser-integration-tests/suites/replay/fileInput/template.html new file mode 100644 index 000000000000..eb183083d872 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/fileInput/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/browser-integration-tests/suites/replay/fileInput/test.ts b/packages/browser-integration-tests/suites/replay/fileInput/test.ts new file mode 100644 index 000000000000..660f5ebb1f32 --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/fileInput/test.ts @@ -0,0 +1,54 @@ +import { expect } from '@playwright/test'; +import { IncrementalSource } from '@sentry-internal/rrweb'; +import type { inputData } from '@sentry-internal/rrweb/typings/types'; + +import { sentryTest } from '../../../utils/fixtures'; +import type { IncrementalRecordingSnapshot } from '../../../utils/replayHelpers'; +import { + getIncrementalRecordingSnapshots, + shouldSkipReplayTest, + waitForReplayRequest, +} from '../../../utils/replayHelpers'; + +function isInputMutation( + snap: IncrementalRecordingSnapshot, +): snap is IncrementalRecordingSnapshot & { data: inputData } { + return snap.data.source == IncrementalSource.Input; +} + +sentryTest('should not capture file input mutations', async ({ forceFlushReplay, getLocalTestPath, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + const reqPromise1 = waitForReplayRequest(page, 1); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestPath({ testDir: __dirname }); + + await page.goto(url); + + await reqPromise0; + + await page.setInputFiles('#file-input', { + name: 'file.csv', + mimeType: 'text/csv', + buffer: Buffer.from('this,is,test'), + }); + + await forceFlushReplay(); + + const res1 = await reqPromise1; + + const snapshots = getIncrementalRecordingSnapshots(res1).filter(isInputMutation); + + expect(snapshots).toEqual([]); +}); diff --git a/packages/replay/src/util/getPrivacyOptions.ts b/packages/replay/src/util/getPrivacyOptions.ts index a8655bdf76af..a2aec1dcdb9d 100644 --- a/packages/replay/src/util/getPrivacyOptions.ts +++ b/packages/replay/src/util/getPrivacyOptions.ts @@ -88,7 +88,7 @@ export function getPrivacyOptions({ blockSelector, ), unblockSelector: getOption(unblock, ['.sentry-unblock', '[data-sentry-unblock]']), - ignoreSelector: getOption(ignore, ['.sentry-ignore', '[data-sentry-ignore]'], ignoreClass), + ignoreSelector: getOption(ignore, ['.sentry-ignore', '[data-sentry-ignore]', 'input[type="file"]'], ignoreClass), }; if (blockClass instanceof RegExp) { diff --git a/packages/replay/test/integration/rrweb.test.ts b/packages/replay/test/integration/rrweb.test.ts index 3e37df5f2910..cc40061b4a3d 100644 --- a/packages/replay/test/integration/rrweb.test.ts +++ b/packages/replay/test/integration/rrweb.test.ts @@ -20,7 +20,7 @@ describe('Integration | rrweb', () => { "blockSelector": ".sentry-block,[data-sentry-block],base[href=\\"/\\"],img,image,svg,video,object,picture,embed,map,audio,link[rel=\\"icon\\"],link[rel=\\"apple-touch-icon\\"]", "collectFonts": true, "emit": [Function], - "ignoreSelector": ".sentry-test-ignore,.sentry-ignore,[data-sentry-ignore]", + "ignoreSelector": ".sentry-test-ignore,.sentry-ignore,[data-sentry-ignore],input[type=\\"file\\"]", "inlineImages": false, "inlineStylesheet": true, "maskAllInputs": true, diff --git a/packages/replay/test/unit/util/getPrivacyOptions.test.ts b/packages/replay/test/unit/util/getPrivacyOptions.test.ts index 3f13f6410a35..27cf839fdd3b 100644 --- a/packages/replay/test/unit/util/getPrivacyOptions.test.ts +++ b/packages/replay/test/unit/util/getPrivacyOptions.test.ts @@ -20,7 +20,7 @@ describe('Unit | util | getPrivacyOptions', () => { ).toMatchInlineSnapshot(` Object { "blockSelector": ".custom-block,.sentry-block,[data-sentry-block],base[href=\\"/\\"]", - "ignoreSelector": ".custom-ignore,.sentry-ignore,[data-sentry-ignore]", + "ignoreSelector": ".custom-ignore,.sentry-ignore,[data-sentry-ignore],input[type=\\"file\\"]", "maskInputSelector": ".custom-mask,.sentry-mask,[data-sentry-mask]", "maskTextSelector": ".custom-mask,.sentry-mask,[data-sentry-mask]", "unblockSelector": ".custom-unblock,.sentry-unblock,[data-sentry-unblock]", @@ -48,7 +48,7 @@ describe('Unit | util | getPrivacyOptions', () => { ).toMatchInlineSnapshot(` Object { "blockSelector": ".custom-block,.deprecated-block-selector,.sentry-block,[data-sentry-block],base[href=\\"/\\"],.deprecated-block-class", - "ignoreSelector": ".custom-ignore,.sentry-ignore,[data-sentry-ignore],.deprecated-ignore-class", + "ignoreSelector": ".custom-ignore,.sentry-ignore,[data-sentry-ignore],input[type=\\"file\\"],.deprecated-ignore-class", "maskInputSelector": ".custom-mask,.deprecated-mask-selector,.sentry-mask,[data-sentry-mask],.deprecated-mask-class", "maskTextSelector": ".custom-mask,.deprecated-mask-selector,.sentry-mask,[data-sentry-mask],.deprecated-mask-class", "unblockSelector": ".custom-unblock,.sentry-unblock,[data-sentry-unblock]", @@ -74,7 +74,7 @@ describe('Unit | util | getPrivacyOptions', () => { Object { "blockClass": /deprecated-block-\\*/, "blockSelector": ".custom-block,.sentry-block,[data-sentry-block],base[href=\\"/\\"]", - "ignoreSelector": ".custom-ignore,.sentry-ignore,[data-sentry-ignore]", + "ignoreSelector": ".custom-ignore,.sentry-ignore,[data-sentry-ignore],input[type=\\"file\\"]", "maskInputSelector": ".custom-mask,.sentry-mask,[data-sentry-mask]", "maskTextClass": /deprecated-mask-\\*/, "maskTextSelector": ".custom-mask,.sentry-mask,[data-sentry-mask]", From 7ae28fe8cb208e0ac3622313dbbff78ad5a77785 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 17 Mar 2023 08:58:09 +0100 Subject: [PATCH 2/2] skip test on webkit --- .../suites/replay/fileInput/test.ts | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/packages/browser-integration-tests/suites/replay/fileInput/test.ts b/packages/browser-integration-tests/suites/replay/fileInput/test.ts index 660f5ebb1f32..685c626ec470 100644 --- a/packages/browser-integration-tests/suites/replay/fileInput/test.ts +++ b/packages/browser-integration-tests/suites/replay/fileInput/test.ts @@ -16,39 +16,43 @@ function isInputMutation( return snap.data.source == IncrementalSource.Input; } -sentryTest('should not capture file input mutations', async ({ forceFlushReplay, getLocalTestPath, page }) => { - if (shouldSkipReplayTest()) { - sentryTest.skip(); - } - - const reqPromise0 = waitForReplayRequest(page, 0); - const reqPromise1 = waitForReplayRequest(page, 1); - - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), +sentryTest( + 'should not capture file input mutations', + async ({ forceFlushReplay, getLocalTestPath, page, browserName }) => { + // This seems to be flaky on webkit, so skipping there + if (shouldSkipReplayTest() || browserName === 'webkit') { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + const reqPromise1 = waitForReplayRequest(page, 1); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); }); - }); - const url = await getLocalTestPath({ testDir: __dirname }); + const url = await getLocalTestPath({ testDir: __dirname }); - await page.goto(url); + await page.goto(url); - await reqPromise0; + await reqPromise0; - await page.setInputFiles('#file-input', { - name: 'file.csv', - mimeType: 'text/csv', - buffer: Buffer.from('this,is,test'), - }); + await page.setInputFiles('#file-input', { + name: 'file.csv', + mimeType: 'text/csv', + buffer: Buffer.from('this,is,test'), + }); - await forceFlushReplay(); + await forceFlushReplay(); - const res1 = await reqPromise1; + const res1 = await reqPromise1; - const snapshots = getIncrementalRecordingSnapshots(res1).filter(isInputMutation); + const snapshots = getIncrementalRecordingSnapshots(res1).filter(isInputMutation); - expect(snapshots).toEqual([]); -}); + expect(snapshots).toEqual([]); + }, +);