11import { Compiler } from "webpack" ;
2- import { getDebugIdSnippet , sentryUnpluginFactory } from "../src" ;
2+ import { getDebugIdSnippet , sentryUnpluginFactory , createRollupDebugIdInjectionHooks } from "../src" ;
33
44describe ( "getDebugIdSnippet" , ( ) => {
55 it ( "returns the debugId injection snippet for a passed debugId" , ( ) => {
@@ -10,6 +10,85 @@ describe("getDebugIdSnippet", () => {
1010 } ) ;
1111} ) ;
1212
13+ describe ( "createRollupDebugIdInjectionHooks" , ( ) => {
14+ const hooks = createRollupDebugIdInjectionHooks ( ) ;
15+
16+ describe ( "renderChunk" , ( ) => {
17+ it ( "should inject debug ID into clean JavaScript files" , ( ) => {
18+ const code = 'console.log("Hello world");' ;
19+ const result = hooks . renderChunk ( code , { fileName : "bundle.js" } ) ;
20+
21+ expect ( result ) . not . toBeNull ( ) ;
22+ expect ( result ?. code ) . toContain ( "_sentryDebugIdIdentifier" ) ;
23+ expect ( result ?. code ) . toContain ( 'console.log("Hello world");' ) ;
24+ } ) ;
25+
26+ it ( "should inject debug ID after 'use strict'" , ( ) => {
27+ const code = '"use strict";\nconsole.log("Hello world");' ;
28+ const result = hooks . renderChunk ( code , { fileName : "bundle.js" } ) ;
29+
30+ expect ( result ) . not . toBeNull ( ) ;
31+ expect ( result ?. code ) . toMatch ( / ^ " u s e s t r i c t " ; .* ; { try/ ) ;
32+ } ) ;
33+
34+ it . each ( [
35+ [ "bundle.js" , true ] ,
36+ [ "bundle.mjs" , true ] ,
37+ [ "bundle.cjs" , true ] ,
38+ [ "bundle.js?foo=bar" , true ] ,
39+ [ "bundle.js#hash" , true ] ,
40+ [ "index.html" , false ] ,
41+ [ "styles.css" , false ] ,
42+ ] ) ( "should process file '%s': %s" , ( fileName , shouldProcess ) => {
43+ const code = 'console.log("test");' ;
44+ const result = hooks . renderChunk ( code , { fileName } ) ;
45+
46+ if ( shouldProcess ) {
47+ expect ( result ) . not . toBeNull ( ) ;
48+ expect ( result ?. code ) . toContain ( "_sentryDebugIdIdentifier" ) ;
49+ } else {
50+ expect ( result ) . toBeNull ( ) ;
51+ }
52+ } ) ;
53+
54+ it . each ( [
55+ [
56+ "inline format at start" ,
57+ ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};console.log("test");' ,
58+ ] ,
59+ [
60+ "comment format at end" ,
61+ 'console.log("test");\n//# debugId=f6ccd6f4-7ea0-4854-8384-1c9f8340af81\n//# sourceMappingURL=bundle.js.map' ,
62+ ] ,
63+ [
64+ "inline format with large file" ,
65+ '"use strict";\n' +
66+ "// comment\n" . repeat ( 10 ) +
67+ ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' +
68+ '\nconsole.log("line");\n' . repeat ( 100 ) ,
69+ ] ,
70+ ] ) ( "should NOT inject when debug ID already exists (%s)" , ( _description , code ) => {
71+ const result = hooks . renderChunk ( code , { fileName : "bundle.js" } ) ;
72+ expect ( result ) . toBeNull ( ) ;
73+ } ) ;
74+
75+ it ( "should only check boundaries for performance (not entire file)" , ( ) => {
76+ // Inline format beyond first 2KB boundary
77+ const codeWithInlineBeyond2KB =
78+ "a" . repeat ( 2100 ) +
79+ ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' ;
80+
81+ expect ( hooks . renderChunk ( codeWithInlineBeyond2KB , { fileName : "bundle.js" } ) ) . not . toBeNull ( ) ;
82+
83+ // Comment format beyond last 500 bytes boundary
84+ const codeWithCommentBeyond500B =
85+ "//# debugId=f6ccd6f4-7ea0-4854-8384-1c9f8340af81\n" + "a" . repeat ( 600 ) ;
86+
87+ expect ( hooks . renderChunk ( codeWithCommentBeyond500B , { fileName : "bundle.js" } ) ) . not . toBeNull ( ) ;
88+ } ) ;
89+ } ) ;
90+ } ) ;
91+
1392describe ( "sentryUnpluginFactory sourcemaps.disable behavior" , ( ) => {
1493 const mockReleaseInjectionPlugin = jest . fn ( ( _injectionCode : string ) => ( {
1594 name : "mock-release-injection-plugin" ,
0 commit comments