diff --git a/packages/browser-integration-tests/fixtures/loader.js b/packages/browser-integration-tests/fixtures/loader.js index c95b5eabdcac..36d7d2401856 100644 --- a/packages/browser-integration-tests/fixtures/loader.js +++ b/packages/browser-integration-tests/fixtures/loader.js @@ -1,4 +1,5 @@ -!function(n,e,t,r,o,a,i,c,_,p){for(var s=p,forceLoad=!1,f=0;f-1){s&&"no"===document.scripts[f].getAttribute("data-lazy")&&(s=!1);break}var u=!1,l=[],d=function(n){("e"in n||"p"in n||n.f&&n.f.indexOf("capture")>-1||n.f&&n.f.indexOf("showReportDialog")>-1)&&s&&E(l),d.data.push(n)};function E(i){if(!u){u=!0;var p=e.scripts[0],s=e.createElement(t);s.src=c,s.crossOrigin="anonymous",s.addEventListener("load",(function(){try{n[r]&&n[r].__SENTRY_LOADER__&&(n[r]=R),n[o]&&n[o].__SENTRY_LOADER__&&(n[o]=h),n.SENTRY_SDK_SOURCE="loader";var e=n[a],t=e.init,c=[];_.tracesSampleRate&&c.push(new e.BrowserTracing),(_.replaysSessionSampleRate||_.replaysOnErrorSampleRate)&&c.push(new e.Replay),c.length&&(_.integrations=c),e.init=function(n){var e=_;for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r]);t(e)},function(e,t){try{for(var a=0;a-1){p&&"no"===document.scripts[s].getAttribute("data-lazy")&&(p=!1);break}var u=!1,l=[],d=function(n){("e"in n||"p"in n||n.f&&n.f.indexOf("capture")>-1||n.f&&n.f.indexOf("showReportDialog")>-1)&&p&&R(l),d.data.push(n)};function R(o){if(!u){u=!0;var f=e.scripts[0],p=e.createElement(r);p.src=c,p.crossOrigin="anonymous",p.addEventListener("load",(function(){try{n[t]&&n[t].__SENTRY_LOADER__&&(n[t]=E),n[a]&&n[a].__SENTRY_LOADER__&&(n[a]=v),n.SENTRY_SDK_SOURCE="loader";var e=n[i],r=e.init;e.init=function(n){var t=_;for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&(t[a]=n[a]);!function(n,e){var r=n.integrations||[];if(!Array.isArray(r))return;var t=r.map((function(n){return n.name}));n.tracesSampleRate&&-1===t.indexOf("BrowserTracing")&&r.push(new e.BrowserTracing);(n.replaysSessionSampleRate||n.replaysOnErrorSampleRate)&&-1===t.indexOf("Replay")&&r.push(new e.Replay);n.integrations=r}(t,e),r(t)},function(e,r){try{for(var i=0;i { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const req = waitForTransactionRequest(page); + + const url = await getLocalTestUrl({ testDir: __dirname }); + await page.goto(url); + + const eventData = envelopeRequestParser(await req); + const timeOrigin = await page.evaluate('window._testBaseTimestamp'); + + const { start_timestamp: startTimestamp } = eventData; + + expect(startTimestamp).toBeCloseTo(timeOrigin, 1); + + expect(eventData.contexts?.trace?.op).toBe('pageload'); + expect(eventData.spans?.length).toBeGreaterThan(0); + expect(eventData.transaction_info?.source).toEqual('url'); + + const tracePropagationTargets = await page.evaluate(() => { + const browserTracing = (window as any).Sentry.getCurrentHub().getClient().getIntegrationById('BrowserTracing'); + return browserTracing.options.tracePropagationTargets; + }); + + expect(tracePropagationTargets).toEqual(['http://localhost:1234']); +}); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/init.js b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/init.js new file mode 100644 index 000000000000..a5440c1979c5 --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/init.js @@ -0,0 +1,19 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +class CustomIntegration { + constructor() { + this.name = 'CustomIntegration'; + } + + setupOnce() {} +} + +Sentry.onLoad(function () { + Sentry.init({ + integrations: [new CustomIntegration()], + }); + + window.__sentryLoaded = true; +}); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/subject.js b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/subject.js new file mode 100644 index 000000000000..707e54eefe7a --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/subject.js @@ -0,0 +1 @@ +Sentry.forceLoad(); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/test.ts b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/test.ts new file mode 100644 index 000000000000..836d10a8d486 --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrations/test.ts @@ -0,0 +1,40 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { shouldSkipTracingTest } from '../../../../utils/helpers'; +import { shouldSkipReplayTest } from '../../../../utils/replayHelpers'; + +sentryTest('should handle custom added integrations & default integrations', async ({ getLocalTestUrl, page }) => { + const shouldHaveReplay = !shouldSkipReplayTest(); + const shouldHaveBrowserTracing = !shouldSkipTracingTest(); + + 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 getLocalTestUrl({ testDir: __dirname }); + await page.goto(url); + + await page.waitForFunction(() => { + return (window as any).__sentryLoaded; + }); + + const hasCustomIntegration = await page.evaluate(() => { + return !!(window as any).Sentry.getCurrentHub().getClient().getIntegrationById('CustomIntegration'); + }); + + const hasReplay = await page.evaluate(() => { + return !!(window as any).Sentry.getCurrentHub().getClient().getIntegrationById('Replay'); + }); + const hasBrowserTracing = await page.evaluate(() => { + return !!(window as any).Sentry.getCurrentHub().getClient().getIntegrationById('BrowserTracing'); + }); + + expect(hasCustomIntegration).toEqual(true); + expect(hasReplay).toEqual(shouldHaveReplay); + expect(hasBrowserTracing).toEqual(shouldHaveBrowserTracing); +}); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/init.js b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/init.js new file mode 100644 index 000000000000..4c1e600794d5 --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/init.js @@ -0,0 +1,19 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +class CustomIntegration { + constructor() { + this.name = 'CustomIntegration'; + } + + setupOnce() {} +} + +Sentry.onLoad(function () { + Sentry.init({ + integrations: integrations => [new CustomIntegration()].concat(integrations), + }); + + window.__sentryLoaded = true; +}); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/subject.js b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/subject.js new file mode 100644 index 000000000000..707e54eefe7a --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/subject.js @@ -0,0 +1 @@ +Sentry.forceLoad(); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/test.ts b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/test.ts new file mode 100644 index 000000000000..7ff989922f33 --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customIntegrationsFunction/test.ts @@ -0,0 +1,38 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; + +sentryTest( + 'should not add default integrations if integrations function is provided', + async ({ getLocalTestUrl, page }) => { + 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 getLocalTestUrl({ testDir: __dirname }); + await page.goto(url); + + await page.waitForFunction(() => { + return (window as any).__sentryLoaded; + }); + + const hasCustomIntegration = await page.evaluate(() => { + return !!(window as any).Sentry.getCurrentHub().getClient().getIntegrationById('CustomIntegration'); + }); + + const hasReplay = await page.evaluate(() => { + return !!(window as any).Sentry.getCurrentHub().getClient().getIntegrationById('Replay'); + }); + const hasBrowserTracing = await page.evaluate(() => { + return !!(window as any).Sentry.getCurrentHub().getClient().getIntegrationById('BrowserTracing'); + }); + + expect(hasCustomIntegration).toEqual(true); + expect(hasReplay).toEqual(false); + expect(hasBrowserTracing).toEqual(false); + }, +); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customReplay/init.js b/packages/browser-integration-tests/loader-suites/loader/onLoad/customReplay/init.js new file mode 100644 index 000000000000..64d2463ed668 --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customReplay/init.js @@ -0,0 +1,14 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.onLoad(function () { + Sentry.init({ + integrations: [ + // Without this syntax, this will be re-written by the test framework + new window['Sentry'].Replay({ + useCompression: false, + }), + ], + }); +}); diff --git a/packages/browser-integration-tests/loader-suites/loader/onLoad/customReplay/test.ts b/packages/browser-integration-tests/loader-suites/loader/onLoad/customReplay/test.ts new file mode 100644 index 000000000000..f42868cf9ead --- /dev/null +++ b/packages/browser-integration-tests/loader-suites/loader/onLoad/customReplay/test.ts @@ -0,0 +1,35 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getReplayEvent, shouldSkipReplayTest, waitForReplayRequest } from '../../../../utils/replayHelpers'; + +sentryTest('should handle custom added Replay integration', async ({ getLocalTestUrl, page }) => { + if (shouldSkipReplayTest()) { + 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 req = waitForReplayRequest(page); + + const url = await getLocalTestUrl({ testDir: __dirname }); + await page.goto(url); + + const eventData = getReplayEvent(await req); + + expect(eventData).toBeDefined(); + expect(eventData.segment_id).toBe(0); + + const useCompression = await page.evaluate(() => { + const replay = (window as any).Sentry.getCurrentHub().getClient().getIntegrationById('Replay'); + return replay._replay.getOptions().useCompression; + }); + + expect(useCompression).toEqual(false); +}); diff --git a/packages/browser-integration-tests/package.json b/packages/browser-integration-tests/package.json index a61de94fb0bc..c8b9c92d19e8 100644 --- a/packages/browser-integration-tests/package.json +++ b/packages/browser-integration-tests/package.json @@ -41,7 +41,8 @@ "test:loader:full": "PW_BUNDLE=loader_tracing_replay yarn test:loader", "test:ci": "playwright test ./suites --browser='all' --reporter='line'", "test:update-snapshots": "yarn test --update-snapshots --browser='all' && yarn test --update-snapshots", - "test:detect-flaky": "ts-node scripts/detectFlakyTests.ts" + "test:detect-flaky": "ts-node scripts/detectFlakyTests.ts", + "validate:es5": "es-check es5 'fixtures/loader.js'" }, "dependencies": { "@babel/preset-typescript": "^7.16.7", diff --git a/packages/integrations/package.json b/packages/integrations/package.json index 6b79350fa5a9..6e799214516a 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -44,6 +44,7 @@ "lint": "run-s lint:prettier lint:eslint", "lint:eslint": "eslint . --format stylish", "lint:prettier": "prettier --check \"{src,test,scripts}/**/**.ts\"", + "validate:es5": "es-check es5 'build/bundles/*.es5*.js'", "test": "jest", "test:watch": "jest --watch", "yalc:publish": "ts-node ../../scripts/prepack.ts --bundles && yalc publish ./build/npm --push"