MOBILE-3738 behat: Implement navigation tests
parent
17006dcc4e
commit
778298a455
|
@ -194,6 +194,24 @@
|
|||
return isElementVisible(element.parentElement, container);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an element is selected.
|
||||
*
|
||||
* @param {HTMLElement} element Element
|
||||
* @param {HTMLElement} container Container
|
||||
* @returns {boolean} Whether the element is selected or not
|
||||
*/
|
||||
var isElementSelected = (element, container) => {
|
||||
const ariaCurrent = element.getAttribute('aria-current');
|
||||
if (ariaCurrent && ariaCurrent !== 'false')
|
||||
return true;
|
||||
|
||||
if (!element.parentElement || element.parentElement === container)
|
||||
return false;
|
||||
|
||||
return isElementSelected(element.parentElement, container);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic shared function to find possible xpath matches within the document, that are visible,
|
||||
* and then process them using a callback function.
|
||||
|
@ -330,43 +348,61 @@
|
|||
*/
|
||||
var behatPressStandard = function(button) {
|
||||
log('Action - Click standard button: ' + button);
|
||||
var selector;
|
||||
switch (button) {
|
||||
case 'back' :
|
||||
selector = 'ion-navbar > button.back-button-md';
|
||||
break;
|
||||
case 'main menu' :
|
||||
// Change in app version 3.8.
|
||||
selector = 'page-core-mainmenu .tab-button > ion-icon[aria-label=more], ' +
|
||||
'page-core-mainmenu .tab-button > ion-icon[aria-label=menu]';
|
||||
break;
|
||||
case 'page menu' :
|
||||
// This lang string was changed in app version 3.6.
|
||||
selector = 'core-context-menu > button[aria-label=Info], ' +
|
||||
'core-context-menu > button[aria-label=Information], ' +
|
||||
'core-context-menu > button[aria-label="Display options"]';
|
||||
break;
|
||||
default:
|
||||
return 'ERROR: Unsupported standard button type';
|
||||
}
|
||||
var buttons = Array.from(document.querySelectorAll(selector));
|
||||
|
||||
// Find button
|
||||
var foundButton = null;
|
||||
var tooMany = false;
|
||||
buttons.forEach(function(button) {
|
||||
if (button.offsetParent) {
|
||||
if (foundButton === null) {
|
||||
foundButton = button;
|
||||
} else {
|
||||
tooMany = true;
|
||||
}
|
||||
|
||||
if (window.BehatMoodleAppLegacy) {
|
||||
var selector;
|
||||
switch (button) {
|
||||
case 'back' :
|
||||
selector = 'ion-navbar > button.back-button-md';
|
||||
break;
|
||||
case 'main menu' :
|
||||
// Change in app version 3.8.
|
||||
selector = 'page-core-mainmenu .tab-button > ion-icon[aria-label=more], ' +
|
||||
'page-core-mainmenu .tab-button > ion-icon[aria-label=menu]';
|
||||
break;
|
||||
case 'page menu' :
|
||||
// This lang string was changed in app version 3.6.
|
||||
selector = 'core-context-menu > button[aria-label=Info], ' +
|
||||
'core-context-menu > button[aria-label=Information], ' +
|
||||
'core-context-menu > button[aria-label="Display options"]';
|
||||
break;
|
||||
default:
|
||||
return 'ERROR: Unsupported standard button type';
|
||||
}
|
||||
var buttons = Array.from(document.querySelectorAll(selector));
|
||||
var tooMany = false;
|
||||
buttons.forEach(function(button) {
|
||||
if (button.offsetParent) {
|
||||
if (foundButton === null) {
|
||||
foundButton = button;
|
||||
} else {
|
||||
tooMany = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!foundButton) {
|
||||
return 'ERROR: Could not find button';
|
||||
}
|
||||
if (tooMany) {
|
||||
return 'ERROR: Found too many buttons';
|
||||
}
|
||||
} else {
|
||||
switch (button) {
|
||||
case 'back':
|
||||
foundButton = findElementBasedOnText('Back');
|
||||
break;
|
||||
case 'main menu':
|
||||
foundButton = findElementBasedOnText('more', 'Notifications');
|
||||
break;
|
||||
default:
|
||||
return 'ERROR: Unsupported standard button type';
|
||||
}
|
||||
});
|
||||
if (!foundButton) {
|
||||
return 'ERROR: Could not find button';
|
||||
}
|
||||
if (tooMany) {
|
||||
return 'ERROR: Found too many buttons';
|
||||
}
|
||||
|
||||
// Click button
|
||||
foundButton.click();
|
||||
|
||||
// Mark busy until the button click finishes processing.
|
||||
|
@ -449,6 +485,25 @@
|
|||
return window.appProvider.appCtrl.getRootNavs()[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether an item is selected or not.
|
||||
*
|
||||
* @param {string} text Text (full or partial)
|
||||
* @param {string} near Optional 'near' text
|
||||
* @return {string} YES or NO if successful, or ERROR: followed by message
|
||||
*/
|
||||
var behatIsSelected = function(text, near) {
|
||||
log(`Action - Is Selected: "${text}"${near ? ` near "${near}"`: ''}`);
|
||||
|
||||
try {
|
||||
const element = findElementBasedOnText(text, near);
|
||||
|
||||
return isElementSelected(element, document.body) ? 'YES' : 'NO';
|
||||
} catch (error) {
|
||||
return 'ERROR: ' + error.message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to press arbitrary item based on its text or Aria label.
|
||||
*
|
||||
|
@ -639,6 +694,7 @@
|
|||
pressStandard : behatPressStandard,
|
||||
closePopup : behatClosePopup,
|
||||
find : behatFind,
|
||||
isSelected : behatIsSelected,
|
||||
press : behatPress,
|
||||
setField : behatSetField,
|
||||
getHeader : behatGetHeader,
|
||||
|
|
|
@ -120,6 +120,40 @@ class behat_app extends behat_base {
|
|||
$this->wait_for_pending_js();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if elements are selected in the app.
|
||||
*
|
||||
* @Then /^"(?P<text_string>(?:[^"]|\\")*)"(?: near "(?P<near_string>(?:[^"]|\\")*)")? should(?P<not_boolean> not)? be selected in the app$/
|
||||
* @param string $text
|
||||
*/
|
||||
public function be_selected_in_the_app($text, $near='', $not='') {
|
||||
$not = !empty($not);
|
||||
$text = addslashes_js($text);
|
||||
$near = addslashes_js($near);
|
||||
|
||||
$this->spin(function() use ($not, $text, $near) {
|
||||
$result = $this->evaluate_script("return window.behat.isSelected(\"$text\", \"$near\");");
|
||||
|
||||
switch ($result) {
|
||||
case 'YES':
|
||||
if ($not) {
|
||||
throw new ExpectationException("Item was selected and shouldn't have", $this->getSession()->getDriver());
|
||||
}
|
||||
break;
|
||||
case 'NO':
|
||||
if (!$not) {
|
||||
throw new ExpectationException("Item wasn't selected and should have", $this->getSession()->getDriver());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new DriverException('Error finding item - ' . $result);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
$this->wait_for_pending_js();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the Behat setup - tags and configuration.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
@app @javascript
|
||||
Feature: It navigates properly between pages.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username |
|
||||
| student1 |
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 2 | C2 |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student1 | C2 | student |
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course |
|
||||
| Grade category C1 | C1 |
|
||||
| Grade category C2 | C2 |
|
||||
And the following "grade items" exist:
|
||||
| gradecategory | itemname | grademin | grademax | course |
|
||||
| Grade category C1 | Grade item C1 | 20 | 40 | C1 |
|
||||
| Grade category C2 | Grade item C2 | 60 | 80 | C2 |
|
||||
|
||||
Scenario: Navigate between split-view items in mobiles
|
||||
|
||||
# Open more tab
|
||||
Given I enter the app
|
||||
And I log in as "student1"
|
||||
And I press the main menu button in the app
|
||||
|
||||
# Open grades tab
|
||||
When I press "Grades" in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Course 1" in the app
|
||||
And I should find "Course 2" in the app
|
||||
|
||||
# Open C1 course grades
|
||||
When I press "Course 1" in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Grade category C1" in the app
|
||||
|
||||
# Open C1 grade item
|
||||
When I press "Grade item C1" in the app
|
||||
Then the header should be "Grade" in the app
|
||||
And I should find "20" near "Range" in the app
|
||||
And I should find "40" near "Range" in the app
|
||||
|
||||
# Go back to course grades
|
||||
When I press the back button in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Grade category C1" in the app
|
||||
|
||||
# Go back to grades tab
|
||||
When I press the back button in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Course 1" in the app
|
||||
And I should find "Course 2" in the app
|
||||
|
||||
# Open C2 course grades
|
||||
When I press "Course 2" in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Grade category C2" in the app
|
||||
|
||||
# Open C2 grade item
|
||||
When I press "Grade item C2" in the app
|
||||
Then the header should be "Grade" in the app
|
||||
And I should find "60" near "Range" in the app
|
||||
And I should find "80" near "Range" in the app
|
||||
|
||||
# Go back to course grades
|
||||
When I press the back button in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Grade category C2" in the app
|
||||
|
||||
# Go back to grades tab
|
||||
When I press the back button in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Course 1" in the app
|
||||
And I should find "Course 2" in the app
|
||||
|
||||
# Go back to more tab
|
||||
When I press the back button in the app
|
||||
Then I should find "Grades" in the app
|
||||
And I should find "App settings" in the app
|
||||
But I should not find "Back" in the app
|
||||
|
||||
Scenario: Navigate between split-view items in tablets
|
||||
|
||||
# Open more tab
|
||||
Given I enter the app
|
||||
And I change viewport size to "1200x640"
|
||||
And I log in as "student1"
|
||||
|
||||
# Open grades tab
|
||||
When I press "Grades" in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Course 1" in the app
|
||||
And I should find "Course 2" in the app
|
||||
And I should find "Grade category C1" in the app
|
||||
|
||||
# Open C1 course grades
|
||||
When I press "Grade item C1" in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Grade category C1" in the app
|
||||
And I should find "20" near "Range" in the app
|
||||
And I should find "40" near "Range" in the app
|
||||
|
||||
# Go back to grades tab
|
||||
When I press the back button in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Course 1" in the app
|
||||
And I should find "Course 2" in the app
|
||||
|
||||
# Select C2 course
|
||||
When I press "Course 2" in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And "Course 2" should be selected in the app
|
||||
And I should find "Grade category C2" in the app
|
||||
|
||||
# Open C2 course grades
|
||||
When I press "Grade item C2" in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Grade category C2" in the app
|
||||
And I should find "60" near "Range" in the app
|
||||
And I should find "80" near "Range" in the app
|
||||
|
||||
# Go back to grades tab
|
||||
When I press the back button in the app
|
||||
Then the header should be "Grades" in the app
|
||||
And I should find "Course 1" in the app
|
||||
And I should find "Course 2" in the app
|
||||
But I should not find "Back" in the app
|
Loading…
Reference in New Issue