@@ -38,16 +38,14 @@ class OnPrefixDir {
3838
3939describe ( 'security integration tests' , function ( ) {
4040 beforeEach ( ( ) => {
41+ // Disable logging for these tests.
42+ spyOn ( console , 'log' ) . and . callFake ( ( ) => { } ) ;
43+
4144 TestBed . configureTestingModule ( {
4245 declarations : [ SecuredComponent , OnPrefixDir ] ,
4346 } ) ;
4447 } ) ;
4548
46- beforeEach ( ( ) => {
47- // Disable logging for these tests.
48- spyOn ( console , 'log' ) . and . callFake ( ( ) => { } ) ;
49- } ) ;
50-
5149 describe ( 'events' , ( ) => {
5250 // this test is similar to the previous one, but since on-prefixed attributes validation now
5351 // happens at runtime, we need to invoke change detection to trigger elementProperty call
@@ -56,8 +54,7 @@ describe('security integration tests', function () {
5654 TestBed . overrideComponent ( SecuredComponent , { set : { template} } ) ;
5755
5856 expect ( ( ) => {
59- const cmp = TestBed . createComponent ( SecuredComponent ) ;
60- cmp . detectChanges ( ) ;
57+ TestBed . createComponent ( SecuredComponent ) ;
6158 } ) . toThrowError (
6259 / 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 \) = .../ ,
6360 ) ;
@@ -97,6 +94,44 @@ describe('security integration tests', function () {
9794 expect ( div . nativeElement . onclick ) . not . toBe ( value ) ;
9895 expect ( div . nativeElement . hasAttribute ( 'onclick' ) ) . toEqual ( false ) ;
9996 } ) ;
97+
98+ for ( const ngDevModeValue of [ true , false ] ) {
99+ it ( `should disallow binding to attr.on* in host bindings with ngDevMode=${ ngDevModeValue } ` , ( ) => {
100+ const originalNgDevMode = ( globalThis as any ) . ngDevMode ;
101+ ( globalThis as any ) . ngDevMode = ngDevModeValue ;
102+
103+ @Directive ( {
104+ selector : '[dirOnclick]' ,
105+ standalone : false ,
106+ } )
107+ class LocalHostOnclickDirective {
108+ @HostBinding ( 'attr.onclick' ) @Input ( ) dirOnclick : string | undefined ;
109+ }
110+
111+ @Component ( {
112+ selector : 'local-comp' ,
113+ template : `<button [dirOnclick]="ctxProp"></button>` ,
114+ standalone : false ,
115+ } )
116+ class LocalSecuredComponent {
117+ ctxProp : any = 'some value' ;
118+ }
119+
120+ try {
121+ TestBed . configureTestingModule ( {
122+ declarations : [ LocalSecuredComponent , LocalHostOnclickDirective ] ,
123+ } ) ;
124+
125+ expect ( ( ) => {
126+ TestBed . createComponent ( LocalSecuredComponent ) ;
127+ } ) . toThrowError (
128+ / 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 \) = .../ ,
129+ ) ;
130+ } finally {
131+ ( globalThis as any ) . ngDevMode = originalNgDevMode ;
132+ }
133+ } ) ;
134+ }
100135 } ) ;
101136
102137 describe ( 'safe HTML values' , function ( ) {
0 commit comments