/** * Manually adds a reviewer for workshop participant. * * This step should start on manual allocation page. * * @When /^I add a reviewer "(?P<reviewer_name_string>(?:[^"]|\\")*)" for workshop participant "(?P<participant_name_string>(?:[^"]|\\")*)"$/ * @param string $reviewername * @param string $participantname */ public function i_add_a_reviewer_for_workshop_participant($reviewername, $participantname) { $participantnameliteral = behat_context_helper::escape($participantname); $xpathtd = "//table[contains(concat(' ', normalize-space(@class), ' '), ' allocations ')]/" . "tbody/tr[./td[contains(concat(' ', normalize-space(@class), ' '), ' peer ')]" . "[contains(.,{$participantnameliteral})]]/" . "td[contains(concat(' ', normalize-space(@class), ' '), ' reviewedby ')]"; $xpathselect = $xpathtd . "/descendant::select"; try { $selectnode = $this->find('xpath', $xpathselect); } catch (Exception $ex) { $this->find_button(get_string('showallparticipants', 'workshopallocation_manual'))->press(); $selectnode = $this->find('xpath', $xpathselect); } $selectformfield = behat_field_manager::get_form_field($selectnode, $this->getSession()); $selectformfield->set_value($reviewername); if (!$this->running_javascript()) { // Without Javascript we need to press the "Go" button. $go = behat_context_helper::escape(get_string('go')); $this->find('xpath', $xpathtd . "/descendant::input[@value={$go}]")->click(); } else { // With Javascript we just wait for the page to reload. $this->getSession()->wait(self::EXTENDED_TIMEOUT, self::PAGE_READY_JS); } // Check the success string to appear. $allocatedtext = behat_context_helper::escape(get_string('allocationadded', 'workshopallocation_manual')); $this->find('xpath', "//*[contains(.,{$allocatedtext})]"); }
/** * Given a field locator, appends a value to it. * * @Given /^I append to "([^"]*)" "([^"]*)"$/ */ public function i_append_to($fieldlocator, $value) { $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this); $configuration = $field->get_value(); $configuration .= "\n" . $value; $field->set_value($configuration); }
/** * Select the text in an Atto field. * * @Given /^I select the text in the "([^"]*)" Atto editor$/ * @throws ElementNotFoundException Thrown by behat_base::find * @param string $field * @return void */ public function select_the_text_in_the_atto_editor($fieldlocator) { if (!$this->running_javascript()) { throw new coding_exception('Selecting text requires javascript.'); } // We delegate to behat_form_field class, it will // guess the type properly. $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this); if (!method_exists($field, 'select_text')) { throw new coding_exception('Field does not support the select_text function.'); } $field->select_text(); }
public function i_set_the_following_administration_settings_values(TableNode $table) { if (!($data = $table->getRowsHash())) { return; } foreach ($data as $label => $value) { // We expect admin block to be visible, otherwise go to homepage. if (!$this->getSession()->getPage()->find('css', '.block_settings')) { $this->getSession()->visit($this->locate_path('/')); $this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); } // Search by label. $searchbox = $this->find_field(get_string('searchinsettings', 'admin')); $searchbox->setValue($label); $submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]'); $submitsearch->press(); $this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); // 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 = behat_context_helper::escape($label); // Single element settings. try { $fieldxpath = "//*[self::input | self::textarea | self::select]" . "[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" . "[@id=//label[contains(normalize-space(.), {$label})]/@for or " . "@id=//span[contains(normalize-space(.), {$label})]/preceding-sibling::label[1]/@for]"; $fieldnode = $this->find('xpath', $fieldxpath, $exception); $formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[contains(concat(' ', @class, ' '), ' form-setting ')]" . "/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div"); } catch (ElementNotFoundException $e) { // Multi element settings, interacting only the first one. $fieldxpath = "//*[label[contains(., {$label})]|span[contains(., {$label})]]" . "/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" . "/descendant::div[contains(concat(' ', @class, ' '), ' form-group ')]" . "/descendant::*[self::input | self::textarea | self::select]" . "[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]"; $fieldnode = $this->find('xpath', $fieldxpath); // It is the same one that contains the type. $formfieldtypenode = $fieldnode; } // Getting the class which contains the field type. $classes = explode(' ', $formfieldtypenode->getAttribute('class')); $type = false; foreach ($classes as $class) { if (substr($class, 0, 5) == 'form-') { $type = substr($class, 5); } } // Instantiating the appropiate field type. $field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession()); $field->set_value($value); $this->find_button(get_string('savechanges'))->press(); } }
protected function upload_file_to_filemanager($filepath, $filemanagerelement, TableNode $data, $overwriteaction = false) { global $CFG; $filemanagernode = $this->get_filepicker_node($filemanagerelement); // Opening the select repository window and selecting the upload repository. $this->open_add_file_window($filemanagernode, get_string('pluginname', 'repository_upload')); // Ensure all the form is ready. $noformexception = new ExpectationException('The upload file form is not ready', $this->getSession()); $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' file-picker ')]" . "[contains(concat(' ', normalize-space(@class), ' '), ' repository_upload ')]" . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content ')]" . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-upload-form ')]" . "/descendant::form", $noformexception); // After this we have the elements we want to interact with. // Form elements to interact with. $file = $this->find_file('repo_upload_file'); // Attaching specified file to the node. // Replace 'admin/' if it is in start of path with $CFG->admin . if (substr($filepath, 0, 6) === 'admin/') { $filepath = $CFG->dirroot . DIRECTORY_SEPARATOR . $CFG->admin . DIRECTORY_SEPARATOR . substr($filepath, 6); } $filepath = str_replace('/', DIRECTORY_SEPARATOR, $filepath); if (!is_readable($filepath)) { $filepath = $CFG->dirroot . DIRECTORY_SEPARATOR . $filepath; if (!is_readable($filepath)) { throw new ExpectationException('The file to be uploaded does not exist.', $this->getSession()); } } $file->attachFile($filepath); // Fill the form in Upload window. $datahash = $data->getRowsHash(); // The action depends on the field type. foreach ($datahash as $locator => $value) { $field = behat_field_manager::get_form_field_from_label($locator, $this); // Delegates to the field class. $field->set_value($value); } // Submit the file. $submit = $this->find_button(get_string('upload', 'repository')); $submit->press(); // We wait for all the JS to finish as it is performing an action. $this->getSession()->wait(self::TIMEOUT, self::PAGE_READY_JS); if ($overwriteaction !== false) { $overwritebutton = $this->find_button($overwriteaction); $this->ensure_node_is_visible($overwritebutton); $overwritebutton->click(); // We wait for all the JS to finish. $this->getSession()->wait(self::TIMEOUT, self::PAGE_READY_JS); } }
/** * Sets the specified site settings. A table with | Setting label | value | is expected. * * @Given /^I set the following administration settings values:$/ * @param TableNode $table */ public function i_set_the_following_administration_settings_values(TableNode $table) { if (!($data = $table->getRowsHash())) { return; } foreach ($data as $label => $value) { // We expect admin block to be visible, otherwise go to homepage. if (!$this->getSession()->getPage()->find('css', '.block_settings')) { $this->getSession()->visit($this->locate_path('/')); $this->wait(self::TIMEOUT, '(document.readyState === "complete")'); } // Search by label. $searchbox = $this->find_field('Search in settings'); $searchbox->setValue($label); $submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]'); $submitsearch->press(); $this->wait(self::TIMEOUT, '(document.readyState === "complete")'); // 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 '); $fieldxpath = "//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" . "[@id=//label[contains(normalize-space(string(.)), '" . $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"); // Getting the class which contains the field type. $classes = explode(' ', $formfieldtypenode->getAttribute('class')); foreach ($classes as $class) { if (substr($class, 0, 5) == 'form-') { $type = substr($class, 5); } } // Instantiating the appropiate field type. $field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession()); $field->set_value($value); $this->find_button('Save changes')->press(); } }
/** * Guesses the element type we are dealing with in case is not a text-based element. * * This class is the generic field type, behat_field_manager::get_form_field() * should be able to find the appropiate class for the field type, but * in cases like moodle form group elements we can not find the type of * the field through the DOM so we also need to take care of the * different field types from here. If we need to deal with more complex * moodle form elements we will need to refactor this simple HTML elements * guess method. * * @return behat_form_field */ private function guess_type() { global $CFG; // We default to the text-based field if nothing was detected. if (!($type = behat_field_manager::guess_field_type($this->field, $this->session))) { $type = 'text'; } $classname = 'behat_form_' . $type; $classpath = $CFG->dirroot . '/lib/behat/form_field/' . $classname . '.php'; require_once $classpath; return new $classname($this->session, $this->field); }
/** * Picks the file from private files repository * * @throws ExpectationException Thrown by behat_base::find * @param string $filepath * @param string $repository * @param string $filemanagerelement * @param TableNode $data Data to fill the form in Select file dialogue * @param false|string $overwriteaction false if we don't expect that file with the same name already exists, * or button text in overwrite dialogue ("Overwrite", "Rename to ...", "Cancel") */ protected function add_file_from_repository_to_filemanager($filepath, $repository, $filemanagerelement, TableNode $data, $overwriteaction = false) { $filemanagernode = $this->get_filepicker_node($filemanagerelement); // Opening the select repository window and selecting the upload repository. $this->open_add_file_window($filemanagernode, $repository); $this->open_element_contextual_menu($filepath); // Fill the form in Select window. $datahash = $data->getRowsHash(); // The action depends on the field type. foreach ($datahash as $locator => $value) { $field = behat_field_manager::get_form_field_from_label($locator, $this); // Delegates to the field class. $field->set_value($value); } $this->find_button(get_string('getfile', 'repository'))->click(); // We wait for all the JS to finish as it is performing an action. $this->getSession()->wait(self::TIMEOUT, self::PAGE_READY_JS); if ($overwriteaction !== false) { $overwritebutton = $this->find_button($overwriteaction); $this->ensure_node_is_visible($overwritebutton); $overwritebutton->click(); // We wait for all the JS to finish. $this->getSession()->wait(self::TIMEOUT, self::PAGE_READY_JS); } }
/** * Tries to fill the current page form elements with the provided options. * * This step is slow as it spins over each provided option, we are * not expected to have lots of provided options, anyways, is better * to be conservative and wait for the elements to appear rather than * to have false failures. * * @param TableNode $options The backup and restore options or false if no options provided * @return void */ protected function fill_backup_restore_form($options) { // Nothing to fill if no options are provided. if (!$options) { return; } // Wait for the page to be loaded and the JS ready. $this->wait(); // If we find any of the provided options in the current form we should set the value. $datahash = $options->getRowsHash(); foreach ($datahash as $locator => $value) { try { // Using $this->find* to enforce stability over speed. $fieldnode = $this->find_field($locator); $field = behat_field_manager::get_form_field($fieldnode, $this->getSession()); $field->set_value($value); } catch (ElementNotFoundException $e) { // Next provided option then, this one should be part of another page's fields. } } }
/** * Generic field setter. * * Internal API method, a generic *I set "VALUE" to "FIELD" field* * could be created based on it. * * @param string $fieldlocator The pointer to the field, it will depend on the field type. * @param string $value * @return void */ protected function set_field_value($fieldlocator, $value) { // We delegate to behat_form_field class, it will // guess the type properly as it is a select tag. $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this); $field->set_value($value); }
/** * Checks grade values with or without a edit box. * * @Then /^the grade for "([^"]*)" in grade item "([^"]*)" should match "([^"]*)"$/ * @throws Exception * @throws ElementNotFoundException * @param string $student * @param string $itemname * @param string $value * @return Then */ public function the_grade_should_match($student, $itemname, $value) { $xpath = $this->get_student_and_grade_value_selector($student, $itemname); $gradefield = $this->getSession()->getPage()->find('xpath', $xpath); if (!empty($gradefield)) { // Get the field. $fieldtype = behat_field_manager::guess_field_type($gradefield, $this->getSession()); if (!$fieldtype) { throw new Exception('Could not get field type for grade field "' . $itemname . '"'); } $field = behat_field_manager::get_field_instance($fieldtype, $gradefield, $this->getSession()); if (!$field->matches($value)) { $fieldvalue = $field->get_value(); throw new ExpectationException('The "' . $student . '" and "' . $itemname . '" grade is "' . $fieldvalue . '", "' . $value . '" expected', $this->getSession()); } } else { // If there isn't a form field, just search for contents. $valueliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($value); $xpath = $this->get_student_and_grade_cell_selector($student, $itemname); $xpath .= "[contains(normalize-space(.)," . $valueliteral . ")]"; $node = $this->getSession()->getDriver()->find($xpath); if (empty($node)) { $locatorexceptionmsg = 'Cell for "' . $student . '" and "' . $itemname . '" with value "' . $value . '"'; throw new ElementNotFoundException($this->getSession(), $locatorexceptionmsg, null, $xpath); } } }
/** * Fills the advanced permissions form with the provided data. Expects a table with capability name and permission (Inherit/Allow/Prevent/Prohibit) columns. * @Given /^I fill the capabilities form with the following permissions:$/ * @param TableNode $table * @return void */ public function i_fill_the_capabilities_form_with_the_following_permissions($table) { // Ensure we are using the advanced view. // Wrapped in a try/catch to capture the exception and continue execution, we don't know if advanced mode was already enabled. try { $advancedtoggle = $this->find_button(get_string('showadvanced', 'form')); if ($advancedtoggle) { $advancedtoggle->click(); // Wait for the page to load. $this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); } } catch (Exception $e) { // We already are in advanced mode. } // Using getRows() as we are not sure if tests writers will add the header. foreach ($table->getRows() as $key => $row) { if (count($row) !== 2) { throw new ExpectationException('You should specify a table with capability/permission columns', $this->getSession()); } list($capability, $permission) = $row; // Skip the headers row if it was provided if (strtolower($capability) == 'capability' || strtolower($capability) == 'capabilities') { continue; } // Checking the permission value. $permissionconstant = 'CAP_' . strtoupper($permission); if (!defined($permissionconstant)) { throw new ExpectationException('The provided permission value "' . $permission . '" is not valid. Use Inherit, Allow, Prevent or Prohibited', $this->getSession()); } // Converting from permission to constant value. $permissionvalue = constant($permissionconstant); // Here we wait for the element to appear and exception if it does not exist. $radio = $this->find('xpath', '//input[@name="' . $capability . '" and @value="' . $permissionvalue . '"]'); $field = behat_field_manager::get_field_instance('radio', $radio, $this->getSession()); $field->set_value(1); } }
/** * Tries to fill the current page form elements with the provided options. * * This step is slow as it spins over each provided option, we are * not expected to have lots of provided options, anyways, is better * to be conservative and wait for the elements to appear rather than * to have false failures. * * @param TableNode $options The backup and restore options or false if no options provided * @return void */ protected function fill_backup_restore_form($options) { // Nothing to fill if no options are provided. if (!$options) { return; } // If we find any of the provided options in the current form we should set the value. $datahash = $options->getRowsHash(); foreach ($datahash as $locator => $value) { $field = behat_field_manager::get_form_field_from_label($locator, $this); $field->set_value($value); } }
/** * Tries to fill the current page form elements with the provided options. * * This step is slow as it spins over each provided option, we are * not expected to have lots of provided options, anyways, is better * to be conservative and wait for the elements to appear rather than * to have false failures. * * @param TableNode $options The backup and restore options or false if no options provided * @return void */ protected function fill_backup_restore_form($options) { // Nothing to fill if no options are provided. if (!$options) { return; } // If we find any of the provided options in the current form we should set the value. $datahash = $options->getRowsHash(); foreach ($datahash as $locator => $value) { try { $field = behat_field_manager::get_form_field_from_label($locator, $this); $field->set_value($value); } catch (ElementNotFoundException $e) { // Next provided option then, this one should be part of another page's fields. } } }
/** * Checks that the form element field have the specified value. * * @Then /^the "(?P<field_string>(?:[^"]|\\")*)" field should match "(?P<value_string>(?:[^"]|\\")*)" value$/ * @throws ExpectationException * @throws ElementNotFoundException Thrown by behat_base::find * @param string $locator * @param string $value */ public function the_field_should_match_value($locator, $value) { $fieldnode = $this->find_field($locator); // Get the field. $field = behat_field_manager::get_form_field($fieldnode, $this->getSession()); $fieldvalue = $field->get_value(); // Checks if the provided value matches the current field value. if (trim($value) != trim($fieldvalue)) { throw new ExpectationException('The \'' . $locator . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected', $this->getSession()); } }
/** * Replaces text in the field's content. * The step begins in a form. * * @Given /^I replace in field "(?P<field_string>(?:[^"]|\\")*)" "(?P<text_string>(?:[^"]|\\")*)" with "(?P<replacement_string>(?:[^"]|\\")*)"$/ * @param string $locator * @param string $text * @param string $replacement */ public function i_replace_in_field_with($locator, $text, $replacement) { $node = $this->find_field($locator); $field = behat_field_manager::get_form_field($node, $this->getSession()); $value = $field->get_value(); $value = str_replace($text, $replacement, $value); // Hack to remove new line characters from editor field value. if (get_class($field) == 'behat_form_editor') { $value = str_replace(array("\n", "\r"), '', $value); } $field->set_value($value); }
/** * Generic field setter. * * Internal API method, a generic *I set "VALUE" to "FIELD" field* * could be created based on it. * * @param string $fieldlocator The pointer to the field, it will depend on the field type. * @param string $value * @return void */ protected function set_field_value($fieldlocator, $value) { $node = $this->find_field($fieldlocator); // We delegate to behat_form_field class, it will // guess the type properly as it is a select tag. $field = behat_field_manager::get_form_field($node, $this->getSession()); $field->set_value($value); }