Commit 38976081 authored by David Monllaó's avatar David Monllaó Committed by David Monllao
Browse files

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
parent dedb9738
......@@ -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