mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
MDL-39635 behat: XPath cleanups
- Escaping steps arguments redirected to other steps - Adding normalized-space() in all contains() assertions - General xpaths review - Convering provided xpath text strings to xpath literals to avoid problems with arguments containing both single quotes and double quotes
This commit is contained in:
parent
dedb973878
commit
3897608152
@ -72,8 +72,12 @@ class behat_admin extends behat_base {
|
||||
// Admin settings does not use the same DOM structure than other moodle forms
|
||||
// but we also need to use lib/behat/form_field/* to deal with the different moodle form elements.
|
||||
$exception = new ElementNotFoundException($this->getSession(), '"' . $label . '" administration setting ');
|
||||
|
||||
// The argument should be converted to an xpath literal.
|
||||
$label = $this->getSession()->getSelectorsHandler()->xpathLiteral($label);
|
||||
|
||||
$fieldxpath = "//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" .
|
||||
"[@id=//label[contains(normalize-space(string(.)), '" . $label . "')]/@for]";
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath, $exception);
|
||||
$formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[@class='form-setting']" .
|
||||
"/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div");
|
||||
|
@ -15,7 +15,7 @@ Feature: Display extended course names
|
||||
And I should not see "C_shortname Course fullname"
|
||||
|
||||
Scenario: Courses list with extended course names
|
||||
Given I click on "Courses" "link" in the "//div[@id='settingsnav']//descendant::li[contains(concat(' ', @class, ' '), ' type_setting ')][not(contains(., 'Site administration'))][contains(., 'Appearance')]" "xpath_element"
|
||||
Given I click on "Courses" "link" in the "//div[@id='settingsnav']/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' type_setting ')][not(contains(., 'Site administration'))][contains(., 'Appearance')]" "xpath_element"
|
||||
And I check "Display extended course names"
|
||||
When I press "Save changes"
|
||||
And I am on homepage
|
||||
|
@ -37,7 +37,7 @@ Feature: Page contents assertions
|
||||
And I follow "Course 1"
|
||||
When I click on "Move this to the dock" "button" in the ".block_settings" "css_element"
|
||||
Then I should not see "Question bank"
|
||||
And I click on "//div[@id='dock']/descendant::*[contains(., 'Administration')]/h2" "xpath_element"
|
||||
And I click on "//div[@id='dock']/descendant::h2[normalize-space(.)='Administration']" "xpath_element"
|
||||
|
||||
@javascript
|
||||
Scenario: Locators inside specific DOM nodes using XPath
|
||||
@ -45,5 +45,5 @@ Feature: Page contents assertions
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
When I click on "Move this to the dock" "button" in the "//*[contains(concat(' ', normalize-space(@class), ' '), ' block_settings ')]" "xpath_element"
|
||||
When I click on "Move this to the dock" "button" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' block_settings ')]" "xpath_element"
|
||||
Then I should not see "Turn editing on"
|
||||
|
@ -30,17 +30,17 @@ Feature: Set up contextual data for tests
|
||||
Then I should see "Course 1"
|
||||
And I should see "Course 2"
|
||||
And I should see "Course 3"
|
||||
When I go to the courses management page
|
||||
And I go to the courses management page
|
||||
And I follow "Cat 1"
|
||||
Then I should see "Cat 2"
|
||||
And I should see "Cat 2"
|
||||
And I should see "Cat 3"
|
||||
When I follow "Cat 3"
|
||||
Then I should see "Course 1"
|
||||
And I follow "Cat 3"
|
||||
And I should see "Course 1"
|
||||
And I should see "Course 2"
|
||||
When I select "Cat 2" from "Course categories:"
|
||||
Then I should see "No courses in this category"
|
||||
When I select "Miscellaneous" from "Course categories:"
|
||||
Then I should see "Course 3"
|
||||
And I select "Cat 1 / Cat 2" from "Course categories:"
|
||||
And I should see "No courses in this category"
|
||||
And I select "Miscellaneous" from "Course categories:"
|
||||
And I should see "Course 3"
|
||||
|
||||
@javascript
|
||||
Scenario: Add a bunch of groups and groupings
|
||||
|
@ -50,8 +50,8 @@ class behat_auth extends behat_base {
|
||||
|
||||
return array(new Given('I am on homepage'),
|
||||
new Given('I follow "' . get_string('login') . '"'),
|
||||
new Given('I fill in "' . get_string('username') . '" with "'.$username.'"'),
|
||||
new Given('I fill in "' . get_string('password') . '" with "'.$username.'"'),
|
||||
new Given('I fill in "' . get_string('username') . '" with "' . $this->escape($username) . '"'),
|
||||
new Given('I fill in "' . get_string('password') . '" with "'. $this->escape($username) . '"'),
|
||||
new Given('I press "' . get_string('login') . '"')
|
||||
);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ Feature: Backup Moodle courses
|
||||
And I should not see "Section 3"
|
||||
And I press "Continue"
|
||||
And I click on "Continue" "button" in the ".bcs-current-course" "css_element"
|
||||
And I click on "//div[contains(concat(' ', @class, ' '), ' fitem ')][contains(., 'Include calendar events')]/descendant::img" "xpath_element"
|
||||
And I click on "setting_root_logs" "checkbox" in the "//div[contains(@class, 'fitem')][contains(., 'Include course logs')]" "xpath_element"
|
||||
And "//div[contains(concat(' ', normalize-space(@class), ' '), ' fitem ')][contains(., 'Include calendar events')]/descendant::img" "xpath_element" should exists
|
||||
And I check "Include course logs"
|
||||
And I press "Cancel"
|
||||
And I click on "Cancel" "button" in the ".confirmation-dialogue" "css_element"
|
||||
|
@ -105,15 +105,16 @@ class behat_backup extends behat_base {
|
||||
// Click the course link.
|
||||
$this->find_link($tocourse)->click();
|
||||
|
||||
// Click the backup link.
|
||||
// Click the import link.
|
||||
$this->find_link(get_string('import'))->click();
|
||||
|
||||
// Select the course.
|
||||
$exception = new ExpectationException('"' . $fromcourse . '" course not found in the list of courses to import from', $this->getSession());
|
||||
|
||||
$fromcourse = str_replace("'", "\'", $fromcourse);
|
||||
$xpath = "//div[contains(concat(' ', @class, ' '), ' ics-results ')]" .
|
||||
"/descendant::tr[contains(., '" . $fromcourse . "')]" .
|
||||
// The argument should be converted to an xpath literal.
|
||||
$fromcourse = $this->getSession()->getSelectorsHandler()->xpathLiteral($fromcourse);
|
||||
$xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' ics-results ')]" .
|
||||
"/descendant::tr[contains(., $fromcourse)]" .
|
||||
"/descendant::input[@type='radio']";
|
||||
$radionode = $this->find('xpath', $xpath, $exception);
|
||||
$radionode->check();
|
||||
@ -150,17 +151,19 @@ class behat_backup extends behat_base {
|
||||
// Confirm restore.
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// The argument should be converted to an xpath literal.
|
||||
$existingcourse = $this->getSession()->getSelectorsHandler()->xpathLiteral($existingcourse);
|
||||
|
||||
// Selecting the specified course (we can not call behat_forms::select_radio here as is in another behat subcontext).
|
||||
$existingcourse = str_replace("'", "\'", $existingcourse);
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-existing-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-existing-course ')]" .
|
||||
"/descendant::div[@class='restore-course-search']" .
|
||||
"/descendant::tr[contains(., '" . $existingcourse . "')]" .
|
||||
"/descendant::tr[contains(., $existingcourse)]" .
|
||||
"/descendant::input[@type='radio']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore into an existing course section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-existing-course')]" .
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-existing-course ')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
@ -182,14 +185,14 @@ class behat_backup extends behat_base {
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// The first category in the list.
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-new-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-new-course ')]" .
|
||||
"/descendant::div[@class='restore-course-search']" .
|
||||
"/descendant::input[@type='radio']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore into an existing course section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-new-course')]" .
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-new-course ')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
@ -211,13 +214,13 @@ class behat_backup extends behat_base {
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// Merge without deleting radio option.
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='radio'][@name='target'][@value='1']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore merging section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
@ -239,13 +242,13 @@ class behat_backup extends behat_base {
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// Delete contents radio option.
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='radio'][@name='target'][@value='0']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore merging section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
@ -265,7 +268,11 @@ class behat_backup extends behat_base {
|
||||
|
||||
// Using xpath as there are other restore links before this one.
|
||||
$exception = new ExpectationException('The "' . $backupfilename . '" backup file can not be found in this page', $this->getSession());
|
||||
$xpath = "//tr[contains(., '" . $backupfilename . "')]/descendant::a[contains(., '" . get_string('restore') . "')]";
|
||||
|
||||
// The argument should be converted to an xpath literal.
|
||||
$backupfilename = $this->getSession()->getSelectorsHandler()->xpathLiteral($backupfilename);
|
||||
|
||||
$xpath = "//tr[contains(., $backupfilename)]/descendant::a[contains(., '" . get_string('restore') . "')]";
|
||||
$restorelink = $this->find('xpath', $xpath, $exception);
|
||||
$restorelink->click();
|
||||
|
||||
@ -341,6 +348,10 @@ class behat_backup extends behat_base {
|
||||
*/
|
||||
protected function wait($timeout = false) {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$timeout) {
|
||||
$timeout = self::TIMEOUT;
|
||||
}
|
||||
|
@ -91,8 +91,11 @@ class behat_block_comments extends behat_base {
|
||||
|
||||
$exception = new ElementNotFoundException($this->getSession(), '"' . $comment . '" comment ');
|
||||
|
||||
$commentxpath = "//div[contains(concat(' ', @class, ' '), ' block_comments ')]" .
|
||||
"/descendant::div[@class='comment-message'][contains(., '" . $comment . "')]";
|
||||
// Using xpath liternal to avoid possible problems with comments containing quotes.
|
||||
$commentliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($comment);
|
||||
|
||||
$commentxpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' block_comments ')]" .
|
||||
"/descendant::div[@class='comment-message'][contains(., $commentliteral)]";
|
||||
$commentnode = $this->find('xpath', $commentxpath, $exception);
|
||||
|
||||
// Click on delete icon.
|
||||
@ -101,7 +104,7 @@ class behat_block_comments extends behat_base {
|
||||
$deleteicon->click();
|
||||
|
||||
// Yes confirm.
|
||||
$confirmnode = $this->find('xpath', "//div[@class='comment-delete-confirm']/descendant::a[contains(., 'Yes')]");
|
||||
$confirmnode = $this->find('xpath', "//div[@class='comment-delete-confirm']/descendant::a[contains(., '" . get_string('yes') . "')]");
|
||||
$confirmnode->click();
|
||||
|
||||
// Wait for the AJAX request.
|
||||
|
@ -46,7 +46,7 @@ class behat_blocks extends behat_base {
|
||||
* @param string $blockname
|
||||
*/
|
||||
public function i_add_the_block($blockname) {
|
||||
$steps = new Given('I select "' . $blockname . '" from "bui_addblock"');
|
||||
$steps = new Given('I select "' . $this->escape($blockname) . '" from "bui_addblock"');
|
||||
|
||||
// If we are running without javascript we need to submit the form.
|
||||
if (!$this->running_javascript()) {
|
||||
|
@ -32,4 +32,4 @@ Feature: Add and configure blocks throughout the site
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
# The first block matching the pattern should be top-left block
|
||||
And I should see "Comments" in the "//*[@id='region-pre']/descendant::div[contains(concat(' ', @class, ' '), ' block ')]" "xpath_element"
|
||||
And I should see "Comments" in the "//*[@id='region-pre']/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]" "xpath_element"
|
||||
|
@ -54,7 +54,7 @@ class behat_cohort extends behat_base {
|
||||
$userid = $DB->get_field('user', 'id', array('username' => $username));
|
||||
|
||||
$steps = array(
|
||||
new Given('I click on "' . get_string('assign', 'cohort') . '" "link" in the "//table[@id=\'cohorts\']//tr[contains(., \'' . $cohortidnumber . '\')]" "xpath_element"'),
|
||||
new Given('I click on "' . get_string('assign', 'cohort') . '" "link" in the "' . $this->escape($cohortidnumber) . '" table row'),
|
||||
new Given('I select "' . $userid . '" from "' . get_string('potusers', 'cohort') . '"'),
|
||||
new Given('I press "' . get_string('add') . '"'),
|
||||
new Given('I press "' . get_string('backtocohorts', 'cohort') . '"')
|
||||
|
@ -32,11 +32,11 @@ Feature: Upload users to a cohort
|
||||
And I press "Upload users"
|
||||
And I press "Continue"
|
||||
And I follow "Cohorts"
|
||||
And I click on "Assign" "link" in the "//table[@id='cohorts']//tr[contains(., 'Cohort 1')]" "xpath_element"
|
||||
And I click on "Assign" "link" in the "Cohort 1" table row
|
||||
Then the "Current users" select box should contain "Tom Jones (tomjones@example.com)"
|
||||
And the "Current users" select box should contain "Bob Jones (bobjones@example.com)"
|
||||
And I press "Back to cohorts"
|
||||
And I click on "Assign" "link" in the "//table[@id='cohorts']//tr[contains(., 'Cohort 2')]" "xpath_element"
|
||||
And I click on "Assign" "link" in the "Cohort 2" table row
|
||||
And the "Current users" select box should contain "Mary Smith (marysmith@example.com)"
|
||||
And the "Current users" select box should contain "Alice Smith (alicesmith@example.com)"
|
||||
And I am on homepage
|
||||
|
@ -50,12 +50,13 @@ class behat_completion extends behat_base {
|
||||
public function user_has_completed_activity($userfullname, $activityname) {
|
||||
|
||||
// Will throw an exception if the element can not be hovered.
|
||||
$titleliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($userfullname . ", " . $activityname . ": Completed");
|
||||
$xpath = "//table[@id='completion-progress']" .
|
||||
"/descendant::img[contains(@title, '" . $userfullname . ", " . $activityname . ": Completed')]";
|
||||
"/descendant::img[contains(@title, $titleliteral)]";
|
||||
|
||||
return array(
|
||||
new Given('I go to the current course activity completion report'),
|
||||
new Given('I hover "' . $xpath . '" "xpath_element"')
|
||||
new Given('I hover "' . $this->escape($xpath) . '" "xpath_element"')
|
||||
);
|
||||
}
|
||||
|
||||
@ -68,11 +69,13 @@ class behat_completion extends behat_base {
|
||||
*/
|
||||
public function user_has_not_completed_activity($userfullname, $activityname) {
|
||||
|
||||
// Will throw an exception if the element can not be hovered.
|
||||
$titleliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($userfullname . ", " . $activityname . ": Not completed");
|
||||
$xpath = "//table[@id='completion-progress']" .
|
||||
"/descendant::img[contains(@title, '" . $userfullname . ", " . $activityname . ": Not completed')]";
|
||||
"/descendant::img[contains(@title, $titleliteral)]";
|
||||
return array(
|
||||
new Given('I go to the current course activity completion report'),
|
||||
new Given('I hover "' . $xpath . '" "xpath_element"')
|
||||
new Given('I hover "' . $this->escape($xpath) . '" "xpath_element"')
|
||||
);
|
||||
|
||||
return $steps;
|
||||
@ -89,9 +92,9 @@ class behat_completion extends behat_base {
|
||||
|
||||
// Expand reports node if we can't see the link.
|
||||
try {
|
||||
$this->find('xpath', "//*[@id='settingsnav']" .
|
||||
$this->find('xpath', "//div[@id='settingsnav']" .
|
||||
"/descendant::li" .
|
||||
"/descendant::li[not(contains(@class,'collapsed'))]" .
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/descendant::p[contains(., '" . get_string('pluginname', 'report_progress') . "')]");
|
||||
} catch (ElementNotFoundException $e) {
|
||||
$steps[] = new Given('I expand "' . get_string('reports') . '" node');
|
||||
|
@ -27,21 +27,21 @@ Feature: Toggle activities groups mode from the course page
|
||||
| Force group mode | No |
|
||||
When I press "Save changes"
|
||||
Then "No groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
And I click on "No groups (Click to change)" "link" in the "Test forum name" activity
|
||||
And I wait "3" seconds
|
||||
And "Separate groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And I reload the page
|
||||
And "Separate groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And I click on "Separate groups (Click to change)" "link" in the "Test forum name" activity
|
||||
And I wait "3" seconds
|
||||
And "Visible groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And I reload the page
|
||||
And "Visible groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And I click on "Visible groups (Click to change)" "link" in the "Test forum name" activity
|
||||
And "No groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
|
@ -26,7 +26,7 @@ Feature: Indent items on the course page
|
||||
When I indent right "Test glossary name" activity
|
||||
Then "#section-1 li.glossary div.mod-indent-1" "css_element" should exists
|
||||
And I indent right "Test glossary name" activity
|
||||
And "//*[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should exists
|
||||
And "//li[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should exists
|
||||
And "#section-1 li.glossary div.mod-indent-2" "css_element" should exists
|
||||
And I reload the page
|
||||
And "#section-1 li.glossary div.mod-indent-2" "css_element" should exists
|
||||
@ -34,4 +34,4 @@ Feature: Indent items on the course page
|
||||
And I indent left "Test glossary name" activity
|
||||
And "#section-1 li.glossary div.mod-indent-2" "css_element" should not exists
|
||||
And "#section-1 li.glossary div.mod-indent-1" "css_element" should not exists
|
||||
And "//*[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should not exists
|
||||
And "//li[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should not exists
|
||||
|
@ -100,7 +100,7 @@ class behat_course extends behat_base {
|
||||
public function i_add_to_section_and_i_fill_the_form_with($activity, $section, TableNode $data) {
|
||||
|
||||
return array(
|
||||
new Given('I add a "'.$activity.'" to section "'.$section.'"'),
|
||||
new Given('I add a "' . $this->escape($activity) . '" to section "' . $this->escape($section) . '"'),
|
||||
new Given('I fill the moodle form with:', $data),
|
||||
new Given('I press "' . get_string('savechangesandreturntocourse') . '"')
|
||||
);
|
||||
@ -116,7 +116,9 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
public function i_add_to_section($activity, $section) {
|
||||
|
||||
$sectionxpath = "//*[@id='section-" . $section . "']";
|
||||
$sectionxpath = "//li[@id='section-" . $section . "']";
|
||||
|
||||
$activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral(ucfirst($activity));
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
|
||||
@ -126,9 +128,9 @@ class behat_course extends behat_base {
|
||||
$sectionnode->click();
|
||||
|
||||
// Clicks the selected activity if it exists.
|
||||
$activity = ucfirst($activity);
|
||||
$activityxpath = "//div[@id='chooseform']/descendant::label" .
|
||||
"/descendant::span[contains(concat(' ', @class, ' '), ' typename ')][contains(.,'" . $activity . "')]" .
|
||||
"/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" .
|
||||
"[contains(., $activityliteral)]" .
|
||||
"/parent::label/child::input";
|
||||
$activitynode = $this->find('xpath', $activityxpath);
|
||||
$activitynode->doubleClick();
|
||||
@ -137,8 +139,8 @@ class behat_course extends behat_base {
|
||||
// Without Javascript.
|
||||
|
||||
// Selecting the option from the select box which contains the option.
|
||||
$selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', @class, ' '), ' section_add_menus ')]" .
|
||||
"/descendant::select[contains(., '" . $activity . "')]";
|
||||
$selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" .
|
||||
"/descendant::select[contains(., $activityliteral)]";
|
||||
$selectnode = $this->find('xpath', $selectxpath);
|
||||
$selectnode->selectOption($activity);
|
||||
|
||||
@ -162,7 +164,7 @@ class behat_course extends behat_base {
|
||||
$xpath = $this->section_exists($sectionnumber);
|
||||
|
||||
return array(
|
||||
new Given('I click on "' . get_string('markthistopic') . '" "link" in the "' . $xpath . '" "xpath_element"'),
|
||||
new Given('I click on "' . get_string('markthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
|
||||
new Given('I wait "2" seconds')
|
||||
);
|
||||
}
|
||||
@ -179,7 +181,7 @@ class behat_course extends behat_base {
|
||||
$xpath = $this->section_exists($sectionnumber);
|
||||
|
||||
return array(
|
||||
new Given('I click on "' . get_string('markedthistopic') . '" "link" in the "' . $xpath . '" "xpath_element"'),
|
||||
new Given('I click on "' . get_string('markedthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
|
||||
new Given('I wait "2" seconds')
|
||||
);
|
||||
}
|
||||
@ -268,7 +270,7 @@ class behat_course extends behat_base {
|
||||
|
||||
// Section should be hidden.
|
||||
$exception = new ExpectationException('The section is not hidden', $this->getSession());
|
||||
$this->find('xpath', $sectionxpath . "[contains(concat(' ', @class, ' '), ' hidden ')]", $exception);
|
||||
$this->find('xpath', $sectionxpath . "[contains(concat(' ', normalize-space(@class), ' '), ' hidden ')]", $exception);
|
||||
|
||||
// The checking are different depending on user permissions.
|
||||
if ($this->is_course_editor()) {
|
||||
@ -284,8 +286,8 @@ class behat_course extends behat_base {
|
||||
foreach ($activities as $activity) {
|
||||
|
||||
// Dimmed.
|
||||
$this->find('xpath', "//div[contains(concat(' ', @class, ' '), ' activityinstance ')]" .
|
||||
"/a[contains(concat(' ', @class, ' '), ' dimmed ')]", $dimmedexception, $activity);
|
||||
$this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' activityinstance ')]" .
|
||||
"/a[contains(concat(' ', normalize-space(@class), ' '), ' dimmed ')]", $dimmedexception, $activity);
|
||||
|
||||
// Non-JS browsers can not click on img elements.
|
||||
if ($this->running_javascript()) {
|
||||
@ -319,7 +321,8 @@ class behat_course extends behat_base {
|
||||
$sectionxpath = $this->section_exists($sectionnumber);
|
||||
|
||||
// Section should not be hidden.
|
||||
if (!$this->getSession()->getPage()->find('xpath', $sectionxpath . "[not(contains(concat(' ', @class, ' '), ' hidden '))]")) {
|
||||
$xpath = $sectionxpath . "[not(contains(concat(' ', normalize-space(@class), ' '), ' hidden '))]";
|
||||
if (!$this->getSession()->getPage()->find('xpath', $xpath)) {
|
||||
throw new ExpectationException('The section is hidden', $this->getSession());
|
||||
}
|
||||
|
||||
@ -449,10 +452,11 @@ class behat_course extends behat_base {
|
||||
// JS enabled.
|
||||
if ($this->running_javascript()) {
|
||||
|
||||
$destinationxpath = $sectionxpath . "/descendant::ul[contains(@class, 'yui3-dd-drop')]";
|
||||
$destinationxpath = $sectionxpath . "/descendant::ul[contains(concat(' ', normalize-space(@class), ' '), ' yui3-dd-drop ')]";
|
||||
|
||||
return array(
|
||||
new Given('I drag "' . $activitynode->getXpath() . '" "xpath_element" and I drop it in "' . $destinationxpath . '" "xpath_element"'),
|
||||
new Given('I drag "' . $this->escape($activitynode->getXpath()) . '" "xpath_element" ' .
|
||||
'and I drop it in "' . $this->escape($destinationxpath) . '" "xpath_element"'),
|
||||
);
|
||||
|
||||
} else {
|
||||
@ -460,8 +464,8 @@ class behat_course extends behat_base {
|
||||
|
||||
// Moving to the fist spot of the section (before all other section's activities).
|
||||
return array(
|
||||
new Given('I click on "a.editing_move" "css_element" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "li.movehere a" "css_element" in the "' . $sectionxpath . '" "xpath_element"'),
|
||||
new Given('I click on "a.editing_move" "css_element" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I click on "li.movehere a" "css_element" in the "' . $this->escape($sectionxpath) . '" "xpath_element"'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -482,8 +486,8 @@ class behat_course extends behat_base {
|
||||
|
||||
// Adding chr(10) to save changes.
|
||||
return array(
|
||||
new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $activityname .'" activity'),
|
||||
new Given('I fill in "title" with "' . $newactivityname . chr(10) . '"'),
|
||||
new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $this->escape($activityname) .'" activity'),
|
||||
new Given('I fill in "title" with "' . $this->escape($newactivityname) . chr(10) . '"'),
|
||||
new Given('I wait "2" seconds')
|
||||
);
|
||||
}
|
||||
@ -497,7 +501,7 @@ class behat_course extends behat_base {
|
||||
public function i_indent_right_activity($activityname) {
|
||||
|
||||
$steps = array(
|
||||
new Given('I click on "' . get_string('moveright') . '" "link" in the "' . $activityname . '" activity')
|
||||
new Given('I click on "' . get_string('moveright') . '" "link" in the "' . $this->escape($activityname) . '" activity')
|
||||
);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
@ -516,7 +520,7 @@ class behat_course extends behat_base {
|
||||
public function i_indent_left_activity($activityname) {
|
||||
|
||||
$steps = array(
|
||||
new Given('I click on "' . get_string('moveleft') . '" "link" in the "' . $activityname . '" activity')
|
||||
new Given('I click on "' . get_string('moveleft') . '" "link" in the "' . $this->escape($activityname) . '" activity')
|
||||
);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
@ -553,7 +557,7 @@ class behat_course extends behat_base {
|
||||
|
||||
// With JS disabled.
|
||||
$steps = array(
|
||||
new Given('I click on "' . $deletestring . '" "link" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "' . $this->escape($deletestring) . '" "link" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I press "' . get_string('yes') . '"')
|
||||
);
|
||||
|
||||
@ -569,7 +573,7 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
public function i_duplicate_activity($activityname) {
|
||||
return array(
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I press "' . get_string('continue') .'"'),
|
||||
new Given('I press "' . get_string('duplicatecontcourse') .'"')
|
||||
);
|
||||
@ -584,7 +588,7 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
public function i_duplicate_activity_editing_the_new_copy_with($activityname, TableNode $data) {
|
||||
return array(
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I press "' . get_string('continue') .'"'),
|
||||
new Given('I press "' . get_string('duplicatecontedit') . '"'),
|
||||
new Given('I fill the moodle form with:', $data),
|
||||
@ -657,9 +661,9 @@ class behat_course extends behat_base {
|
||||
$courseformat = $this->get_course_format();
|
||||
|
||||
// Checking the show button alt text and show icon.
|
||||
$showtext = get_string('showfromothers', $courseformat);
|
||||
$linkxpath = $xpath . "/descendant::a[@title='". $showtext ."']";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt='". $showtext ."'][contains(@src, 'show')]";
|
||||
$showtext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('showfromothers', $courseformat));
|
||||
$linkxpath = $xpath . "/descendant::a[@title=$showtext]";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt=$showtext][contains(@src, 'show')]";
|
||||
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Show section icon ');
|
||||
$this->find('xpath', $imgxpath, $exception);
|
||||
@ -684,9 +688,9 @@ class behat_course extends behat_base {
|
||||
$courseformat = $this->get_course_format();
|
||||
|
||||
// Checking the hide button alt text and hide icon.
|
||||
$hidetext = get_string('hidefromothers', $courseformat);
|
||||
$linkxpath = $xpath . "/descendant::a[@title='" . $hidetext . "']";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt='" . $hidetext ."'][contains(@src, 'hide')]";
|
||||
$hidetext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('hidefromothers', $courseformat));
|
||||
$linkxpath = $xpath . "/descendant::a[@title=$hidetext]";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt=$hidetext][contains(@src, 'hide')]";
|
||||
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Hide section icon ');
|
||||
$this->find('xpath', $imgxpath, $exception);
|
||||
@ -730,7 +734,7 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
protected function get_section_activities($sectionxpath) {
|
||||
|
||||
$xpath = $sectionxpath . "/descendant::li[contains(concat(' ', @class, ' '), ' activity ')]";
|
||||
$xpath = $sectionxpath . "/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]";
|
||||
|
||||
// We spin here, as activities usually require a lot of time to load.
|
||||
try {
|
||||
@ -751,8 +755,8 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
protected function get_activity_node($activityname) {
|
||||
|
||||
$activityname = str_replace("'", "\'", $activityname);
|
||||
$xpath = "//li[contains(concat(' ', @class, ' '), ' activity ')][contains(., '" .$activityname. "')]";
|
||||
$activityname = $this->getSession()->getSelectorsHandler()->xpathLiteral($activityname);
|
||||
$xpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityname)]";
|
||||
|
||||
return $this->find('xpath', $xpath);
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ Feature: Force group mode in a course
|
||||
| Group mode | Separate groups |
|
||||
| Force group mode | Yes |
|
||||
When I press "Save changes"
|
||||
Then ".//a//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And ".//a//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
Then "//a/child::img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And "//a/child::img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
|
||||
@javascript
|
||||
Scenario: Forced group mode using visible groups
|
||||
@ -40,11 +40,11 @@ Feature: Force group mode in a course
|
||||
| Group mode | Visible groups |
|
||||
| Force group mode | Yes |
|
||||
And I press "Save changes"
|
||||
Then ".//a//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And ".//a//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
Then "//a/child::img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And "//a/child::img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
|
||||
@javascript
|
||||
Scenario: Forced group mode without groups
|
||||
@ -52,9 +52,9 @@ Feature: Force group mode in a course
|
||||
| Group mode | No groups |
|
||||
| Force group mode | Yes |
|
||||
And I press "Save changes"
|
||||
Then ".//a//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And ".//a//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
Then "//a/child::img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And "//a/child::img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
|
||||
|
@ -52,7 +52,7 @@ class behat_enrol extends behat_base {
|
||||
return array(
|
||||
new Given('I expand "' . get_string('users', 'admin') . '" node'),
|
||||
new Given('I follow "' . get_string('type_enrol_plural', 'plugin') . '"'),
|
||||
new Given('I select "' . $enrolmethod . '" from "' . get_string('addinstance', 'enrol') . '"'),
|
||||
new Given('I select "' . $this->escape($enrolmethod) . '" from "' . get_string('addinstance', 'enrol') . '"'),
|
||||
new Given('I fill the moodle form with:', $table),
|
||||
new Given('I press "' . get_string('addinstance', 'enrol') . '"')
|
||||
);
|
||||
|
@ -51,30 +51,33 @@ class behat_groups extends behat_base {
|
||||
global $DB;
|
||||
|
||||
$user = $DB->get_record('user', array('username' => $username));
|
||||
$userfullname = fullname($user);
|
||||
$userfullname = $this->getSession()->getSelectorsHandler()->xpathLiteral(fullname($user));
|
||||
|
||||
// Using a xpath liternal to avoid problems with quotes and double quotes.
|
||||
$groupname = $this->getSession()->getSelectorsHandler()->xpathLiteral($groupname);
|
||||
|
||||
// We don't know the option text as it contains the number of users in the group.
|
||||
$select = $this->find_field('groups');
|
||||
$xpath = "//select[@id='groups']/descendant::option[contains(., '" . $groupname . "')]";
|
||||
$xpath = "//select[@id='groups']/descendant::option[contains(., $groupname)]";
|
||||
$groupoption = $this->find('xpath', $xpath);
|
||||
$fulloption = $groupoption->getText();
|
||||
$select->selectOption($fulloption);
|
||||
|
||||
// Here we don't need to wait for the AJAX response.
|
||||
$this->find_button('Add/remove users')->click();
|
||||
$this->find_button(get_string('adduserstogroup', 'group'))->click();
|
||||
|
||||
// Wait for add/remove members page to be loaded.
|
||||
$this->getSession()->wait(self::TIMEOUT, '(document.readyState === "complete")');
|
||||
|
||||
// Getting the option and selecting it.
|
||||
$select = $this->find_field('addselect');
|
||||
$xpath = "//select[@id='addselect']/descendant::option[contains(., '" . $userfullname . "')]";
|
||||
$xpath = "//select[@id='addselect']/descendant::option[contains(., $userfullname)]";
|
||||
$memberoption = $this->find('xpath', $xpath);
|
||||
$fulloption = $memberoption->getText();
|
||||
$select->selectOption($fulloption);
|
||||
|
||||
// Click add button.
|
||||
$this->find_button('Add')->click();
|
||||
$this->find_button(get_string('add'))->click();
|
||||
|
||||
// Wait for the page to load.
|
||||
$this->getSession()->wait(self::TIMEOUT, '(document.readyState === "complete")');
|
||||
|
@ -64,9 +64,10 @@ class behat_files extends behat_base {
|
||||
$exception = new ExpectationException('"' . $filepickerelement . '" filepicker can not be found', $this->getSession());
|
||||
|
||||
// Gets the ffilemanager node specified by the locator which contains the filepicker container.
|
||||
$filepickerelement = $this->getSession()->getSelectorsHandler()->xpathLiteral($filepickerelement);
|
||||
$filepickercontainer = $this->find(
|
||||
'xpath',
|
||||
"//input[./@id = //label[contains(normalize-space(string(.)), '" . $filepickerelement . "')]/@for]" .
|
||||
"//input[./@id = //label[normalize-space(.)=$filepickerelement]/@for]" .
|
||||
"//ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ') or " .
|
||||
"contains(concat(' ', normalize-space(@class), ' '), ' ffilepicker ')]",
|
||||
$exception
|
||||
@ -118,6 +119,9 @@ class behat_files extends behat_base {
|
||||
|
||||
$exception = new ExpectationException($exceptionmsg, $this->getSession());
|
||||
|
||||
// Avoid quote-related problems.
|
||||
$name = $this->getSession()->getSelectorsHandler()->xpathLiteral($name);
|
||||
|
||||
// Get a filepicker element (folder or file).
|
||||
try {
|
||||
|
||||
@ -126,7 +130,8 @@ class behat_files extends behat_base {
|
||||
'xpath',
|
||||
"//div[@class='fp-content']" .
|
||||
"//descendant::*[self::div | self::a][contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')]" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' fp-folder ')][contains(normalize-space(string(.)), '" . $name . "')]" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' fp-folder ')]" .
|
||||
"[normalize-space(.)=$name]" .
|
||||
"//descendant::a[contains(concat(' ', normalize-space(@class), ' '), ' fp-contextmenu ')]",
|
||||
$exception,
|
||||
$containernode
|
||||
@ -139,7 +144,7 @@ class behat_files extends behat_base {
|
||||
'xpath',
|
||||
"//div[@class='fp-content']" .
|
||||
"//descendant::*[self::div | self::a][contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')]" .
|
||||
"[contains(normalize-space(string(.)), '" . $name . "')]" .
|
||||
"[normalize-space(.)=$name]" .
|
||||
"//descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-thumbnail ')]",
|
||||
false,
|
||||
$containernode
|
||||
@ -176,12 +181,15 @@ class behat_files extends behat_base {
|
||||
// Getting the repository link and opening it.
|
||||
$repoexception = new ExpectationException('The "' . $repositoryname . '" repository has not been found', $this->getSession());
|
||||
|
||||
// Avoid problems with both double and single quotes in the same string.
|
||||
$repositoryname = $this->getSession()->getSelectorsHandler()->xpathLiteral($repositoryname);
|
||||
|
||||
// Here we don't need to look inside the selected filepicker because there can only be one modal window.
|
||||
$repositorylink = $this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-area ')]" .
|
||||
"//descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-name ')]" .
|
||||
"[contains(normalize-space(string(.)), '" . $repositoryname . "')]",
|
||||
"[normalize-space(.)=$repositoryname]",
|
||||
$repoexception
|
||||
);
|
||||
|
||||
@ -226,10 +234,10 @@ class behat_files extends behat_base {
|
||||
// only used when accessing the filepicker, there is no filemanager-loading after selecting the file.
|
||||
$this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', @class, ' '), ' filemanager ')]" .
|
||||
"[not(contains(concat(' ', @class, ' '), ' fm-updating '))]" .
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' filemanager ')]" .
|
||||
"[not(contains(concat(' ', normalize-space(@class), ' '), ' fm-updating '))]" .
|
||||
"|" .
|
||||
"//div[contains(concat(' ', @class, ' '), ' filemanager-loading ')]" .
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' filemanager-loading ')]" .
|
||||
"[contains(@style, 'display: none;')]",
|
||||
$exception,
|
||||
$filepickernode
|
||||
|
@ -58,10 +58,13 @@ class behat_form_select extends behat_form_field {
|
||||
|
||||
// Single select needs an extra click in the option.
|
||||
if (!$this->field->hasAttribute('multiple')) {
|
||||
|
||||
$value = $this->session->getSelectorsHandler()->xpathLiteral($value);
|
||||
|
||||
// Using the driver direcly because Element methods are messy when dealing
|
||||
// with elements inside containers.
|
||||
$optionxpath = $this->field->getXpath() .
|
||||
"/descendant::option[(./@value = '" . $value . "' or contains(normalize-space(string(.)), '" . $value . "'))]";
|
||||
"/descendant::option[(./@value=$value or normalize-space(.)=$value)]";
|
||||
$optionnodes = $this->session->getDriver()->find($optionxpath);
|
||||
if ($optionnodes) {
|
||||
current($optionnodes)->click();
|
||||
|
@ -132,8 +132,8 @@ class behat_forms extends behat_base {
|
||||
|
||||
// Show all fields.
|
||||
$showmorestr = get_string('showmore', 'form');
|
||||
$showmores = $this->find_all('xpath', "//a[contains(concat(' ', normalize-space(.), ' '), '" . $showmorestr . "')]" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]");
|
||||
$showmores = $this->find_all('xpath', "//a[normalize-space(.)='" . $showmorestr . "']" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler ')]");
|
||||
|
||||
// We are supposed to have 'show more's here, otherwise exception.
|
||||
|
||||
@ -186,9 +186,12 @@ class behat_forms extends behat_base {
|
||||
return;
|
||||
}
|
||||
|
||||
// Single select needs an extra click in the option.
|
||||
if (!$selectnode->hasAttribute('multiple')) {
|
||||
// Single select needs an extra click in the option.
|
||||
$xpath = ".//option[(./@value = '" . $option . "' or contains(normalize-space(string(.)), '" . $option . "'))]";
|
||||
|
||||
// Avoid quotes problems.
|
||||
$option = $this->getSession()->getSelectorsHandler()->xpathLiteral($option);
|
||||
$xpath = "//option[(./@value=$option or normalize-space(.)=$option)]";
|
||||
$optionnode = $this->find('xpath', $xpath, false, $selectnode);
|
||||
$optionnode->click();
|
||||
} else {
|
||||
|
@ -242,8 +242,8 @@ class behat_general extends behat_base {
|
||||
|
||||
// The table row container.
|
||||
$nocontainerexception = new ElementNotFoundException($this->getSession(), '"' . $tablerowtext . '" row text ');
|
||||
$tablerowtext = str_replace("'", "\'", $tablerowtext);
|
||||
$rownode = $this->find('xpath', "//tr[contains(., '" . $tablerowtext . "')]", $nocontainerexception);
|
||||
$tablerowtext = $this->getSession()->getSelectorsHandler()->xpathLiteral($tablerowtext);
|
||||
$rownode = $this->find('xpath', "//tr[contains(., $tablerowtext)]", $nocontainerexception);
|
||||
|
||||
// Looking for the element DOM node inside the specified row.
|
||||
list($selector, $locator) = $this->transform_selector($selectortype, $element);
|
||||
@ -285,7 +285,7 @@ class behat_general extends behat_base {
|
||||
public function assert_page_contains_text($text) {
|
||||
|
||||
$xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text);
|
||||
$xpath = "/descendant::*[contains(., " . $xpathliteral. ")]";
|
||||
$xpath = "/descendant::*[contains(., $xpathliteral)]";
|
||||
|
||||
// Wait until it finds the text, otherwise custom exception.
|
||||
try {
|
||||
@ -305,7 +305,7 @@ class behat_general extends behat_base {
|
||||
public function assert_page_not_contains_text($text) {
|
||||
|
||||
$xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text);
|
||||
$xpath = "/descendant::*[not(contains(., " . $xpathliteral. "))]";
|
||||
$xpath = "/descendant::*[not(contains(., $xpathliteral))]";
|
||||
|
||||
// Wait until it finds the text, otherwise custom exception.
|
||||
try {
|
||||
|
@ -56,16 +56,19 @@ class behat_navigation extends behat_base {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid problems with quotes.
|
||||
$nodetextliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($nodetext);
|
||||
|
||||
$xpath = "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/child::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed ')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]" .
|
||||
"|" .
|
||||
"//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed'))]" .
|
||||
"/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]";
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed ')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]";
|
||||
|
||||
$exception = new ExpectationException('The "' . $nodetext . '" node can not be expanded', $this->getSession());
|
||||
$node = $this->find('xpath', $xpath, $exception);
|
||||
@ -86,15 +89,18 @@ class behat_navigation extends behat_base {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid problems with quotes.
|
||||
$nodetextliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($nodetext);
|
||||
|
||||
$xpath = "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/child::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]" .
|
||||
"|" .
|
||||
"//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed'))]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]";
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]";
|
||||
|
||||
$exception = new ExpectationException('The "' . $nodetext . '" node can not be collapsed', $this->getSession());
|
||||
$node = $this->find('xpath', $xpath, $exception);
|
||||
|
@ -73,7 +73,7 @@ class behat_permissions extends behat_base {
|
||||
public function i_override_the_system_permissions_of_role_with($rolename, $table) {
|
||||
|
||||
// We don't know the number of overrides so we have to get it to match the option contents.
|
||||
$roleoption = $this->find('xpath', '//select[@name="roleid"]/option[contains(text(),"' . $this->escape($rolename) . '")]');
|
||||
$roleoption = $this->find('xpath', '//select[@name="roleid"]/option[contains(.,"' . $this->escape($rolename) . '")]');
|
||||
|
||||
return array(
|
||||
new Given('I select "' . $this->escape($roleoption->getText()) . '" from "' . get_string('advancedoverride', 'role') . '"'),
|
||||
|
@ -67,10 +67,10 @@ class behat_message extends behat_base {
|
||||
}
|
||||
|
||||
$steps[] = new Given('I follow "' . get_string('messages', 'message') . '"');
|
||||
$steps[] = new Given('I fill in "' . get_string('searchcombined', 'message') . '" with "' . $tofullname . '"');
|
||||
$steps[] = new Given('I fill in "' . get_string('searchcombined', 'message') . '" with "' . $this->escape($tofullname) . '"');
|
||||
$steps[] = new Given('I press "' . get_string('searchcombined', 'message') . '"');
|
||||
$steps[] = new Given('I follow "' . get_string('sendmessageto', 'message', $tofullname) . '"');
|
||||
$steps[] = new Given('I fill in "id_message" with "' . $messagecontent . '"');
|
||||
$steps[] = new Given('I follow "' . $this->escape(get_string('sendmessageto', 'message', $tofullname)) . '"');
|
||||
$steps[] = new Given('I fill in "id_message" with "' . $this->escape($messagecontent) . '"');
|
||||
$steps[] = new Given('I press "' . get_string('sendmessage', 'message') . '"');
|
||||
|
||||
return $steps;
|
||||
|
@ -38,7 +38,7 @@ Feature: Set a certain number of discussions as a completion condition for a for
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then I hover "//li[contains(concat(' ', @class, ' '), ' modtype_forum ')]/descendant::img[@alt='Not completed: Test forum name']" "xpath_element"
|
||||
Then I hover "//li[contains(concat(' ', normalize-space(@class), ' '), ' modtype_forum ')]/descendant::img[@alt='Not completed: Test forum name']" "xpath_element"
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Post 1 subject |
|
||||
| Message | Body 1 content |
|
||||
@ -46,7 +46,7 @@ Feature: Set a certain number of discussions as a completion condition for a for
|
||||
| Subject | Post 2 subject |
|
||||
| Message | Body 2 content |
|
||||
And I follow "Course 1"
|
||||
And I hover "//li[contains(concat(' ', @class, ' '), ' modtype_forum ')]/descendant::img[contains(@alt, 'Completed: Test forum name')]" "xpath_element"
|
||||
And I hover "//li[contains(concat(' ', normalize-space(@class), ' '), ' modtype_forum ')]/descendant::img[contains(@alt, 'Completed: Test forum name')]" "xpath_element"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
|
@ -66,7 +66,7 @@ class behat_mod_glossary extends behat_base {
|
||||
new Given('I follow "' . get_string('categoryview', 'mod_glossary') . '"'),
|
||||
new Given('I press "' . get_string('editcategories', 'mod_glossary') . '"'),
|
||||
new Given('I press "' . get_string('add').' '.get_string('category', 'glossary') . '"'),
|
||||
new Given('I fill in "name" with "' . $categoryname . '"'),
|
||||
new Given('I fill in "name" with "' . $this->escape($categoryname) . '"'),
|
||||
new Given('I press "' . get_string('savechanges') . '"'),
|
||||
new Given('I press "' . get_string('back', 'mod_glossary') . '"')
|
||||
);
|
||||
|
@ -34,7 +34,7 @@ Feature: A teacher can choose whether to provide a printer-friendly glossary ent
|
||||
| Concept | Just a test concept |
|
||||
| Definition | Concept definition |
|
||||
Then "Printer-friendly version" "link" should exists
|
||||
And "//*[contains(concat(' ', @class, ' '), ' printicon ')][contains(@href, 'print.php')]" "xpath_element" should exists
|
||||
And "//*[contains(concat(' ', normalize-space(@class), ' '), ' printicon ')][contains(@href, 'print.php')]" "xpath_element" should exists
|
||||
And I follow "Printer-friendly version"
|
||||
And I should see "Just a test concept"
|
||||
|
||||
@ -51,4 +51,4 @@ Feature: A teacher can choose whether to provide a printer-friendly glossary ent
|
||||
| Concept | Just a test concept |
|
||||
| Definition | Concept definition |
|
||||
Then "Printer-friendly version" "link" should not exists
|
||||
And "//*[contains(concat(' ', @class, ' '), ' printicon ')][contains(@href, 'print.php')]" "xpath_element" should not exists
|
||||
And "//*[contains(concat(' ', normalize-space(@class), ' '), ' printicon ')][contains(@href, 'print.php')]" "xpath_element" should not exists
|
||||
|
@ -40,7 +40,7 @@ Feature: In a lesson activity, students can navigate through a series of pages i
|
||||
| id_jumpto_1 | Next page |
|
||||
And I press "Save page"
|
||||
And I follow "Expanded"
|
||||
And I click on "Add a question page here" "link" in the "//div[contains(concat(' ', @class, ' '), ' addlinks ')][3]" "xpath_element"
|
||||
And I click on "Add a question page here" "link" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' addlinks ')][3]" "xpath_element"
|
||||
And I select "Numerical" from "Select a question type"
|
||||
And I press "Add a question page"
|
||||
And I fill the moodle form with:
|
||||
|
@ -51,13 +51,15 @@ class behat_question extends behat_base {
|
||||
*/
|
||||
public function i_add_a_question_filling_the_form_with($questiontypename, TableNode $questiondata) {
|
||||
|
||||
$questiontypexpath = "//span[@class='qtypename'][.='" . $questiontypename . "']" .
|
||||
// Using xpath literal to avoid quotes problems.
|
||||
$questiontypename = $this->getSession()->getSelectorsHandler()->xpathLiteral($questiontypename);
|
||||
$questiontypexpath = "//span[@class='qtypename'][normalize-space(.)=$questiontypename]" .
|
||||
"/ancestor::div[@class='qtypeoption']/descendant::input";
|
||||
|
||||
return array(
|
||||
new Given('I follow "' . get_string('questionbank', 'question') . '"'),
|
||||
new Given('I press "' . get_string('createnewquestion', 'question') . '"'),
|
||||
new Given('I click on "' . $questiontypexpath . '" "xpath_element"'),
|
||||
new Given('I click on "' . $this->escape($questiontypexpath) . '" "xpath_element"'),
|
||||
new Given('I click on "Next" "button" in the "#qtypechoicecontainer" "css_element"'),
|
||||
new Given('I fill the moodle form with:', $questiondata),
|
||||
new Given('I press "' . get_string('savechanges') . '"')
|
||||
@ -75,14 +77,18 @@ class behat_question extends behat_base {
|
||||
*/
|
||||
public function the_state_of_question_is_shown_as($questiondescription, $state) {
|
||||
|
||||
// Using xpath literal to avoid quotes problems.
|
||||
$questiondescriptionliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($questiondescription);
|
||||
$stateliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($state);
|
||||
|
||||
// Split in two checkings to give more feedback in case of exception.
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Question "' . $questiondescription . '" ');
|
||||
$questionxpath = "//div[contains(concat(' ', @class, ' '), ' qtext ')][contains(., '" . $questiondescription . "')]";
|
||||
$questionxpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' qtext ')][contains(., $questiondescriptionliteral)]";
|
||||
$this->find('xpath', $questionxpath, $exception);
|
||||
|
||||
$exception = new ExpectationException('Question "' . $questiondescription . '" state is not "' . $state . '"', $this->getSession());
|
||||
$xpath = $questionxpath . "/ancestor::div[contains(concat(' ', @class, ' '), ' que ')]" .
|
||||
"/descendant::div[@class='state'][contains(., '" . $state . "')]";
|
||||
$xpath = $questionxpath . "/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' que ')]" .
|
||||
"/descendant::div[@class='state'][contains(., $stateliteral)]";
|
||||
$this->find('xpath', $xpath, $exception);
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,8 @@ class behat_filepicker extends behat_files {
|
||||
// Just in case there is any contents refresh in progress.
|
||||
$this->wait_until_contents_are_updated($fieldnode);
|
||||
|
||||
$folderliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($foldername);
|
||||
|
||||
// We look both in the pathbar and in the contents.
|
||||
try {
|
||||
|
||||
@ -99,8 +101,8 @@ class behat_filepicker extends behat_files {
|
||||
$folder = $this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-folder ')]" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' fp-filename ')]" .
|
||||
"[normalize-space(.)='" . $foldername . "']",
|
||||
"/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-filename ')]" .
|
||||
"[normalize-space(.)=$folderliteral]",
|
||||
$exception,
|
||||
$fieldnode
|
||||
);
|
||||
@ -110,7 +112,7 @@ class behat_filepicker extends behat_files {
|
||||
$folder = $this->find(
|
||||
'xpath',
|
||||
"//a[contains(concat(' ', normalize-space(@class), ' '), ' fp-path-folder-name ')]" .
|
||||
"[normalize-space(.)='" . $foldername . "']",
|
||||
"[normalize-space(.)=$folderliteral]",
|
||||
$exception,
|
||||
$fieldnode
|
||||
);
|
||||
|
@ -24,7 +24,7 @@ Feature: A selected file can be cancelled
|
||||
And I upload "lib/tests/fixtures/upload_users.csv" file to "Files" filepicker
|
||||
And I click on "#fitem_id_files .fp-btn-add a" "css_element"
|
||||
And I click on "Recent files" "link" in the ".fp-repo-area" "css_element"
|
||||
And I click on "//a[contains(concat(' ', @class, ' '), ' fp-file ')][contains(., 'empty.txt')]" "xpath_element"
|
||||
And I click on "//a[contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')][normalize-space(.)='empty.txt']" "xpath_element"
|
||||
And I click on ".yui3-panel-focused .fp-select .fp-select-cancel" "css_element"
|
||||
And I click on ".yui3-panel-focused .file-picker button.yui3-button-close" "css_element"
|
||||
And I press "Save and display"
|
||||
|
@ -65,10 +65,10 @@ class behat_repository_upload extends behat_files {
|
||||
$noformexception = new ExpectationException('The upload file form is not ready', $this->getSession());
|
||||
$this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', @class, ' '), ' file-picker ')]" .
|
||||
"[contains(concat(' ', @class, ' '), ' repository_upload ')]" .
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' file-picker ')]" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' repository_upload ')]" .
|
||||
"/descendant::div[@class='fp-content']" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' fp-upload-form ')]" .
|
||||
"/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-upload-form ')]" .
|
||||
"/descendant::form",
|
||||
$noformexception
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user