angularunit-testingangular-unit-test

Angular unit testing form


I am trying to unit test a Login Form, but I am not able to execute it as expected.

TestBed configuration:

beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [FormsModule],
      declarations: [AuthComponent],
    });
    fixture = TestBed.createComponent(AuthComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
it('form should be invalid', () => {
    component.authForm.controls['email'].markAsTouched();

    expect(component.authForm.invalid).toBeTruthy();
});

When the above test executes I am getting the following error TypeError: Cannot read properties of undefined (reading 'markAsTouched').

When modifying the test with fakeAsync and whenstable like this

it('form should be invalid', fakeAsync(() => {
    fixture.whenStable().then(() => {
      component.authForm.controls['email'].markAsTouched();
      expect(component.authForm.invalid).toBeTruthy();
    });
  }));

The test result shows as SPEC HAS NO EXPECTATIONS form should be invalid.

Not sure what I am doing wrong.


Solution

  • Your updated spec function is mixing real asynchronous code (fixture.whenStable()) with the fake async test zone by using fakeAsync(). You have to pick one. The reason why you are getting that new error is because the function execution is over before the whenStable() promise resolves.

    Once you fix your inconsistency, they should work about the same way, waiting for all pending tasks in the macro-task queue like setTimeout() to resolve.

    "Real" Async

    it('form should be invalid', async (() => {
      await fixture.whenStable(); // wait until all pending macro tasks are resolves
      component.authForm.controls['email'].markAsTouched();
      expect(component.authForm.invalid).toBeTruthy();
    }));
    

    Fake Async Zone

    it('form should be invalid', fakeAsync(() => {
      flush(); // invoke all remaining pending macro tasks.
      component.authForm.controls['email'].markAsTouched();
      expect(component.authForm.invalid).toBeTruthy();
    }));
    

    For the life of me I don't know which is better. Also I don't know if this will fix your original problem, since you didn't provide the component code.