@testing-library/user-event
Version:
Fire events the same way the user does
101 lines (98 loc) • 5.2 kB
JavaScript
import { PointerEventsCheckLevel } from '../../options.js';
import { getWindow } from '../misc/getWindow.js';
import { isElementType } from '../misc/isElementType.js';
import { ApiLevel, getLevelRef } from '../misc/level.js';
function hasPointerEvents(instance, element) {
var _checkPointerEvents;
return ((_checkPointerEvents = checkPointerEvents(instance, element)) === null || _checkPointerEvents === undefined ? undefined : _checkPointerEvents.pointerEvents) !== 'none';
}
function closestPointerEventsDeclaration(element) {
const window = getWindow(element);
for(let el = element, tree = []; el === null || el === undefined ? undefined : el.ownerDocument; el = el.parentElement){
tree.push(el);
const pointerEvents = window.getComputedStyle(el).pointerEvents;
if (pointerEvents && ![
'inherit',
'unset'
].includes(pointerEvents)) {
return {
pointerEvents,
tree
};
}
}
return undefined;
}
const PointerEventsCheck = Symbol('Last check for pointer-events');
function checkPointerEvents(instance, element) {
const lastCheck = element[PointerEventsCheck];
const needsCheck = instance.config.pointerEventsCheck !== PointerEventsCheckLevel.Never && (!lastCheck || hasBitFlag(instance.config.pointerEventsCheck, PointerEventsCheckLevel.EachApiCall) && lastCheck[ApiLevel.Call] !== getLevelRef(instance, ApiLevel.Call) || hasBitFlag(instance.config.pointerEventsCheck, PointerEventsCheckLevel.EachTrigger) && lastCheck[ApiLevel.Trigger] !== getLevelRef(instance, ApiLevel.Trigger));
if (!needsCheck) {
return lastCheck === null || lastCheck === undefined ? undefined : lastCheck.result;
}
const declaration = closestPointerEventsDeclaration(element);
element[PointerEventsCheck] = {
[ApiLevel.Call]: getLevelRef(instance, ApiLevel.Call),
[ApiLevel.Trigger]: getLevelRef(instance, ApiLevel.Trigger),
result: declaration
};
return declaration;
}
function assertPointerEvents(instance, element) {
const declaration = checkPointerEvents(instance, element);
if ((declaration === null || declaration === undefined ? undefined : declaration.pointerEvents) === 'none') {
throw new Error([
`Unable to perform pointer interaction as the element ${declaration.tree.length > 1 ? 'inherits' : 'has'} \`pointer-events: none\`:`,
'',
printTree(declaration.tree)
].join('\n'));
}
}
function printTree(tree) {
return tree.reverse().map((el, i)=>[
''.padEnd(i),
el.tagName,
el.id && `#${el.id}`,
el.hasAttribute('data-testid') && `(testId=${el.getAttribute('data-testid')})`,
getLabelDescr(el),
tree.length > 1 && i === 0 && ' <-- This element declared `pointer-events: none`',
tree.length > 1 && i === tree.length - 1 && ' <-- Asserted pointer events here'
].filter(Boolean).join('')).join('\n');
}
function getLabelDescr(element) {
var _element_labels;
let label;
if (element.hasAttribute('aria-label')) {
label = element.getAttribute('aria-label');
} else if (element.hasAttribute('aria-labelledby')) {
var _element_ownerDocument_getElementById_textContent, _element_ownerDocument_getElementById;
label = (_element_ownerDocument_getElementById = element.ownerDocument.getElementById(element.getAttribute('aria-labelledby'))) === null || _element_ownerDocument_getElementById === undefined ? undefined : (_element_ownerDocument_getElementById_textContent = _element_ownerDocument_getElementById.textContent) === null || _element_ownerDocument_getElementById_textContent === undefined ? undefined : _element_ownerDocument_getElementById_textContent.trim();
} else if (isElementType(element, [
'button',
'input',
'meter',
'output',
'progress',
'select',
'textarea'
]) && ((_element_labels = element.labels) === null || _element_labels === undefined ? undefined : _element_labels.length)) {
label = Array.from(element.labels).map((el)=>{
var _el_textContent;
return (_el_textContent = el.textContent) === null || _el_textContent === undefined ? undefined : _el_textContent.trim();
}).join('|');
} else if (isElementType(element, 'button')) {
var _element_textContent;
label = (_element_textContent = element.textContent) === null || _element_textContent === undefined ? undefined : _element_textContent.trim();
}
label = label === null || label === undefined ? undefined : label.replace(/\n/g, ' ');
if (Number(label === null || label === undefined ? undefined : label.length) > 30) {
label = `${label === null || label === undefined ? undefined : label.substring(0, 29)}…`;
}
return label ? `(label=${label})` : '';
}
// With the eslint rule and prettier the bitwise operation isn't nice to read
function hasBitFlag(conf, flag) {
// eslint-disable-next-line no-bitwise
return (conf & flag) > 0;
}
export { assertPointerEvents, hasPointerEvents };