@@ -30,16 +30,14 @@ class OnPrefixDir {
3030
3131describe ( 'security integration tests' , function ( ) {
3232 beforeEach ( ( ) => {
33+ // Disable logging for these tests.
34+ spyOn ( console , 'log' ) . and . callFake ( ( ) => { } ) ;
35+
3336 TestBed . configureTestingModule ( {
3437 declarations : [ SecuredComponent , OnPrefixDir ] ,
3538 } ) ;
3639 } ) ;
3740
38- beforeEach ( ( ) => {
39- // Disable logging for these tests.
40- spyOn ( console , 'log' ) . and . callFake ( ( ) => { } ) ;
41- } ) ;
42-
4341 describe ( 'events' , ( ) => {
4442 // this test is similar to the previous one, but since on-prefixed attributes validation now
4543 // happens at runtime, we need to invoke change detection to trigger elementProperty call
@@ -48,8 +46,7 @@ describe('security integration tests', function () {
4846 TestBed . overrideComponent ( SecuredComponent , { set : { template} } ) ;
4947
5048 expect ( ( ) => {
51- const cmp = TestBed . createComponent ( SecuredComponent ) ;
52- cmp . detectChanges ( ) ;
49+ TestBed . createComponent ( SecuredComponent ) ;
5350 } ) . toThrowError (
5451 / B i n d i n g t o e v e n t a t t r i b u t e ' o n c l i c k ' i s d i s a l l o w e d f o r s e c u r i t y r e a s o n s , p l e a s e u s e \( c l i c k \) = .../ ,
5552 ) ;
@@ -89,6 +86,44 @@ describe('security integration tests', function () {
8986 expect ( div . nativeElement . onclick ) . not . toBe ( value ) ;
9087 expect ( div . nativeElement . hasAttribute ( 'onclick' ) ) . toEqual ( false ) ;
9188 } ) ;
89+
90+ for ( const ngDevModeValue of [ true , false ] ) {
91+ it ( `should disallow binding to attr.on* in host bindings with ngDevMode=${ ngDevModeValue } ` , ( ) => {
92+ const originalNgDevMode = ( globalThis as any ) . ngDevMode ;
93+ ( globalThis as any ) . ngDevMode = ngDevModeValue ;
94+
95+ @Directive ( {
96+ selector : '[dirOnclick]' ,
97+ standalone : false ,
98+ } )
99+ class LocalHostOnclickDirective {
100+ @HostBinding ( 'attr.onclick' ) @Input ( ) dirOnclick : string | undefined ;
101+ }
102+
103+ @Component ( {
104+ selector : 'local-comp' ,
105+ template : `<button [dirOnclick]="ctxProp"></button>` ,
106+ standalone : false ,
107+ } )
108+ class LocalSecuredComponent {
109+ ctxProp : any = 'some value' ;
110+ }
111+
112+ try {
113+ TestBed . configureTestingModule ( {
114+ declarations : [ LocalSecuredComponent , LocalHostOnclickDirective ] ,
115+ } ) ;
116+
117+ expect ( ( ) => {
118+ TestBed . createComponent ( LocalSecuredComponent ) ;
119+ } ) . toThrowError (
120+ / B i n d i n g t o e v e n t a t t r i b u t e ' o n c l i c k ' i s d i s a l l o w e d f o r s e c u r i t y r e a s o n s , p l e a s e u s e \( c l i c k \) = .../ ,
121+ ) ;
122+ } finally {
123+ ( globalThis as any ) . ngDevMode = originalNgDevMode ;
124+ }
125+ } ) ;
126+ }
92127 } ) ;
93128
94129 describe ( 'safe HTML values' , function ( ) {
0 commit comments