Testing Library and Angular

June 28, 2022    Web Development Angular

Testing Library with Angular

Over the years , I’ve attempted to efficiently write TestBed component unit tests of the virtual DOM for Angular. It’s always been a challenge and I’ve recently came back on an Angular project. It’s still slow and difficult to get the tests to pass and quickly write them.

Wallaby Js helps run them faster than KarmaJs, I recommend checking it out. It’s been worth the licensing cost for me.

In the State of Js 2021 Testing Library had a 96% top rating among testing tools.

Github

Twitter @testinglib

https://testing-library.com/docs/

For Angular

“The Angular Testing Library is a very lightweight solution for testing Angular components. It provides light utility functions on top of DOM Testing Library in a way that encourages better testing practices.” ~ https://testing-library.com/docs/angular-testing-library/intro/

Guidelines

Their guiding principles leads us to better, longer lasting tests. “ The more your tests resemble the way your software is used, the more confidence they can give you.

Don’t test the implementation details, but how your user interacts through the interface.

Prefer one test over multiple tests. Similar to how the user would use the page.

A few more of my own:

  • If you are testing methods in the component for correctness, simply new up the component and call the method directly.

Adding Tests

I’ll be adding tests to my Cascading Material AutoCompletes in Angular code in Github .

There are many examples in their Github repo .

@tim_deschryver has 2 great articles that I’m following. Good testing practices and Getting the most value .

First install with npm npm install --save-dev @testing-library/angular

Add or overwrite the .spec.ts file from the ng generate component X cli command.

Use await render, add imports, set componentProperties

 const routerFake = fakeRouter();
await render(FeedbackComponent, {
    imports: [ReactiveFormsModule, MaterialModule],
    // set @Input and @Output
    componentProperties: {

    },
    declarations: [],
    // similar to the TestBed.configureTestingModule
    // add providers to fake out services
    providers: [
      { provide: Router, useValue: routerFake }
    ]
  });

routerFake implementation

export const fakeRouter = (): Mocked & Spied<Router> => {
  const spy = jasmine.createSpyObj('Router', [
    'navigate',
    'events',
    'getCurrentNavigation'
  ]) as Spied<Router>;
  (spy.events as any).pipe = () => {
    return { subscribe: () => {} };
  };
  return spy;
};

Both Testing Library and the

Querying

Use screen. methods for querying the DOM . Add await screen.... for async. There is no need for waitForAsync() of fixture.detectChanges()!

Events

Use fireEvent....() to fire an event.

userEvent.type(), userEvent.SelectOptions(...), userEvent.click(submit), etc are handy.Bring it in with npm install --save-dev @testing-library/user-event @testing-library/dom

an event will run a change detection cycle by calling detectChanges() after the event is fired.

I had some problems with the selectOptions and found some help in an issue .

I needed to use await before events, even though the examples didn’t have it….

Matchers

It took some fighting to get jasmine-dom to work with WallabyJs. Checkout my code in the repo.

npm install --save-dev @testing-library/jasmine-dom (there’s one for jest as well) brings in toHaveValue() and more . Make sure to add “@testing-library/jasmine-dom” to the tsconfig.spec.json > compilerOptions > types. you might need beforeAll(() => { jasmine.getEnv().addMatchers(JasmineDOM) // I needed (jasmine.getEnv() as any).addMatchers(JasmineDOM);; }); as well

Running the tests

Get WallabyJs or ng test to start your Karma/Jest runner.

Recap

I like the approach of Testing Library. It does work well with Angular. I did get stuck on my shirt size mat-select for longer than I’d like to admit. I don’t know why I needed await before each event, but after adding those it worked and runs quickly.

There are a lot of helpful examples and articles from Tim Deschryver and in the docs.

My preferred Angular testing is now:

  1. Directly call functions on the component for unit tests.
  2. Use Testing Library to interact with the DOM as the user would (avoid the Angular testing approach unless there’s something that can’t be covered with Testing Library. I can’t think of any reasons right now).
  3. Use Cypress for a few end to end happy tests that use data from a real API/database to give more confidence if needed.

I’m going to keep using Testing Library and try to add more information to this article as it comes up.



Watch the Story for Good News

Please consider using Brave and adding me to your BAT payment ledger. Then you won't have to see ads!

Use Brave

Also check out my Resources Page for referrals that would help me.


Swan Bitcoin referral image
Use Swan Bitcoin to onramp with low fees and automatic daily cost averaging and get $10 in BTC when you sign up.