From e7bc30eced8d3e00c699e783635f53209245e254 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 13 Jan 2023 15:56:11 +0100 Subject: [PATCH 01/10] test(replay): Test against CDN bundles in Playwright integration tests --- .../suites/replay/captureReplay/test.ts | 4 ++-- .../integration-tests/suites/replay/init.js | 3 ++- .../suites/replay/sampling/init.js | 3 ++- .../suites/replay/sampling/test.ts | 4 ++-- .../integration-tests/utils/generatePlugin.ts | 18 ++++++++++++++++++ rollup/plugins/bundlePlugins.js | 2 ++ 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/integration-tests/suites/replay/captureReplay/test.ts b/packages/integration-tests/suites/replay/captureReplay/test.ts index 51a1d900f9ed..f29705917a69 100644 --- a/packages/integration-tests/suites/replay/captureReplay/test.ts +++ b/packages/integration-tests/suites/replay/captureReplay/test.ts @@ -6,8 +6,8 @@ import { sentryTest } from '../../../utils/fixtures'; import { getFirstSentryEnvelopeRequest } from '../../../utils/helpers'; sentryTest('captureReplay', async ({ getLocalTestPath, page }) => { - // Currently bundle tests are not supported for replay - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_')) { + // Replay bundles are es6 only + if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { sentryTest.skip(); } diff --git a/packages/integration-tests/suites/replay/init.js b/packages/integration-tests/suites/replay/init.js index 9050f274417c..7afa0ecc24e3 100644 --- a/packages/integration-tests/suites/replay/init.js +++ b/packages/integration-tests/suites/replay/init.js @@ -1,7 +1,8 @@ import * as Sentry from '@sentry/browser'; +import { Replay } from '@sentry/replay'; window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ +window.Replay = new Replay({ flushMinDelay: 200, initialFlushDelay: 200, }); diff --git a/packages/integration-tests/suites/replay/sampling/init.js b/packages/integration-tests/suites/replay/sampling/init.js index 67b681515697..83338d6f5a1c 100644 --- a/packages/integration-tests/suites/replay/sampling/init.js +++ b/packages/integration-tests/suites/replay/sampling/init.js @@ -1,7 +1,8 @@ import * as Sentry from '@sentry/browser'; +import { Replay } from '@sentry/replay'; window.Sentry = Sentry; -window.Replay = new Sentry.Replay({ +window.Replay = new Replay({ flushMinDelay: 200, initialFlushDelay: 200, }); diff --git a/packages/integration-tests/suites/replay/sampling/test.ts b/packages/integration-tests/suites/replay/sampling/test.ts index 9a351ce30f6f..bcb8dc858a08 100644 --- a/packages/integration-tests/suites/replay/sampling/test.ts +++ b/packages/integration-tests/suites/replay/sampling/test.ts @@ -4,8 +4,8 @@ import { sentryTest } from '../../../utils/fixtures'; import { getReplaySnapshot } from '../../../utils/helpers'; sentryTest('sampling', async ({ getLocalTestPath, page }) => { - // Currently bundle tests are not supported for replay - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_')) { + // Replay bundles are es6 only + if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { sentryTest.skip(); } diff --git a/packages/integration-tests/utils/generatePlugin.ts b/packages/integration-tests/utils/generatePlugin.ts index 3e00d97f7803..4c8d4bd9471e 100644 --- a/packages/integration-tests/utils/generatePlugin.ts +++ b/packages/integration-tests/utils/generatePlugin.ts @@ -40,6 +40,12 @@ const BUNDLE_PATHS: Record> = { 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', + }, }; /* @@ -87,6 +93,7 @@ function generateSentryAlias(): Record { class SentryScenarioGenerationPlugin { public requiresTracing: boolean = false; public requiredIntegrations: string[] = []; + public requiresReplay = false; private _name: string = 'SentryScenarioGenerationPlugin'; @@ -99,6 +106,7 @@ class SentryScenarioGenerationPlugin { '@sentry/browser': 'Sentry', '@sentry/tracing': 'Sentry', '@sentry/integrations': 'Sentry.Integrations', + '@sentry/replay': 'Sentry.Integrations', } : {}; @@ -113,6 +121,8 @@ 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; } }, ); @@ -140,6 +150,14 @@ 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/rollup/plugins/bundlePlugins.js b/rollup/plugins/bundlePlugins.js index bcfa53989f3d..da748f22c793 100644 --- a/rollup/plugins/bundlePlugins.js +++ b/rollup/plugins/bundlePlugins.js @@ -107,6 +107,8 @@ export function makeTerserPlugin() { '_driver', '_initStorage', '_support', + // We want to keept he _replay variable unmangled to enable integration tests to access it + '_replay', ], }, }, From 58b63e7f023ee7b1cb8e0f6868030185f51e584b Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 13 Jan 2023 16:10:27 +0100 Subject: [PATCH 02/10] add test to continue checking replay browser export --- .../replay/captureReplayViaBrowser/init.js | 16 +++++ .../captureReplayViaBrowser/template.html | 9 +++ .../replay/captureReplayViaBrowser/test.ts | 68 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 packages/integration-tests/suites/replay/captureReplayViaBrowser/init.js create mode 100644 packages/integration-tests/suites/replay/captureReplayViaBrowser/template.html create mode 100644 packages/integration-tests/suites/replay/captureReplayViaBrowser/test.ts diff --git a/packages/integration-tests/suites/replay/captureReplayViaBrowser/init.js b/packages/integration-tests/suites/replay/captureReplayViaBrowser/init.js new file mode 100644 index 000000000000..9050f274417c --- /dev/null +++ b/packages/integration-tests/suites/replay/captureReplayViaBrowser/init.js @@ -0,0 +1,16 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.Replay = new Sentry.Replay({ + flushMinDelay: 200, + initialFlushDelay: 200, +}); + +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/captureReplayViaBrowser/template.html b/packages/integration-tests/suites/replay/captureReplayViaBrowser/template.html new file mode 100644 index 000000000000..2b3e2f0b27b4 --- /dev/null +++ b/packages/integration-tests/suites/replay/captureReplayViaBrowser/template.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/integration-tests/suites/replay/captureReplayViaBrowser/test.ts b/packages/integration-tests/suites/replay/captureReplayViaBrowser/test.ts new file mode 100644 index 000000000000..d97b684e08d5 --- /dev/null +++ b/packages/integration-tests/suites/replay/captureReplayViaBrowser/test.ts @@ -0,0 +1,68 @@ +import { expect } from '@playwright/test'; +import { SDK_VERSION } from '@sentry/browser'; +import type { Event } from '@sentry/types'; + +import { sentryTest } from '../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../utils/helpers'; + +sentryTest('captureReplay', async ({ getLocalTestPath, page }) => { + // For this test, we skip all bundle tests, as we're only interested in Replay being correctly + // exported from the `@sentry/browser` npm package. + if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_')) { + 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 url = await getLocalTestPath({ testDir: __dirname }); + await page.goto(url); + + await page.click('button'); + await page.waitForTimeout(300); + + const replayEvent = await getFirstSentryEnvelopeRequest(page, url); + + expect(replayEvent).toBeDefined(); + expect(replayEvent).toEqual({ + type: 'replay_event', + timestamp: expect.any(Number), + error_ids: [], + trace_ids: [], + urls: [expect.stringContaining('/dist/index.html')], + replay_id: expect.stringMatching(/\w{32}/), + segment_id: 2, + replay_type: 'session', + event_id: expect.stringMatching(/\w{32}/), + environment: 'production', + sdk: { + integrations: [ + 'InboundFilters', + 'FunctionToString', + 'TryCatch', + 'Breadcrumbs', + 'GlobalHandlers', + 'LinkedErrors', + 'Dedupe', + 'HttpContext', + 'Replay', + ], + version: SDK_VERSION, + name: 'sentry.javascript.browser', + }, + sdkProcessingMetadata: {}, + request: { + url: expect.stringContaining('/dist/index.html'), + headers: { + 'User-Agent': expect.stringContaining(''), + }, + }, + platform: 'javascript', + tags: { sessionSampleRate: 1, errorSampleRate: 0 }, + }); +}); From c0107506098dc9d4ba5d0a91e7cf79ebeb5abd05 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 13:49:16 +0100 Subject: [PATCH 03/10] adjust new integration test --- packages/integration-tests/suites/replay/errorResponse/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integration-tests/suites/replay/errorResponse/test.ts b/packages/integration-tests/suites/replay/errorResponse/test.ts index 1febee5916fb..60521f39a013 100644 --- a/packages/integration-tests/suites/replay/errorResponse/test.ts +++ b/packages/integration-tests/suites/replay/errorResponse/test.ts @@ -5,7 +5,7 @@ import { getReplaySnapshot } from '../../../utils/helpers'; sentryTest('errorResponse', async ({ getLocalTestPath, page }) => { // Currently bundle tests are not supported for replay - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_')) { + if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle_es5')) { sentryTest.skip(); } From 290f41f54e3aaa73b67686833ebb05f8e0203c57 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 15:37:55 +0100 Subject: [PATCH 04/10] fix _isEnabled --- .../integration-tests/suites/replay/errorResponse/test.ts | 5 ++++- packages/integration-tests/utils/helpers.ts | 8 +++++++- rollup/plugins/bundlePlugins.js | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/integration-tests/suites/replay/errorResponse/test.ts b/packages/integration-tests/suites/replay/errorResponse/test.ts index 60521f39a013..039a426bfe6d 100644 --- a/packages/integration-tests/suites/replay/errorResponse/test.ts +++ b/packages/integration-tests/suites/replay/errorResponse/test.ts @@ -31,7 +31,10 @@ sentryTest('errorResponse', async ({ getLocalTestPath, page }) => { await page.waitForTimeout(5001); expect(called).toBe(1); + debugger; const replay = await getReplaySnapshot(page); + debugger; - expect(replay['_isEnabled']).toBe(false); + // @ts-ignore private API + expect(replay._isEnabled).toBe(false); }); diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts index 54e1cd44a0bb..f832af70d1cb 100644 --- a/packages/integration-tests/utils/helpers.ts +++ b/packages/integration-tests/utils/helpers.ts @@ -1,5 +1,5 @@ import type { Page, Request } from '@playwright/test'; -import type { ReplayContainer } from '@sentry/replay/build/npm/types/types'; +import { ReplayContainer } from '@sentry/replay/build/npm/types/types'; import type { Event, EventEnvelopeHeaders } from '@sentry/types'; const envelopeUrlRegex = /\.sentry\.io\/api\/\d+\/envelope\//; @@ -60,6 +60,12 @@ async function getSentryEvents(page: Page, url?: string): Promise> */ export async function getReplaySnapshot(page: Page): Promise { const replayIntegration = await page.evaluate<{ _replay: ReplayContainer }>('window.Replay'); + debugger; + console.log(replayIntegration._replay); + console.log(typeof replayIntegration); + console.log(Object.getPrototypeOf(replayIntegration._replay)); + console.log('isenabled', replayIntegration._replay.isEnabled); + return replayIntegration._replay; } diff --git a/rollup/plugins/bundlePlugins.js b/rollup/plugins/bundlePlugins.js index da748f22c793..d6521e53a614 100644 --- a/rollup/plugins/bundlePlugins.js +++ b/rollup/plugins/bundlePlugins.js @@ -107,8 +107,9 @@ export function makeTerserPlugin() { '_driver', '_initStorage', '_support', - // We want to keept he _replay variable unmangled to enable integration tests to access it + // We want to keept he _replay and _isEnabled variable unmangled to enable integration tests to access it '_replay', + '_isEnabled', ], }, }, From 927e4ea6a76fd0a3aeced6fe9a8a2d04c172fb4b Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 16:09:52 +0100 Subject: [PATCH 05/10] remove job condition --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c331823234af..f83624f23cbf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -191,7 +191,6 @@ jobs: - name: Check build cache uses: actions/cache@v3 id: cache_built_packages - if: needs.job_get_metadata.outputs.force_skip_cache == 'false' with: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} From 4239931dec57ad30190fcc5706745dcfd742b767 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 16:23:14 +0100 Subject: [PATCH 06/10] remove debug output --- packages/integration-tests/utils/helpers.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts index f832af70d1cb..22de4b815c9f 100644 --- a/packages/integration-tests/utils/helpers.ts +++ b/packages/integration-tests/utils/helpers.ts @@ -60,12 +60,6 @@ async function getSentryEvents(page: Page, url?: string): Promise> */ export async function getReplaySnapshot(page: Page): Promise { const replayIntegration = await page.evaluate<{ _replay: ReplayContainer }>('window.Replay'); - debugger; - console.log(replayIntegration._replay); - console.log(typeof replayIntegration); - console.log(Object.getPrototypeOf(replayIntegration._replay)); - console.log('isenabled', replayIntegration._replay.isEnabled); - return replayIntegration._replay; } From 59dbb571f4f82ec2d701d063fad53163e0da24ae Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 16:48:49 +0100 Subject: [PATCH 07/10] remove debugger stmt --- packages/integration-tests/suites/replay/errorResponse/test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/integration-tests/suites/replay/errorResponse/test.ts b/packages/integration-tests/suites/replay/errorResponse/test.ts index 039a426bfe6d..68086d793cb1 100644 --- a/packages/integration-tests/suites/replay/errorResponse/test.ts +++ b/packages/integration-tests/suites/replay/errorResponse/test.ts @@ -31,9 +31,7 @@ sentryTest('errorResponse', async ({ getLocalTestPath, page }) => { await page.waitForTimeout(5001); expect(called).toBe(1); - debugger; const replay = await getReplaySnapshot(page); - debugger; // @ts-ignore private API expect(replay._isEnabled).toBe(false); From 1218c95b1b266ab16958c6ab78fdb6c86033c121 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 17:12:58 +0100 Subject: [PATCH 08/10] try waitForFunction --- .../integration-tests/suites/replay/errorResponse/test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/integration-tests/suites/replay/errorResponse/test.ts b/packages/integration-tests/suites/replay/errorResponse/test.ts index 68086d793cb1..49f02bec4ec4 100644 --- a/packages/integration-tests/suites/replay/errorResponse/test.ts +++ b/packages/integration-tests/suites/replay/errorResponse/test.ts @@ -31,6 +31,12 @@ sentryTest('errorResponse', async ({ getLocalTestPath, page }) => { await page.waitForTimeout(5001); expect(called).toBe(1); + + await page.waitForFunction(() => { + // @ts-ignore private API + return window.Replay._replay !== undefined; + }); + const replay = await getReplaySnapshot(page); // @ts-ignore private API From cd0994a5706f251c236dd94a5f65f1ea1a7144cd Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 17:40:00 +0100 Subject: [PATCH 09/10] fix linter error --- packages/integration-tests/utils/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts index 22de4b815c9f..54e1cd44a0bb 100644 --- a/packages/integration-tests/utils/helpers.ts +++ b/packages/integration-tests/utils/helpers.ts @@ -1,5 +1,5 @@ import type { Page, Request } from '@playwright/test'; -import { ReplayContainer } from '@sentry/replay/build/npm/types/types'; +import type { ReplayContainer } from '@sentry/replay/build/npm/types/types'; import type { Event, EventEnvelopeHeaders } from '@sentry/types'; const envelopeUrlRegex = /\.sentry\.io\/api\/\d+\/envelope\//; From 589a4389bc0ad9c88fc4c5c6cabef176790c8838 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 16 Jan 2023 18:07:08 +0100 Subject: [PATCH 10/10] remove waitForFunction --- .../integration-tests/suites/replay/errorResponse/test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/integration-tests/suites/replay/errorResponse/test.ts b/packages/integration-tests/suites/replay/errorResponse/test.ts index 49f02bec4ec4..e3e3fa2d7217 100644 --- a/packages/integration-tests/suites/replay/errorResponse/test.ts +++ b/packages/integration-tests/suites/replay/errorResponse/test.ts @@ -32,11 +32,6 @@ sentryTest('errorResponse', async ({ getLocalTestPath, page }) => { expect(called).toBe(1); - await page.waitForFunction(() => { - // @ts-ignore private API - return window.Replay._replay !== undefined; - }); - const replay = await getReplaySnapshot(page); // @ts-ignore private API