components
components copied to clipboard
bug(MatSnackBarHarness): Testing a snack bar with a duration
Reproduction
https://stackblitz.com/edit/components-issue-v9512z?file=src%2Fapp%2Fexample-test.spec.ts
Steps to reproduce:
- Try to e.g.
await harness.getMessage()
a snack bar that was opened with aduration
. You can see this simply by following the link above, which will run that automatically.
Expected Behavior
The harness returns the message in the snack bar.
Actual Behavior
The test hangs for the duration that the snack bar is open, then fails with "Failed to find element".
Environment
- Angular: 9.1.5
- CDK/Material: 9.2.2
- Browser(s): Chrome
- Operating System (e.g. Windows, macOS, Ubuntu): Windows
Commentary
Using the same test code, I can test a snack bar that was opened without a duration. But if my production code does use a duration it does not appear possible to test it with the harness. Am I missing something? I assume assigning a duration is a common use-case.
I can confirm this is still an issue with
- Angular: 11.1.1
- Material: 11.1.1
I am having this issue as well, any ideas as to a work around?
My "workaround" involves using a whole test library (that I wrote). It runs test in the fakeAsync
zone and does not flush timeouts before searching for harnesses. You can use the AngularContext
for testing e.g. services, and ComponentContext
for components.
For an example that uses MatSnackBar
, you can see this test
The issue is still present with:
- Angular 13.2.5
- Material 13.2.5
Trying to retrieve the harness with await loader.getHarness(MatSnackBarHarness)
fails with:
Error: Failed to find element matching one of the following queries:
(MatSnackBarHarness with host element matching selector: ".mat-snack-bar-container")
Also, as described ersimont, the test is still hanging for the duration the snackbar is open.
If it's not planned to fix it any time soon, it would be nice to indicate in the doc that this Harness is broken to avoid people wasting time on it, and wondering why their test is failing (what I experimented this morning).
The issue is still present with Angular v15 and the MDC-based Snack Bar.
I had the same issue on Angular 14.2.12 and Material 14.2.7. Getting the error:
Error: Failed to find element matching one of the following queries:
(MatSnackBarHarness with host element matching selector: ".mat-snack-bar-container")
when using await loader.getHarness(MatSnackBarHarness)
It still had the same issue on Angular 16.2.12 and Material 16.2.14, and I got a workaround to fix it by simply wrap harness code block into fakeAsync
:
it('can test snack bars', async () => {
fixture.componentInstance.sayHello();
fakeAsync(() => {
const snackBar = await loader.getHarness(MatSnackBarHarness);
expect(await snackBar.getMessage()).toBe('Hello!');
})(); // must invoke the returned function
});
I ran into this problem recently and I've come up with a solution which I believe is easy and fast. As a note: My test environment uses Jest, but I think other testing frameworks would also work in a similar way.
Instead of using a harness to get the snackbar, just spy on it instead.
snackSpy = jest.spyOn(TestBed.inject(MatSnackBar), 'open').mockReturnValue(null)
// important to return null, otherwise the test will wait for the snackbar to close
You can then test the snackbar opening with specific values in a few ways
// test everything
expect(snackSpy).toHaveBeenCalledWith('Some message', 'Close', { duration: 2000 })
// only test the message
expect(snackSpy.mock.lastCall[0]).toEqual('abc123')
You might also have some success experimenting with jest.useFakeTimers()
but that might be getting a bit too specific for this question.