Skip to content

Instantly share code, notes, and snippets.

@merlosy
Last active February 12, 2025 11:27
Show Gist options
  • Save merlosy/59dcb1fb76eafc469748ea7e06cdfaa7 to your computer and use it in GitHub Desktop.
Save merlosy/59dcb1fb76eafc469748ea7e06cdfaa7 to your computer and use it in GitHub Desktop.
Angular Jasmine/Jest Testing utils
import { DebugElement } from '@angular/core';
import { ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
const testAttribute = 'data-int';
/** Find an element by integration test id
* @return a debugElement or null when not found
*/
export function findByIntId<T>(fixture: ComponentFixture<T> , intId: string): DebugElement | null {
return fixture.debugElement.query(By.css(`[${testAttribute}=${intId}]`));
}
/** Find an HTML element by integration test id
* @return a HTMLElement
*/
export function findNativeElementByIntId<T>(fixture: ComponentFixture<T> , intId: string): any {
try {
return findByIntId(fixture, intId).nativeElement;
} catch (e) {
// Allow a more debuggable info than "Cannot get nativeElement of null"
throw new Error(`Cannot get native element from integration id: ${intId}`);
}
}
/**
* Triggers user click on a select option given the option index
* @param fixture
* @param intId
* @param index
*/
export function clickOptionByIndex<T>(fixture: ComponentFixture<T>, intId: string, index: number): void {
const select: HTMLSelectElement = findNativeElementByIntId(fixture, intId) as HTMLSelectElement;
select.click();
fixture.detectChanges();
const options: DebugElement[] = fixture.debugElement.queryAll(By.css(`[data-int=${intId}] option`));
const event: Event = new Event('change', { bubbles: true, cancelable: true });
options[index].nativeElement.dispatchEvent(event);
fixture.detectChanges();
}
/**
* Select an option by value. Ensures the value exists in the options, otherwise selection remains unchanged.
* @param el
* @param value
*/
export function selectByValue(el: DebugElement, value: unknown) {
if (el.componentInstance instanceof MatSelect) {
const select = el.componentInstance;
select.options.find(i => i.value === value)?.select();
}
else if (el.nativeElement instanceof HTMLSelectElement) {
// TODO: to be verified
const matchOption = el.queryAll(By.css('option')).find(option => option.nativeElement.value === value);
if (matchOption) {
const event: Event = new Event('change', { bubbles: true, cancelable: true });
matchOption.nativeElement.dispatchEvent(event);
}
} else {
throw new Error('Selection not supported for ' + el.componentInstance.constructor.name);
}
}
/**
* Type a value in an input field
*/
export function typeValue<T>(fixture: ComponentFixture<T>, intId: string, text: string | null): void {
const input: HTMLInputElement = findNativeElementByIntId(fixture, intId);
input.value = text;
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
}
/**
* Trigger a click event on a template element
* @see https://v17.angular.io/guide/testing-components-scenarios#trigger-event-handler
* @param el
* @param eventObj <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button#value">see button values</a>
*/
export function clickOn(el: DebugElement | HTMLElement, eventObj: any = { button: 0 }) {
if (el instanceof HTMLElement) {
el.click();
}
else {
el.triggerEventHandler('click', eventObj);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment