1- import type * as SentryCore from '@sentry/core' ;
2- import { createEnvelope , makeDsn , serializeEnvelope } from '@sentry/core' ;
1+ import type { Client } from '@sentry/core' ;
2+ import { createEnvelope , getCurrentScope , makeDsn , serializeEnvelope } from '@sentry/core' ;
33import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest' ;
4+ import { serveTunnelIntegration } from '@sentry/core/server' ;
45import { createSentryTunnelRoute , POST } from '../../src/tunnel' ;
56
6- const { mockGetClient } = vi . hoisted ( ( ) => ( { mockGetClient : vi . fn ( ) } ) ) ;
7-
8- vi . mock ( '@sentry/core' , async importOriginal => ( {
9- ...( await importOriginal < typeof SentryCore > ( ) ) ,
10- getClient : mockGetClient ,
11- } ) ) ;
12-
137const SERVER_DSN = 'https://public@o1.ingest.sentry.io/1' ;
148const BROWSER_DSN = 'https://browser@o1.ingest.sentry.io/2' ;
159
@@ -33,7 +27,8 @@ function createEnvelopeRequest(dsn: string): { request: Request; body: Uint8Arra
3327}
3428
3529function useClientDsn ( dsn : string | undefined ) : void {
36- mockGetClient . mockReturnValue ( dsn ? { getDsn : ( ) => makeDsn ( dsn ) } : undefined ) ;
30+ const client = dsn ? ( { getDsn : ( ) => makeDsn ( dsn ) , getOptions : ( ) => ( { } ) } as unknown as Client ) : undefined ;
31+ getCurrentScope ( ) . setClient ( client ) ;
3732}
3833
3934let fetchSpy : ReturnType < typeof vi . spyOn > ;
@@ -75,9 +70,6 @@ describe('POST', () => {
7570 const response = await POST ( request ) ;
7671
7772 expect ( response . status ) . toBe ( 500 ) ;
78- await expect ( response . text ( ) ) . resolves . toBe (
79- 'Tunnel route requires Sentry server SDK initialized with a DSN, or pass allowedDsns explicitly.' ,
80- ) ;
8173 expect ( fetchSpy ) . not . toHaveBeenCalled ( ) ;
8274 } ) ;
8375
@@ -91,6 +83,22 @@ describe('POST', () => {
9183 expect ( fetchSpy ) . not . toHaveBeenCalled ( ) ;
9284 } ) ;
9385
86+ it ( 'accepts the DSNs `serveTunnelIntegration` allows' , async ( ) => {
87+ const integration = serveTunnelIntegration ( { allowedDsns : [ BROWSER_DSN ] } ) ;
88+ const options = { } ;
89+ const client = {
90+ getDsn : ( ) => makeDsn ( SERVER_DSN ) ,
91+ getOptions : ( ) => options ,
92+ getIntegrationByName : ( ) => integration ,
93+ } as unknown as Client ;
94+ integration . setup ?.( client ) ;
95+ getCurrentScope ( ) . setClient ( client ) ;
96+
97+ const response = await POST ( createEnvelopeRequest ( BROWSER_DSN ) . request ) ;
98+
99+ expect ( response . status ) . toBe ( 200 ) ;
100+ } ) ;
101+
94102 it ( 'does not accept DSNs from environment variables' , async ( ) => {
95103 useClientDsn ( SERVER_DSN ) ;
96104 vi . stubEnv ( 'SENTRY_DSN' , BROWSER_DSN ) ;
@@ -104,16 +112,18 @@ describe('POST', () => {
104112} ) ;
105113
106114describe ( 'createSentryTunnelRoute' , ( ) => {
107- it ( 'accepts only the DSNs in `allowedDsns`' , async ( ) => {
115+ it ( 'accepts the DSNs in `allowedDsns` and the server DSN ' , async ( ) => {
108116 useClientDsn ( SERVER_DSN ) ;
109117 const { POST : handler } = createSentryTunnelRoute ( { allowedDsns : [ BROWSER_DSN ] } ) ;
110118
111- const allowedResponse = await handler ( createEnvelopeRequest ( BROWSER_DSN ) . request ) ;
112- const rejectedResponse = await handler ( createEnvelopeRequest ( SERVER_DSN ) . request ) ;
119+ const browserResponse = await handler ( createEnvelopeRequest ( BROWSER_DSN ) . request ) ;
120+ const serverResponse = await handler ( createEnvelopeRequest ( SERVER_DSN ) . request ) ;
121+ const otherResponse = await handler ( createEnvelopeRequest ( 'https://other@o2.ingest.sentry.io/3' ) . request ) ;
113122
114- expect ( allowedResponse . status ) . toBe ( 200 ) ;
115- expect ( rejectedResponse . status ) . toBe ( 403 ) ;
116- expect ( fetchSpy ) . toHaveBeenCalledTimes ( 1 ) ;
123+ expect ( browserResponse . status ) . toBe ( 200 ) ;
124+ expect ( serverResponse . status ) . toBe ( 200 ) ;
125+ expect ( otherResponse . status ) . toBe ( 403 ) ;
126+ expect ( fetchSpy ) . toHaveBeenCalledTimes ( 2 ) ;
117127 } ) ;
118128
119129 it . each ( [
@@ -138,15 +148,13 @@ describe('createSentryTunnelRoute', () => {
138148 expect ( response . status ) . toBe ( 200 ) ;
139149 } ) ;
140150
141- it ( 'responds with 500 when no allowed DSN is valid' , async ( ) => {
151+ it ( 'responds with 500 when no allowed DSN is valid and the server SDK has no DSN ' , async ( ) => {
142152 vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => undefined ) ;
143- useClientDsn ( SERVER_DSN ) ;
144153 const { POST : handler } = createSentryTunnelRoute ( { allowedDsns : [ 'not-a-dsn' ] } ) ;
145154
146155 const response = await handler ( createEnvelopeRequest ( SERVER_DSN ) . request ) ;
147156
148157 expect ( response . status ) . toBe ( 500 ) ;
149- await expect ( response . text ( ) ) . resolves . toBe ( 'Tunnel route has no valid DSN in allowedDsns.' ) ;
150158 expect ( fetchSpy ) . not . toHaveBeenCalled ( ) ;
151159 } ) ;
152160} ) ;
0 commit comments