diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 9285725cd791..3e9ce04dc91e 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -28,7 +28,7 @@ "test:cjs": "PW_BUNDLE=cjs yarn test", "test:esm": "PW_BUNDLE=esm yarn test", "test:ci": "playwright test ./suites --browser='all' --reporter='line'", - "test:update-snapshots": "yarn test --update-snapshots --browser='all'" + "test:update-snapshots": "yarn test --update-snapshots --browser='all' && yarn test --update-snapshots" }, "dependencies": { "@babel/preset-typescript": "^7.16.7", diff --git a/packages/integration-tests/suites/replay/flushing/init.js b/packages/integration-tests/suites/replay/flushing/init.js new file mode 100644 index 000000000000..f64b8fff4e50 --- /dev/null +++ b/packages/integration-tests/suites/replay/flushing/init.js @@ -0,0 +1,16 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 500, + flushMaxDelay: 500, +}); + +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/integration-tests/suites/replay/flushing/subject.js b/packages/integration-tests/suites/replay/flushing/subject.js new file mode 100644 index 000000000000..7aa69584f070 --- /dev/null +++ b/packages/integration-tests/suites/replay/flushing/subject.js @@ -0,0 +1,6 @@ +document.getElementById('go-background').addEventListener('click', () => { + Object.defineProperty(document, 'hidden', { value: true, writable: true }); + const ev = document.createEvent('Event'); + ev.initEvent('visibilitychange'); + document.dispatchEvent(ev); +}); diff --git a/packages/integration-tests/suites/replay/flushing/template.html b/packages/integration-tests/suites/replay/flushing/template.html new file mode 100644 index 000000000000..31cfc73ec3c3 --- /dev/null +++ b/packages/integration-tests/suites/replay/flushing/template.html @@ -0,0 +1,9 @@ + + +
+ + + + + + diff --git a/packages/integration-tests/suites/replay/flushing/test.ts b/packages/integration-tests/suites/replay/flushing/test.ts new file mode 100644 index 000000000000..e448a57dd964 --- /dev/null +++ b/packages/integration-tests/suites/replay/flushing/test.ts @@ -0,0 +1,62 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../utils/fixtures'; +import { getExpectedReplayEvent } from '../../../utils/replayEventTemplates'; +import { getReplayEvent, shouldSkipReplayTest, waitForReplayRequest } from '../../../utils/replayHelpers'; + +// Sync this with init.js - not we take seconds here instead of ms +const FLUSH_DELAY_SECONDS = 0.5; + +sentryTest('replay recording flushes every 5s', async ({ getLocalTestPath, page }) => { + if (shouldSkipReplayTest()) { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + const reqPromise1 = waitForReplayRequest(page, 1); + const reqPromise2 = waitForReplayRequest(page, 2); + + 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); + const replayEvent0 = getReplayEvent(await reqPromise0); + expect(replayEvent0).toEqual(getExpectedReplayEvent()); + + // trigger mouse click + void page.click('#go-background'); + + const replayEvent1 = getReplayEvent(await reqPromise1); + expect(replayEvent1).toEqual(getExpectedReplayEvent({ replay_start_timestamp: undefined, segment_id: 1, urls: [] })); + + // trigger mouse click every 100ms, it should still flush after 5s even if clicks are ongoing + for (let i = 0; i < 70; i++) { + setTimeout(async () => { + try { + await page.click('#go-background'); + } catch { + // ignore errors here, we don't care if the page is closed + } + }, i * 100); + } + + const replayEvent2 = getReplayEvent(await reqPromise2); + expect(replayEvent2).toEqual(getExpectedReplayEvent({ replay_start_timestamp: undefined, segment_id: 2, urls: [] })); + + // Ensure time diff is about 500ms between each event + const diff1 = replayEvent1.timestamp! - replayEvent0.timestamp!; + const diff2 = replayEvent2.timestamp! - replayEvent1.timestamp!; + + // We want to check that the diff is between 0.1 and 0.9 seconds, to accomodate for some wiggle room + expect(diff1).toBeLessThan(FLUSH_DELAY_SECONDS + 0.4); + expect(diff1).toBeGreaterThanOrEqual(FLUSH_DELAY_SECONDS - 0.4); + expect(diff2).toBeLessThan(FLUSH_DELAY_SECONDS + 0.4); + expect(diff2).toBeGreaterThanOrEqual(FLUSH_DELAY_SECONDS - 0.4); +}); diff --git a/packages/integration-tests/suites/replay/privacyBlock/test.ts-snapshots/privacy.json b/packages/integration-tests/suites/replay/privacyBlock/test.ts-snapshots/privacy.json index 4b08d64a07b3..a120d5e44a5e 100644 --- a/packages/integration-tests/suites/replay/privacyBlock/test.ts-snapshots/privacy.json +++ b/packages/integration-tests/suites/replay/privacyBlock/test.ts-snapshots/privacy.json @@ -32,8 +32,8 @@ "type": 2, "tagName": "link", "attributes": { - "rr_width": "0px", - "rr_height": "0px" + "rr_width": "[0-50]px", + "rr_height": "[0-50]px" }, "childNodes": [], "id": 6 @@ -271,8 +271,8 @@ "type": 2, "tagName": "video", "attributes": { - "rr_width": "30px", - "rr_height": "30px" + "rr_width": "[0-50]px", + "rr_height": "[0-50]px" }, "childNodes": [], "id": 38 @@ -287,8 +287,8 @@ "tagName": "div", "attributes": { "class": "nested-hide", - "rr_width": "1264px", - "rr_height": "18px" + "rr_width": "[1250-1300]px", + "rr_height": "[0-50]px" }, "childNodes": [], "id": 40 diff --git a/packages/integration-tests/suites/replay/privacyDefault/test.ts-snapshots/privacy.json b/packages/integration-tests/suites/replay/privacyDefault/test.ts-snapshots/privacy.json index f29f31d2eb75..f31f8b967d12 100644 --- a/packages/integration-tests/suites/replay/privacyDefault/test.ts-snapshots/privacy.json +++ b/packages/integration-tests/suites/replay/privacyDefault/test.ts-snapshots/privacy.json @@ -154,8 +154,8 @@ "type": 2, "tagName": "svg", "attributes": { - "rr_width": "200px", - "rr_height": "200px" + "rr_width": "[200-250]px", + "rr_height": "[200-250]px" }, "childNodes": [], "isSVG": true, @@ -214,8 +214,8 @@ "type": 2, "tagName": "img", "attributes": { - "rr_width": "100px", - "rr_height": "100px" + "rr_width": "[100-150]px", + "rr_height": "[100-150]px" }, "childNodes": [], "id": 31 @@ -245,8 +245,8 @@ "type": 2, "tagName": "video", "attributes": { - "rr_width": "30px", - "rr_height": "30px" + "rr_width": "[0-50]px", + "rr_height": "[0-50]px" }, "childNodes": [], "id": 35