Skip to content

Commit 821e986

Browse files
authored
fix(browser): Respect tunnel in diagnoseSdkConnectivity (#18616)
The example pages the Sentry wizard adds to the codebase use `.diagnoseSdkConnectivity()`. It's also possible to already set up a tunnel through the wizard. However, this tunnel was previously not respected. Closes #17991
1 parent 159cb23 commit 821e986

File tree

2 files changed

+95
-14
lines changed

2 files changed

+95
-14
lines changed

packages/browser/src/diagnose-sdk.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,28 @@ export async function diagnoseSdkConnectivity(): Promise<
2222
return 'no-dsn-configured';
2323
}
2424

25+
// Check if a tunnel is configured and use it if available
26+
const tunnel = client.getOptions().tunnel;
27+
28+
// We are using the
29+
// - "sentry-sdks" org with id 447951 not to pollute any actual organizations.
30+
// - "diagnose-sdk-connectivity" project with id 4509632503087104
31+
// - the public key of said org/project, which is disabled in the project settings
32+
// => this DSN: https://[email protected]/4509632503087104 (i.e. disabled)
33+
const defaultUrl =
34+
'https://o447951.ingest.sentry.io/api/4509632503087104/envelope/?sentry_version=7&sentry_key=c1dfb07d783ad5325c245c1fd3725390&sentry_client=sentry.javascript.browser%2F1.33.7';
35+
36+
const url = tunnel || defaultUrl;
37+
2538
try {
2639
await suppressTracing(() =>
2740
// If fetch throws, there is likely an ad blocker active or there are other connective issues.
28-
fetch(
29-
// We are using the
30-
// - "sentry-sdks" org with id 447951 not to pollute any actual organizations.
31-
// - "diagnose-sdk-connectivity" project with id 4509632503087104
32-
// - the public key of said org/project, which is disabled in the project settings
33-
// => this DSN: https://[email protected]/4509632503087104 (i.e. disabled)
34-
'https://o447951.ingest.sentry.io/api/4509632503087104/envelope/?sentry_version=7&sentry_key=c1dfb07d783ad5325c245c1fd3725390&sentry_client=sentry.javascript.browser%2F1.33.7',
35-
{
36-
body: '{}',
37-
method: 'POST',
38-
mode: 'cors',
39-
credentials: 'omit',
40-
},
41-
),
41+
fetch(url, {
42+
body: '{}',
43+
method: 'POST',
44+
mode: 'cors',
45+
credentials: 'omit',
46+
}),
4247
);
4348
} catch {
4449
return 'sentry-unreachable';

packages/browser/test/diagnose-sdk.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ describe('diagnoseSdkConnectivity', () => {
4242
it('returns "no-dsn-configured" when client.getDsn() returns undefined', async () => {
4343
const mockClient: Partial<Client> = {
4444
getDsn: vi.fn().mockReturnValue(undefined),
45+
getOptions: vi.fn().mockReturnValue({}),
4546
};
4647
mockGetClient.mockReturnValue(mockClient);
4748

@@ -55,6 +56,7 @@ describe('diagnoseSdkConnectivity', () => {
5556
it('returns "sentry-unreachable" when fetch throws an error', async () => {
5657
const mockClient: Partial<Client> = {
5758
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
59+
getOptions: vi.fn().mockReturnValue({}),
5860
};
5961
mockGetClient.mockReturnValue(mockClient);
6062
mockFetch.mockRejectedValue(new Error('Network error'));
@@ -77,6 +79,7 @@ describe('diagnoseSdkConnectivity', () => {
7779
it('returns "sentry-unreachable" when fetch throws a TypeError (common for network issues)', async () => {
7880
const mockClient: Partial<Client> = {
7981
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
82+
getOptions: vi.fn().mockReturnValue({}),
8083
};
8184
mockGetClient.mockReturnValue(mockClient);
8285
mockFetch.mockRejectedValue(new TypeError('Failed to fetch'));
@@ -91,6 +94,7 @@ describe('diagnoseSdkConnectivity', () => {
9194
it('returns undefined when connectivity check succeeds', async () => {
9295
const mockClient: Partial<Client> = {
9396
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
97+
getOptions: vi.fn().mockReturnValue({}),
9498
};
9599
mockGetClient.mockReturnValue(mockClient);
96100
mockFetch.mockResolvedValue(new Response('{}', { status: 200 }));
@@ -113,6 +117,7 @@ describe('diagnoseSdkConnectivity', () => {
113117
it('returns undefined even when fetch returns an error status (4xx, 5xx)', async () => {
114118
const mockClient: Partial<Client> = {
115119
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
120+
getOptions: vi.fn().mockReturnValue({}),
116121
};
117122
mockGetClient.mockReturnValue(mockClient);
118123
// Mock a 403 response (expected since the DSN is disabled)
@@ -129,6 +134,7 @@ describe('diagnoseSdkConnectivity', () => {
129134
it('uses the correct test endpoint URL', async () => {
130135
const mockClient: Partial<Client> = {
131136
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
137+
getOptions: vi.fn().mockReturnValue({}),
132138
};
133139
mockGetClient.mockReturnValue(mockClient);
134140
mockFetch.mockResolvedValue(new Response('{}', { status: 200 }));
@@ -149,6 +155,7 @@ describe('diagnoseSdkConnectivity', () => {
149155
it('uses correct fetch options', async () => {
150156
const mockClient: Partial<Client> = {
151157
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
158+
getOptions: vi.fn().mockReturnValue({}),
152159
};
153160
mockGetClient.mockReturnValue(mockClient);
154161
mockFetch.mockResolvedValue(new Response('{}', { status: 200 }));
@@ -168,6 +175,7 @@ describe('diagnoseSdkConnectivity', () => {
168175

169176
const mockClient: Partial<Client> = {
170177
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
178+
getOptions: vi.fn().mockReturnValue({}),
171179
};
172180
mockGetClient.mockReturnValue(mockClient);
173181
mockFetch.mockResolvedValue(new Response('{}', { status: 200 }));
@@ -176,4 +184,72 @@ describe('diagnoseSdkConnectivity', () => {
176184

177185
expect(suppressTracingSpy).toHaveBeenCalledTimes(1);
178186
});
187+
188+
it('uses tunnel URL when tunnel option is configured', async () => {
189+
const tunnelUrl = '/monitor';
190+
const mockClient: Partial<Client> = {
191+
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
192+
getOptions: vi.fn().mockReturnValue({ tunnel: tunnelUrl }),
193+
};
194+
mockGetClient.mockReturnValue(mockClient);
195+
mockFetch.mockResolvedValue(new Response('{}', { status: 200 }));
196+
197+
const result = await diagnoseSdkConnectivity();
198+
199+
expect(result).toBeUndefined();
200+
expect(mockFetch).toHaveBeenCalledWith(
201+
tunnelUrl,
202+
expect.objectContaining({
203+
body: '{}',
204+
method: 'POST',
205+
mode: 'cors',
206+
credentials: 'omit',
207+
}),
208+
);
209+
});
210+
211+
it('uses default URL when tunnel is not configured', async () => {
212+
const mockClient: Partial<Client> = {
213+
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
214+
getOptions: vi.fn().mockReturnValue({}),
215+
};
216+
mockGetClient.mockReturnValue(mockClient);
217+
mockFetch.mockResolvedValue(new Response('{}', { status: 200 }));
218+
219+
const result = await diagnoseSdkConnectivity();
220+
221+
expect(result).toBeUndefined();
222+
expect(mockFetch).toHaveBeenCalledWith(
223+
'https://o447951.ingest.sentry.io/api/4509632503087104/envelope/?sentry_version=7&sentry_key=c1dfb07d783ad5325c245c1fd3725390&sentry_client=sentry.javascript.browser%2F1.33.7',
224+
expect.objectContaining({
225+
body: '{}',
226+
method: 'POST',
227+
mode: 'cors',
228+
credentials: 'omit',
229+
}),
230+
);
231+
});
232+
233+
it('returns "sentry-unreachable" when tunnel is configured but unreachable', async () => {
234+
const tunnelUrl = '/monitor';
235+
const mockClient: Partial<Client> = {
236+
getDsn: vi.fn().mockReturnValue('https://[email protected]/123'),
237+
getOptions: vi.fn().mockReturnValue({ tunnel: tunnelUrl }),
238+
};
239+
mockGetClient.mockReturnValue(mockClient);
240+
mockFetch.mockRejectedValue(new Error('Network error'));
241+
242+
const result = await diagnoseSdkConnectivity();
243+
244+
expect(result).toBe('sentry-unreachable');
245+
expect(mockFetch).toHaveBeenCalledWith(
246+
tunnelUrl,
247+
expect.objectContaining({
248+
body: '{}',
249+
method: 'POST',
250+
mode: 'cors',
251+
credentials: 'omit',
252+
}),
253+
);
254+
});
179255
});

0 commit comments

Comments
 (0)