@@ -153,23 +153,29 @@ fn builtins_still_work_after_custom_registration() {
153153 } ) ;
154154}
155155
156- // ── Override prevention ────────────────────────────────────────────────────
156+ // ── Built-in override ── ────────────────────────────────────────────────────
157157
158158#[ test]
159- #[ should_panic( expected = "conflicts with a built-in module" ) ]
160- fn registering_builtin_name_panics ( ) {
159+ #[ should_panic( expected = "Cannot override the 'require' module" ) ]
160+ fn overriding_require_panics ( ) {
161161 #[ rquickjs:: module( rename_vars = "camelCase" ) ]
162- mod fake_io {
162+ mod fake_require {
163163 #[ rquickjs:: function]
164- pub fn print ( _txt : String ) { }
164+ pub fn require ( _name : String ) -> String {
165+ String :: from ( "fake" )
166+ }
165167 }
166168
167169 hyperlight_js_runtime:: modules:: register_native_module (
168- "io " ,
169- hyperlight_js_runtime:: modules:: declaration :: < js_fake_io > ( ) ,
170+ "require " ,
171+ hyperlight_js_runtime:: modules:: declaration :: < js_fake_require > ( ) ,
170172 ) ;
171173}
172174
175+ // Note: overriding io/crypto/console is allowed but tested via the
176+ // full-pipeline extended_runtime fixture to avoid poisoning the shared
177+ // static module registry used by other tests in this process.
178+
173179// ── native_modules! macro ──────────────────────────────────────────────────
174180
175181#[ rquickjs:: module( rename_vars = "camelCase" ) ]
@@ -192,9 +198,20 @@ fn setup_test_constant(ctx: &rquickjs::Ctx<'_>) -> rquickjs::Result<()> {
192198 Ok ( ( ) )
193199}
194200
201+ fn setup_console_extensions ( ctx : & rquickjs:: Ctx < ' _ > ) -> rquickjs:: Result < ( ) > {
202+ ctx. eval :: < ( ) , _ > (
203+ r#"
204+ console.warn = console.log;
205+ console.error = console.log;
206+ "# ,
207+ ) ?;
208+ Ok ( ( ) )
209+ }
210+
195211// The macro generates init_custom_globals() which calls each setup function
196212hyperlight_js_runtime:: custom_globals! {
197213 setup_test_constant,
214+ setup_console_extensions,
198215}
199216
200217#[ test]
@@ -460,6 +477,26 @@ fn full_pipeline_console_log_with_custom_modules() {
460477
461478// ── custom_globals! tests ──────────────────────────────────────────────────
462479
480+ #[ test]
481+ fn e2e_console_warn_works_via_custom_globals ( ) {
482+ let mut runtime =
483+ hyperlight_js_runtime:: JsRuntime :: new ( NoOpHost ) . expect ( "Failed to create JsRuntime" ) ;
484+
485+ let handler = r#"
486+ export function handler() {
487+ console.warn("warn test");
488+ console.error("error test");
489+ return "ok";
490+ }
491+ "# ;
492+
493+ runtime. register_handler ( "warn_test" , handler, "." ) . unwrap ( ) ;
494+ let result = runtime
495+ . run_handler ( "warn_test" . into ( ) , "{}" . into ( ) , false )
496+ . unwrap ( ) ;
497+ assert_eq ! ( result, "\" ok\" " ) ;
498+ }
499+
463500#[ test]
464501fn e2e_custom_globals_are_available_in_handlers ( ) {
465502 let mut runtime =
@@ -574,3 +611,102 @@ fn full_pipeline_custom_globals_with_modules() {
574611 "Expected 42 + 8 = 50, got: {stdout}"
575612 ) ;
576613}
614+ // ── globals freeze tests ───────────────────────────────────────────────────
615+
616+ #[ test]
617+ fn e2e_console_is_extensible_during_custom_globals ( ) {
618+ // setup_test_constant already runs via custom_globals! in this file.
619+ // Verify custom globals constant works (proves custom_globals! ran).
620+ let mut runtime =
621+ hyperlight_js_runtime:: JsRuntime :: new ( NoOpHost ) . expect ( "Failed to create JsRuntime" ) ;
622+
623+ let handler = r#"
624+ export function handler() {
625+ return TEST_CUSTOM_GLOBAL;
626+ }
627+ "# ;
628+
629+ runtime
630+ . register_handler ( "extensible_test" , handler, "." )
631+ . unwrap ( ) ;
632+
633+ let result = runtime
634+ . run_handler ( "extensible_test" . into ( ) , "{}" . into ( ) , false )
635+ . unwrap ( ) ;
636+ assert_eq ! ( result, "99" ) ;
637+ }
638+
639+ #[ test]
640+ fn e2e_console_frozen_after_init ( ) {
641+ let mut runtime =
642+ hyperlight_js_runtime:: JsRuntime :: new ( NoOpHost ) . expect ( "Failed to create JsRuntime" ) ;
643+
644+ let handler = r#"
645+ export function handler() {
646+ try {
647+ console.custom = function() {};
648+ return "not_frozen";
649+ } catch(e) {
650+ return "frozen";
651+ }
652+ }
653+ "# ;
654+
655+ runtime
656+ . register_handler ( "freeze_test" , handler, "." )
657+ . unwrap ( ) ;
658+ let result = runtime
659+ . run_handler ( "freeze_test" . into ( ) , "{}" . into ( ) , false )
660+ . unwrap ( ) ;
661+ assert ! (
662+ result. contains( "frozen" ) ,
663+ "console should be frozen, got: {result}"
664+ ) ;
665+ }
666+
667+ #[ test]
668+ fn e2e_print_frozen_after_init ( ) {
669+ let mut runtime =
670+ hyperlight_js_runtime:: JsRuntime :: new ( NoOpHost ) . expect ( "Failed to create JsRuntime" ) ;
671+
672+ let handler = r#"
673+ export function handler() {
674+ try {
675+ globalThis.print = function() {};
676+ return "not_frozen";
677+ } catch(e) {
678+ return "frozen";
679+ }
680+ }
681+ "# ;
682+
683+ runtime
684+ . register_handler ( "print_freeze" , handler, "." )
685+ . unwrap ( ) ;
686+ let result = runtime
687+ . run_handler ( "print_freeze" . into ( ) , "{}" . into ( ) , false )
688+ . unwrap ( ) ;
689+ assert ! (
690+ result. contains( "frozen" ) ,
691+ "print should be frozen, got: {result}"
692+ ) ;
693+ }
694+
695+ #[ test]
696+ fn e2e_console_log_still_works_after_freeze ( ) {
697+ let mut runtime =
698+ hyperlight_js_runtime:: JsRuntime :: new ( NoOpHost ) . expect ( "Failed to create JsRuntime" ) ;
699+
700+ let handler = r#"
701+ export function handler() {
702+ console.log("still works");
703+ return "ok";
704+ }
705+ "# ;
706+
707+ runtime. register_handler ( "log_test" , handler, "." ) . unwrap ( ) ;
708+ let result = runtime
709+ . run_handler ( "log_test" . into ( ) , "{}" . into ( ) , false )
710+ . unwrap ( ) ;
711+ assert_eq ! ( result, "\" ok\" " ) ;
712+ }
0 commit comments