import { TextUniDriver } from '@wix/design-system/dist/testkit/unidriver'; import { InputWithOptionsUniDriver } from '@wix/design-system/dist/types/InputWithOptions/InputWithOptions.uni.driver'; import { UniDriver, waitFor } from '@wix/wix-ui-test-utils/unidriver'; import shuffle from 'lodash/shuffle'; import { isSled2, isSled3 } from '../../unidriver/nativeEnv'; export const CollectionDropdownFilterUniDriver = < T extends Omit, >( optionsDriver: T, dataHook: string, base: UniDriver, body: UniDriver, ) => { const waitForOptions = async (total = 1, timeout = 3000) => { await waitFor( async () => (await optionsDriver.dropdownLayoutDriver.optionsLength()) >= total, timeout, ); return optionsDriver.dropdownLayoutDriver.options(); }; const getDropdownLayoutBase = async () => { const contentDataHook = await base.attr('data-content-hook'); if (contentDataHook) { return body.$(`[data-content-element="${contentDataHook}"]`); } const baseDataHook = await base.attr('data-hook'); return body.$(`[data-hook="${baseDataHook}-content"]`); }; const getOptions = async (ids: string[]) => { return ids.map(async (id) => { return optionsDriver.dropdownLayoutDriver.optionById(id); }); }; const getOptionsCount = () => { return optionsDriver.dropdownLayoutDriver.optionsLength(); }; const getAvailableOptionsIds = async () => { const options = await optionsDriver.dropdownLayoutDriver.options(); const maybeIds = await Promise.all( options.map(async (option) => { const hook = await option.element().attr('data-hook'); return hook?.replace(/^dropdown-item-/, ''); }), ); return maybeIds.filter((value): value is string => value != null); }; const getInputPlaceholder = () => { return optionsDriver.inputDriver.getPlaceholder(); }; const isNoSearchResults = async () => (await getDropdownLayoutBase()).$('[data-hook="empty-state"]').exists(); const isErrorStateExists = async () => (await getDropdownLayoutBase()) .$('[data-hook="filter-error-state"]') .exists(); const getEmptyStateText = async () => TextUniDriver( (await getDropdownLayoutBase()).$('[data-hook="empty-state-text"]'), body, ).getText(); const initialLoaderExists = async () => (await getDropdownLayoutBase()).$('[data-hook="initial-loader"]').exists(); const infiniteScrollLoaderExists = async () => (await getDropdownLayoutBase()) .$('[data-hook="dropdownLayout-loader"]') .exists(); const clickOptions = async (ids: string[]) => { for (const id of ids) { await optionsDriver.dropdownLayoutDriver.clickAtOptionByDataHook( `dropdown-item-${id}`, ); } return ids; }; const existInFilter = async (dataHook: string) => (await getDropdownLayoutBase()).$(`[data-hook="${dataHook}"]`).exists(); const selectRandomOptions = async ( count: number, options: { closeDropdown?: boolean } = {}, ) => { await optionsDriver.inputDriver.click(); const ids = await getRandomOptions(count); return selectOptions(ids, options); }; const close = () => optionsDriver.dropdownLayoutDriver.mouseClickOutside(); const clickInputClear = () => optionsDriver.inputDriver.clickClear(); const getRandomOptions = async (count: number) => { await waitForOptions(count); const options = await optionsDriver.dropdownLayoutDriver.options(); const maybeIds = await Promise.all( options.map(async (option) => { const dataHook = await option.element().attr('data-hook'); return dataHook?.replace(/^dropdown-item-/, ''); }), ); const ids = maybeIds.filter((value): value is string => value != null); return shuffle(ids).slice(0, count); }; const selectOptions = async ( ids: string[], { closeDropdown = true }: { closeDropdown?: boolean } = {}, ) => { await optionsDriver.inputDriver.click(); await waitForOptions(); const clickedIds = await clickOptions(ids); if (closeDropdown) { await close(); } return clickedIds; }; const selectOption = async (id: string) => { await optionsDriver.inputDriver.click(); await waitForOptions(); const clickedId = await clickOptions([id]); return clickedId[0] || []; }; const hasDivider = async () => { return (await getAvailableOptionsIds()).some( (id) => id === 'promoted-section-divider', ); }; const isOptionDisabled = async (id: string) => { const option = await optionsDriver.dropdownLayoutDriver.optionById(id); return option.isDisabled(); }; const hasOptionDisabledTooltip = async (id: string) => { const option = await optionsDriver.dropdownLayoutDriver.optionById(id); return option .element() .$('[data-hook="list-item-select-disabled-tooltip"]') .exists(); }; return { ...optionsDriver, waitForOptions, getOptions, clickOptions, close, clickInputClear, selectOptions, selectOption, selectRandomOptions, getRandomOptions, getOptionsCount, getAvailableOptionsIds, getInputPlaceholder, isNoSearchResults, getEmptyStateText, isErrorStateExists, initialLoaderExists, infiniteScrollLoaderExists, hasDivider, isOptionDisabled, hasOptionDisabledTooltip, existInFilter, _getDropdownLayoutBase: getDropdownLayoutBase, scrollDown: async () => { const element = await base.getNative(); const contentHook = await base.attr('data-content-hook'); const baseDataHook = await base.attr('data-hook'); const contentSelector = contentHook ? `[data-content-element="${contentHook}"]` : `[data-hook="${baseDataHook}-content"]`; // puppeteer if (isSled2(element)) { const { page } = element as { page: { evaluate: Function } }; await page.evaluate( (_dataHook: string, _contentSelector: string) => { const e = document.querySelector( `[data-hook="${_dataHook}"] ${_contentSelector}`, )!; e.scrollBy({ behavior: 'smooth', top: e.scrollHeight }); }, dataHook, contentSelector, ); } // playwright else if (isSled3(element)) { const baseLocator = (await base.unwrap()) as { locator: (selector: string) => { evaluate: (fn: (el: HTMLElement) => void) => Promise; }; }; await baseLocator.locator(contentSelector).evaluate((el) => { el.scrollBy({ behavior: 'smooth', top: el.scrollHeight }); }); } // jsdom else { await ( await base.$(contentSelector).getNative() ).dispatchEvent(new Event('scroll')); } }, }; };