Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Include component template in unit test coverage with Angular

With Angular 4 it is possible to test the Component's template, for example checking if clicking a button triggers the expected method and stuff like that.

But how can templates be included in the test coverage? By default they are not (using Angular CLI tests with Karma+Jasmine+Istanbul).

like image 829
Francesco Borzi Avatar asked Sep 05 '17 09:09

Francesco Borzi


1 Answers

Did you by any chance mean that you want to test the actual representation of the templates? Then you have to completely switch to jest instead of karma/jasmine combination. With jest you can generate template snapshots in your tests which are pushed alongside the component and checked on CI tests.

For example let's say you have a main.component which shows a loader while a SessionService is not ready and then the router-outlet for route content when it's done. A jest snapshot would look somewhat like this:

exports[`MainComponent renders: default state 1`] = `
<main
  isReady$={[Function BehaviorSubject]}
  sessionService={[Function Object]}
>
  <loader-line
    ng-reflect-active="true"
  />
</main>
`;

exports[`MainComponent session storage is ready renders 1`] = `
<main
  isReady$={[Function BehaviorSubject]}
  sessionService={[Function Object]}
>
  <main>
    <router-outlet />
  </main>
</main>
`;

And the test code looks like that:

describe('MainComponent', () => {
  let fixture: ComponentFixture<MainComponent>;

  const isReady$ = new BehaviorSubject(false);
  const mockSessionStorage = Mock.all<SessionService>();

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MainComponent, MockComponents(LoaderLineComponent)],
      imports: [RouterTestingModule],
      providers: [mockWith(SessionService, mockSessionStorage)],
    })
      .compileComponents();
  }));

  afterAll(() => {
    isReady$.complete();
  });

  beforeEach(() => {
    Mock.extend(mockSessionStorage).with({isReady$});
    fixture = TestBed.createComponent(MainComponent);
    detectChanges(fixture);
  });

  it(`creates instance`, () => expect(fixture.componentInstance).toBeTruthy());

  it(`renders`, () => expect(fixture).toMatchSnapshot(`default state`));

  describe(`session storage is ready`, () => {
    beforeEach(() => {
      isReady$.next(true);
      detectChanges(fixture);
    });

    it(`renders`, () => expect(fixture).toMatchSnapshot());
  });
});

That's it, no more querying of <loader-line> or <router-outlet> in the spec file code, just look at the snapshot and you're done.

Note: I'm also using ng-mocks, ts-mockery and some own util functions, but the main thing for you to look for are the expect(fixture).toMatchSnapshot() lines which are jest native.

like image 168
Alex Rempel Avatar answered Oct 21 '22 05:10

Alex Rempel