MOBILE-3934 behat: Implement `within` locator

main
Noel De Martin 2021-12-23 17:49:20 +01:00 committed by Pau Ferrer Ocaña
parent 7b4975b48f
commit bf2ae1ece7
2 changed files with 43 additions and 5 deletions

View File

@ -345,6 +345,26 @@
return element.parentElement || (element.getRootNode() && element.getRootNode().host) || null; return element.parentElement || (element.getRootNode() && element.getRootNode().host) || null;
}; };
/**
* Get closest element matching a selector, without traversing up a given container.
*
* @param {HTMLElement} element Element.
* @param {string} selector Selector.
* @param {HTMLElement} container Topmost container to search within.
* @return {HTMLElement} Closest matching element.
*/
const getClosestMatching = function(element, selector, container) {
if (element.matches(selector)) {
return element;
}
if (element === container || !element.parentElement) {
return null;
}
return getClosestMatching(element.parentElement, selector, container);
};
/** /**
* Function to find elements based on their text or Aria label. * Function to find elements based on their text or Aria label.
* *
@ -361,6 +381,24 @@
let container = topContainer; let container = topContainer;
if (locator.within) {
const withinElements = findElementsBasedOnText(locator.within);
if (withinElements.length === 0) {
throw new Error('There was no match for within text')
} else if (withinElements.length > 1) {
const withinElementsAncestors = getTopAncestors(withinElements);
if (withinElementsAncestors.length > 1) {
throw new Error('Too many matches for within text');
}
topContainer = container = withinElementsAncestors[0];
} else {
topContainer = container = withinElements[0];
}
}
if (topContainer && locator.near) { if (topContainer && locator.near) {
const nearElements = findElementsBasedOnText(locator.near); const nearElements = findElementsBasedOnText(locator.near);
@ -382,7 +420,7 @@
do { do {
const elements = findElementsBasedOnTextWithin(container, locator.text); const elements = findElementsBasedOnTextWithin(container, locator.text);
const filteredElements = locator.selector const filteredElements = locator.selector
? elements.filter(element => element.matches(locator.selector)) ? elements.map(element => getClosestMatching(element, locator.selector, container)).filter(element => !!element)
: elements; : elements;
if (filteredElements.length > 0) { if (filteredElements.length > 0) {

View File

@ -1020,7 +1020,7 @@ class behat_app extends behat_base {
* @return object * @return object
*/ */
public function parse_element_locator(string $text): object { public function parse_element_locator(string $text): object {
preg_match('/^"((?:[^"]|\\")*?)"(?: "([^"]*?)")?(?: near "((?:[^"]|\\")*?)"(?: "([^"]*?)")?)?$/', $text, $matches); preg_match('/^"((?:[^"]|\\")*?)"(?: "([^"]*?)")?(?: (near|within) "((?:[^"]|\\")*?)"(?: "([^"]*?)")?)?$/', $text, $matches);
$locator = [ $locator = [
'text' => str_replace('\\"', '"', $matches[1]), 'text' => str_replace('\\"', '"', $matches[1]),
@ -1028,9 +1028,9 @@ class behat_app extends behat_base {
]; ];
if (!empty($matches[3])) { if (!empty($matches[3])) {
$locator['near'] = (object) [ $locator[$matches[3]] = (object) [
'text' => str_replace('\\"', '"', $matches[3]), 'text' => str_replace('\\"', '"', $matches[4]),
'selector' => $matches[4] ?? null, 'selector' => $matches[5] ?? null,
]; ];
} }