diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index cd82966591ce..765e1c53615f 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -33,6 +33,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GH_RELEASE_PAT }} with: - version: ${{ steps.version.outputs.match != '' }} + version: ${{ steps.version.outputs.group1 }} force: false merge_target: master diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a9f6372afb9..45aa5f4ec595 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -298,11 +298,14 @@ jobs: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} - name: Check bundle sizes - uses: getsentry/size-limit-action@main-skip-step + uses: getsentry/size-limit-action@runForBranch with: github_token: ${{ secrets.GITHUB_TOKEN }} skip_step: build main_branch: develop + # When on release branch, we want to always run + # Else, we fall back to the default handling of the action + run_for_branch: ${{ (needs.job_get_metadata.outputs.is_release == 'true' && 'true') || '' }} job_lint: name: Lint diff --git a/packages/integration-tests/README.md b/packages/integration-tests/README.md index 47aa171cec21..075163a4b9dc 100644 --- a/packages/integration-tests/README.md +++ b/packages/integration-tests/README.md @@ -12,6 +12,9 @@ Each case group has a default HTML skeleton named `template.hbs`, and also a def `test.ts` is required for each test case, which contains the assertions (and if required the script injection logic). For every case, any set of `init.js`, `template.hbs` and `subject.js` can be defined locally, and each one of them will have precedence over the default definitions of the test group. +To test page multi-page navigations, you can specify additional `page-*.html` (e.g. `page-0.html`, `page-1.html`) files. These will also be compiled and initialized with the same `init.js` and `subject.js` files that are applied to `template.hbs/html`. Note: `page-*.html` file lookup **doesn not** fall back to the +parent directories, meaning that page files have to be directly in the `test.ts` directory. + ``` suites/ |---- breadcrumbs/ @@ -23,6 +26,7 @@ suites/ |---- init.js [optional case specific init] |---- subject.js [optional case specific subject] |---- test.ts [assertions] + |---- page-*.html [optional, NO fallback!] ``` ## Writing Tests diff --git a/packages/integration-tests/suites/replay/multiple-pages/init.js b/packages/integration-tests/suites/replay/multiple-pages/init.js new file mode 100644 index 000000000000..0242b48100b8 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/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, + + integrations: [window.Replay], +}); diff --git a/packages/integration-tests/suites/replay/multiple-pages/page-0.html b/packages/integration-tests/suites/replay/multiple-pages/page-0.html new file mode 100644 index 000000000000..f6cb8d50a131 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/page-0.html @@ -0,0 +1,13 @@ + + + + + + +

Secondary Page

