@@ -108,6 +108,130 @@ describe('Sentry Metro Serializer', () => {
108108 expect ( debugIdMatch2 ?. [ 1 ] ) . toBe ( debugId ) ;
109109 }
110110 } ) ;
111+
112+ describe ( 'calculateDebugId' , ( ) => {
113+ // We need to access the private function for testing
114+ const crypto = require ( 'crypto' ) ;
115+ const { stringToUUID } = require ( '../../src/js/tools/utils' ) ;
116+
117+ function calculateDebugId ( bundleCode : string , modules ?: Array < [ id : number , code : string ] > ) : string {
118+ const hash = crypto . createHash ( 'md5' ) ;
119+ hash . update ( bundleCode ) ;
120+ if ( modules ) {
121+ for ( const [ , code ] of modules ) {
122+ hash . update ( code ) ;
123+ }
124+ }
125+ return stringToUUID ( hash . digest ( 'hex' ) ) ;
126+ }
127+
128+ test ( 'generates a valid UUID v4 format' , ( ) => {
129+ const bundleCode = 'console.log("test");' ;
130+ const debugId = calculateDebugId ( bundleCode ) ;
131+
132+ expect ( debugId ) . toMatch ( / ^ [ 0 - 9 a - f A - F ] { 8 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 12 } $ / ) ;
133+ } ) ;
134+
135+ test ( 'generates deterministic debug ID for the same bundle code' , ( ) => {
136+ const bundleCode = 'console.log("test");' ;
137+ const debugId1 = calculateDebugId ( bundleCode ) ;
138+ const debugId2 = calculateDebugId ( bundleCode ) ;
139+
140+ expect ( debugId1 ) . toBe ( debugId2 ) ;
141+ } ) ;
142+
143+ test ( 'generates different debug IDs for different bundle code' , ( ) => {
144+ const bundleCode1 = 'console.log("test1");' ;
145+ const bundleCode2 = 'console.log("test2");' ;
146+ const debugId1 = calculateDebugId ( bundleCode1 ) ;
147+ const debugId2 = calculateDebugId ( bundleCode2 ) ;
148+
149+ expect ( debugId1 ) . not . toBe ( debugId2 ) ;
150+ } ) ;
151+
152+ test ( 'handles undefined modules parameter' , ( ) => {
153+ const bundleCode = 'console.log("test");' ;
154+ const debugId = calculateDebugId ( bundleCode , undefined ) ;
155+
156+ expect ( debugId ) . toMatch ( / ^ [ 0 - 9 a - f A - F ] { 8 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 12 } $ / ) ;
157+ } ) ;
158+
159+ test ( 'handles empty modules array' , ( ) => {
160+ const bundleCode = 'console.log("test");' ;
161+ const debugId1 = calculateDebugId ( bundleCode , [ ] ) ;
162+ const debugId2 = calculateDebugId ( bundleCode ) ;
163+
164+ // Should generate the same debug ID as without modules
165+ expect ( debugId1 ) . toBe ( debugId2 ) ;
166+ } ) ;
167+
168+ test ( 'includes modules in debug ID calculation' , ( ) => {
169+ const bundleCode = 'console.log("test");' ;
170+ const modules : Array < [ id : number , code : string ] > = [
171+ [ 1 , 'function foo() { return "bar"; }' ] ,
172+ [ 2 , 'function baz() { return "qux"; }' ] ,
173+ ] ;
174+
175+ const debugIdWithModules = calculateDebugId ( bundleCode , modules ) ;
176+ const debugIdWithoutModules = calculateDebugId ( bundleCode ) ;
177+
178+ expect ( debugIdWithModules ) . not . toBe ( debugIdWithoutModules ) ;
179+ } ) ;
180+
181+ test ( 'generates different debug IDs when modules differ' , ( ) => {
182+ const bundleCode = 'console.log("test");' ;
183+ const modules1 : Array < [ id : number , code : string ] > = [ [ 1 , 'function foo() { return "bar"; }' ] ] ;
184+ const modules2 : Array < [ id : number , code : string ] > = [ [ 1 , 'function foo() { return "baz"; }' ] ] ;
185+
186+ const debugId1 = calculateDebugId ( bundleCode , modules1 ) ;
187+ const debugId2 = calculateDebugId ( bundleCode , modules2 ) ;
188+
189+ expect ( debugId1 ) . not . toBe ( debugId2 ) ;
190+ } ) ;
191+
192+ test ( 'generates same debug ID when modules have same content but different IDs' , ( ) => {
193+ const bundleCode = 'console.log("test");' ;
194+ const modules1 : Array < [ id : number , code : string ] > = [ [ 1 , 'function foo() { return "bar"; }' ] ] ;
195+ const modules2 : Array < [ id : number , code : string ] > = [ [ 2 , 'function foo() { return "bar"; }' ] ] ;
196+
197+ const debugId1 = calculateDebugId ( bundleCode , modules1 ) ;
198+ const debugId2 = calculateDebugId ( bundleCode , modules2 ) ;
199+
200+ // Module IDs are not used in the hash calculation, only the code
201+ expect ( debugId1 ) . toBe ( debugId2 ) ;
202+ } ) ;
203+
204+ test ( 'generates different debug IDs when module order differs' , ( ) => {
205+ const bundleCode = 'console.log("test");' ;
206+ const modules1 : Array < [ id : number , code : string ] > = [
207+ [ 1 , 'function foo() { return "bar"; }' ] ,
208+ [ 2 , 'function baz() { return "qux"; }' ] ,
209+ ] ;
210+ const modules2 : Array < [ id : number , code : string ] > = [
211+ [ 2 , 'function baz() { return "qux"; }' ] ,
212+ [ 1 , 'function foo() { return "bar"; }' ] ,
213+ ] ;
214+
215+ const debugId1 = calculateDebugId ( bundleCode , modules1 ) ;
216+ const debugId2 = calculateDebugId ( bundleCode , modules2 ) ;
217+
218+ // Order matters in hash calculation
219+ expect ( debugId1 ) . not . toBe ( debugId2 ) ;
220+ } ) ;
221+
222+ test ( 'handles empty bundle code' , ( ) => {
223+ const debugId = calculateDebugId ( '' ) ;
224+
225+ expect ( debugId ) . toMatch ( / ^ [ 0 - 9 a - f A - F ] { 8 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 12 } $ / ) ;
226+ } ) ;
227+
228+ test ( 'handles large bundle code' , ( ) => {
229+ const largeBundleCode = 'console.log("test");' . repeat ( 10000 ) ;
230+ const debugId = calculateDebugId ( largeBundleCode ) ;
231+
232+ expect ( debugId ) . toMatch ( / ^ [ 0 - 9 a - f A - F ] { 8 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 4 } - [ 0 - 9 a - f A - F ] { 12 } $ / ) ;
233+ } ) ;
234+ } ) ;
111235} ) ;
112236
113237function mockMinSerializerArgs ( options ?: {
0 commit comments