forked from EVOgeek/Vmeda.Online
		
	Improve location of elements and containers
This commit is contained in:
		
							parent
							
								
									00f7cda5bf
								
							
						
					
					
						commit
						77c5418f0c
					
				| @ -224,13 +224,13 @@ | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * Finds elements within a given container. | ||||
|      * Finds elements within a given container with exact info. | ||||
|      * | ||||
|      * @param {HTMLElement} container Parent element to search the element within | ||||
|      * @param {string} text Text to look for | ||||
|      * @return {HTMLElement} Elements containing the given text | ||||
|      * @return {Array} Elements containing the given text with exact boolean. | ||||
|      */ | ||||
|     const findElementsBasedOnTextWithin = (container, text) => { | ||||
|     const findElementsBasedOnTextWithinWithExact = (container, text) => { | ||||
|         const elements = []; | ||||
|         const attributesSelector = `[aria-label*="${text}"], a[title*="${text}"], img[alt*="${text}"]`; | ||||
| 
 | ||||
| @ -238,7 +238,8 @@ | ||||
|             if (!isElementVisible(foundByAttributes, container)) | ||||
|                 continue; | ||||
| 
 | ||||
|             elements.push(foundByAttributes); | ||||
|             const exact = foundByAttributes.title == text || foundByAttributes.alt == text || foundByAttributes.ariaLabel == text; | ||||
|             elements.push({ element: foundByAttributes, exact: exact }); | ||||
|         } | ||||
| 
 | ||||
|         const treeWalker = document.createTreeWalker( | ||||
| @ -269,7 +270,7 @@ | ||||
|         while (currentNode = treeWalker.nextNode()) { | ||||
|             if (currentNode instanceof Text) { | ||||
|                 if (currentNode.textContent.includes(text)) { | ||||
|                     elements.push(currentNode.parentElement); | ||||
|                     elements.push({ element: currentNode.parentElement, exact: currentNode.textContent.trim() == text }); | ||||
|                 } | ||||
| 
 | ||||
|                 continue; | ||||
| @ -278,7 +279,7 @@ | ||||
|             const labelledBy = currentNode.getAttribute('aria-labelledby'); | ||||
|             const labelElement = labelledBy && container.querySelector(`#${labelledBy}`); | ||||
|             if (labelElement && labelElement.innerText && labelElement.innerText.includes(text)) { | ||||
|                 elements.push(currentNode); | ||||
|                 elements.push({ element: currentNode, exact: labelElement.innerText.trim() == text }); | ||||
| 
 | ||||
|                 continue; | ||||
|             } | ||||
| @ -296,12 +297,13 @@ | ||||
|                     } | ||||
| 
 | ||||
|                     if (childNode.matches(attributesSelector)) { | ||||
|                         elements.push(childNode); | ||||
|                         const exact = childNode.title == text || childNode.alt == text || childNode.ariaLabel == text; | ||||
|                         elements.push({ element: childNode, exact: exact}); | ||||
| 
 | ||||
|                         continue; | ||||
|                     } | ||||
| 
 | ||||
|                     elements.push(...findElementsBasedOnTextWithin(childNode, text)); | ||||
|                     elements.push(...findElementsBasedOnTextWithinWithExact(childNode, text)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -309,6 +311,24 @@ | ||||
|         return elements; | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * Finds elements within a given container. | ||||
|      * | ||||
|      * @param {HTMLElement} container Parent element to search the element within. | ||||
|      * @param {string} text Text to look for. | ||||
|      * @return {HTMLElement[]} Elements containing the given text. | ||||
|      */ | ||||
|      const findElementsBasedOnTextWithin = (container, text) => { | ||||
|         const elements = findElementsBasedOnTextWithinWithExact(container, text); | ||||
| 
 | ||||
|         // Give more relevance to exact matches.
 | ||||
|         elements.sort((a, b) => { | ||||
|             return b.exact - a.exact; | ||||
|         }); | ||||
| 
 | ||||
|         return elements.map(element => element.element); | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * Given a list of elements, get the top ancestors among all of them. | ||||
|      * | ||||
| @ -365,19 +385,78 @@ | ||||
|         return getClosestMatching(element.parentElement, selector, container); | ||||
|     }; | ||||
| 
 | ||||
|     /** | ||||
|      * Function to find top container element. | ||||
|      * | ||||
|      * @param {string} containerName Whether to search inside the a container name. | ||||
|      * @return {HTMLElement} Found top container element. | ||||
|      */ | ||||
|     const getCurrentTopContainerElement = function (containerName) { | ||||
|         let topContainer; | ||||
|         let containers; | ||||
| 
 | ||||
|         switch (containerName) { | ||||
|             case 'html': | ||||
|                 containers = document.querySelectorAll('html'); | ||||
|                 break; | ||||
|             case 'toast': | ||||
|                 containers = document.querySelectorAll('ion-app ion-toast.hydrated'); | ||||
|                 containers = Array.from(containers).map(container => container.shadowRoot.querySelector('.toast-container')); | ||||
|                 break; | ||||
|             case 'alert': | ||||
|                 containers = document.querySelectorAll('ion-app ion-alert.hydrated'); | ||||
|                 break; | ||||
|             case 'action-sheet': | ||||
|                 containers = document.querySelectorAll('ion-app ion-action-sheet.hydrated'); | ||||
|                 break; | ||||
|             case 'modal': | ||||
|                 containers = document.querySelectorAll('ion-app ion-modal.hydrated'); | ||||
|                 break; | ||||
|             case 'popover': | ||||
|                 containers = document.querySelectorAll('ion-app ion-popover.hydrated'); | ||||
|                 break; | ||||
|             default: | ||||
|                 // Other containerName or not implemented.
 | ||||
|                 const containerSelector = 'ion-alert, ion-popover, ion-action-sheet, ion-modal, page-core-mainmenu, ion-app'; | ||||
|                 containers = document.querySelectorAll(containerSelector); | ||||
|         } | ||||
| 
 | ||||
|         if (containers.length > 0) { | ||||
|             // Get the one with more zIndex.
 | ||||
|             topContainer =  Array.from(containers).reduce((a, b) => { | ||||
|                 return  getComputedStyle(a).zIndex > getComputedStyle(b).zIndex ? a : b; | ||||
|             }, containers[0]); | ||||
|         } | ||||
| 
 | ||||
|         if (containerName == 'page' || containerName == 'split-view content') { | ||||
|             // Find non hidden pages inside the container.
 | ||||
|             let pageContainers = topContainer.querySelectorAll('.ion-page:not(.ion-page-hidden)'); | ||||
|             pageContainers = Array.from(pageContainers).filter((page) => { | ||||
|                 return !page.closest('.ion-page.ion-page-hidden'); | ||||
|             }); | ||||
| 
 | ||||
|             if (pageContainers.length > 0) { | ||||
|                 // Get the more general one to avoid failing.
 | ||||
|                 topContainer = pageContainers[0]; | ||||
|             } | ||||
| 
 | ||||
|             if (containerName == 'split-view content') { | ||||
|                 topContainer = topContainer.querySelector('core-split-view ion-router-outlet'); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return topContainer; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Function to find elements based on their text or Aria label. | ||||
|      * | ||||
|      * @param {object} locator Element locator. | ||||
|      * @param {boolean} insideSplitView Whether to search only inside the split view contents. | ||||
|      * @param {string} containerName Whether to search only inside a specific container. | ||||
|      * @return {HTMLElement} Found elements | ||||
|      */ | ||||
|     const findElementsBasedOnText = function(locator, insideSplitView) { | ||||
|         let topContainer = document.querySelector('ion-alert, ion-popover, ion-action-sheet, core-ion-tab.show-tab ion-page.show-page, ion-page.show-page, html'); | ||||
| 
 | ||||
|         if (insideSplitView) { | ||||
|             topContainer = topContainer.querySelector('core-split-view ion-router-outlet'); | ||||
|         } | ||||
|     const findElementsBasedOnText = function(locator, containerName) { | ||||
|         let topContainer = getCurrentTopContainerElement(containerName); | ||||
| 
 | ||||
|         let container = topContainer; | ||||
| 
 | ||||
| @ -544,20 +623,20 @@ | ||||
|      * Function to find an arbitrary element based on its text or aria label. | ||||
|      * | ||||
|      * @param {object} locator Element locator. | ||||
|      * @param {boolean} insideSplitView Whether to search only inside the split view contents. | ||||
|      * @param {string} containerName Whether to search only inside a specific container content. | ||||
|      * @return {string} OK if successful, or ERROR: followed by message | ||||
|      */ | ||||
|     const behatFind = function(locator, insideSplitView) { | ||||
|         log('Action - Find', { locator, insideSplitView }); | ||||
|     const behatFind = function(locator, containerName) { | ||||
|         log('Action - Find', { locator, containerName }); | ||||
| 
 | ||||
|         try { | ||||
|             const element = findElementsBasedOnText(locator, insideSplitView)[0]; | ||||
|             const element = findElementsBasedOnText(locator, containerName)[0]; | ||||
| 
 | ||||
|             if (!element) { | ||||
|                 return 'ERROR: No matches for text'; | ||||
|             } | ||||
| 
 | ||||
|             log('Action - Found', { locator, insideSplitView, element }); | ||||
|             log('Action - Found', { locator, containerName, element }); | ||||
|             return 'OK'; | ||||
|         } catch (error) { | ||||
|             return 'ERROR: ' + error.message; | ||||
|  | ||||
| @ -154,18 +154,22 @@ class behat_app extends behat_base { | ||||
|     /** | ||||
|      * Finds elements in the app. | ||||
|      * | ||||
|      * @Then /^I should( not)? find (".+")( inside the split-view content)? in the app$/ | ||||
|      * @Then /^I should( not)? find (".+")( inside the .+)? in the app$/ | ||||
|      * @param bool $not | ||||
|      * @param string $locator | ||||
|      * @param bool $insidesplitview | ||||
|      * @param string $containerName | ||||
|      */ | ||||
|     public function i_find_in_the_app(bool $not, string $locator, bool $insidesplitview = false) { | ||||
|     public function i_find_in_the_app(bool $not, string $locator, string $containerName = '') { | ||||
|         $locator = $this->parse_element_locator($locator); | ||||
|         $locatorjson = json_encode($locator); | ||||
|         $insidesplitviewjson = json_encode($insidesplitview); | ||||
|         if (!empty($containerName)) { | ||||
|             preg_match('/^ inside the (.+)$/', $containerName, $matches); | ||||
|             $containerName = $matches[1]; | ||||
|         } | ||||
|         $containerName = json_encode($containerName); | ||||
| 
 | ||||
|         $this->spin(function() use ($not, $locatorjson, $insidesplitviewjson) { | ||||
|             $result = $this->evaluate_script("return window.behat.find($locatorjson, $insidesplitviewjson);"); | ||||
|         $this->spin(function() use ($not, $locatorjson, $containerName) { | ||||
|             $result = $this->evaluate_script("return window.behat.find($locatorjson, $containerName);"); | ||||
| 
 | ||||
|             if ($not && $result === 'OK') { | ||||
|                 throw new DriverException('Error, found an item that should not be found'); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user