+ + + + Go Back to first page + + diff --git a/packages/integration-tests/suites/replay/multiple-pages/subject.js b/packages/integration-tests/suites/replay/multiple-pages/subject.js new file mode 100644 index 000000000000..0f867559c98b --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/subject.js @@ -0,0 +1,10 @@ +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); +}); + +document.getElementById('spa-navigation').addEventListener('click', () => { + window.history.pushState({}, '', '/spa'); +}); diff --git a/packages/integration-tests/suites/replay/multiple-pages/template.html b/packages/integration-tests/suites/replay/multiple-pages/template.html new file mode 100644 index 000000000000..12bc2cc67ba0 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/template.html @@ -0,0 +1,10 @@ + + + + + + + + Go To new page + + diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts b/packages/integration-tests/suites/replay/multiple-pages/test.ts new file mode 100644 index 000000000000..914c7dd856ca --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts @@ -0,0 +1,332 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../utils/fixtures'; +import { + expectedClickBreadcrumb, + expectedFCPPerformanceSpan, + expectedFPPerformanceSpan, + expectedLCPPerformanceSpan, + expectedMemoryPerformanceSpan, + expectedNavigationBreadcrumb, + expectedNavigationPerformanceSpan, + expectedNavigationPushPerformanceSpan, + expectedReloadPerformanceSpan, + getExpectedReplayEvent, +} from '../../../utils/replayEventTemplates'; +import { + getReplayEvent, + getReplayRecordingContent, + normalize, + shouldSkipReplayTest, + waitForReplayRequest, +} from '../../../utils/replayHelpers'; + +/* +This is a quite complex test with the goal to ensure correct recording across multiple pages, +navigations and page reloads. In particular, we want to check that all breadcrumbs, spans as +well as the correct DOM snapshots and updates are recorded and sent. +*/ +sentryTest( + 'record page navigations and performance entries across multiple pages', + async ({ getLocalTestPath, page, browserName }) => { + // 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(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const reqPromise0 = waitForReplayRequest(page, 0); + const reqPromise1 = waitForReplayRequest(page, 1); + + const url = await getLocalTestPath({ testDir: __dirname }); + + await page.goto(url); + const replayEvent0 = getReplayEvent(await reqPromise0); + const recording0 = getReplayRecordingContent(await reqPromise0); + + expect(replayEvent0).toEqual(getExpectedReplayEvent({ segment_id: 0 })); + expect(normalize(recording0.fullSnapshots)).toMatchSnapshot('seg-0-snap-full'); + expect(recording0.incrementalSnapshots.length).toEqual(0); + + await page.click('#go-background'); + + const replayEvent1 = getReplayEvent(await reqPromise1); + const recording1 = getReplayRecordingContent(await reqPromise1); + + expect(replayEvent1).toEqual( + getExpectedReplayEvent({ segment_id: 1, urls: [], replay_start_timestamp: undefined }), + ); + expect(recording1.fullSnapshots.length).toEqual(0); + expect(normalize(recording1.incrementalSnapshots)).toMatchSnapshot('seg-1-snap-incremental'); + + // We can't guarantee the order of the performance spans, or in which of the two segments they are sent + // So to avoid flakes, we collect them all and check that they are all there + const collectedPerformanceSpans = [...recording0.performanceSpans, ...recording1.performanceSpans]; + const collectedBreadcrumbs = [...recording0.breadcrumbs, ...recording1.breadcrumbs]; + + expect(collectedPerformanceSpans.length).toEqual(6); + expect(collectedPerformanceSpans).toEqual( + expect.arrayContaining([ + expectedNavigationPerformanceSpan, + expectedLCPPerformanceSpan, + expectedFPPerformanceSpan, + expectedFCPPerformanceSpan, + expectedMemoryPerformanceSpan, // two memory spans - once per flush + expectedMemoryPerformanceSpan, + ]), + ); + + expect(collectedBreadcrumbs).toEqual([expectedClickBreadcrumb]); + + // ----------------------------------------------------------------------------------------- + // Test page reload + + await page.reload(); + + const reqPromise2 = waitForReplayRequest(page, 2); + const reqPromise3 = waitForReplayRequest(page, 3); + + const replayEvent2 = getReplayEvent(await reqPromise2); + const recording2 = getReplayRecordingContent(await reqPromise2); + + expect(replayEvent2).toEqual(getExpectedReplayEvent({ segment_id: 2, replay_start_timestamp: undefined })); + expect(normalize(recording2.fullSnapshots)).toMatchSnapshot('seg-2-snap-full'); + expect(recording2.incrementalSnapshots.length).toEqual(0); + + await page.click('#go-background'); + + const replayEvent3 = getReplayEvent(await reqPromise3); + const recording3 = getReplayRecordingContent(await reqPromise3); + + expect(replayEvent3).toEqual( + getExpectedReplayEvent({ segment_id: 3, urls: [], replay_start_timestamp: undefined }), + ); + expect(recording3.fullSnapshots.length).toEqual(0); + expect(normalize(recording3.incrementalSnapshots)).toMatchSnapshot('seg-3-snap-incremental'); + + const collectedPerformanceSpansAfterReload = [...recording2.performanceSpans, ...recording3.performanceSpans]; + const collectedBreadcrumbsAdterReload = [...recording2.breadcrumbs, ...recording3.breadcrumbs]; + + expect(collectedPerformanceSpansAfterReload.length).toEqual(6); + expect(collectedPerformanceSpansAfterReload).toEqual( + expect.arrayContaining([ + expectedReloadPerformanceSpan, + expectedLCPPerformanceSpan, + expectedFPPerformanceSpan, + expectedFCPPerformanceSpan, + expectedMemoryPerformanceSpan, + expectedMemoryPerformanceSpan, + ]), + ); + + expect(collectedBreadcrumbsAdterReload).toEqual([expectedClickBreadcrumb]); + + // ----------------------------------------------------------------------------------------- + // Test subsequent link navigation to another page + + await page.click('a'); + + const reqPromise4 = waitForReplayRequest(page, 4); + const reqPromise5 = waitForReplayRequest(page, 5); + + const replayEvent4 = getReplayEvent(await reqPromise4); + const recording4 = getReplayRecordingContent(await reqPromise4); + + expect(replayEvent4).toEqual( + getExpectedReplayEvent({ + segment_id: 4, + replay_start_timestamp: undefined, + // @ts-ignore this is fine + urls: [expect.stringContaining('page-0.html')], + request: { + // @ts-ignore this is fine + url: expect.stringContaining('page-0.html'), + headers: { + // @ts-ignore this is fine + 'User-Agent': expect.stringContaining(''), + }, + }, + }), + ); + expect(normalize(recording4.fullSnapshots)).toMatchSnapshot('seg-4-snap-full'); + expect(recording4.incrementalSnapshots.length).toEqual(0); + + await page.click('#go-background'); + + const replayEvent5 = getReplayEvent(await reqPromise5); + const recording5 = getReplayRecordingContent(await reqPromise5); + + expect(replayEvent5).toEqual( + getExpectedReplayEvent({ + segment_id: 5, + urls: [], + replay_start_timestamp: undefined, + request: { + // @ts-ignore this is fine + url: expect.stringContaining('page-0.html'), + headers: { + // @ts-ignore this is fine + 'User-Agent': expect.stringContaining(''), + }, + }, + }), + ); + expect(recording5.fullSnapshots.length).toEqual(0); + expect(normalize(recording5.incrementalSnapshots)).toMatchSnapshot('seg-5-snap-incremental'); + + const collectedPerformanceSpansAfterLinkNavigation = [ + ...recording4.performanceSpans, + ...recording5.performanceSpans, + ]; + const collectedBreadcrumbsAfterLinkNavigation = [...recording4.breadcrumbs, ...recording5.breadcrumbs]; + + expect(collectedPerformanceSpansAfterLinkNavigation).toEqual( + expect.arrayContaining([ + expectedNavigationPerformanceSpan, + expectedLCPPerformanceSpan, + expectedFPPerformanceSpan, + expectedFCPPerformanceSpan, + expectedMemoryPerformanceSpan, + expectedMemoryPerformanceSpan, + ]), + ); + + expect(collectedBreadcrumbsAfterLinkNavigation.length).toEqual(1); + expect(collectedBreadcrumbsAfterLinkNavigation).toEqual([expectedClickBreadcrumb]); + + // ----------------------------------------------------------------------------------------- + // Test subsequent navigation without a page reload (i.e. SPA navigation) + + await page.click('#spa-navigation'); + + const reqPromise6 = waitForReplayRequest(page, 6); + const replayEvent6 = getReplayEvent(await reqPromise6); + const recording6 = getReplayRecordingContent(await reqPromise6); + + expect(replayEvent6).toEqual( + getExpectedReplayEvent({ + segment_id: 6, + urls: ['/spa'], + replay_start_timestamp: undefined, + request: { + // @ts-ignore this is fine + url: expect.stringContaining('page-0.html'), + headers: { + // @ts-ignore this is fine + 'User-Agent': expect.stringContaining(''), + }, + }, + }), + ); + expect(recording6.fullSnapshots.length).toEqual(0); + expect(normalize(recording6.incrementalSnapshots)).toMatchSnapshot('seg-6-snap-incremental'); + + await page.click('#go-background'); + + const reqPromise7 = waitForReplayRequest(page, 7); + const replayEvent7 = getReplayEvent(await reqPromise7); + const recording7 = getReplayRecordingContent(await reqPromise7); + + expect(replayEvent7).toEqual( + getExpectedReplayEvent({ + segment_id: 7, + urls: [], + replay_start_timestamp: undefined, + request: { + // @ts-ignore this is fine + url: expect.stringContaining('page-0.html'), + headers: { + // @ts-ignore this is fine + 'User-Agent': expect.stringContaining(''), + }, + }, + }), + ); + expect(recording7.fullSnapshots.length).toEqual(0); + expect(normalize(recording7.incrementalSnapshots)).toMatchSnapshot('seg-7-snap-incremental'); + + const collectedPerformanceSpansAfterSPANavigation = [ + ...recording6.performanceSpans, + ...recording7.performanceSpans, + ]; + const collectedBreadcrumbsAfterSPANavigation = [...recording6.breadcrumbs, ...recording7.breadcrumbs]; + + expect(collectedPerformanceSpansAfterSPANavigation.length).toEqual(3); + expect(collectedPerformanceSpansAfterSPANavigation).toEqual( + expect.arrayContaining([ + expectedNavigationPushPerformanceSpan, + expectedMemoryPerformanceSpan, + expectedMemoryPerformanceSpan, + ]), + ); + + expect(collectedBreadcrumbsAfterSPANavigation).toEqual([ + expectedClickBreadcrumb, + expectedNavigationBreadcrumb, + expectedClickBreadcrumb, + ]); + + // // ----------------------------------------------------------------------------------------- + // // And just to finish this off, let's go back to the index page + + await page.click('a'); + + const reqPromise8 = waitForReplayRequest(page, 8); + const reqPromise9 = waitForReplayRequest(page, 9); + + const replayEvent8 = getReplayEvent(await reqPromise8); + const recording8 = getReplayRecordingContent(await reqPromise8); + + expect(replayEvent8).toEqual( + getExpectedReplayEvent({ + segment_id: 8, + replay_start_timestamp: undefined, + }), + ); + expect(normalize(recording8.fullSnapshots)).toMatchSnapshot('seg-8-snap-full'); + expect(recording8.incrementalSnapshots.length).toEqual(0); + + await page.click('#go-background'); + + const replayEvent9 = getReplayEvent(await reqPromise9); + const recording9 = getReplayRecordingContent(await reqPromise9); + + expect(replayEvent9).toEqual( + getExpectedReplayEvent({ + segment_id: 9, + urls: [], + replay_start_timestamp: undefined, + }), + ); + expect(recording9.fullSnapshots.length).toEqual(0); + expect(normalize(recording9.incrementalSnapshots)).toMatchSnapshot('seg-9-snap-incremental'); + + const collectedPerformanceSpansAfterIndexNavigation = [ + ...recording8.performanceSpans, + ...recording9.performanceSpans, + ]; + const collectedBreadcrumbsAfterIndexNavigation = [...recording8.breadcrumbs, ...recording9.breadcrumbs]; + + expect(collectedPerformanceSpansAfterIndexNavigation.length).toEqual(6); + expect(collectedPerformanceSpansAfterIndexNavigation).toEqual( + expect.arrayContaining([ + expectedNavigationPerformanceSpan, + expectedLCPPerformanceSpan, + expectedFPPerformanceSpan, + expectedFCPPerformanceSpan, + expectedMemoryPerformanceSpan, + expectedMemoryPerformanceSpan, + ]), + ); + + expect(collectedBreadcrumbsAfterIndexNavigation).toEqual([expectedClickBreadcrumb]); + }, +); diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-0-snap-full b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-0-snap-full new file mode 100644 index 000000000000..cfd7928e8d9d --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-0-snap-full @@ -0,0 +1,109 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/page-0.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** ** *** ****", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 15 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-0-snap-full-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-0-snap-full-chromium new file mode 100644 index 000000000000..cfd7928e8d9d --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-0-snap-full-chromium @@ -0,0 +1,109 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/page-0.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** ** *** ****", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 15 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-1-snap-incremental b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-1-snap-incremental new file mode 100644 index 000000000000..fd46cda96828 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-1-snap-incremental @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 18, + "id": 9, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 5, + "id": 9 + }, + { + "source": 2, + "type": 0, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 2, + "id": 9, + "x": 41, + "y": 18 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-1-snap-incremental-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-1-snap-incremental-chromium new file mode 100644 index 000000000000..fd46cda96828 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-1-snap-incremental-chromium @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 18, + "id": 9, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 5, + "id": 9 + }, + { + "source": 2, + "type": 0, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 2, + "id": 9, + "x": 41, + "y": 18 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-2-snap-full b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-2-snap-full new file mode 100644 index 000000000000..cfd7928e8d9d --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-2-snap-full @@ -0,0 +1,109 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/page-0.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** ** *** ****", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 15 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-2-snap-full-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-2-snap-full-chromium new file mode 100644 index 000000000000..cfd7928e8d9d --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-2-snap-full-chromium @@ -0,0 +1,109 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/page-0.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** ** *** ****", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 15 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-3-snap-incremental b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-3-snap-incremental new file mode 100644 index 000000000000..fd46cda96828 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-3-snap-incremental @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 18, + "id": 9, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 5, + "id": 9 + }, + { + "source": 2, + "type": 0, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 2, + "id": 9, + "x": 41, + "y": 18 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-3-snap-incremental-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-3-snap-incremental-chromium new file mode 100644 index 000000000000..fd46cda96828 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-3-snap-incremental-chromium @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 18, + "id": 9, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 5, + "id": 9 + }, + { + "source": 2, + "type": 0, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 2, + "id": 9, + "x": 41, + "y": 18 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-4-snap-full b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-4-snap-full new file mode 100644 index 000000000000..a6c4b9f7c908 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-4-snap-full @@ -0,0 +1,152 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "h1", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "********* ****", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "spa-navigation" + }, + "childNodes": [ + { + "type": 3, + "textContent": "***** * *** **********", + "id": 16 + } + ], + "id": 15 + }, + { + "type": 3, + "textContent": "\n ", + "id": 17 + }, + { + "type": 3, + "textContent": "\n ", + "id": 18 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/index.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** **** ** ***** ****", + "id": 20 + } + ], + "id": 19 + }, + { + "type": 3, + "textContent": "\n ", + "id": 21 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 22 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-4-snap-full-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-4-snap-full-chromium new file mode 100644 index 000000000000..a6c4b9f7c908 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-4-snap-full-chromium @@ -0,0 +1,152 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "h1", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "********* ****", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "spa-navigation" + }, + "childNodes": [ + { + "type": 3, + "textContent": "***** * *** **********", + "id": 16 + } + ], + "id": 15 + }, + { + "type": 3, + "textContent": "\n ", + "id": 17 + }, + { + "type": 3, + "textContent": "\n ", + "id": 18 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/index.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** **** ** ***** ****", + "id": 20 + } + ], + "id": 19 + }, + { + "type": 3, + "textContent": "\n ", + "id": 21 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 22 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-5-snap-incremental b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-5-snap-incremental new file mode 100644 index 000000000000..d8651b3c919b --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-5-snap-incremental @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 90, + "id": 12, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 5, + "id": 12 + }, + { + "source": 2, + "type": 0, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 2, + "id": 12, + "x": 41, + "y": 90 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-5-snap-incremental-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-5-snap-incremental-chromium new file mode 100644 index 000000000000..d8651b3c919b --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-5-snap-incremental-chromium @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 90, + "id": 12, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 5, + "id": 12 + }, + { + "source": 2, + "type": 0, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 2, + "id": 12, + "x": 41, + "y": 90 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-6-snap-incremental b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-6-snap-incremental new file mode 100644 index 000000000000..065aeaf45bd9 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-6-snap-incremental @@ -0,0 +1,44 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 157, + "y": 90, + "id": 15, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 15, + "x": 157, + "y": 90 + }, + { + "source": 2, + "type": 6, + "id": 12 + }, + { + "source": 2, + "type": 5, + "id": 15 + }, + { + "source": 2, + "type": 0, + "id": 15, + "x": 157, + "y": 90 + }, + { + "source": 2, + "type": 2, + "id": 15, + "x": 157, + "y": 90 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-6-snap-incremental-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-6-snap-incremental-chromium new file mode 100644 index 000000000000..065aeaf45bd9 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-6-snap-incremental-chromium @@ -0,0 +1,44 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 157, + "y": 90, + "id": 15, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 15, + "x": 157, + "y": 90 + }, + { + "source": 2, + "type": 6, + "id": 12 + }, + { + "source": 2, + "type": 5, + "id": 15 + }, + { + "source": 2, + "type": 0, + "id": 15, + "x": 157, + "y": 90 + }, + { + "source": 2, + "type": 2, + "id": 15, + "x": 157, + "y": 90 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-7-snap-incremental b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-7-snap-incremental new file mode 100644 index 000000000000..9ca283b6ba8f --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-7-snap-incremental @@ -0,0 +1,44 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 90, + "id": 12, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 6, + "id": 15 + }, + { + "source": 2, + "type": 5, + "id": 12 + }, + { + "source": 2, + "type": 0, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 2, + "id": 12, + "x": 41, + "y": 90 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-7-snap-incremental-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-7-snap-incremental-chromium new file mode 100644 index 000000000000..9ca283b6ba8f --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-7-snap-incremental-chromium @@ -0,0 +1,44 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 90, + "id": 12, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 6, + "id": 15 + }, + { + "source": 2, + "type": 5, + "id": 12 + }, + { + "source": 2, + "type": 0, + "id": 12, + "x": 41, + "y": 90 + }, + { + "source": 2, + "type": 2, + "id": 12, + "x": 41, + "y": 90 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-8-snap-full b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-8-snap-full new file mode 100644 index 000000000000..cfd7928e8d9d --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-8-snap-full @@ -0,0 +1,109 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/page-0.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** ** *** ****", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 15 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-8-snap-full-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-8-snap-full-chromium new file mode 100644 index 000000000000..cfd7928e8d9d --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-8-snap-full-chromium @@ -0,0 +1,109 @@ +[ + { + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "id": "go-background" + }, + "childNodes": [ + { + "type": 3, + "textContent": "*** ***", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "a", + "attributes": { + "href": "/page-0.html" + }, + "childNodes": [ + { + "type": 3, + "textContent": "** ** *** ****", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 15 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-9-snap-incremental b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-9-snap-incremental new file mode 100644 index 000000000000..fd46cda96828 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-9-snap-incremental @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 18, + "id": 9, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 5, + "id": 9 + }, + { + "source": 2, + "type": 0, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 2, + "id": 9, + "x": 41, + "y": 18 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-9-snap-incremental-chromium b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-9-snap-incremental-chromium new file mode 100644 index 000000000000..fd46cda96828 --- /dev/null +++ b/packages/integration-tests/suites/replay/multiple-pages/test.ts-snapshots/seg-9-snap-incremental-chromium @@ -0,0 +1,39 @@ +[ + { + "source": 1, + "positions": [ + { + "x": 41, + "y": 18, + "id": 9, + "timeOffset": 0 + } + ] + }, + { + "source": 2, + "type": 1, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 5, + "id": 9 + }, + { + "source": 2, + "type": 0, + "id": 9, + "x": 41, + "y": 18 + }, + { + "source": 2, + "type": 2, + "id": 9, + "x": 41, + "y": 18 + } +] \ No newline at end of file diff --git a/packages/integration-tests/suites/replay/privacy/test.ts-snapshots/privacy.json b/packages/integration-tests/suites/replay/privacy/test.ts-snapshots/privacy.json new file mode 100644 index 000000000000..d0cb968d61ff --- /dev/null +++ b/packages/integration-tests/suites/replay/privacy/test.ts-snapshots/privacy.json @@ -0,0 +1,266 @@ +{ + "node": { + "type": 0, + "childNodes": [ + { + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 + }, + { + "type": 2, + "tagName": "html", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ + { + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "utf-8" + }, + "childNodes": [], + "id": 5 + } + ], + "id": 4 + }, + { + "type": 3, + "textContent": "\n ", + "id": 6 + }, + { + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "\n ", + "id": 8 + }, + { + "type": 2, + "tagName": "button", + "attributes": { + "aria-label": "***** **", + "onclick": "console.log('Test log')" + }, + "childNodes": [ + { + "type": 3, + "textContent": "***** **", + "id": 10 + } + ], + "id": 9 + }, + { + "type": 3, + "textContent": "\n ", + "id": 11 + }, + { + "type": 2, + "tagName": "div", + "attributes": {}, + "childNodes": [ + { + "type": 3, + "textContent": "**** ****** ** ****** ** *******", + "id": 13 + } + ], + "id": 12 + }, + { + "type": 3, + "textContent": "\n ", + "id": 14 + }, + { + "type": 2, + "tagName": "div", + "attributes": { + "data-sentry-unmask": "" + }, + "childNodes": [ + { + "type": 3, + "textContent": "This should be unmasked due to data attribute", + "id": 16 + } + ], + "id": 15 + }, + { + "type": 3, + "textContent": "\n ", + "id": 17 + }, + { + "type": 2, + "tagName": "input", + "attributes": { + "placeholder": "*********** ****** ** ******" + }, + "childNodes": [], + "id": 18 + }, + { + "type": 3, + "textContent": "\n ", + "id": 19 + }, + { + "type": 2, + "tagName": "div", + "attributes": { + "title": "***** ****** ** ******" + }, + "childNodes": [ + { + "type": 3, + "textContent": "***** ****** ** ******", + "id": 21 + } + ], + "id": 20 + }, + { + "type": 3, + "textContent": "\n ", + "id": 22 + }, + { + "type": 2, + "tagName": "svg", + "attributes": { + "rr_width": "200px", + "rr_height": "200px" + }, + "childNodes": [], + "isSVG": true, + "id": 23 + }, + { + "type": 3, + "textContent": "\n ", + "id": 24 + }, + { + "type": 2, + "tagName": "svg", + "attributes": { + "style": "width:200px;height:200px", + "viewBox": "0 0 80 80", + "data-sentry-unblock": "" + }, + "childNodes": [ + { + "type": 2, + "tagName": "path", + "attributes": { + "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 + }, + { + "type": 3, + "textContent": "\n ", + "id": 29 + }, + { + "type": 2, + "tagName": "img", + "attributes": { + "rr_width": "100px", + "rr_height": "100px" + }, + "childNodes": [], + "id": 30 + }, + { + "type": 3, + "textContent": "\n ", + "id": 31 + }, + { + "type": 2, + "tagName": "img", + "attributes": { + "data-sentry-unblock": "", + "style": "width:100px;height:100px", + "src": "file:///none.png" + }, + "childNodes": [], + "id": 32 + }, + { + "type": 3, + "textContent": "\n ", + "id": 33 + }, + { + "type": 2, + "tagName": "video", + "attributes": { + "rr_width": "30px", + "rr_height": "30px" + }, + "childNodes": [], + "id": 34 + }, + { + "type": 3, + "textContent": "\n ", + "id": 35 + }, + { + "type": 3, + "textContent": "\n\n", + "id": 36 + } + ], + "id": 7 + } + ], + "id": 3 + } + ], + "id": 1 + }, + "initialOffset": { + "left": 0, + "top": 0 + } +} \ No newline at end of file diff --git a/packages/integration-tests/utils/fixtures.ts b/packages/integration-tests/utils/fixtures.ts index 15c41ab10c14..0d4c75353700 100644 --- a/packages/integration-tests/utils/fixtures.ts +++ b/packages/integration-tests/utils/fixtures.ts @@ -57,6 +57,20 @@ const sentryTest = base.extend({ await generatePage(init, subject, template, testDir); } + + const additionalPages = fs + .readdirSync(testDir) + .filter(filename => filename.startsWith('page-') && filename.endsWith('.html')); + + const outDir = path.dirname(testInfo.file); + for (const pageFilename of additionalPages) { + // create a new page with the same subject and init as before + const subject = getAsset(testDir, 'subject.js'); + const pageFile = getAsset(testDir, pageFilename); + const init = getAsset(testDir, 'init.js'); + await generatePage(init, subject, pageFile, outDir, pageFilename); + } + return pagePath; }); }, diff --git a/packages/integration-tests/utils/generatePage.ts b/packages/integration-tests/utils/generatePage.ts index fea623129e93..e48485101dd3 100644 --- a/packages/integration-tests/utils/generatePage.ts +++ b/packages/integration-tests/utils/generatePage.ts @@ -10,9 +10,10 @@ export async function generatePage( subjectPath: string, templatePath: string, outPath: string, + outPageName: string = 'index.html', ): Promise { const localPath = `${outPath}/dist`; - const bundlePath = `${localPath}/index.html`; + const bundlePath = `${localPath}/${outPageName}}`; if (!existsSync(localPath)) { mkdirSync(localPath, { recursive: true }); @@ -33,7 +34,7 @@ export async function generatePage( plugins: [ new SentryScenarioGenerationPlugin(), new HtmlWebpackPlugin({ - filename: 'index.html', + filename: outPageName, template: templatePath, inject: 'body', }), diff --git a/packages/integration-tests/utils/replayEventTemplates.ts b/packages/integration-tests/utils/replayEventTemplates.ts index 17aa903a0391..3a4b4b5f9789 100644 --- a/packages/integration-tests/utils/replayEventTemplates.ts +++ b/packages/integration-tests/utils/replayEventTemplates.ts @@ -71,6 +71,25 @@ export const expectedNavigationPerformanceSpan = { }, }; +export const expectedNavigationPushPerformanceSpan = { + op: 'navigation.push', + description: expect.any(String), + startTimestamp: expect.any(Number), + endTimestamp: expect.any(Number), + data: {}, +}; + +export const expectedReloadPerformanceSpan = { + op: 'navigation.reload', + description: '', + startTimestamp: expect.any(Number), + endTimestamp: expect.any(Number), + data: { + duration: expect.any(Number), + size: expect.any(Number), + }, +}; + export const expectedMemoryPerformanceSpan = { op: 'memory', description: 'memory', @@ -122,3 +141,13 @@ export const expectedClickBreadcrumb = { nodeId: expect.any(Number), }, }; + +export const expectedNavigationBreadcrumb = { + timestamp: expect.any(Number), + type: 'default', + category: 'navigation', + data: { + from: expect.any(String), + to: expect.any(String), + }, +}; diff --git a/packages/integration-tests/utils/replayHelpers.ts b/packages/integration-tests/utils/replayHelpers.ts index 11a4131e6753..703cb11e0393 100644 --- a/packages/integration-tests/utils/replayHelpers.ts +++ b/packages/integration-tests/utils/replayHelpers.ts @@ -86,6 +86,16 @@ export function getReplayEvent(replayRequest: Request): ReplayEvent { return event; } +type CustomRecordingContent = { + breadcrumbs: Breadcrumb[]; + performanceSpans: PerformanceSpan[]; +}; + +type RecordingContent = { + fullSnapshots: RecordingSnapshot[]; + incrementalSnapshots: RecordingSnapshot[]; +} & CustomRecordingContent; + /** * Takes an uncompressed replay request and returns the custom recording events, * i.e. the events we emit as type 5 rrweb events @@ -93,10 +103,7 @@ export function getReplayEvent(replayRequest: Request): ReplayEvent { * @param replayRequest * @returns an object containing the replay breadcrumbs and performance spans */ -export function getCustomRecordingEvents(replayRequest: Request): { - breadcrumbs: Breadcrumb[]; - performanceSpans: PerformanceSpan[]; -} { +export function getCustomRecordingEvents(replayRequest: Request): CustomRecordingContent { const recordingEvents = getDecompressedRecordingEvents(replayRequest); const breadcrumbs = getReplayBreadcrumbs(recordingEvents); @@ -126,10 +133,23 @@ export function getFullRecordingSnapshots(replayRequest: Request): RecordingSnap return events.filter(event => event.type === 2).map(event => event.data as RecordingSnapshot); } +function getincrementalRecordingSnapshots(replayRequest: Request): RecordingSnapshot[] { + const events = getDecompressedRecordingEvents(replayRequest) as RecordingEvent[]; + return events.filter(event => event.type === 3).map(event => event.data as RecordingSnapshot); +} + function getDecompressedRecordingEvents(replayRequest: Request): RecordingEvent[] { return replayEnvelopeRequestParser(replayRequest, 5) as RecordingEvent[]; } +export function getReplayRecordingContent(replayRequest: Request): RecordingContent { + const fullSnapshots = getFullRecordingSnapshots(replayRequest); + const incrementalSnapshots = getincrementalRecordingSnapshots(replayRequest); + const customEvents = getCustomRecordingEvents(replayRequest); + + return { fullSnapshots, incrementalSnapshots, ...customEvents }; +} + /** * Copy of the envelopeParser from ./helpers.ts, but with the ability * to decompress zlib-compressed envelope payloads which we need to inspect for replay recordings. @@ -189,3 +209,14 @@ 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'); } + +/** + * Takes a replay recording payload and returns a normalized string representation. + * This is necessary because the DOM snapshots contain absolute paths to other HTML + * files which break the tests on different machines. + */ +export function normalize(obj: unknown): string { + const rawString = JSON.stringify(obj, null, 2); + const normalizedString = rawString.replace(/"file:\/\/.+(\/.*\.html)"/g, '"$1"'); + return normalizedString; +}