@@ -299,6 +299,136 @@ describe('control directive', () => {
299299 expect ( component . customControl ( ) . required ( ) ) . toBe ( true ) ;
300300 } ) ;
301301 } ) ;
302+
303+ describe ( 'max' , ( ) => {
304+ it ( 'native control' , ( ) => {
305+ @Component ( {
306+ imports : [ Control ] ,
307+ template : `<input type="number" [control]="f">` ,
308+ } )
309+ class TestCmp {
310+ readonly max = signal ( 10 ) ;
311+ readonly f = form ( signal ( 5 ) , ( p ) => {
312+ max ( p , this . max ) ;
313+ } ) ;
314+ }
315+
316+ const fixture = act ( ( ) => TestBed . createComponent ( TestCmp ) ) ;
317+ const element = fixture . nativeElement . firstChild as HTMLInputElement ;
318+ expect ( element . max ) . toBe ( '10' ) ;
319+
320+ act ( ( ) => fixture . componentInstance . max . set ( 5 ) ) ;
321+ expect ( element . max ) . toBe ( '5' ) ;
322+ } ) ;
323+
324+ it ( 'custom control' , ( ) => {
325+ @Component ( { selector : 'custom-control' , template : `` } )
326+ class CustomControl {
327+ readonly value = model ( 0 ) ;
328+ readonly max = input < number | null > ( null ) ;
329+ }
330+
331+ @Component ( {
332+ imports : [ Control , CustomControl ] ,
333+ template : `<custom-control [control]="f" />` ,
334+ } )
335+ class TestCmp {
336+ readonly max = signal ( 10 ) ;
337+ readonly f = form ( signal ( 5 ) , ( p ) => {
338+ max ( p , this . max ) ;
339+ } ) ;
340+ readonly customControl = viewChild . required ( CustomControl ) ;
341+ }
342+
343+ const fixture = act ( ( ) => TestBed . createComponent ( TestCmp ) ) ;
344+ const component = fixture . componentInstance ;
345+ expect ( component . customControl ( ) . max ( ) ) . toBe ( 10 ) ;
346+
347+ act ( ( ) => component . max . set ( 5 ) ) ;
348+ expect ( component . customControl ( ) . max ( ) ) . toBe ( 5 ) ;
349+ } ) ;
350+
351+ it ( 'is not set on native control if type does not support it' , ( ) => {
352+ @Component ( {
353+ imports : [ Control ] ,
354+ template : `<input type="text" [control]="f">` ,
355+ } )
356+ class TestCmp {
357+ readonly f = form ( signal ( 5 ) , ( p ) => {
358+ max ( p , 10 ) ;
359+ } ) ;
360+ }
361+
362+ const fixture = act ( ( ) => TestBed . createComponent ( TestCmp ) ) ;
363+ const element = fixture . nativeElement . firstChild as HTMLInputElement ;
364+ expect ( element . max ) . toBe ( '' ) ;
365+ } ) ;
366+ } ) ;
367+
368+ describe ( 'min' , ( ) => {
369+ it ( 'native control' , ( ) => {
370+ @Component ( {
371+ imports : [ Control ] ,
372+ template : `<input type="number" [control]="f">` ,
373+ } )
374+ class TestCmp {
375+ readonly min = signal ( 10 ) ;
376+ readonly f = form ( signal ( 15 ) , ( p ) => {
377+ min ( p , this . min ) ;
378+ } ) ;
379+ }
380+
381+ const fixture = act ( ( ) => TestBed . createComponent ( TestCmp ) ) ;
382+ const element = fixture . nativeElement . firstChild as HTMLInputElement ;
383+ expect ( element . min ) . toBe ( '10' ) ;
384+
385+ act ( ( ) => fixture . componentInstance . min . set ( 5 ) ) ;
386+ expect ( element . min ) . toBe ( '5' ) ;
387+ } ) ;
388+
389+ it ( 'custom control' , ( ) => {
390+ @Component ( { selector : 'custom-control' , template : `` } )
391+ class CustomControl {
392+ readonly value = model ( 0 ) ;
393+ readonly min = input < number > ( ) ;
394+ }
395+
396+ @Component ( {
397+ imports : [ Control , CustomControl ] ,
398+ template : `<custom-control [control]="f" />` ,
399+ } )
400+ class TestCmp {
401+ readonly min = signal ( 10 ) ;
402+ readonly f = form ( signal ( 15 ) , ( p ) => {
403+ min ( p , this . min ) ;
404+ } ) ;
405+ readonly customControl = viewChild . required ( CustomControl ) ;
406+ }
407+
408+ const fixture = act ( ( ) => TestBed . createComponent ( TestCmp ) ) ;
409+ const component = fixture . componentInstance ;
410+ expect ( component . customControl ( ) . min ( ) ) . toBe ( 10 ) ;
411+
412+ act ( ( ) => component . min . set ( 5 ) ) ;
413+ expect ( component . customControl ( ) . min ( ) ) . toBe ( 5 ) ;
414+ } ) ;
415+
416+ it ( 'is not set on native control if type does not support it' , ( ) => {
417+ @Component ( {
418+ imports : [ Control ] ,
419+ template : `<input type="text" [control]="f">` ,
420+ } )
421+ class TestCmp {
422+ readonly f = form ( signal ( 15 ) , ( p ) => {
423+ min ( p , 10 ) ;
424+ } ) ;
425+ }
426+
427+ const fixture = act ( ( ) => TestBed . createComponent ( TestCmp ) ) ;
428+ const element = fixture . nativeElement . firstChild as HTMLInputElement ;
429+ expect ( element . min ) . toBe ( '' ) ;
430+ } ) ;
431+ } ) ;
302432 } ) ;
303433
304434 it ( 'synchronizes a basic form with a custom control' , ( ) => {
0 commit comments