test: run frontend unit tests in browsers (#38860)

Run them in headless [vitest browser
mode](https://vitest.dev/guide/browser/) in chromium and firefox.
Similar UX than current tests, it's about 5 times as slow (goes from 1s
to 5s on my machine), but definitely worth it as it removes all
happy-dom problems.

---------

Signed-off-by: silverwind <me@silverwind.io>
This commit is contained in:
silverwind
2026-08-18 00:22:54 +02:00
committed by GitHub
parent 55e7cafcb6
commit df71d5f5e2
22 changed files with 211 additions and 146 deletions
+1 -8
View File
@@ -1,7 +1,6 @@
import {debounce} from './func.ts';
import type {Promisable} from '../types.ts';
import type $ from 'jquery';
import {isInFrontendUnitTest} from './testhelper.ts';
type ArrayLikeIterable<T> = ArrayLike<T> & Iterable<T>; // for NodeListOf and Array
type ElementArg = Element | string | ArrayLikeIterable<Element> | ReturnType<typeof $>;
@@ -73,11 +72,6 @@ export function queryElemSiblings<T extends Element>(el: Element, selector = '*'
/** it works like jQuery.children: only the direct children are selected */
export function queryElemChildren<T extends Element>(parent: Element | ParentNode, selector = '*', fn?: ElementsCallback<T>): ArrayLikeIterable<T> {
if (isInFrontendUnitTest()) {
// https://github.com/capricorn86/happy-dom/issues/1620 : ":scope" doesn't work
const selected = Array.from<T>(parent.children as any).filter((child) => child.matches(selector));
return applyElemsCallback<T>(selected, fn);
}
return applyElemsCallback<T>(parent.querySelectorAll(`:scope > ${selector}`), fn);
}
@@ -261,8 +255,7 @@ export function isElemVisible(el: HTMLElement): boolean {
// Check if an element is visible, equivalent to jQuery's `:visible` pseudo.
// This function DOESN'T account for all possible visibility scenarios, its behavior is covered by the tests of "querySingleVisibleElem"
if (!el) return false;
// checking el.style.display is not necessary for browsers, but it is required by some tests with happy-dom because happy-dom doesn't really do layout
return Boolean(!el.classList.contains('tw-hidden') && (el.offsetWidth || el.offsetHeight || el.getClientRects().length) && el.style.display !== 'none');
return Boolean(!el.classList.contains('tw-hidden') && (el.offsetWidth || el.offsetHeight || el.getClientRects().length));
}
export function createElementFromHTML<T extends Element>(htmlString: string): T {