import {act, fireEvent, waitFor} from '@testing-library/react'; import {PointerEventsCheckLevel, userEvent} from '@testing-library/user-event'; import {bindUniDriverApiMethods, UniDriverBase, type UniDriverBaseApi} from '@wix/unidriver-common'; import {type UniDriver} from '@wix/unidriver-core'; import {type DriverContext} from '@wix/unidriver-core/internal'; import {UniDriverClassList} from './UniDriverClassList'; import {enterText} from './utils/enterText'; import {enterValue} from './utils/enterValue'; type NativeElement = HTMLElement; export class UniDriverClass extends UniDriverBase implements UniDriver { type = 'react' as const; protected override defaults = { interval: 0, }; constructor(ctx: DriverContext) { super(ctx); bindUniDriverApiMethods(this, ['get', 'getAll']); } override get: UniDriver['get'] = async (selector, options) => { return waitFor( () => { return super.get(selector, options); }, {timeout: this.getTimeout(options?.timeout)}, ); }; override getAll: UniDriver['getAll'] = async (selector, options) => { return waitFor( () => { return super.getAll(selector, options); }, {timeout: this.getTimeout(options?.timeout)}, ); }; protected override api: UniDriverBaseApi = { Class: UniDriverClass, ListClass: UniDriverClassList, getType: () => 'jsdom-react', getElementsBySelector: async (base, selector) => [...base.querySelectorAll(selector)], click: async (base, options) => { const clickParams: Parameters[1] = { delay: null, // We don't check pointer events for jsdom as we can't compute styles pointerEventsCheck: PointerEventsCheckLevel.Never, }; if (options?.type === 'double') { return userEvent.dblClick(base, clickParams); } return userEvent.click(base, clickParams); }, text: async (base) => base.textContent, value: async (base) => { const value: unknown = (base as HTMLInputElement).value; return typeof value === 'object' ? JSON.stringify(value) : // eslint-disable-next-line @typescript-eslint/no-base-to-string String(value ?? ''); }, enterText: async (base, value, options) => { await enterText(base, value, options); }, enterValue: async (base, value, options) => { await enterValue(base, value, options); }, pressKey: async (base, keyMeta) => { await act(async () => { fireEvent.keyDown(base, keyMeta); fireEvent.keyUp(base, keyMeta); }); }, attr: async (base, attr) => base.getAttribute(attr), hasClass: async (base, className) => base.classList.contains(className), prop: async (base, prop) => base[prop as keyof typeof base], mouse: { press: async (base) => { await act(async () => { fireEvent.mouseDown(base); }); }, release: async (base) => { await act(async () => { fireEvent.mouseUp(base); }); }, hover: async (base) => { await act(async () => { fireEvent.mouseEnter(base); }); }, leave: async (base) => { await act(async () => { fireEvent.mouseLeave(base); }); }, moveTo: async (base, to) => { const {left, top} = (await to.unwrap()).getBoundingClientRect(); await act(async () => { fireEvent.mouseMove(base, {clientX: left, clientY: top}); }); }, }, }; }