type HTMLTypes = T extends `HTML${infer C}Element` ? C : never; type HTMLElementTypes = HTMLTypes; export function isHTMLElement( element: unknown | null | undefined, type: T = "" as T ): element is InstanceType { if(element) { let { defaultView } = (element as Element).ownerDocument; let Constructor = (defaultView as unknown as Record)?.[`HTML${type}Element`]; return typeof Constructor == "function" && element instanceof Constructor; } else { return false; } } export const delay = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)); export function isDefined(value: T | null | undefined): value is T { return value !== null && value !== undefined; } export function isDisabled(element: T): boolean; export function isDisabled(element?: T | null): boolean | undefined; export function isDisabled(element?: T | null): boolean | undefined { if (isHTMLElement(element, "Button")) return element.disabled; return element ? element.getAttribute("aria-disabled") == "true" : undefined; } export function getInputLabel( input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement ): HTMLLabelElement | undefined { return ( input.labels?.[0] ?? input.previousElementSibling ?.getAttribute("aria-labelledby") ?.split(" ") .map((labelId) => input.ownerDocument.getElementById(labelId)) .map((element) => (isHTMLElement(element, "Label") ? element : null)) .find(isDefined) ?? [input.parentElement?.previousElementSibling] .map((element) => (isHTMLElement(element, "Label") ? element : null)) .find(isDefined) ); } // NOTE: Copy-paste from https://github.com/thefrontside/bigtest/blob/v0/packages/interactor/src/fill-in.ts export function setValue(element: HTMLInputElement, value: string): void { let property = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element), "value"); if (property && property.set) { property.set.call(element, value); } else { // if the value property on the element protoype is not present // then there are worse problems. But this is very typesafe! element.value = value; } } export function dispatchChange(element: HTMLElement): boolean { let Event = element.ownerDocument.defaultView?.Event || window.Event; return element.dispatchEvent(new Event("change", { bubbles: true, cancelable: false })); } export function dispatchMouseDown(element: HTMLElement, options: MouseEventInit = {}): boolean { let MouseEvent = element.ownerDocument.defaultView?.MouseEvent || window.MouseEvent; return element.dispatchEvent( new MouseEvent("mousedown", Object.assign({ bubbles: true, cancelable: true }, options)) ); }