First, you need to understand what spectator.focus()
method does.
Let's take a look at this method in Spectator source code:
public focus(selector: SpectatorElement = this.element): void {
const element = this.getNativeElement(selector);
if (!(element instanceof HTMLElement)) {
throw new Error(`Cannot focus: ${selector} is not a HTMLElement`);
}
patchElementFocus(element);
element.focus();
this.detectChanges();
}
We can notice that before triggering native element.focus()
method it also calls patchElementFocus(element);
Here's the code of this method:
export function patchElementFocus(element: HTMLElement): void {
element.focus = () => dispatchFakeEvent(element, 'focus');
element.blur = () => dispatchFakeEvent(element, 'blur');
}
where dispatchFakeEvent
calls node.dispatchEvent(event);
native method under the hood.
So, spectator.focus(element)
triggers node.dispatchEvent(...)
.
Now, you need to understand difference between trusted and untrusted events.
Events fired by using node.dispatchEvent are called untrusted events and they do not trigger default browser actions (w3.org reference)
That means that manually firing an event does not generate the default action associated with that event. For example, manually firing a focus event does not cause the element to receive focus, manually firing a submit event does not submit a form.
You can only listen to that manually created events through events handlers.
This is what Spectator demonstrates us. (Test https://github.com/ngneat/spectator/blob/fcdb6a809571706fac3d7b5d8da5bf2f7ba0e305/projects/spectator/test/events/events.component.spec.ts#L13) (Listener https://github.com/ngneat/spectator/blob/fcdb6a809571706fac3d7b5d8da5bf2f7ba0e305/projects/spectator/test/events/events.component.html#L2)
Finally, the solution here is to use native element.focus()
method to be able to set focus on your div. Also, tabindex attribute
is required here.
spectator.query<HTMLDivElement>('.hello').focus();
expect(spectator.query('.hello')).toBeFocused();
Stackblitz Example