Jean D.
Jean D.

Reputation: 169

Event emitter in Angular unit test isn't called

Given this component ...

export class MyComponent {
  @Output() onActivateEditMode = new EventEmitter<boolean>();

  constructor() {}

  emitActivateEditMode(flag: boolean) {
    this.onActivateEditMode.emit(flag);
  }

... and this template ...

<a (click)="emitActivateEditMode(true)" data-test-start-edit-project-btn>Edit</a>

... then this test fails:

describe('MyComponent', () => {

  ... (TestBed imports etc)

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    spyOn(component, 'emitActivateEditMode');
    fixture.detectChanges();
  });

  it('should activate editmode on click', () => {
    const onActivateEditModeSpy = jest.spyOn(
      component.onActivateEditMode,
      'emit'
    );
    const startEditProjectBtn = fixture.debugElement.nativeElement.querySelector(
      '[data-test-start-edit-project-btn]'
    );
    startEditProjectBtn.dispatchEvent(new Event('click')); // startEditProjectBtn.click() doesn't change the result, too
    fixture.detectChanges();
    expect(component.onActivateEditMode.emit).toHaveBeenCalledWith(true);
    // expect(onActivateEditModeSpy).toHaveBeenCalledWith(true) ... doesn't change the result, too
  });

});

Test output is:

Expected: true
Number of calls: 0

The functionality works in the browser, but something on this test setup is wrong.

Upvotes: 0

Views: 6420

Answers (1)

AliF50
AliF50

Reputation: 18859

I assume you're using Jasmine and Jest at the same time. The issue is that when you're spying on the function (spyOn), you're essentially just spying on the function for calls and the implementation details go away. To have the implementation details in tact, you can do spyOn(component, 'emitActivateEditMode').and.callThrough(); but I think for you, it is not needed.

describe('MyComponent', () => {

  ... (TestBed imports etc)

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    // remove the mock/spyOn to the function emitActivateEditMode
    fixture.detectChanges();
  });

  it('should activate editmode on click', () => {
    // spy on emit calls on onActivatedEditMode
    const emitSpy = spyOn(component.onActivateEditMode, 'emit');
    const startEditProjectBtn = fixture.debugElement.nativeElement.querySelector(
      '[data-test-start-edit-project-btn]'
    );
    startEditProjectBtn.click();
    fixture.detectChanges(); // fixture.detectChanges is not needed here, only if you want to see the update in the HTML.
    expect(emitSpy).toHaveBeenCalledWith(true);
});

Upvotes: 1

Related Questions