Angular Testing For Angular-Material On Mat-Menu
Answer :
My final test ended up looking like this:
import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { AppComponent } from './app.component'; import { RouterTestingModule } from '@angular/router/testing'; import { AppRoutes } from './app.routes'; import { MatToolbarModule, MatIconModule, MatMenuModule, MatButtonModule } from '@angular/material'; import { HomeComponent } from './home/home.component'; import { UserService } from './user/user.service'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { BehaviorSubject } from '../../node_modules/rxjs'; class MockUserService { signedIn$: BehaviorSubject<boolean> = new BehaviorSubject(false); signIn() {} } describe('AppComponent', () => { let app: AppComponent; let fixture: ComponentFixture<AppComponent>; let dom; let button; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [AppComponent, HomeComponent], providers: [{ provide: UserService, useClass: MockUserService }], imports: [ NoopAnimationsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatButtonModule, RouterTestingModule.withRoutes(AppRoutes) ] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(AppComponent); fixture.autoDetectChanges(true); //this was the key fix spyOn(MockUserService.prototype, 'signIn').and.callThrough(); app = fixture.debugElement.componentInstance; dom = fixture.nativeElement; button = dom.querySelector('#userMenu'); }); it('should create the app', async(() => { expect(app).toBeTruthy(); })); describe('user menu', () => { it('should not have the menu open', async () => { const menu = dom.parentNode.querySelector('.mat-menu-panel'); expect(menu).toBeFalsy(); }); it('open the menu when clicking on the account button', async () => { button.click(); const menu = dom.parentNode.querySelector('.mat-menu-panel'); expect(menu).toBeTruthy(); }); it('call user.signIn() once sign in button is pressed', async () => { button.click(); const mockUser = TestBed.get(UserService); dom.parentNode.querySelector('#userSignIn').click(); expect(mockUser['signIn']).toHaveBeenCalled(); }); }); describe('navigation icons', () => { it('navigation icons show when user.signedIn$ emits true', async () => { const mockUser = TestBed.get(UserService); await mockUser.signedIn$.next(true); await fixture.detectChanges(); expect( dom.parentNode.querySelector('button[routerLink="/emails/received"]') ).toBeTruthy(); expect( dom.parentNode.querySelector('button[routerLink="/emails/mapping"]') ).toBeTruthy(); }); it('navigation icons don\t show until user.signedIn$ emits true', async () => { expect( dom.parentNode.querySelector('button[routerLink="/emails/received"]') ).toBeFalsy(); expect( dom.parentNode.querySelector('button[routerLink="/emails/mapping"]') ).toBeFalsy(); }); it('navigation icons don\t show until user.signedIn$ emits false', async () => { const mockUser = TestBed.get(UserService); await mockUser.signedIn$.next(false); await fixture.detectChanges(); expect( dom.parentNode.querySelector('button[routerLink="/emails/received"]') ).toBeFalsy(); expect( dom.parentNode.querySelector('button[routerLink="/emails/mapping"]') ).toBeFalsy(); }); it('navigation icons re-hide on user.signedIn$ false', async () => { const mockUser = TestBed.get(UserService); await mockUser.signedIn$.next(true); await fixture.detectChanges(); await mockUser.signedIn$.next(false); await fixture.detectChanges(); expect( dom.parentNode.querySelector('button[routerLink="/emails/received"]') ).toBeFalsy(); expect( dom.parentNode.querySelector('button[routerLink="/emails/mapping"]') ).toBeFalsy(); }); }); });
There is simpler way:
you can use @ViewChild in component
@ViewChild('menuTrigger') menuTrigger: MatMenuTrigger;
in html template there is:
<button mat-icon-button [matMenuTriggerFor]="menu" #menuTrigger='matMenuTrigger'> </button>
then there is "openMenu()" in test:
fit('should show menu', () => { component.menuTrigger.openMenu() }
Comments
Post a Comment