commit
462e868582
|
@ -120,7 +120,7 @@ Feature: Test basic usage of assignment activity in app
|
|||
When I switch offline mode to "false"
|
||||
And I press the back button in the app
|
||||
And I press "assignment1" in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Information" in the app
|
||||
And I press "Refresh" in the app
|
||||
Then I should find "Submitted for grading" in the app
|
||||
But I should not find "This Assignment has offline data to be synchronised." in the app
|
||||
|
|
|
@ -93,7 +93,7 @@ Feature: Test basic usage of choice activity in app
|
|||
And I press "Test single choice name" in the app
|
||||
Then I should find "Test single choice description" in the app
|
||||
|
||||
When I press "Display options" in the app
|
||||
When I press "Information" in the app
|
||||
And I press "Refresh" in the app
|
||||
Then I should find "Option 1: 0" in the app
|
||||
And I should find "Option 2: 1" in the app
|
||||
|
@ -132,7 +132,7 @@ Feature: Test basic usage of choice activity in app
|
|||
| choice | Test multi choice name | Test multi choice description | C1 | choice2 | Option 1, Option 2, Option 3 | 1 | 1 | 1 |
|
||||
| choice | Test single choice name | Test single choice description | C1 | choice1 | Option 1, Option 2, Option 3 | 0 | 0 | 1 |
|
||||
When I enter the course "Course 1" as "student1" in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Course summary" in the app
|
||||
And I press "Course downloads" in the app
|
||||
And I press "Download" within "Test single choice name" "ion-item" in the app
|
||||
Then I should find "Downloaded" within "Test single choice name" "ion-item" in the app
|
||||
|
@ -182,7 +182,7 @@ Feature: Test basic usage of choice activity in app
|
|||
And I press "Choice name" in the app
|
||||
Then I should find "Test choice description" in the app
|
||||
|
||||
When I press "Display options" in the app
|
||||
When I press "Information" in the app
|
||||
And I press "Open in browser" in the app
|
||||
And I switch to the browser tab opened by the app
|
||||
And I log in as "teacher1"
|
||||
|
|
|
@ -402,7 +402,6 @@ Feature: Test basic usage of one course in app
|
|||
|
||||
Scenario: Self enrol
|
||||
Given I enter the course "Course 1" as "teacher1" in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Course summary" in the app
|
||||
And I press "Open in browser" in the app
|
||||
And I switch to the browser tab opened by the app
|
||||
|
@ -437,7 +436,6 @@ Feature: Test basic usage of one course in app
|
|||
|
||||
Scenario: Guest access
|
||||
Given I enter the course "Course 1" as "teacher1" in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Course summary" in the app
|
||||
And I press "Open in browser" in the app
|
||||
And I switch to the browser tab opened by the app
|
||||
|
@ -451,7 +449,7 @@ Feature: Test basic usage of one course in app
|
|||
And I press "Site home" in the app
|
||||
And I press "Available courses" in the app
|
||||
And I press "Course 1" in the app
|
||||
Then I should find "Download course" in the app
|
||||
Then I should find "Course downloads" in the app
|
||||
And I should find "Course" in the app
|
||||
|
||||
When I press "Course" "ion-button" in the app
|
||||
|
|
|
@ -103,12 +103,11 @@ Feature: Test basic usage of courses in app
|
|||
# Configure assignment as teacher
|
||||
When I enter the course "Course 1" as "teacher1" in the app
|
||||
And I press "assignment" in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Information" in the app
|
||||
And I press "Open in browser" in the app
|
||||
And I switch to the browser tab opened by the app
|
||||
And I log in as "teacher1"
|
||||
And I press "Actions menu"
|
||||
And I follow "Settings"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I press "Expand all"
|
||||
And I click on "duedate[enabled]" "checkbox"
|
||||
And I click on "gradingduedate[enabled]" "checkbox"
|
||||
|
|
|
@ -182,7 +182,7 @@ Feature: Test basic usage of forum activity in app
|
|||
Then I should find "Auto-test" in the app
|
||||
|
||||
When I press the back button in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Course summary" in the app
|
||||
And I press "Course downloads" in the app
|
||||
And I press "Download" within "Test forum name" "ion-item" in the app
|
||||
And I press the back button in the app
|
||||
|
@ -209,7 +209,7 @@ Feature: Test basic usage of forum activity in app
|
|||
Then I should find "Auto-test" in the app
|
||||
|
||||
When I press the back button in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Course summary" in the app
|
||||
And I press "Course downloads" in the app
|
||||
And I press "Download" within "Test forum name" "ion-item" in the app
|
||||
And I press the back button in the app
|
||||
|
@ -256,7 +256,7 @@ Feature: Test basic usage of forum activity in app
|
|||
And I switch offline mode to "true"
|
||||
And I press "None" near "test2" 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." 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
|
||||
And I should find "Average of ratings: -" in the app
|
||||
And I should find "Average of ratings: 1" in the app
|
||||
|
||||
|
@ -264,7 +264,7 @@ Feature: Test basic usage of forum activity in app
|
|||
And I press the back button in the app
|
||||
Then I should find "This Forum has offline data to be synchronised." in the app
|
||||
|
||||
When I press "Display options" near "Test forum name" in the app
|
||||
When I press "Information" near "Test forum name" in the app
|
||||
And I press "Synchronise now" in the app
|
||||
Then I should not find "This Forum has offline data to be synchronised." in the app
|
||||
|
||||
|
@ -288,7 +288,7 @@ Feature: Test basic usage of forum activity in app
|
|||
And I set the field "Message" to "DiscussionMessage" in the app
|
||||
And I press "Post to forum" in the app
|
||||
And I press the back button in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Course summary" in the app
|
||||
And I press "Course downloads" in the app
|
||||
And I press "Download" within "Test forum name" "ion-item" in the app
|
||||
And I press the back button in the app
|
||||
|
@ -326,8 +326,8 @@ Feature: Test basic usage of forum activity in app
|
|||
When I switch offline mode to "false"
|
||||
And I press the back button in the app
|
||||
And I press "Test forum name" in the app
|
||||
And I press "Display options" near "Test forum name" in the app
|
||||
And I press "Refresh discussions" in the app
|
||||
And I press "Information" near "Test forum name" in the app
|
||||
And I press "Refresh" in the app
|
||||
And I press "DiscussionSubject" near "Sort by last post creation date in descending order" in the app
|
||||
Then I should find "DiscussionSubject" in the app
|
||||
And I should find "DiscussionMessage" in the app
|
||||
|
@ -367,7 +367,7 @@ Feature: Test basic usage of forum activity in app
|
|||
Then I should find "DiscussionSubject 1" in the app
|
||||
|
||||
When I press the back button in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Course summary" in the app
|
||||
And I press "Course downloads" in the app
|
||||
And I press "Download" within "Test forum name" "ion-item" in the app
|
||||
Then I should find "Downloaded" within "Test forum name" "ion-item" in the app
|
||||
|
|
|
@ -156,7 +156,7 @@ Feature: Attempt a quiz in app
|
|||
|
||||
When I enter the course "Course 1" as "teacher1" in the app
|
||||
And I press "Quiz 1" in the app
|
||||
And I press "Display options" in the app
|
||||
And I press "Information" in the app
|
||||
And I press "Open in browser" in the app
|
||||
And I switch to the browser tab opened by the app
|
||||
And I log in as "teacher1"
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -32,11 +32,12 @@ Feature: It opens external links properly.
|
|||
|
||||
When I close the browser tab opened by the app
|
||||
And I press the back button in the app
|
||||
And I press the page menu button in the app
|
||||
And I press "Information" in the app
|
||||
And I press "Open in browser" in the app
|
||||
Then the app should have opened a browser tab
|
||||
|
||||
When I close the browser tab opened by the app
|
||||
When I close the popup in the app
|
||||
And I press "Forum topic" in the app
|
||||
And I press "moodle.org" in the app
|
||||
And I select "Don't show again." in the app
|
||||
|
|
|
@ -44,7 +44,7 @@ Feature: It navigates properly within settings.
|
|||
|
||||
When I press the back button in the app
|
||||
And I press "Manage downloads" in the app
|
||||
Then I should find "Total space usage" in the app
|
||||
Then I should find "Total space used" in the app
|
||||
|
||||
Scenario: Tablet navigation
|
||||
Given I enter the app
|
||||
|
@ -79,4 +79,4 @@ Feature: It navigates properly within settings.
|
|||
|
||||
When I press "Manage downloads" in the app
|
||||
Then "Manage downloads" should be selected in the app
|
||||
And I should find "Total space usage" in the app
|
||||
And I should find "Total space used" in the app
|
||||
|
|
Loading…
Reference in New Issue