diff --git a/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/init.js b/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/init.js new file mode 100644 index 000000000000..8c0a0cd9fca4 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/init.js @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [Sentry.browserTracingIntegration({ idleTimeout: 3000, childSpanTimeout: 3000 })], + tracesSampleRate: 1, +}); diff --git a/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/subject.js b/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/subject.js new file mode 100644 index 000000000000..c1239ac16b0e --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/subject.js @@ -0,0 +1 @@ +Sentry.diagnoseSdkConnectivity().then(res => console.log('SDK connectivity:', res)); diff --git a/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/test.ts b/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/test.ts new file mode 100644 index 000000000000..294e60b34bfd --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/diagnoseSdkConnectivity/test.ts @@ -0,0 +1,49 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../utils/fixtures'; +import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../utils/helpers'; + +sentryTest('makes a call to sentry.io to diagnose SDK connectivity', async ({ getLocalTestUrl, page }) => { + const bundle = process.env.PW_BUNDLE as string | undefined; + if (shouldSkipTracingTest() || !!bundle) { + // the CDN bundle doesn't export diagnoseSdkConnectivity. So skipping the test for bundles. + sentryTest.skip(); + } + + const pageloadRequestPromise = waitForTransactionRequest(page, e => e.contexts?.trace?.op === 'pageload'); + + // mock sdk connectivity url to avoid making actual request to sentry.io + page.route('**/api/4509632503087104/envelope/**/*', route => { + return route.fulfill({ + status: 200, + body: '{}', + }); + }); + + const diagnoseMessagePromise = new Promise(resolve => { + page.on('console', msg => { + if (msg.text().includes('SDK connectivity:')) { + resolve(msg.text()); + } + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + await page.goto(url); + + const pageLoadEvent = envelopeRequestParser(await pageloadRequestPromise); + + // undefined is expected and means the request was successful + expect(await diagnoseMessagePromise).toEqual('SDK connectivity: undefined'); + + // the request to sentry.io should not be traced, hence no http.client span should be sent. + const httpClientSpans = pageLoadEvent.spans?.filter(s => s.op === 'http.client'); + expect(httpClientSpans).toHaveLength(0); + + // no fetch breadcrumb should be sent (only breadcrumb for the console log) + expect(pageLoadEvent.breadcrumbs).toEqual([ + expect.objectContaining({ + category: 'console', + message: 'SDK connectivity: undefined', + }), + ]); +}); diff --git a/packages/browser/src/diagnose-sdk.ts b/packages/browser/src/diagnose-sdk.ts index a8b433856f01..0ad4bef69d6c 100644 --- a/packages/browser/src/diagnose-sdk.ts +++ b/packages/browser/src/diagnose-sdk.ts @@ -1,4 +1,4 @@ -import { getClient } from '@sentry/core'; +import { getClient, suppressTracing } from '@sentry/core'; /** * A function to diagnose why the SDK might not be successfully sending data. @@ -23,20 +23,22 @@ export async function diagnoseSdkConnectivity(): Promise< } try { - // If fetch throws, there is likely an ad blocker active or there are other connective issues. - await fetch( - // We are using the - // - "sentry-sdks" org with id 447951 not to pollute any actual organizations. - // - "diagnose-sdk-connectivity" project with id 4509632503087104 - // - the public key of said org/project, which is disabled in the project settings - // => this DSN: https://c1dfb07d783ad5325c245c1fd3725390@o447951.ingest.us.sentry.io/4509632503087104 (i.e. disabled) - 'https://o447951.ingest.sentry.io/api/4509632503087104/envelope/?sentry_version=7&sentry_key=c1dfb07d783ad5325c245c1fd3725390&sentry_client=sentry.javascript.browser%2F1.33.7', - { - body: '{}', - method: 'POST', - mode: 'cors', - credentials: 'omit', - }, + await suppressTracing(() => + // If fetch throws, there is likely an ad blocker active or there are other connective issues. + fetch( + // We are using the + // - "sentry-sdks" org with id 447951 not to pollute any actual organizations. + // - "diagnose-sdk-connectivity" project with id 4509632503087104 + // - the public key of said org/project, which is disabled in the project settings + // => this DSN: https://c1dfb07d783ad5325c245c1fd3725390@o447951.ingest.us.sentry.io/4509632503087104 (i.e. disabled) + 'https://o447951.ingest.sentry.io/api/4509632503087104/envelope/?sentry_version=7&sentry_key=c1dfb07d783ad5325c245c1fd3725390&sentry_client=sentry.javascript.browser%2F1.33.7', + { + body: '{}', + method: 'POST', + mode: 'cors', + credentials: 'omit', + }, + ), ); } catch { return 'sentry-unreachable'; diff --git a/packages/browser/test/diagnose-sdk.test.ts b/packages/browser/test/diagnose-sdk.test.ts index 36584a97f63b..5bc05dc6cf56 100644 --- a/packages/browser/test/diagnose-sdk.test.ts +++ b/packages/browser/test/diagnose-sdk.test.ts @@ -162,4 +162,18 @@ describe('diagnoseSdkConnectivity', () => { credentials: 'omit', }); }); + + it('calls suppressTracing to avoid tracing the fetch call to sentry', async () => { + const suppressTracingSpy = vi.spyOn(sentryCore, 'suppressTracing'); + + const mockClient: Partial = { + getDsn: vi.fn().mockReturnValue('https://test@example.com/123'), + }; + mockGetClient.mockReturnValue(mockClient); + mockFetch.mockResolvedValue(new Response('{}', { status: 200 })); + + await diagnoseSdkConnectivity(); + + expect(suppressTracingSpy).toHaveBeenCalledTimes(1); + }); });