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.
https://testing-library.com/docs/
“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/
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:
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
Use screen. methods
for
querying the DOM
. Add await screen....
for async. There is no need for waitForAsync() of fixture.detectChanges()
!
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….
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
Get WallabyJs or ng test
to start your Karma/Jest runner.
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:
I’m going to keep using Testing Library and try to add more information to this article as it comes up.
Please consider using Brave and adding me to your BAT payment ledger. Then you won't have to see ads! (when I get to $100 in Google Ads for a payout, I pledge to turn off ads)
Also check out my Resources Page for referrals that would help me.