Smokovsky
Smokovsky

Reputation: 579

Angular Karma testing: method doesn't change class properties?

I'm having a hard time to understand why my test is failing.

Class short:

export class Viewer implements OnChanges {
    // ...
    selectedTimePeriod: number;
    timePeriods = [20, 30, 40];
    
    constructor( /* ... */) {
        this.selectLastDays(15);
    }
    
    selectLastDays(days: number): void { // happens on click
        this.selectedTimePeriod = days;
        // ...
    }
}

HTML short:

// ...
<ul>
    <li *ngFor="let period of timePeriods">
        <a [ngClass]="{'active': selectedTimePeriod === period}" 
           (click)="selectLastDays(period)">{{ period }} days
        </a>
    </li>
</ul>

Test short:

beforeEach(() => {
    fixture = TestBed.createComponent(HistoryViewerComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    dh = new DOMHelper(fixture);
});


it('should change selectedTimePeriod value to 20', async () => {
    spyOn(component, 'selectLastDays');

    dh.queryOne('li a').triggerEventHandler('click', null); // button value of 20
    dh.queryOne('li a').nativeElement.click(); // clicked even twice
    await fixture.whenStable();
    fixture.detectChanges();
    expect(component.selectLastDays).toHaveBeenCalledTimes(2); // <- true
    expect(component.selectedTimePeriod).toEqual(20); // <- false
});

it('should change selectedTimePeriod', () => { // this test passes
    expect(component.selectedTimePeriod).toEqual(15);
    component.selectLastDays(20);
    expect(component.selectedTimePeriod).toEqual(20);
});

On that button click method selectLastDays is called with param 20. Application works pretty fine, so why this test fails?

Upvotes: 0

Views: 484

Answers (1)

Erbsenkoenig
Erbsenkoenig

Reputation: 1659

The problem with your first test is, that you actually spy on the selectLastDays method. Just using spyOn will create an empty stub which makes the function existent but the function will not do anything.

If you need the stub to verify the method is called, then you should tell the stub to actually execute the function. That's done with .and.callThrough()

it('should change selectedTimePeriod value to 20', async () => {
    spyOn(component, 'selectLastDays').and.callThrough();  // <= !!important

    dh.queryOne('li a').triggerEventHandler('click', null); // button value of 20
    dh.queryOne('li a').nativeElement.click(); // clicked even twice
    await fixture.whenStable();
    fixture.detectChanges();
    expect(component.selectLastDays).toHaveBeenCalledTimes(2); // <- true
    expect(component.selectedTimePeriod).toEqual(20); // <- false
});

Upvotes: 1

Related Questions