@@ -3508,7 +3508,7 @@ describe('MatSelect', () => {
35083508 expect ( trigger . textContent ) . not . toContain ( 'None' ) ;
35093509 } ) ) ;
35103510
3511- it ( 'should not mark the reset option as selected ' , fakeAsync ( ( ) => {
3511+ it ( 'should not mark the reset option as selected' , fakeAsync ( ( ) => {
35123512 options [ 5 ] . click ( ) ;
35133513 fixture . detectChanges ( ) ;
35143514 flush ( ) ;
@@ -3545,6 +3545,102 @@ describe('MatSelect', () => {
35453545 } ) ;
35463546 } ) ;
35473547
3548+ describe ( 'allowing selection of nullable options' , ( ) => {
3549+ beforeEach ( waitForAsync ( ( ) => configureMatSelectTestingModule ( [ ResetValuesSelect ] ) ) ) ;
3550+
3551+ let fixture : ComponentFixture < ResetValuesSelect > ;
3552+ let trigger : HTMLElement ;
3553+ let formField : HTMLElement ;
3554+ let options : NodeListOf < HTMLElement > ;
3555+ let label : HTMLLabelElement ;
3556+
3557+ beforeEach ( fakeAsync ( ( ) => {
3558+ fixture = TestBed . createComponent ( ResetValuesSelect ) ;
3559+ fixture . componentInstance . canSelectNullableOptions = true ;
3560+ fixture . detectChanges ( ) ;
3561+ trigger = fixture . debugElement . query ( By . css ( '.mat-mdc-select-trigger' ) ) ! . nativeElement ;
3562+ formField = fixture . debugElement . query ( By . css ( '.mat-mdc-form-field' ) ) ! . nativeElement ;
3563+ label = formField . querySelector ( 'label' ) ! ;
3564+
3565+ trigger . click ( ) ;
3566+ fixture . detectChanges ( ) ;
3567+ flush ( ) ;
3568+
3569+ options = overlayContainerElement . querySelectorAll ( 'mat-option' ) as NodeListOf < HTMLElement > ;
3570+ options [ 0 ] . click ( ) ;
3571+ fixture . detectChanges ( ) ;
3572+ flush ( ) ;
3573+ } ) ) ;
3574+
3575+ it ( 'should select an option with an undefined value' , fakeAsync ( ( ) => {
3576+ options [ 4 ] . click ( ) ;
3577+ fixture . detectChanges ( ) ;
3578+ flush ( ) ;
3579+
3580+ expect ( fixture . componentInstance . control . value ) . toBe ( undefined ) ;
3581+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3582+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3583+ expect ( trigger . textContent ) . toContain ( 'Undefined' ) ;
3584+ } ) ) ;
3585+
3586+ it ( 'should select an option with a null value' , fakeAsync ( ( ) => {
3587+ options [ 5 ] . click ( ) ;
3588+ fixture . detectChanges ( ) ;
3589+ flush ( ) ;
3590+
3591+ expect ( fixture . componentInstance . control . value ) . toBe ( null ) ;
3592+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3593+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3594+ expect ( trigger . textContent ) . toContain ( 'Null' ) ;
3595+ } ) ) ;
3596+
3597+ it ( 'should select a blank option' , fakeAsync ( ( ) => {
3598+ options [ 6 ] . click ( ) ;
3599+ fixture . detectChanges ( ) ;
3600+ flush ( ) ;
3601+
3602+ expect ( fixture . componentInstance . control . value ) . toBe ( undefined ) ;
3603+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3604+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3605+ expect ( trigger . textContent ) . toContain ( 'None' ) ;
3606+ } ) ) ;
3607+
3608+ it ( 'should mark a nullable option as selected' , fakeAsync ( ( ) => {
3609+ options [ 5 ] . click ( ) ;
3610+ fixture . detectChanges ( ) ;
3611+ flush ( ) ;
3612+
3613+ fixture . componentInstance . select . open ( ) ;
3614+ fixture . detectChanges ( ) ;
3615+ flush ( ) ;
3616+
3617+ expect ( options [ 5 ] . classList ) . toContain ( 'mdc-list-item--selected' ) ;
3618+ } ) ) ;
3619+
3620+ it ( 'should not reset when any other falsy option is selected' , fakeAsync ( ( ) => {
3621+ options [ 3 ] . click ( ) ;
3622+ fixture . detectChanges ( ) ;
3623+ flush ( ) ;
3624+
3625+ expect ( fixture . componentInstance . control . value ) . toBe ( false ) ;
3626+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3627+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3628+ expect ( trigger . textContent ) . toContain ( 'Falsy' ) ;
3629+ } ) ) ;
3630+
3631+ it ( 'should consider the nullable values as selected when resetting the form control' , ( ) => {
3632+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3633+
3634+ fixture . componentInstance . control . reset ( ) ;
3635+ fixture . detectChanges ( ) ;
3636+
3637+ expect ( fixture . componentInstance . control . value ) . toBe ( null ) ;
3638+ expect ( fixture . componentInstance . select . selected ) . toBeTruthy ( ) ;
3639+ expect ( label . classList ) . toContain ( 'mdc-floating-label--float-above' ) ;
3640+ expect ( trigger . textContent ) . toContain ( 'Null' ) ;
3641+ } ) ;
3642+ } ) ;
3643+
35483644 describe ( 'with reset option and a form control' , ( ) => {
35493645 let fixture : ComponentFixture < SelectWithResetOptionAndFormControl > ;
35503646 let options : HTMLElement [ ] ;
@@ -5057,7 +5153,7 @@ class BasicSelectWithTheming {
50575153 template : `
50585154 <mat-form-field>
50595155 <mat-label>Select a food</mat-label>
5060- <mat-select [formControl]="control">
5156+ <mat-select [formControl]="control" [canSelectNullableOptions]="canSelectNullableOptions" >
50615157 @for (food of foods; track food) {
50625158 <mat-option [value]="food.value">{{ food.viewValue }}</mat-option>
50635159 }
@@ -5076,7 +5172,8 @@ class ResetValuesSelect {
50765172 { viewValue : 'Undefined' } ,
50775173 { value : null , viewValue : 'Null' } ,
50785174 ] ;
5079- control = new FormControl ( '' as string | boolean | null ) ;
5175+ control = new FormControl ( '' as string | boolean | null | undefined ) ;
5176+ canSelectNullableOptions = false ;
50805177
50815178 @ViewChild ( MatSelect ) select : MatSelect ;
50825179}
0 commit comments