Cuga
Cuga

Reputation: 17904

Angular unit test click method isn't appearing to be clicked

This seems like it should be simple, but I'm having trouble verifying that a click handler is invoked on my component.

header.component.ts

import { Component, EventEmitter, OnInit, Output } from '@angular/core';

@Component({
    selector: 'app-header',
    templateUrl: './header.component.html',
    styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
    @Output() hamburgerToggle = new EventEmitter<void>();

    constructor() {}

    ngOnInit(): void {}

    hamburgerClicked(): void {
        this.hamburgerToggle.emit();
    }
}

header.component.html

<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
    <div class="hamburger header-toggle">
        <button (click)="hamburgerClicked()" class="btn btn-link btn-sm order-first order-first header-toggle" id="sidebarToggle" href="/">
            <i class="material-icons header-toggle">menu</i>
        </button>
    </div>
</nav>

header.component.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { HeaderComponent } from './header.component';

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

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            declarations: [HeaderComponent]
        }).compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(HeaderComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('clicking the toggle button invoke our click handler', () => {
        const fixture = TestBed.createComponent(HeaderComponent);

        const clickSpy = spyOn(component, 'hamburgerClicked');
        const toggleButton = fixture.debugElement.query(By.css('#sidebarToggle'));
        toggleButton.triggerEventHandler('click', toggleButton);

        fixture.detectChanges();

        expect(clickSpy).toHaveBeenCalledTimes(1);
    });
});

The error message given is:

Expected spy hamburgerClicked to have been called once. It was called 0 times.

I've also tried this inside an async block, but received the same result:

fit('clicking the toggle button invoke our click handler', fakeAsync(() => {
    const fixture = TestBed.createComponent(HeaderComponent);

    const clickSpy = spyOn(component, 'hamburgerClicked');
    const toggleButton = fixture.nativeElement.querySelector('#sidebarToggle');
    toggleButton.click();

    tick();
    fixture.detectChanges();

    fixture.whenStable().then(() => {
        expect(clickSpy).toHaveBeenCalledTimes(1);
    });
}));

I've been at this for hours and can't figure out what I'm missing. Any help is much appreciated.

Upvotes: 0

Views: 201

Answers (1)

Lin Du
Lin Du

Reputation: 102457

You create a new fixture(component instance) in each test case. But you spy the component which created in beforeEach. So, you are triggering the click event on each new component instance, they are not the same component.

You should add a spy, query DOM element, and trigger the click event on the same component instance.

Remove the below statement in each test case will work:

const fixture = TestBed.createComponent(HeaderComponent);

header.component.ts:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { HeaderComponent } from './header.component';

fdescribe('HeaderComponent', () => {
  let component: HeaderComponent;
  let fixture: ComponentFixture<HeaderComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [HeaderComponent],
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(HeaderComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('clicking the toggle button invoke our click handler', () => {
    const clickSpy = spyOn(component, 'hamburgerClicked');
    const toggleButton = fixture.debugElement.query(By.css('#sidebarToggle'));
    toggleButton.triggerEventHandler('click', toggleButton);
    expect(clickSpy).toHaveBeenCalledTimes(1);
  });

  it('clicking the toggle button invoke our click handler', () => {
    const clickSpy = spyOn(component, 'hamburgerClicked');
    const toggleButton = fixture.nativeElement.querySelector('#sidebarToggle');
    toggleButton.click();
    expect(clickSpy).toHaveBeenCalledTimes(1);
  });
});

unit test result:

Chrome 80.0.3987.87 (Mac OS 10.13.6): Executed 2 of 17 (skipped 15) SUCCESS (0.1 secs / 0.045 secs)
TOTAL: 2 SUCCESS
✔ Browser application bundle generation complete.
✔ Browser application bundle generation complete.

Upvotes: 2

Related Questions