MOBILE-4069 behat: Make it easier to find text in modals, popover, ...
parent
2c80555c1b
commit
11ca2bd7fc
|
@ -247,7 +247,7 @@ Feature: Test basic usage of forum activity in app
|
||||||
And I switch offline mode to "true"
|
And I switch offline mode to "true"
|
||||||
And I press "None" near "test2" in the app
|
And I press "None" near "test2" in the app
|
||||||
And I press "0" near "Cancel" in the app
|
And I press "0" near "Cancel" in the app
|
||||||
Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." inside the toast in the app
|
Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app
|
||||||
And I should find "Average of ratings: -" in the app
|
And I should find "Average of ratings: -" in the app
|
||||||
And I should find "Average of ratings: 1" in the app
|
And I should find "Average of ratings: 1" in the app
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,9 @@ import { NgZone } from '@singletons';
|
||||||
import { TestsBehatBlocking } from './behat-blocking';
|
import { TestsBehatBlocking } from './behat-blocking';
|
||||||
import { TestBehatElementLocator } from './behat-runtime';
|
import { TestBehatElementLocator } from './behat-runtime';
|
||||||
|
|
||||||
|
// Containers that block containers behind them.
|
||||||
|
const blockingContainers = ['ION-ALERT', 'ION-POPOVER', 'ION-ACTION-SHEET', 'CORE-USER-TOURS-USER-TOUR', 'ION-PAGE'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Behat Dom Utils helper functions.
|
* Behat Dom Utils helper functions.
|
||||||
*/
|
*/
|
||||||
|
@ -251,71 +254,68 @@ export class TestsBehatDomUtils {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to find top container element.
|
* Function to find top container elements.
|
||||||
*
|
*
|
||||||
* @param containerName Whether to search inside the a container name.
|
* @param containerName Whether to search inside the a container name.
|
||||||
* @return Found top container element.
|
* @return Found top container elements.
|
||||||
*/
|
*/
|
||||||
protected static getCurrentTopContainerElement(containerName: string): HTMLElement | null {
|
protected static getCurrentTopContainerElements(containerName: string): HTMLElement[] {
|
||||||
let topContainer: HTMLElement | null = null;
|
const topContainers: HTMLElement[] = [];
|
||||||
let containers: HTMLElement[] = [];
|
let containers = Array.from(document.querySelectorAll<HTMLElement>([
|
||||||
const nonImplementedSelectors =
|
'ion-alert.hydrated',
|
||||||
'ion-alert, ion-popover, ion-action-sheet, ion-modal, core-user-tours-user-tour.is-active, page-core-mainmenu, ion-app';
|
'ion-popover.hydrated',
|
||||||
|
'ion-action-sheet.hydrated',
|
||||||
|
'ion-modal.hydrated',
|
||||||
|
'core-user-tours-user-tour.is-active',
|
||||||
|
'ion-toast.hydrated',
|
||||||
|
'page-core-mainmenu',
|
||||||
|
'ion-app',
|
||||||
|
].join(', ')));
|
||||||
|
|
||||||
switch (containerName) {
|
containers = containers
|
||||||
case 'html':
|
.filter(container => {
|
||||||
containers = Array.from(document.querySelectorAll<HTMLElement>('html'));
|
if (container.tagName === 'ION-ALERT') {
|
||||||
break;
|
// For some reason, in Behat sometimes alerts aren't removed from DOM, the close animation doesn't finish.
|
||||||
case 'toast':
|
// Filter alerts with pointer-events none since that style is set before the close animation starts.
|
||||||
containers = Array.from(document.querySelectorAll('ion-app ion-toast.hydrated'));
|
return container.style.pointerEvents !== 'none';
|
||||||
containers = containers.map(container => container?.shadowRoot?.querySelector('.toast-container') || container);
|
}
|
||||||
break;
|
|
||||||
case 'alert':
|
// Ignore pages that are inside other visible pages.
|
||||||
containers = Array.from(document.querySelectorAll('ion-app ion-alert.hydrated'));
|
return container.tagName !== 'ION-PAGE' || !container.closest('.ion-page.ion-page-hidden');
|
||||||
break;
|
})
|
||||||
case 'action-sheet':
|
// Sort them by z-index.
|
||||||
containers = Array.from(document.querySelectorAll('ion-app ion-action-sheet.hydrated'));
|
.sort((a, b) => Number(getComputedStyle(b).zIndex) - Number(getComputedStyle(a).zIndex));
|
||||||
break;
|
|
||||||
case 'modal':
|
if (containerName === 'split-view content') {
|
||||||
containers = Array.from(document.querySelectorAll('ion-app ion-modal.hydrated'));
|
// Find non hidden pages inside the containers.
|
||||||
break;
|
containers.some(container => {
|
||||||
case 'popover':
|
if (!container.classList.contains('ion-page')) {
|
||||||
containers = Array.from(document.querySelectorAll('ion-app ion-popover.hydrated'));
|
return false;
|
||||||
break;
|
}
|
||||||
case 'user-tour':
|
|
||||||
containers = Array.from(document.querySelectorAll('core-user-tours-user-tour.is-active'));
|
const pageContainers = Array.from(container.querySelectorAll<HTMLElement>('.ion-page:not(.ion-page-hidden)'));
|
||||||
break;
|
let topContainer = pageContainers.find((page) => !page.closest('.ion-page.ion-page-hidden')) ?? null;
|
||||||
default:
|
|
||||||
// Other containerName or not implemented.
|
topContainer = (topContainer || container).querySelector<HTMLElement>('core-split-view ion-router-outlet');
|
||||||
containers = Array.from(document.querySelectorAll<HTMLElement>(nonImplementedSelectors));
|
topContainer && topContainers.push(topContainer);
|
||||||
|
|
||||||
|
return !!topContainer;
|
||||||
|
});
|
||||||
|
|
||||||
|
return topContainers;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (containers.length > 0) {
|
// Get containers until one blocks other views.
|
||||||
// Get the one with more zIndex.
|
containers.find(container => {
|
||||||
topContainer =
|
if (container.tagName === 'ION-TOAST') {
|
||||||
containers.reduce((a, b) => getComputedStyle(a).zIndex > getComputedStyle(b).zIndex ? a : b, containers[0]);
|
container = container.shadowRoot?.querySelector('.toast-container') || container;
|
||||||
}
|
|
||||||
|
|
||||||
if (!topContainer) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (containerName == 'page' || containerName == 'split-view content') {
|
|
||||||
// Find non hidden pages inside the container.
|
|
||||||
let pageContainers = Array.from(topContainer.querySelectorAll<HTMLElement>('.ion-page:not(.ion-page-hidden)'));
|
|
||||||
pageContainers = pageContainers.filter((page) => !page.closest('.ion-page.ion-page-hidden'));
|
|
||||||
|
|
||||||
if (pageContainers.length > 0) {
|
|
||||||
// Get the more general one to avoid failing.
|
|
||||||
topContainer = pageContainers[0];
|
|
||||||
}
|
}
|
||||||
|
topContainers.push(container);
|
||||||
|
|
||||||
if (containerName == 'split-view content') {
|
return blockingContainers.includes(container.tagName);
|
||||||
topContainer = topContainer.querySelector<HTMLElement>('core-split-view ion-router-outlet');
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return topContainer;
|
return topContainers;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -337,9 +337,24 @@ export class TestsBehatDomUtils {
|
||||||
* @return Found elements
|
* @return Found elements
|
||||||
*/
|
*/
|
||||||
protected static findElementsBasedOnText(locator: TestBehatElementLocator, containerName = ''): HTMLElement[] {
|
protected static findElementsBasedOnText(locator: TestBehatElementLocator, containerName = ''): HTMLElement[] {
|
||||||
let topContainer = this.getCurrentTopContainerElement(containerName);
|
const topContainers = this.getCurrentTopContainerElements(containerName);
|
||||||
|
|
||||||
let container = topContainer;
|
return topContainers.reduce((elements, container) =>
|
||||||
|
elements.concat(this.findElementsBasedOnTextInContainer(locator, container)), <HTMLElement[]> []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to find elements based on their text or Aria label.
|
||||||
|
*
|
||||||
|
* @param locator Element locator.
|
||||||
|
* @param container Container to search in.
|
||||||
|
* @return Found elements
|
||||||
|
*/
|
||||||
|
protected static findElementsBasedOnTextInContainer(
|
||||||
|
locator: TestBehatElementLocator,
|
||||||
|
topContainer: HTMLElement,
|
||||||
|
): HTMLElement[] {
|
||||||
|
let container: HTMLElement | null = topContainer;
|
||||||
|
|
||||||
if (locator.within) {
|
if (locator.within) {
|
||||||
const withinElements = this.findElementsBasedOnText(locator.within);
|
const withinElements = this.findElementsBasedOnText(locator.within);
|
||||||
|
|
Loading…
Reference in New Issue