MOBILE-3738 behat: Implement navigation tests
parent
17006dcc4e
commit
778298a455
|
@ -194,6 +194,24 @@
|
||||||
return isElementVisible(element.parentElement, container);
|
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,
|
* Generic shared function to find possible xpath matches within the document, that are visible,
|
||||||
* and then process them using a callback function.
|
* and then process them using a callback function.
|
||||||
|
@ -330,43 +348,61 @@
|
||||||
*/
|
*/
|
||||||
var behatPressStandard = function(button) {
|
var behatPressStandard = function(button) {
|
||||||
log('Action - Click standard button: ' + button);
|
log('Action - Click standard button: ' + button);
|
||||||
var selector;
|
|
||||||
switch (button) {
|
// Find 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 foundButton = null;
|
var foundButton = null;
|
||||||
var tooMany = false;
|
|
||||||
buttons.forEach(function(button) {
|
if (window.BehatMoodleAppLegacy) {
|
||||||
if (button.offsetParent) {
|
var selector;
|
||||||
if (foundButton === null) {
|
switch (button) {
|
||||||
foundButton = button;
|
case 'back' :
|
||||||
} else {
|
selector = 'ion-navbar > button.back-button-md';
|
||||||
tooMany = true;
|
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();
|
foundButton.click();
|
||||||
|
|
||||||
// Mark busy until the button click finishes processing.
|
// Mark busy until the button click finishes processing.
|
||||||
|
@ -449,6 +485,25 @@
|
||||||
return window.appProvider.appCtrl.getRootNavs()[0];
|
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.
|
* Function to press arbitrary item based on its text or Aria label.
|
||||||
*
|
*
|
||||||
|
@ -639,6 +694,7 @@
|
||||||
pressStandard : behatPressStandard,
|
pressStandard : behatPressStandard,
|
||||||
closePopup : behatClosePopup,
|
closePopup : behatClosePopup,
|
||||||
find : behatFind,
|
find : behatFind,
|
||||||
|
isSelected : behatIsSelected,
|
||||||
press : behatPress,
|
press : behatPress,
|
||||||
setField : behatSetField,
|
setField : behatSetField,
|
||||||
getHeader : behatGetHeader,
|
getHeader : behatGetHeader,
|
||||||
|
|
|
@ -120,6 +120,40 @@ class behat_app extends behat_base {
|
||||||
$this->wait_for_pending_js();
|
$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.
|
* 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