2

I have the following component template:

    <div>
      <mat-checkbox [(ngModel)]="model.value" required="true" #checkbox="ngModel">{{model.title}}</mat-checkbox>
      <mat-error *ngIf="checkbox.invalid && checkbox.dirty">Some Error</mat-error>
    </div>

And in my test I would like to test the the error state is shown. However I need to access the input control "#checkbox" in my test and set as dirty.

      it('should show error on invalid', () => {
        const checkbox = fixture.debugElement.query(By.directive(MatCheckbox))
        // I have the mat-checkbox, however not sure how to access the form control to set as dirty
      })

If I add a ViewChild to my component I can access this in the test:

    @Component({
      selector: 'my-checkbox',
      templateUrl: './checkbox.component.html',
      styleUrls: ['./checkbox.component.scss']
    })
    export class CheckboxComponent {
      @Input() model: any;
    
      // Don't ever use this in production, but added for tests
      @ViewChild('checkbox', { static: false }) checkbox: NgModel;
    }

    ...
   
    // At that point I can access in test through the component
    component.checkbox.control.markAsDirty();

However, I would like to access the model inside my test without adding a variable to the component itself as that model is never used.

EDIT: I have also tried to just modify the value to toggle the control to dirty:

    it('should show error on invalid', (done) => {
      component.model.value = false  // set value to unchecked
      fixture.detectChanges()
    
      fixture.whenStable().then(() => {
        const error = fixture.debugElement.query(By.directive(MatError))
        // error is null here, verified that control is not marked as dirty
        done();
      })
    })
Owen Kelvin
  • 14,054
  • 10
  • 41
  • 74
lostintranslation
  • 23,756
  • 50
  • 159
  • 262
  • That style of NgModel binding creates a Form control automatically. Gaining access would require traversing the component to that element and finding a ref to it. If you can get it there's an onNgmodelCange event where you can alter the form control dirty value directly. It shouldn't be impossible but may be that way. Read this article https://dev.to/jwp/ngmodel-internals-2m9f – JWP Oct 26 '20 at 21:59
  • @JohnPeters that looks like it implies adding ngModelChange to the template solely to test. – lostintranslation Oct 26 '20 at 22:03
  • For that state all you need to do is change value. That makes it dirty. I also mentioned how to try to access the model. Did you try it? – JWP Oct 26 '20 at 22:08
  • @JohnPeters yup seems simple enough, tried that as well. I will update the answer. – lostintranslation Oct 26 '20 at 22:10

2 Answers2

3

I was able to grab the model as follows:

const model = fixture.debugElement.query(By.directive(MatCheckbox)).references['checkbox']

And then mark as dirty

model.control.markAsDirty()
lostintranslation
  • 23,756
  • 50
  • 159
  • 262
-1

Can't you check directly using Id of that particular control itself fixture.debugElement.query(By.css("#id")).markAsDirty()