@@ -3,6 +3,7 @@ import { SDK_VERSION } from '@sentry/core';
33import { Hono } from 'hono' ;
44import { beforeEach , describe , expect , it , type Mock , vi } from 'vitest' ;
55import { sentry } from '../../src/bun/middleware' ;
6+ import { init } from '../../src/bun/sdk' ;
67
78vi . mock ( '@sentry/bun' , ( ) => ( {
89 init : vi . fn ( ) ,
@@ -18,10 +19,14 @@ vi.mock('@sentry/core', async () => {
1819 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1920 // @ts -ignore
2021 applySdkMetadata : vi . fn ( actual . applySdkMetadata ) ,
22+ getClient : vi . fn ( ( ) => undefined ) ,
23+ // Pass-through so console.warn calls inside consoleSandbox are observable in tests
24+ consoleSandbox : vi . fn ( ( cb : ( ) => unknown ) => cb ( ) ) ,
2125 } ;
2226} ) ;
2327
2428const applySdkMetadataMock = SentryCore . applySdkMetadata as Mock ;
29+ const getClientMock = SentryCore . getClient as Mock ;
2530
2631describe ( 'Hono Bun Middleware' , ( ) => {
2732 beforeEach ( ( ) => {
@@ -51,7 +56,8 @@ describe('Hono Bun Middleware', () => {
5156 expect ( applySdkMetadataMock ) . toHaveBeenCalledWith ( options , 'hono' , [ 'hono' , 'bun' ] ) ;
5257 } ) ;
5358
54- it ( 'calls init from @sentry/bun' , ( ) => {
59+ it ( 'calls init from @sentry/bun when no client exists yet' , ( ) => {
60+ getClientMock . mockReturnValue ( undefined ) ;
5561 const app = new Hono ( ) ;
5662 const options = {
5763 dsn : 'https://public@dsn.ingest.sentry.io/1337' ,
@@ -156,4 +162,47 @@ describe('Hono Bun Middleware', () => {
156162 ) ;
157163 } ) ;
158164 } ) ;
165+
166+ describe ( 'double-init guard' , ( ) => {
167+ it ( 'still calls init even when Sentry is already initialized' , ( ) => {
168+ const fakeClient = { getOptions : ( ) => ( { } ) } ;
169+ getClientMock . mockReturnValue ( fakeClient as unknown as SentryCore . Client ) ;
170+
171+ const app = new Hono ( ) ;
172+ sentry ( app , { dsn : 'https://public@dsn.ingest.sentry.io/1337' } ) ;
173+
174+ expect ( initBunMock ) . toHaveBeenCalledTimes ( 1 ) ;
175+ } ) ;
176+
177+ it ( 'emits a console.warn directing to remove the duplicate init call when Sentry is already initialized' , ( ) => {
178+ const warnSpy = vi . spyOn ( console , 'warn' ) ;
179+ const fakeClient = { getOptions : ( ) => ( { } ) } ;
180+ getClientMock . mockReturnValue ( fakeClient as unknown as SentryCore . Client ) ;
181+
182+ const app = new Hono ( ) ;
183+ sentry ( app , { dsn : 'https://public@dsn.ingest.sentry.io/1337' } ) ;
184+
185+ expect ( warnSpy ) . toHaveBeenCalledTimes ( 1 ) ;
186+ expect ( warnSpy ) . toHaveBeenCalledWith ( expect . stringContaining ( 'Sentry is already initialized' ) ) ;
187+ expect ( warnSpy ) . toHaveBeenCalledWith ( expect . stringContaining ( 'Remove the `Sentry.init()` call' ) ) ;
188+ } ) ;
189+
190+ it ( 'does not emit a console.warn when no client exists yet' , ( ) => {
191+ const warnSpy = vi . spyOn ( console , 'warn' ) ;
192+ getClientMock . mockReturnValue ( undefined ) ;
193+
194+ const app = new Hono ( ) ;
195+ sentry ( app , { dsn : 'https://public@dsn.ingest.sentry.io/1337' } ) ;
196+
197+ expect ( warnSpy ) . not . toHaveBeenCalled ( ) ;
198+ } ) ;
199+
200+ it ( 'always calls init regardless of whether a client already exists' , ( ) => {
201+ getClientMock . mockReturnValue ( undefined ) ;
202+
203+ init ( { dsn : 'https://public@dsn.ingest.sentry.io/1337' } ) ;
204+
205+ expect ( initBunMock ) . toHaveBeenCalledTimes ( 1 ) ;
206+ } ) ;
207+ } ) ;
159208} ) ;
0 commit comments