Proposal: new way to spy output without `any` assertion
Context
I think that there is some pains in spying on the output of a component, which is typified by the fact that you have to use type assertions by any. It is my opinion that the cost to pay for simply subscribing to events emitted by a component and inspecting their values can be lesser.
https://github.com/testing-library/angular-testing-library/blob/main/apps/example-app/src/app/examples/22-signal-inputs.component.spec.ts#L51-L66
test('output emits a value', async () => {
const submitFn = jest.fn();
await render(SignalInputComponent, {
componentInputs: {
greeting: 'Hello',
name: 'world',
},
componentOutputs: {
submit: { emit: submitFn } as any, // <==
},
});
await userEvent.click(screen.getByRole('button'));
expect(submitFn).toHaveBeenCalledWith('world');
});
Goals
- No
anyassertions in output testing scenario - Less and intuitive code to subscribe outputs
Idea
This is a pseudo code and has not been strictly validated for feasibility.
test('output emits a value', async () => {
const submitFn = jest.fn();
const { outputs } = await render(SignalInputComponent, {
componentInputs: {
greeting: 'Hello',
name: 'world',
},
});
outputs.get('submit').subscribe(submitFn);
await userEvent.click(screen.getByRole('button'));
expect(submitFn).toHaveBeenCalledWith('world');
});
- Added
outputsto RenderResult outputs.get(name)can get a output ref by alias-aware name
outputs.get(eventName)
The eventName should be same to its name in HTML template, <some-cmp (eventName)="..." />.
Angular's ComponentMirror has outputs getter which returns a record of propName and tempalteName of outputs. So I think ALT can map the eventName to corresponding property.
https://github.com/angular/angular/blob/main/packages/core/src/render3/component.ts#L104-L139
// pseudo code to get OutputRef from eventName
function getOutputRef<C, T>(componentRef: ComponentRef<C>, eventName: string): OutputRef<T> {
const { outputs } = reflectComponentType(componentRef.componentType);
const output = outputs.find(o => o.propName === eventName);
if (output == null) {
throw new Error(`Output ${eventName} doesn't exist.`);
}
return componentRef.instance[output.templateName];
}