wix-style-react
Version:
wix-style-react
165 lines • 8.86 kB
JavaScript
import ReactTestUtils from 'react-dom/test-utils';
import values from '../utils/operators/values';
import { DATA_HOOKS, DATA_OPTION, DATA_SHOWN, DATA_DIRECTION, DROPDOWN_LAYOUT_DIRECTIONS, OPTION_DATA_HOOKS, DATA_SELECTED_OPTION_ID, } from './DataAttr';
const dropdownLayoutDriverFactory = ({ element, wrapper }) => {
const byDataHook = dataHook => element.querySelector(`[data-hook="${dataHook}"]`);
const contentContainer = byDataHook(DATA_HOOKS.CONTENT_CONTAINER);
const infiniteScrollContainer = byDataHook(DATA_HOOKS.INFINITE_SCROLL_CONTAINER);
const optionElementsContainer = byDataHook(DATA_HOOKS.DROPDOWN_LAYOUT_OPTIONS);
const optionElements = infiniteScrollContainer
? infiniteScrollContainer
: optionElementsContainer;
const getListItemPositionAtSelector = position => `[data-list-type="action"] [data-hook=${DATA_HOOKS.DROPDOWN_LAYOUT_OPTIONS}] > *:nth-child(${position + 1}) > *`;
const optionElementAt = position => {
return (element.querySelector(getListItemPositionAtSelector(position)) ||
optionElements.childNodes[position]);
};
const optionsLength = () => optionElements.childNodes.length;
const doIfOptionExists = (position, onSuccess) => {
if (optionsLength() <= position) {
throw new Error(`index out of bounds, try to get option ${position} while only ${optionsLength()} options exists`);
}
return onSuccess();
};
const getOptionDriver = position => doIfOptionExists(position, () => createOptionDriver(optionElementAt(position)));
const options = () => values(optionElements.childNodes);
return {
/** @deprecated */
classes: () => optionElementsContainer.className,
clickAtOption: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.click();
}),
clickAtOptionWithValue: value => {
for (const _option of options()) {
const optionDriver = createOptionDriver(_option);
if (optionDriver.content() === value) {
return optionDriver.click();
}
}
},
exists: () => !!element,
/** @deprecated deprecated prop */
hasTopArrow: () => !!element.querySelector(`[data-hook="${DATA_HOOKS.TOP_ARROW}"]`),
/** @deprecated deprecated prop */
isDown: () => contentContainer.getAttribute(DATA_DIRECTION) ===
DROPDOWN_LAYOUT_DIRECTIONS.DOWN,
/** @deprecated deprecated prop */
isUp: () => contentContainer.getAttribute(DATA_DIRECTION) ===
DROPDOWN_LAYOUT_DIRECTIONS.UP,
isLinkOption: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.isLink();
}),
isOptionADivider: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.isDivider();
}),
isOptionExists: optionText => [].filter.call(optionElements.childNodes, opt => opt.textContent === optionText).length > 0,
/** returns if an option is hovered. notice that it checks by index and __not__ by id */
isOptionHovered: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.isHovered();
}),
isOptionSelected: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.isSelected();
}),
/** @deprecated */
isOptionHeightSmall: position => doIfOptionExists(position, () => optionElementAt(position).getAttribute(DATA_OPTION.SIZE) === 'small'),
/** @deprecated */
isOptionHeightBig: position => doIfOptionExists(position, () => optionElementAt(position).getAttribute(DATA_OPTION.SIZE) === 'big'),
isListItemFocused: position => document.activeElement ===
element.querySelector(getListItemPositionAtSelector(position)),
isShown: () => contentContainer.hasAttribute(DATA_SHOWN),
mouseEnter: () => ReactTestUtils.Simulate.mouseEnter(element),
mouseEnterAtOption: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.mouseEnter();
}),
mouseLeave: () => ReactTestUtils.Simulate.mouseLeave(element),
/** @deprecated deprecated prop */
mouseClickOutside: () => document.body.dispatchEvent(new Event('mouseup', { cancelable: true, bubbles: true })),
mouseLeaveAtOption: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.mouseLeave();
}),
/** @deprecated Use optionDriver*/
optionAt: optionElementAt,
/** @deprecated This should be a private method since the hook include internal parts ('dropdown-divider-{id}, dropdown-item-{id})') */
optionByHook: hook => {
const option = optionElements.querySelector(`[data-hook=${hook}]`);
if (!option) {
throw new Error(`an option with data-hook ${hook} was not found`);
}
return createOptionDriver(option);
},
optionById(optionId) {
return this.optionByHook(`dropdown-item-${optionId}`);
},
optionContentAt: position => doIfOptionExists(position, () => {
const optionDriver = getOptionDriver(position);
return optionDriver.content();
}),
/** Get option driver given an option index */
optionDriver: createOptionDriver,
/** Get an array of all options including dividers (drivers) */
options: () => {
const drivers = [];
for (let position = 0; position < optionsLength(); position++) {
drivers.push(getOptionDriver(position));
}
return drivers;
},
optionsContent: () => {
const contentArray = [];
for (const option of options()) {
const optionDriver = createOptionDriver(option);
contentArray.push(optionDriver.content());
}
return contentArray;
},
markedOption: async () => {
const hoveredOption = optionElements.querySelector(`[${DATA_OPTION.HOVERED}="true"]`);
return ((hoveredOption && createOptionDriver(hoveredOption).content()) || null);
},
getSelectedOptionId: () => contentContainer.getAttribute(DATA_SELECTED_OPTION_ID),
optionsLength,
/** @deprecated should be private */
optionsScrollTop: () => optionElements.scrollTop,
pressDownKey: () => ReactTestUtils.Simulate.keyDown(element, { key: 'ArrowDown' }),
pressUpKey: () => ReactTestUtils.Simulate.keyDown(element, { key: 'ArrowUp' }),
pressEnterKey: () => ReactTestUtils.Simulate.keyDown(element, { key: 'Enter' }),
pressSpaceKey: () => ReactTestUtils.Simulate.keyDown(element, { key: ' ' }),
pressTabKey: () => ReactTestUtils.Simulate.keyDown(element, { key: 'Tab' }),
pressEscKey: () => ReactTestUtils.Simulate.keyDown(element, { key: 'Escape' }),
keyDownListItem: (position, key) => doIfOptionExists(position, () => {
return ReactTestUtils.Simulate.keyDown(element.querySelector(getListItemPositionAtSelector(position)), {
key,
});
}),
tabIndex: () => element.tabIndex,
getListItemAttribute: (position, attribute) => optionElementAt(position).getAttribute(attribute),
getListType: async (dataHook) => wrapper
.querySelector(`[data-hook="${dataHook}"]`)
.getAttribute('data-list-type'),
getOptionsContainerRole: () => optionElementsContainer.getAttribute('role'),
};
};
const createOptionDriver = option => ({
element: () => option,
mouseEnter: () => ReactTestUtils.Simulate.mouseEnter(option),
mouseLeave: () => ReactTestUtils.Simulate.mouseLeave(option),
isHovered: () => option.hasAttribute(DATA_OPTION.HOVERED),
isSelected: () => option.hasAttribute(DATA_OPTION.SELECTED),
content: () => option.textContent,
click: () => ReactTestUtils.Simulate.click(option),
isDivider: () => {
const divider = option.querySelector(`[data-hook="${OPTION_DATA_HOOKS.DIVIDER}"]`);
return !!divider;
},
isDisabled: () => option.hasAttribute(DATA_OPTION.DISABLED),
isLink: () => option.tagName.toLowerCase() === 'a',
});
export default dropdownLayoutDriverFactory;
//# sourceMappingURL=DropdownLayout.driver.js.map