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 }}
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/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 },
+ });
+});
diff --git a/packages/integration-tests/suites/replay/errorResponse/test.ts b/packages/integration-tests/suites/replay/errorResponse/test.ts
index 1febee5916fb..e3e3fa2d7217 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();
}
@@ -31,7 +31,9 @@ sentryTest('errorResponse', async ({ getLocalTestPath, page }) => {
await page.waitForTimeout(5001);
expect(called).toBe(1);
+
const replay = await getReplaySnapshot(page);
- expect(replay['_isEnabled']).toBe(false);
+ // @ts-ignore private API
+ expect(replay._isEnabled).toBe(false);
});
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..d6521e53a614 100644
--- a/rollup/plugins/bundlePlugins.js
+++ b/rollup/plugins/bundlePlugins.js
@@ -107,6 +107,9 @@ export function makeTerserPlugin() {
'_driver',
'_initStorage',
'_support',
+ // We want to keept he _replay and _isEnabled variable unmangled to enable integration tests to access it
+ '_replay',
+ '_isEnabled',
],
},
},