testing-library/angular-testing-library

new "on" property should not emit "undefined" on output functions with void parameters

Closed this issue · 5 comments

xfh commented

The new "on" method does always return at least an undefined parameter. This is breaking tests that are using a strict evaluation.
To reproduce, change in render.spec.ts toHaveBeenCalled to toHaveBeenCalledWith

This fails with

Expected: called with 0 arguments
Received: undefined

  it('should subscribe passed listener to the component EventEmitter', async () => {
    const spy = jest.fn();
    const { fixture } = await render(TestFixtureWithEventEmitterComponent, { on: { event: spy } });
    fixture.componentInstance.event.emit();
    expect(spy).toHaveBeenCalledWith();
  });

This works:

  it('should subscribe passed listener to the component EventEmitter', async () => {
    const spy = jest.fn();
    const { fixture } = await render(TestFixtureWithEventEmitterComponent, { componentOutputs: { event: {emit: spy } as any} });
    fixture.componentInstance.event.emit();
    expect(spy).toHaveBeenCalledWith();
  });

Thanks for opening this issue @xfh .
Do you want to create a PR with a proposed fix for this?

xfh commented

I'd love to, but I haven't figured out yet where undefined is coming from. Maybe @mumenthalers can give some insights.

I assume the undefined is coming from the following line.
But to be honest, I'm not sure on a correct fix for this.
Filtering out undefined values is an option, but it's value may also be used in applications.

const subscription = eventEmitter.subscribe(cb);

xfh commented

I don't think that filtering undefined is a good option.

It looks like an event emitter always outputs undefined. Here is a test with TestBed for reference:

  it('test event emitter default parameter', async () => {
    // const { fixture } = await render(TestFixtureWithEventEmitterComponent);
    const fixture = TestBed.createComponent(TestFixtureWithEventEmitterComponent);
    const subscription = fixture.componentInstance.event.subscribe(console.log);
    fixture.componentInstance.event.emit();
    subscription.unsubscribe();
  });

output:

undefined

The change of behaviour is coming due to the fact that the spy is now receiving the actually emitted value of Angular's EventEmitter, instead of an intercepted emit call. EventEmitter always emits an (optional) parameter:
https://github.com/angular/angular/blob/5537bf802f8eda54ff7572905cf3bb2fc0e0e431/packages/core/src/event_emitter.ts#L132

Conclusion: change the tests and expect an undefined parameter for void EventEmitters.

Thanks @xfh !