false, specCompat = false ) { const a11y = lazy.accessibility.get(strict); if (lazy.dom.isXULElement(el)) { await chromeClick(el, a11y); } else if (specCompat) { await webdriverClickElement(el, a11y); } else { lazy.logger.trace(`Using non spec-compatible element click`); await seleniumClickElement(el, a11y); } }; async function webdriverClickElement(el, a11y) { const win = getWindow(el); // step 3 if (el.localName == "input" && el.type == "file") { throw new lazy.error.InvalidArgumentError( "Cannot click elements" ); } let containerEl = lazy.dom.getContainer(el); // step 4 if (!lazy.dom.isInView(containerEl)) { lazy.dom.scrollIntoView(containerEl); } // step 5 // TODO(ato): wait for containerEl to be in view // step 6 // if we cannot bring the container element into the viewport // there is no point in checking if it is pointer-interactable if (!lazy.dom.isInView(containerEl)) { throw new lazy.error.ElementNotInteractableError( lazy.pprint`Element ${el} could not be scrolled into view` ); } // step 7 let rects = containerEl.getClientRects(); let clickPoint = lazy.dom.getInViewCentrePoint(rects[0], win); if (lazy.dom.isObscured(containerEl)) { throw new lazy.error.ElementClickInterceptedError( null, {}, containerEl, clickPoint ); } let acc = await a11y.assertAccessible(el, true); a11y.assertVisible(acc, el, true); a11y.assertEnabled(acc, el, true); a11y.assertActionable(acc, el); // step 8 if (el.localName == "option") { interaction.selectOption(el); } else { // Synthesize a pointerMove action. await lazy.event.synthesizeMouseAtPoint( clickPoint.x, clickPoint.y, { type: "mousemove", allowToHandleDragDrop: true, }, win ); if (lazy.dragService?.getCurrentSession(win)) { // Special handling is required if the mousemove started a drag session. // In this case, mousedown event shouldn't be fired, and the mouseup should // end the session. Therefore, we should synthesize only mouseup. await lazy.event.synthesizeMouseAtPoint( clickPoint.x, clickPoint.y, { type: "mouseup", allowToHandleDragDrop: true, }, win ); } else { // step 9 let clicked = interaction.flushEventLoop(containerEl); // Synthesize a pointerDown + pointerUp action. await lazy.event.synthesizeMouseAtPoint( clickPoint.x, clickPoint.y, { allowToHandleDragDrop: true }, win ); await clicked; } } // step 10 // if the click causes navigation, the post-navigation checks are // handled by navigate.js } async function chromeClick(el, a11y) { if (!(await lazy.dom.isEnabled(el))) { throw new lazy.error.InvalidElementStateError("Element is not enabled"); } let acc = await a11y.assertAccessible(el, true); a11y.assertVisible(acc, el, true); a11y.assertEnabled(acc, el, true); a11y.assertActionable(acc, el); if (el.localName == "option") { interaction.selectOption(el); } else { el.click(); } } async function seleniumClickElement(el, a11y) { let win = getWindow(el); let visibilityCheckEl = el; if (el.localName == "option") { visibilityCheckEl = lazy.dom.getContainer(el); } if (!(await lazy.dom.isVisible(visibilityCheckEl))) { throw new lazy.error.ElementNotInteractableError(); } if (!(await lazy.dom.isEnabled(el))) { throw new lazy.error.InvalidElementStateError("Element is not enabled"); } let acc = await a11y.assertAccessible(el, true); a11y.assertVisible(acc, el, true); a11y.assertEnabled(acc, el, true); a11y.assertActionable(acc, el); if (el.localName == "option") { interaction.selectOption(el); } else { let rects = el.getClientRects(); let centre = lazy.dom.getInViewCentrePoint(rects[0], win); let opts = {}; await lazy.event.synthesizeMouseAtPoint(centre.x, centre.y, opts, win); } } /** * Select <option> element in a <select> * list. * * Because the dropdown list of select elements are implemented using * native widget technology, our trusted synthesised events are not able * to reach them. Dropdowns are instead handled mimicking DOM events, * which for obvious reasons is not ideal, but at the current point in * time considered to be good enough. * * @param {HTMLOptionElement} el * Option element to select. * * @throws {TypeError} * If el is a XUL element or not an <option> * element. * @throws {Error} * If unable to find el's parent <select> * element. */ interaction.selectOption = function (el) { if (lazy.dom.isXULElement(el)) { throw new TypeError("XUL dropdowns not supported"); } if (el.localName != "option") { throw new TypeError(lazy.pprint`Expected