Merge branch 'MDL-66979-310-7' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE
This commit is contained in:
@@ -46,6 +46,7 @@ $string['stepsdefinitionstype'] = 'Type';
|
||||
$string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones';
|
||||
$string['unknownexceptioninfo'] = 'There was a problem with Selenium or your browser. Please ensure you are using the latest version of Selenium. Error:';
|
||||
$string['viewsteps'] = 'Filter';
|
||||
$string['warndirrootconfigfound'] = 'A configuration file was found at {$a}. This file is not automatically updated and may become stale. We recommend removing this file.';
|
||||
$string['wheninfo'] = 'When. Action that provokes an event';
|
||||
$string['wrongbehatsetup'] = 'Something is wrong with the behat setup and so step definitions cannot be listed: <b>{$a->errormsg}</b><br/><br/>Please check:<ul>
|
||||
<li>$CFG->behat_dataroot, $CFG->behat_prefix and $CFG->behat_wwwroot are set in config.php with different values from $CFG->dataroot, $CFG->prefix and $CFG->wwwroot.</li>
|
||||
|
||||
@@ -28,16 +28,15 @@ Feature: Verify that keyboard steps work as expected
|
||||
And I press the shift tab key
|
||||
And the focused element is "Username" "field"
|
||||
|
||||
# TODO: Uncomment the following when MDL-66979 is integrated.
|
||||
# @javascript
|
||||
# Scenario: Using the arrow keys allows me to navigate through menus
|
||||
# Given the following "users" exist:
|
||||
# | username | email | firstname | lastname |
|
||||
# | saffronr | [email protected] | Saffron | Rutledge |
|
||||
# And I log in as "saffronr"
|
||||
# And I click on "Saffron Rutledge" "link" in the ".usermenu" "css_element"
|
||||
# When I press the up key
|
||||
# Then the focused element is "Log out" "link"
|
||||
@javascript
|
||||
Scenario: Using the arrow keys allows me to navigate through menus
|
||||
Given the following "users" exist:
|
||||
| username | email | firstname | lastname |
|
||||
| saffronr | saffron.rutledge@example.com | Saffron | Rutledge |
|
||||
And I log in as "saffronr"
|
||||
And I click on "Saffron Rutledge" "link" in the ".usermenu" "css_element"
|
||||
When I press the up key
|
||||
Then the focused element is "Log out" "link"
|
||||
|
||||
@javascript
|
||||
Scenario: The escape key can be used to close a dialogue
|
||||
|
||||
@@ -14,8 +14,6 @@ Feature: Forms manipulation
|
||||
Then the field "First name" matches value "Field value"
|
||||
And the "Select a country" select box should contain "Japan"
|
||||
And the field "New password" matches value "TestPass"
|
||||
And I take focus off "Update profile" "button"
|
||||
And I press "Update profile"
|
||||
|
||||
@javascript
|
||||
Scenario: Expand all fieldsets and advanced elements
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ default:
|
||||
Behat\MinkExtension:
|
||||
base_url: 'http://localhost:8000'
|
||||
goutte: null
|
||||
selenium2: null
|
||||
webdriver: null
|
||||
Moodle\BehatExtension:
|
||||
moodledirroot: /Should/Change/To/Moodle/www/dir
|
||||
steps_definitions: { }
|
||||
|
||||
@@ -46,49 +46,46 @@ Feature: View structural changes in recent activity block
|
||||
| GG3 | G2 |
|
||||
|
||||
Scenario: Check that Added module information is displayed respecting view capability
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Recent activity" block
|
||||
When I add a "Forum" to section "1" and I fill the form with:
|
||||
| name | ForumVisibleGroups |
|
||||
| Description | No description |
|
||||
| groupmode | Visible groups |
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| name | ForumSeparateGroups |
|
||||
| Description | No description |
|
||||
| groupmode | Separate groups |
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| name | ForumHidden |
|
||||
| Description | No description |
|
||||
| Availability | 0 |
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| name | ForumNoGroups |
|
||||
| Description | No description |
|
||||
| groupmode | No groups |
|
||||
And I add a "Forum" to section "2" and I fill the form with:
|
||||
| name | ForumVisibleGroupsG1 |
|
||||
| Description | No description |
|
||||
| groupmode | Visible groups |
|
||||
| Grouping | Grouping 1 |
|
||||
Given the following "activities" exist:
|
||||
| activity | course | section | name | idnumber | description | groupmode | grouping | visible |
|
||||
| forum | C1 | 1 | ForumVisibleGroups | forum1 | No description | 2 | | 1 |
|
||||
| forum | C1 | 1 | ForumSeparateGroups | forum2 | No description | 1 | | 1 |
|
||||
| forum | C1 | 1 | ForumHidden | forum3 | No description | 1 | | 0 |
|
||||
| forum | C1 | 1 | ForumNoGroups | forum4 | No description | 0 | | 1 |
|
||||
| forum | C1 | 2 | ForumVisibleGroupsG1 | forum5 | No description | 2 | GG1 | 1 |
|
||||
| forum | C1 | 2 | ForumSeparateGroupsG1 | forum6 | No description | 1 | GG1 | 1 |
|
||||
| forum | C1 | 3 | ForumVisibleGroupsG2 | forum7 | No description | 2 | GG2 | 1 |
|
||||
| forum | C1 | 3 | ForumSeparateGroupsG2 | forum8 | No description | 1 | GG2 | 1 |
|
||||
And I log in as "teacher1"
|
||||
|
||||
And I am on "Course 1" course homepage
|
||||
And I click on "ForumVisibleGroupsG1" "link"
|
||||
And I click on "Edit settings" "link"
|
||||
And I set the following fields to these values:
|
||||
| Access restrictions | Grouping: Grouping 1 |
|
||||
And I add a "Forum" to section "2" and I fill the form with:
|
||||
| name | ForumSeparateGroupsG1 |
|
||||
| Description | No description |
|
||||
| groupmode | Separate groups |
|
||||
| Grouping | Grouping 1 |
|
||||
| Access restrictions | Grouping: Grouping 1 |
|
||||
And I add a "Forum" to section "3" and I fill the form with:
|
||||
| name | ForumVisibleGroupsG2 |
|
||||
| Description | No description |
|
||||
| groupmode | Visible groups |
|
||||
| Grouping | Grouping 2 |
|
||||
And I press "Save and return to course"
|
||||
|
||||
And I click on "ForumSeparateGroupsG1" "link"
|
||||
And I click on "Edit settings" "link"
|
||||
And I set the following fields to these values:
|
||||
| Access restrictions | Grouping: Grouping 1 |
|
||||
And I press "Save and return to course"
|
||||
|
||||
And I click on "ForumVisibleGroupsG2" "link"
|
||||
And I click on "Edit settings" "link"
|
||||
And I set the following fields to these values:
|
||||
| Access restrictions | Grouping: Grouping 2 |
|
||||
And I add a "Forum" to section "3" and I fill the form with:
|
||||
| name | ForumSeparateGroupsG2 |
|
||||
| Description | No description |
|
||||
| groupmode | Separate groups |
|
||||
| Grouping | Grouping 2 |
|
||||
| Access restrictions | Grouping: Grouping 2 |
|
||||
And I press "Save and return to course"
|
||||
|
||||
And I click on "ForumSeparateGroupsG2" "link"
|
||||
And I click on "Edit settings" "link"
|
||||
And I set the following fields to these values:
|
||||
| Access restrictions | Grouping: Grouping 2 |
|
||||
And I press "Save and return to course"
|
||||
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I add the "Recent activity" block
|
||||
|
||||
Then I should see "ForumVisibleGroups" in the "Recent activity" "block"
|
||||
And I should see "ForumSeparateGroups" in the "Recent activity" "block"
|
||||
And I should see "ForumNoGroups" in the "Recent activity" "block"
|
||||
@@ -98,6 +95,7 @@ Feature: View structural changes in recent activity block
|
||||
And I should see "ForumVisibleGroupsG2" in the "Recent activity" "block"
|
||||
And I should see "ForumSeparateGroupsG2" in the "Recent activity" "block"
|
||||
And I log out
|
||||
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should see "ForumVisibleGroups" in the "Recent activity" "block"
|
||||
@@ -109,6 +107,7 @@ Feature: View structural changes in recent activity block
|
||||
And I should not see "ForumVisibleGroupsG2" in the "Recent activity" "block"
|
||||
And I should not see "ForumSeparateGroupsG2" in the "Recent activity" "block"
|
||||
And I log out
|
||||
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should see "ForumVisibleGroups" in the "Recent activity" "block"
|
||||
@@ -120,6 +119,7 @@ Feature: View structural changes in recent activity block
|
||||
And I should see "ForumVisibleGroupsG2" in the "Recent activity" "block"
|
||||
And I should see "ForumSeparateGroupsG2" in the "Recent activity" "block"
|
||||
And I log out
|
||||
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should see "ForumVisibleGroups" in the "Recent activity" "block"
|
||||
@@ -131,6 +131,7 @@ Feature: View structural changes in recent activity block
|
||||
And I should see "ForumVisibleGroupsG2" in the "Recent activity" "block"
|
||||
And I should see "ForumSeparateGroupsG2" in the "Recent activity" "block"
|
||||
And I log out
|
||||
|
||||
# Teachers have capability to see all groups and hidden activities
|
||||
And I log in as "assistant1"
|
||||
And I am on "Course 1" course homepage
|
||||
@@ -142,15 +143,20 @@ Feature: View structural changes in recent activity block
|
||||
And I log out
|
||||
|
||||
Scenario: Updates and deletes in recent activity block
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | ForumNew |
|
||||
| description | No description |
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Recent activity" block
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| name | ForumNew |
|
||||
| Description | No description |
|
||||
Then I should see "Added Forum" in the "Recent activity" "block"
|
||||
And I should see "ForumNew" in the "Recent activity" "block"
|
||||
And I log out
|
||||
|
||||
# Update forum as a teacher after a second to ensure we have a new timestamp for recent activity.
|
||||
And I wait "1" seconds
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
@@ -159,6 +165,7 @@ Feature: View structural changes in recent activity block
|
||||
And I log out
|
||||
# Update forum as a teacher after a second to ensure we have a new timestamp for recent activity.
|
||||
And I wait "1" seconds
|
||||
|
||||
# Update forum as a teacher
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
@@ -170,6 +177,7 @@ Feature: View structural changes in recent activity block
|
||||
And I log out
|
||||
And I wait "1" seconds
|
||||
# Student 1 already saw that forum was created, now he can see that forum was updated
|
||||
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should not see "Added Forum" in the "Recent activity" "block"
|
||||
@@ -179,6 +187,7 @@ Feature: View structural changes in recent activity block
|
||||
And I log out
|
||||
And I wait "1" seconds
|
||||
# Student 2 has bigger interval and he can see one entry that forum was created but with the new name
|
||||
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should see "Added Forum" in the "Recent activity" "block"
|
||||
@@ -188,6 +197,7 @@ Feature: View structural changes in recent activity block
|
||||
And I log out
|
||||
And I wait "1" seconds
|
||||
# Delete forum as a teacher
|
||||
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I delete "ForumUpdated" activity
|
||||
@@ -195,6 +205,7 @@ Feature: View structural changes in recent activity block
|
||||
And I log out
|
||||
And I wait "1" seconds
|
||||
# Students 1 and 2 see that forum was deleted
|
||||
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should not see "Added Forum" in the "Recent activity" "block"
|
||||
@@ -205,6 +216,7 @@ Feature: View structural changes in recent activity block
|
||||
And I log out
|
||||
And I wait "1" seconds
|
||||
# Student 3 never knew that forum was created, so he does not see anything
|
||||
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should not see "Added Forum" in the "Recent activity" "block"
|
||||
@@ -212,4 +224,3 @@ Feature: View structural changes in recent activity block
|
||||
And I should not see "Updated Forum" in the "Recent activity" "block"
|
||||
And I should not see "ForumUpdated" in the "Recent activity" "block"
|
||||
And I should not see "Deleted Forum" in the "Recent activity" "block"
|
||||
And I log out
|
||||
|
||||
+5
-10
@@ -4,16 +4,11 @@
|
||||
"description": "Moodle - the world's open source learning platform",
|
||||
"type": "project",
|
||||
"homepage": "https://moodle.org",
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/moodlehq/php-webdriver.git"
|
||||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "8.5.*",
|
||||
"moodlehq/behat-extension": "3.310.0",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"instaclick/php-webdriver": "dev-local as 1.x-dev"
|
||||
}
|
||||
"moodlehq/behat-extension": "3.310.2",
|
||||
"mikey179/vfsstream": "^1.6"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
||||
Generated
+759
-585
File diff suppressed because it is too large
Load Diff
@@ -66,7 +66,7 @@ class behat_enrol extends behat_base {
|
||||
|
||||
// Ensure we get button in focus, before pressing button.
|
||||
if ($this->running_javascript()) {
|
||||
$this->execute("behat_general::i_take_focus_off_field", array(get_string('addinstance', 'enrol'), "button"));
|
||||
$this->execute('behat_general::i_press_named_key', ['', 'tab']);
|
||||
}
|
||||
|
||||
// Save changes.
|
||||
|
||||
@@ -65,6 +65,8 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
|
||||
And I click on student "Student 3" for grade item "Item SU"
|
||||
And I set the field "ajaxgrade" to "Very good"
|
||||
And I press the shift tab key
|
||||
And I press the tab key
|
||||
And I press the shift tab key
|
||||
And I click on student "Student 3" for grade item "Item VU"
|
||||
And I set the field "ajaxgrade" to "50"
|
||||
And I press the enter key
|
||||
|
||||
@@ -48,48 +48,20 @@ class behat_groups extends behat_base {
|
||||
* @param string $groupname
|
||||
*/
|
||||
public function i_add_user_to_group_members($userfullname, $groupname) {
|
||||
// Select the group in the select.
|
||||
$this->execute('behat_forms::i_set_the_field_to', [get_string('groups', 'core'), $this->escape($groupname)]);
|
||||
|
||||
$userfullname = behat_context_helper::escape($userfullname);
|
||||
// Press "Add/remove users".
|
||||
$this->execute('behat_general::i_click_on', [get_string('adduserstogroup', 'group'), "button"]);
|
||||
|
||||
// Using a xpath liternal to avoid problems with quotes and double quotes.
|
||||
$groupname = behat_context_helper::escape($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)]";
|
||||
$groupoption = $this->find('xpath', $xpath);
|
||||
$fulloption = $groupoption->getText();
|
||||
$select->selectOption($fulloption);
|
||||
|
||||
// This is needed by some drivers to ensure relevant event is triggred and button is enabled.
|
||||
$driver = $this->getSession()->getDriver();
|
||||
if ($driver instanceof \Moodle\BehatExtension\Driver\MoodleSelenium2Driver) {
|
||||
$script = "Syn.trigger('change', {}, {{ELEMENT}})";
|
||||
$driver->triggerSynScript($select->getXpath(), $script);
|
||||
}
|
||||
$this->getSession()->wait(self::get_timeout() * 1000, self::PAGE_READY_JS);
|
||||
|
||||
// Here we don't need to wait for the AJAX response.
|
||||
$this->find_button(get_string('adduserstogroup', 'group'))->click();
|
||||
|
||||
// Wait for add/remove members page to be loaded.
|
||||
$this->getSession()->wait(self::get_timeout() * 1000, self::PAGE_READY_JS);
|
||||
|
||||
// Getting the option and selecting it.
|
||||
$select = $this->find_field('addselect');
|
||||
$xpath = "//select[@id='addselect']/descendant::option[contains(., $userfullname)]";
|
||||
$memberoption = $this->find('xpath', $xpath);
|
||||
$fulloption = $memberoption->getText();
|
||||
$select->selectOption($fulloption);
|
||||
// Select the user.
|
||||
$this->execute('behat_forms::i_set_the_field_to', ["addselect", $this->escape($userfullname)]);
|
||||
|
||||
// Click add button.
|
||||
$this->find_button(get_string('add'))->click();
|
||||
|
||||
// Wait for the page to load.
|
||||
$this->getSession()->wait(self::get_timeout() * 1000, self::PAGE_READY_JS);
|
||||
$this->execute('behat_general::i_click_on', [get_string('add', 'core'), "button"]);
|
||||
|
||||
// Returning to the main groups page.
|
||||
$this->find_button(get_string('backtogroups', 'group'))->click();
|
||||
$this->execute('behat_general::i_click_on', [get_string('backtogroups', 'group'), "button"]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -179,7 +179,11 @@ class behat_command {
|
||||
}
|
||||
|
||||
// Behat test command.
|
||||
list($output, $code) = self::run(' --help');
|
||||
$dirrootconfigpath = $CFG->dirroot . DIRECTORY_SEPARATOR . 'behat.yml';
|
||||
if (file_exists($dirrootconfigpath)) {
|
||||
self::output_msg(get_string('warndirrootconfigfound', 'tool_behat', $dirrootconfigpath));
|
||||
}
|
||||
list($output, $code) = self::run(" --help");
|
||||
|
||||
if ($code != 0) {
|
||||
|
||||
|
||||
@@ -475,12 +475,12 @@ class behat_config_util {
|
||||
$parallelruns = $this->get_number_of_parallel_run();
|
||||
}
|
||||
|
||||
$selenium2wdhost = array('wd_host' => 'http://localhost:4444/wd/hub');
|
||||
$webdriverwdhost = array('wd_host' => 'http://localhost:4444/wd/hub');
|
||||
// If parallel run, then set wd_host if specified.
|
||||
if (!empty($currentrun) && !empty($parallelruns)) {
|
||||
// Set proper selenium2 wd_host if defined.
|
||||
// Set proper webdriver wd_host if defined.
|
||||
if (!empty($CFG->behat_parallel_run[$currentrun - 1]['wd_host'])) {
|
||||
$selenium2wdhost = array('wd_host' => $CFG->behat_parallel_run[$currentrun - 1]['wd_host']);
|
||||
$webdriverwdhost = array('wd_host' => $CFG->behat_parallel_run[$currentrun - 1]['wd_host']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,7 +525,7 @@ class behat_config_util {
|
||||
'Behat\MinkExtension' => array(
|
||||
'base_url' => $CFG->behat_wwwroot,
|
||||
'goutte' => null,
|
||||
'selenium2' => $selenium2wdhost
|
||||
'webdriver' => $webdriverwdhost
|
||||
),
|
||||
'Moodle\BehatExtension' => array(
|
||||
'moodledirroot' => $CFG->dirroot,
|
||||
@@ -634,20 +634,21 @@ class behat_config_util {
|
||||
// We also need to disable web security, otherwise it can't make CSS requests to the server
|
||||
// on localhost due to CORS restrictions.
|
||||
if (!empty($values['browser']) && $values['browser'] === 'chrome') {
|
||||
if (!isset($values['capabilities'])) {
|
||||
$values['capabilities'] = [];
|
||||
}
|
||||
if (!isset($values['capabilities']['extra_capabilities'])) {
|
||||
$values['capabilities']['extra_capabilities'] = [];
|
||||
}
|
||||
if (!isset($values['capabilities']['extra_capabilities']['chromeOptions'])) {
|
||||
$values['capabilities']['extra_capabilities']['chromeOptions'] = [];
|
||||
}
|
||||
if (!isset($values['capabilities']['extra_capabilities']['chromeOptions']['args'])) {
|
||||
$values['capabilities']['extra_capabilities']['chromeOptions']['args'] = [];
|
||||
}
|
||||
$values['capabilities']['extra_capabilities']['chromeOptions']['args'][] = '--unlimited-storage';
|
||||
$values['capabilities']['extra_capabilities']['chromeOptions']['args'][] = '--disable-web-security';
|
||||
$values = array_merge_recursive(
|
||||
[
|
||||
'capabilities' => [
|
||||
'extra_capabilities' => [
|
||||
'chromeOptions' => [
|
||||
'args' => [
|
||||
'unlimited-storage',
|
||||
'disable-web-security',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
$values
|
||||
);
|
||||
|
||||
// If the mobile app is enabled, check its version and add appropriate tags.
|
||||
if ($mobiletags = $this->get_mobile_version_tags()) {
|
||||
@@ -657,6 +658,14 @@ class behat_config_util {
|
||||
$values['tags'] = $mobiletags;
|
||||
}
|
||||
}
|
||||
|
||||
$values['capabilities']['extra_capabilities']['chromeOptions']['args'] = array_map(function($arg): string {
|
||||
if (substr($arg, 0, 2) === '--') {
|
||||
return substr($arg, 2);
|
||||
}
|
||||
return $arg;
|
||||
}, $values['capabilities']['extra_capabilities']['chromeOptions']['args']);
|
||||
sort($values['capabilities']['extra_capabilities']['chromeOptions']['args']);
|
||||
}
|
||||
|
||||
// Fill tags information.
|
||||
@@ -688,7 +697,7 @@ class behat_config_util {
|
||||
$behatprofileextension = array(
|
||||
'extensions' => array(
|
||||
'Behat\MinkExtension' => array(
|
||||
'selenium2' => $seleniumconfig,
|
||||
'webdriver' => $seleniumconfig,
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -922,6 +931,7 @@ class behat_config_util {
|
||||
// In case user defined overrides respect them over our default ones.
|
||||
if (!empty($CFG->behat_config)) {
|
||||
foreach ($CFG->behat_config as $profile => $values) {
|
||||
$values = $this->fix_legacy_profile_data($profile, $values);
|
||||
$config = $this->merge_config($config, $this->get_behat_config_for_profile($profile, $values));
|
||||
}
|
||||
}
|
||||
@@ -948,11 +958,11 @@ class behat_config_util {
|
||||
$oldconfigvalues = array();
|
||||
if (isset($values['extensions']['Behat\MinkExtension\Extension'])) {
|
||||
$extensionvalues = $values['extensions']['Behat\MinkExtension\Extension'];
|
||||
if (isset($extensionvalues['selenium2']['browser'])) {
|
||||
$oldconfigvalues['browser'] = $extensionvalues['selenium2']['browser'];
|
||||
if (isset($extensionvalues['webdriver']['browser'])) {
|
||||
$oldconfigvalues['browser'] = $extensionvalues['webdriver']['browser'];
|
||||
}
|
||||
if (isset($extensionvalues['selenium2']['wd_host'])) {
|
||||
$oldconfigvalues['wd_host'] = $extensionvalues['selenium2']['wd_host'];
|
||||
if (isset($extensionvalues['webdriver']['wd_host'])) {
|
||||
$oldconfigvalues['wd_host'] = $extensionvalues['webdriver']['wd_host'];
|
||||
}
|
||||
if (isset($extensionvalues['capabilities'])) {
|
||||
$oldconfigvalues['capabilities'] = $extensionvalues['capabilities'];
|
||||
@@ -991,6 +1001,35 @@ class behat_config_util {
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for and attempt to fix legacy profile data.
|
||||
*
|
||||
* The Mink Driver used for W3C no longer uses the `selenium2` naming but otherwise is backwards compatibly.
|
||||
*
|
||||
* Emit a warning that users should update their configuration.
|
||||
*
|
||||
* @param string $profilename The name of this profile
|
||||
* @param array $data The profile data for this profile
|
||||
* @return array Th eamended profile data
|
||||
*/
|
||||
protected function fix_legacy_profile_data(string $profilename, array $data): array {
|
||||
// Check for legacy instaclick profiles.
|
||||
if (!array_key_exists('Behat\MinkExtension', $data['extensions'])) {
|
||||
return $data;
|
||||
}
|
||||
if (array_key_exists('selenium2', $data['extensions']['Behat\MinkExtension'])) {
|
||||
echo("\n\n");
|
||||
echo("=> Warning: Legacy selenium2 profileuration was found for {$profilename} profile.\n");
|
||||
echo("=> This has been renamed from 'selenium2' to 'webdriver'.\n");
|
||||
echo("=> You should update your Behat configuration.\n");
|
||||
echo("\n");
|
||||
$data['extensions']['Behat\MinkExtension']['webdriver'] = $data['extensions']['Behat\MinkExtension']['selenium2'];
|
||||
unset($data['extensions']['Behat\MinkExtension']['selenium2']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the path returned by get_components_with_tests() to standarize it
|
||||
*
|
||||
|
||||
@@ -23,21 +23,24 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
use Behat\Mink\Element\Element;
|
||||
use Behat\Mink\Exception\DriverException;
|
||||
use Behat\Mink\Exception\ExpectationException;
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
use Behat\Mink\Element\Element;
|
||||
use Behat\Mink\Exception\NoSuchWindowException;
|
||||
use Behat\Mink\Session;
|
||||
use Facebook\WebDriver\Exception\ScriptTimeoutException;
|
||||
use Facebook\WebDriver\WebDriverBy;
|
||||
use Facebook\WebDriver\WebDriverElement;
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/component_named_replacement.php');
|
||||
require_once(__DIR__ . '/component_named_selector.php');
|
||||
|
||||
// Alias the WebDriver\Key class to behat_keys to make future transition to a different WebDriver implementation
|
||||
// easier.
|
||||
class_alias('WebDriver\\Key', 'behat_keys');
|
||||
// Alias the Facebook\WebDriver\WebDriverKeys class to behat_keys for better b/c with the older Instaclick driver.
|
||||
class_alias('Facebook\WebDriver\WebDriverKeys', 'behat_keys');
|
||||
|
||||
/**
|
||||
* A trait containing functionality used by the behat base context, and form fields.
|
||||
@@ -253,9 +256,7 @@ trait behat_session_trait {
|
||||
* @param string[] $keys
|
||||
*/
|
||||
public static function type_keys(Session $session, array $keys): void {
|
||||
$session->getDriver()->getWebDriverSession()->keys([
|
||||
'value' => $keys,
|
||||
]);
|
||||
$session->getDriver()->getWebDriver()->getKeyboard()->sendKeys($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -833,7 +834,7 @@ EOF;
|
||||
return M.util.pending_js.join(":");
|
||||
})()'));
|
||||
$pending = self::evaluate_script_in_session($session, $jscode);
|
||||
} catch (NoSuchWindow $nsw) {
|
||||
} catch (NoSuchWindowException $nsw) {
|
||||
// We catch an exception here, in case we just closed the window we were interacting with.
|
||||
// No javascript is running if there is no window right?
|
||||
$pending = '';
|
||||
@@ -973,7 +974,7 @@ EOF;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (NoSuchWindow $e) {
|
||||
} catch (NoSuchWindowException $e) {
|
||||
// If we were interacting with a popup window it will not exists after closing it.
|
||||
} catch (DriverException $e) {
|
||||
// Same reason as above.
|
||||
@@ -1079,17 +1080,62 @@ EOF;
|
||||
if (!$this->running_javascript()) {
|
||||
$node->click();
|
||||
}
|
||||
$this->ensure_node_is_visible($node); // Ensures hidden elements can't be clicked.
|
||||
$xpath = $node->getXpath();
|
||||
$driver = $this->getSession()->getDriver();
|
||||
if ($driver instanceof \Moodle\BehatExtension\Driver\MoodleSelenium2Driver) {
|
||||
$script = "Syn.click({{ELEMENT}})";
|
||||
$driver->triggerSynScript($xpath, $script);
|
||||
if ($driver instanceof \Moodle\BehatExtension\Driver\WebDriver) {
|
||||
$this->execute_js_on_node($node, '{{ELEMENT}}.click();');
|
||||
} else {
|
||||
$driver->click($xpath);
|
||||
$this->ensure_node_is_visible($node); // Ensures hidden elements can't be clicked.
|
||||
$driver->click($node->getXpath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute JS on the specified NodeElement.
|
||||
*
|
||||
* @param NodeElement $node
|
||||
* @param string $script
|
||||
* @param bool $async
|
||||
*/
|
||||
protected function execute_js_on_node(NodeElement $node, string $script, bool $async = false): void {
|
||||
$driver = $this->getSession()->getDriver();
|
||||
if (!($driver instanceof \Moodle\BehatExtension\Driver\WebDriver)) {
|
||||
throw new \coding_exception('Unknown driver');
|
||||
}
|
||||
|
||||
if (preg_match('/^function[\s\(]/', $script)) {
|
||||
$script = preg_replace('/;$/', '', $script);
|
||||
$script = '(' . $script . ')';
|
||||
}
|
||||
|
||||
$script = str_replace('{{ELEMENT}}', 'arguments[0]', $script);
|
||||
|
||||
$webdriver = $driver->getWebDriver();
|
||||
|
||||
$element = $this->get_webdriver_element_from_node_element($node);
|
||||
if ($async) {
|
||||
try {
|
||||
$webdriver->executeAsyncScript($script, [$element]);
|
||||
} catch (ScriptTimeoutException $e) {
|
||||
throw new DriverException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
} else {
|
||||
$webdriver->executeScript($script, [$element]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a Mink NodeElement into a WebDriver Element.
|
||||
*
|
||||
* @param NodeElement $node
|
||||
* @return WebDriverElement
|
||||
*/
|
||||
protected function get_webdriver_element_from_node_element(NodeElement $node): WebDriverElement {
|
||||
return $this->getSession()
|
||||
->getDriver()
|
||||
->getWebDriver()
|
||||
->findElement(WebDriverBy::xpath($node->getXpath()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert page names to URLs for steps like 'When I am on the "[page name]" page'.
|
||||
*
|
||||
|
||||
@@ -235,7 +235,7 @@ XPATH
|
||||
.//descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]/ancestor::*[@data-fieldtype = 'autocomplete']
|
||||
XPATH
|
||||
, 'iframe' => <<<XPATH
|
||||
.//iframe[contains(concat(' ', normalize-space(@class), ' '), %locator% )]
|
||||
.//iframe[(%idOrNameMatch% or (contains(concat(' ', normalize-space(@class), ' '), %locator% )))]
|
||||
XPATH
|
||||
);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/behat_form_field.php');
|
||||
require_once(__DIR__ . '/behat_form_textarea.php');
|
||||
|
||||
/**
|
||||
* Availability form field class.
|
||||
|
||||
@@ -57,9 +57,6 @@ class behat_form_checkbox extends behat_form_field {
|
||||
// Check it if it should be checked and it is not.
|
||||
$this->field->click();
|
||||
|
||||
// Trigger the onchange event as triggered when 'checking' the checkbox.
|
||||
$this->trigger_on_change();
|
||||
|
||||
} else if (empty($value) && $this->field->isChecked()) {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
@@ -69,9 +66,6 @@ class behat_form_checkbox extends behat_form_field {
|
||||
|
||||
// Uncheck if it is checked and shouldn't.
|
||||
$this->field->click();
|
||||
|
||||
// Trigger the onchange event as triggered when 'checking' the checkbox.
|
||||
$this->trigger_on_change();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,17 +97,4 @@ class behat_form_checkbox extends behat_form_field {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger on change event.
|
||||
*/
|
||||
protected function trigger_on_change() {
|
||||
$driver = $this->session->getDriver();
|
||||
if ($driver instanceof \Moodle\BehatExtension\Driver\MoodleSelenium2Driver) {
|
||||
$driver->triggerSynScript(
|
||||
$this->field->getXPath(),
|
||||
"Syn.trigger('change', {}, {{ELEMENT}})"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,12 +218,15 @@ class behat_form_field implements behat_session_interface {
|
||||
* @return int
|
||||
*/
|
||||
protected function get_internal_field_id() {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
throw new coding_exception('You can only get an internal ID using the selenium driver.');
|
||||
}
|
||||
|
||||
return $this->session->getDriver()->getWebDriverSession()->element('xpath', $this->field->getXPath())->getID();
|
||||
return $this->getSession()
|
||||
->getDriver()
|
||||
->getWebDriver()
|
||||
->findElement(WebDriverBy::xpath($node->getXpath()))
|
||||
->getID();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,28 +48,21 @@ class behat_form_passwordunmask extends behat_form_text {
|
||||
* @return void
|
||||
*/
|
||||
public function set_value($value) {
|
||||
if ($this->running_javascript()) {
|
||||
$id = $this->field->getAttribute('id');
|
||||
$js = <<<JS
|
||||
(function() {
|
||||
require(["jquery"], function($) {
|
||||
var wrapper = $(document.getElementById("{$id}")).closest('[data-passwordunmask="wrapper"]');
|
||||
wrapper.find('[data-passwordunmask="edit"]').trigger("click");
|
||||
});
|
||||
})();
|
||||
JS;
|
||||
behat_base::execute_script_in_session($this->session, $js);
|
||||
if (!$this->running_javascript()) {
|
||||
$this->field->setValue($value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->field->setValue($value);
|
||||
$id = $this->field->getAttribute('id');
|
||||
$wrapper = $this->field->getParent()->getParent()->find('css', '[data-passwordunmask="wrapper"]');
|
||||
$wrapper->click();
|
||||
$this->wait_for_pending_js();
|
||||
|
||||
// Ensure all pending JS is finished.
|
||||
if ($this->running_javascript()) {
|
||||
// Press enter key after setting password, so we have a stable page.
|
||||
$this->field->keyDown(13);
|
||||
$this->field->keyPress(13);
|
||||
$this->field->keyUp(13);
|
||||
$this->session->wait(behat_base::get_timeout() * 1000, behat_base::PAGE_READY_JS);
|
||||
}
|
||||
behat_base::type_keys($this->session, str_split($value));
|
||||
$this->wait_for_pending_js();
|
||||
|
||||
// Press enter key after setting password to save.
|
||||
behat_base::type_keys($this->session, [behat_keys::ENTER]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ class behat_form_select extends behat_form_field {
|
||||
|
||||
// Is the select multiple?
|
||||
$multiple = $this->field->hasAttribute('multiple');
|
||||
$singleselect = ($this->field->hasClass('singleselect') || $this->field->hasClass('urlselect'));
|
||||
|
||||
// Here we select the option(s).
|
||||
if ($multiple) {
|
||||
@@ -64,38 +63,9 @@ class behat_form_select extends behat_form_field {
|
||||
$afterfirstoption = true;
|
||||
}
|
||||
} else {
|
||||
// By default, assume the passed value is a non-multiple option.
|
||||
// By default, assume the passed value is a non-multiple option.
|
||||
$this->field->selectOption(trim($value));
|
||||
}
|
||||
|
||||
// Wait for all the possible AJAX requests that have been
|
||||
// already triggered by selectOption() to be finished.
|
||||
if ($this->running_javascript()) {
|
||||
// Trigger change event and click on first skip link, as some OS/browsers (Phantomjs, Mac-FF),
|
||||
// don't close select option field and trigger event.
|
||||
if (!$singleselect) {
|
||||
$dialoguexpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue-focused ')]";
|
||||
if (!$node = $this->session->getDriver()->find($dialoguexpath)) {
|
||||
$script = "Syn.trigger('change', {}, {{ELEMENT}})";
|
||||
try {
|
||||
$driver = $this->session->getDriver();
|
||||
if ($driver instanceof \Moodle\BehatExtension\Driver\MoodleSelenium2Driver) {
|
||||
$driver->triggerSynScript($this->field->getXpath(), $script);
|
||||
}
|
||||
$driver->click('//body//div[@class="skiplinks"]');
|
||||
} catch (\Exception $e) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$this->session->getDriver()->click($dialoguexpath);
|
||||
} catch (\Exception $e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->session->wait(behat_base::get_timeout() * 1000, behat_base::PAGE_READY_JS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,9 +67,11 @@ class behat_forms extends behat_base {
|
||||
// Ensures the button is present, before pressing.
|
||||
$buttonnode = $this->find_button($button);
|
||||
$buttonnode->press();
|
||||
$this->wait_for_pending_js();
|
||||
$this->look_for_exceptions();
|
||||
|
||||
// Switch to main window.
|
||||
$this->getSession()->switchToWindow(behat_general::MAIN_WINDOW_NAME);
|
||||
$this->execute('behat_general::switch_to_the_main_window');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -159,49 +159,30 @@ class behat_general extends behat_base {
|
||||
* Switches to the specified iframe.
|
||||
*
|
||||
* @Given /^I switch to "(?P<iframe_name_string>(?:[^"]|\\")*)" iframe$/
|
||||
* @param string $iframename
|
||||
*/
|
||||
public function switch_to_iframe($iframename) {
|
||||
|
||||
// We spin to give time to the iframe to be loaded.
|
||||
// Using extended timeout as we don't know about which
|
||||
// kind of iframe will be loaded.
|
||||
$this->spin(
|
||||
function($context, $iframename) {
|
||||
$context->getSession()->switchToIFrame($iframename);
|
||||
|
||||
// If no exception we are done.
|
||||
return true;
|
||||
},
|
||||
$iframename,
|
||||
behat_base::get_extended_timeout()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to the iframe containing specified class.
|
||||
*
|
||||
* @Given /^I switch to "(?P<iframe_name_string>(?:[^"]|\\")*)" class iframe$/
|
||||
* @param string $classname
|
||||
* @param string $name The name of the iframe
|
||||
*/
|
||||
public function switch_to_class_iframe($classname) {
|
||||
public function switch_to_iframe($name) {
|
||||
// We spin to give time to the iframe to be loaded.
|
||||
// Using extended timeout as we don't know about which
|
||||
// kind of iframe will be loaded.
|
||||
$this->spin(
|
||||
function($context, $classname) {
|
||||
$iframe = $this->find('iframe', $classname);
|
||||
if (!empty($iframe->getAttribute('id'))) {
|
||||
$iframename = $iframe->getAttribute('id');
|
||||
} else {
|
||||
function($context) use ($name){
|
||||
$iframe = $context->find('iframe', $name);
|
||||
if ($iframe->hasAttribute('name')) {
|
||||
$iframename = $iframe->getAttribute('name');
|
||||
} else {
|
||||
if (!$this->running_javascript()) {
|
||||
throw new \coding_exception('iframe must have a name attribute to use the switchTo command.');
|
||||
}
|
||||
$iframename = uniqid();
|
||||
$this->execute_js_on_node($iframe, "{{ELEMENT}}.name = '{$iframename}';");
|
||||
}
|
||||
$context->getSession()->switchToIFrame($iframename);
|
||||
|
||||
// If no exception we are done.
|
||||
return true;
|
||||
},
|
||||
$classname,
|
||||
behat_base::get_extended_timeout()
|
||||
);
|
||||
}
|
||||
@@ -222,13 +203,11 @@ class behat_general extends behat_base {
|
||||
* @param string $windowname
|
||||
*/
|
||||
public function switch_to_window($windowname) {
|
||||
// In Behat, some browsers (e.g. Chrome) are unable to switch to a
|
||||
// window without a name, and by default the main browser window does
|
||||
// not have a name. To work-around this, when we switch away from an
|
||||
// unnamed window (presumably the main window) to some other named
|
||||
// window, then we first set the main window name to a conventional
|
||||
// value that we can later use this name to switch back.
|
||||
$this->execute_script('if (window.name == "") window.name = "' . self::MAIN_WINDOW_NAME . '"');
|
||||
if ($windowname === self::MAIN_WINDOW_NAME) {
|
||||
// When switching to the main window normalise the window name to null.
|
||||
// This is normalised further in the Mink driver to the root window ID.
|
||||
$windowname = null;
|
||||
}
|
||||
|
||||
$this->getSession()->switchToWindow($windowname);
|
||||
}
|
||||
@@ -239,7 +218,7 @@ class behat_general extends behat_base {
|
||||
* @Given /^I switch to the main window$/
|
||||
*/
|
||||
public function switch_to_the_main_window() {
|
||||
$this->getSession()->switchToWindow(self::MAIN_WINDOW_NAME);
|
||||
$this->switch_to_window(self::MAIN_WINDOW_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,7 +250,7 @@ class behat_general extends behat_base {
|
||||
* @Given /^I accept the currently displayed dialog$/
|
||||
*/
|
||||
public function accept_currently_displayed_alert_dialog() {
|
||||
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
|
||||
$this->getSession()->getDriver()->getWebDriver()->switchTo()->alert()->accept();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,7 +258,7 @@ class behat_general extends behat_base {
|
||||
* @Given /^I dismiss the currently displayed dialog$/
|
||||
*/
|
||||
public function dismiss_currently_displayed_alert_dialog() {
|
||||
$this->getSession()->getDriver()->getWebDriverSession()->dismiss_alert();
|
||||
$this->getSession()->getDriver()->getWebDriver()->switchTo()->alert()->dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,9 +346,9 @@ class behat_general extends behat_base {
|
||||
* @param string $selectortype The type of what we look for
|
||||
*/
|
||||
public function i_hover($element, $selectortype) {
|
||||
|
||||
// Gets the node based on the requested selector type and locator.
|
||||
$node = $this->get_selected_node($selectortype, $element);
|
||||
$this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
|
||||
$node->mouseOver();
|
||||
}
|
||||
|
||||
@@ -418,7 +397,8 @@ class behat_general extends behat_base {
|
||||
*/
|
||||
public function i_click_on_confirming_the_dialogue($element, $selectortype) {
|
||||
$this->i_click_on($element, $selectortype);
|
||||
$this->accept_currently_displayed_alert_dialog();
|
||||
$this->execute('behat_general::accept_currently_displayed_alert_dialog', []);
|
||||
$this->wait_until_the_page_is_ready();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,7 +411,8 @@ class behat_general extends behat_base {
|
||||
*/
|
||||
public function i_click_on_dismissing_the_dialogue($element, $selectortype) {
|
||||
$this->i_click_on($element, $selectortype);
|
||||
$this->dismiss_currently_displayed_alert_dialog();
|
||||
$this->execute('behat_general::dismiss_currently_displayed_alert_dialog', []);
|
||||
$this->wait_until_the_page_is_ready();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1802,16 +1783,16 @@ EOF;
|
||||
$modifier = trim($key);
|
||||
switch (strtoupper($key)) {
|
||||
case 'UP':
|
||||
$keys[] = behat_keys::UP_ARROW;
|
||||
$keys[] = behat_keys::ARROW_UP;
|
||||
break;
|
||||
case 'DOWN':
|
||||
$keys[] = behat_keys::DOWN_ARROW;
|
||||
$keys[] = behat_keys::ARROW_DOWN;
|
||||
break;
|
||||
case 'LEFT':
|
||||
$keys[] = behat_keys::LEFT_ARROW;
|
||||
$keys[] = behat_keys::ARROW_LEFT;
|
||||
break;
|
||||
case 'RIGHT':
|
||||
$keys[] = behat_keys::RIGHT_ARROW;
|
||||
$keys[] = behat_keys::ARROW_RIGHT;
|
||||
break;
|
||||
case 'HOME':
|
||||
$keys[] = behat_keys::HOME;
|
||||
@@ -1852,9 +1833,6 @@ EOF;
|
||||
throw new \coding_exception("Unknown key '$key'}");
|
||||
}
|
||||
|
||||
// Always send the NULL key as the last key.
|
||||
$keys[] = behat_keys::NULL_KEY;
|
||||
|
||||
behat_base::type_keys($this->getSession(), $keys);
|
||||
}
|
||||
|
||||
|
||||
@@ -644,7 +644,7 @@ EOF;
|
||||
// the following scenarios. Some browsers already closes the alert, so
|
||||
// wrapping in a try & catch.
|
||||
try {
|
||||
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
|
||||
$this->getSession()->getDriver()->getWebDriver()->switchTo()->alert()->accept();
|
||||
} catch (Exception $e) {
|
||||
// Catching the generic one as we never know how drivers reacts here.
|
||||
}
|
||||
|
||||
@@ -4,34 +4,39 @@ Feature: In an assignment, teachers can change filters in the grading app
|
||||
As a teacher
|
||||
I need to preserve filter settings between the grader app and grading table.
|
||||
|
||||
@javascript
|
||||
Scenario: Set filters in the grading table and see them in the grading app
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | groupmode |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
| marker1 | Marker | 1 | marker1@example.com |
|
||||
| marker2 | Marker | 2 | marker2@example.com |
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
| marker1 | Marker | 1 | marker1@example.com |
|
||||
| marker2 | Marker | 2 | marker2@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| marker1 | C1 | teacher |
|
||||
| marker2 | C1 | teacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Use marking workflow | Yes |
|
||||
| Use marking allocation | Yes |
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| marker1 | C1 | teacher |
|
||||
| marker2 | C1 | teacher |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| idnumber | assign |
|
||||
| description | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| markingworkflow | 1 |
|
||||
| markingallocation | 1 |
|
||||
|
||||
@javascript
|
||||
Scenario: Set filters in the grading table and see them in the grading app
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
@@ -55,32 +60,8 @@ Feature: In an assignment, teachers can change filters in the grading app
|
||||
|
||||
@javascript
|
||||
Scenario: Set filters in the grading app and see them in the grading table
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | groupmode |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
| marker1 | Marker | 1 | marker1@example.com |
|
||||
| marker2 | Marker | 2 | marker2@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| marker1 | C1 | teacher |
|
||||
| marker2 | C1 | teacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Use marking workflow | Yes |
|
||||
| Use marking allocation | Yes |
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
@@ -97,8 +78,6 @@ Feature: In an assignment, teachers can change filters in the grading app
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I click on "[data-region=user-filters]" "css_element"
|
||||
And I set the field "filter" to "Not submitted"
|
||||
# The popup closes for some reason, so it needs to be reopened.
|
||||
And I click on "[data-region=user-filters]" "css_element"
|
||||
And I set the field "markerfilter" to "Marker 1"
|
||||
And I set the field "workflowfilter" to "In marking"
|
||||
And I click on "View all submissions" "link"
|
||||
|
||||
@@ -165,9 +165,7 @@ class behat_mod_feedback extends behat_base {
|
||||
// If chart data is not visible then expand.
|
||||
$node = $this->get_selected_node("xpath_element", $charttabledataxpath);
|
||||
if ($node) {
|
||||
if (!$node->isVisible()) {
|
||||
// Focus on node, before checking if it's visible.
|
||||
$node->focus();
|
||||
if ($node->getAttribute('aria-expanded') === 'false') {
|
||||
$this->execute('behat_general::i_click_on_in_the', array(
|
||||
get_string('showchartdata'),
|
||||
'link',
|
||||
|
||||
@@ -15,15 +15,18 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
|
||||
@javascript
|
||||
Scenario: An optional forum can have discussions subscribed to
|
||||
Given I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Subscription mode | Optional subscription |
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | Test forum name |
|
||||
| intro | Test forum description |
|
||||
| type | general |
|
||||
| forcesubscribe | 0 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Test post subject one |
|
||||
| Message | Test post message one |
|
||||
@@ -62,11 +65,15 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
|
||||
@javascript
|
||||
Scenario: An automatic subscription forum can have discussions unsubscribed from
|
||||
Given I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Subscription mode | Auto subscription |
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | Test forum name |
|
||||
| intro | Test forum description |
|
||||
| type | general |
|
||||
| forcesubscribe | 2 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Test post subject one |
|
||||
| Message | Test post message one |
|
||||
@@ -105,11 +112,15 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
|
||||
@javascript
|
||||
Scenario: A user does not lose their preferences when a forum is switch from optional to automatic
|
||||
Given I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Subscription mode | Optional subscription |
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | Test forum name |
|
||||
| intro | Test forum description |
|
||||
| type | general |
|
||||
| forcesubscribe | 0 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Test post subject one |
|
||||
| Message | Test post message one |
|
||||
@@ -150,11 +161,15 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
|
||||
@javascript
|
||||
Scenario: A user does not lose their preferences when a forum is switch from optional to automatic
|
||||
Given I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Subscription mode | Optional subscription |
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | Test forum name |
|
||||
| intro | Test forum description |
|
||||
| type | general |
|
||||
| forcesubscribe | 0 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Test post subject one |
|
||||
| Message | Test post message one |
|
||||
@@ -194,11 +209,15 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
And "Subscribe to this discussion" "checkbox" should exist in the "Test post subject two" "table_row"
|
||||
|
||||
Scenario: An optional forum prompts a user to subscribe to a discussion when posting unless they have already chosen not to subscribe
|
||||
Given I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Subscription mode | Optional subscription |
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | Test forum name |
|
||||
| intro | Test forum description |
|
||||
| type | general |
|
||||
| forcesubscribe | 0 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Test post subject one |
|
||||
| Message | Test post message one |
|
||||
@@ -230,11 +249,15 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
And the field "Discussion subscription" matches value "I don't want to be notified of new posts in this discussion"
|
||||
|
||||
Scenario: An automatic forum prompts a user to subscribe to a discussion when posting unless they have already chosen not to subscribe
|
||||
Given I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Subscription mode | Auto subscription |
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | Test forum name |
|
||||
| intro | Test forum description |
|
||||
| type | general |
|
||||
| forcesubscribe | 2 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Test post subject one |
|
||||
| Message | Test post message one |
|
||||
@@ -267,6 +290,7 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
|
||||
Scenario: A guest should not be able to subscribe to a discussion
|
||||
Given I am on site homepage
|
||||
And I turn editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
@@ -285,6 +309,7 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
|
||||
Scenario: A user who is not logged in should not be able to subscribe to a discussion
|
||||
Given I am on site homepage
|
||||
And I turn editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
@@ -301,11 +326,15 @@ Feature: A user can control their own subscription preferences for a discussion
|
||||
And "Unsubscribe from this discussion" "checkbox" should not exist
|
||||
|
||||
Scenario: A user can toggle their subscription preferences when viewing a discussion
|
||||
Given I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Subscription mode | Optional subscription |
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | forum1 |
|
||||
| name | Test forum name |
|
||||
| intro | Test forum description |
|
||||
| type | general |
|
||||
| forcesubscribe | 0 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Test post subject one |
|
||||
| Message | Test post message one |
|
||||
|
||||
@@ -15,6 +15,7 @@ Feature: Confirm progress gets saved on unload events
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I change window size to "large"
|
||||
|
||||
@javascript
|
||||
Scenario: Test progress gets saved correctly when the user navigates away from the scorm activity
|
||||
|
||||
@@ -27,16 +27,15 @@ Feature: Test creating a drag and drop markers question
|
||||
And I set the field "Question text" to "Please place the markers on the map of Milton Keynes and be aware that there is more than one railway station."
|
||||
And I set the field "General feedback" to "The Open University is at the junction of Brickhill Street and Groveway. There are three railway stations, Wolverton, Milton Keynes Central and Bletchley."
|
||||
And I upload "question/type/ddmarker/tests/fixtures/mkmap.png" file to "Background image" filemanager
|
||||
And I expand all fieldsets
|
||||
|
||||
# Markers.
|
||||
And I follow "Markers"
|
||||
And I set the field "id_drags_0_label" to "OU"
|
||||
And I set the field "id_drags_0_noofdrags" to "1"
|
||||
And I set the field "id_drags_1_label" to "Railway station"
|
||||
And I set the field "id_drags_1_noofdrags" to "3"
|
||||
|
||||
# Drop zones.
|
||||
And I follow "Drop zones"
|
||||
And I set the field "id_drops_0_shape" to "Circle"
|
||||
And I set the field "id_drops_0_coords" to "322,213;10"
|
||||
And I set the field "id_drops_0_choice" to "1"
|
||||
|
||||
@@ -40,6 +40,13 @@ body.behat-site {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for MDL-70411.
|
||||
// Pad the side of the message drawer out slightly to ensure that Firefox scroll bar does not cover controls at the
|
||||
// edge of the screen.
|
||||
[data-region="message-drawer"] {
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.phpinfo table,
|
||||
|
||||
@@ -18769,6 +18769,9 @@ body.behat-site .custom-control-input {
|
||||
body.behat-site .custom-control-label::before, body.behat-site .custom-control-label::after {
|
||||
content: none; }
|
||||
|
||||
body.behat-site [data-region="message-drawer"] {
|
||||
padding-right: 10px; }
|
||||
|
||||
.phpinfo table,
|
||||
.phpinfo th,
|
||||
.phpinfo h2 {
|
||||
|
||||
@@ -18950,6 +18950,9 @@ body.behat-site .custom-control-input {
|
||||
body.behat-site .custom-control-label::before, body.behat-site .custom-control-label::after {
|
||||
content: none; }
|
||||
|
||||
body.behat-site [data-region="message-drawer"] {
|
||||
padding-right: 10px; }
|
||||
|
||||
.phpinfo table,
|
||||
.phpinfo th,
|
||||
.phpinfo h2 {
|
||||
|
||||
@@ -17,19 +17,15 @@ Feature: Viewing the list of cohorts to enrol in a course
|
||||
|
||||
@javascript
|
||||
Scenario: Check the teacher does not see the cohorts field without the proper capabilities
|
||||
Given I log in as "admin"
|
||||
Given the following "cohort" exists:
|
||||
| name | Test cohort name |
|
||||
| idnumber | 1337 |
|
||||
| description | Test cohort description |
|
||||
And I log in as "admin"
|
||||
And I set the following system permissions of "Teacher" role:
|
||||
| capability | permission |
|
||||
| moodle/cohort:manage | Prohibit |
|
||||
| moodle/cohort:view | Prohibit |
|
||||
And I navigate to "Users > Accounts >Cohorts" in site administration
|
||||
And I follow "Add new cohort"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test cohort name |
|
||||
| Context | System |
|
||||
| Cohort ID | 1337 |
|
||||
| Description | Test cohort description |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
@@ -40,16 +36,10 @@ Feature: Viewing the list of cohorts to enrol in a course
|
||||
|
||||
@javascript
|
||||
Scenario: Check we show the cohorts field if there are some present
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Accounts >Cohorts" in site administration
|
||||
And I follow "Add new cohort"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test cohort name |
|
||||
| Context | System |
|
||||
| Cohort ID | 1337 |
|
||||
| Description | Test cohort description |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Given the following "cohort" exists:
|
||||
| name | Test cohort name |
|
||||
| idnumber | 1337 |
|
||||
| description | Test cohort description |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to course participants
|
||||
|
||||
Reference in New Issue
Block a user