Merge branch 'MDL-37958_master' of git://github.com/dmonllao/moodle

This commit is contained in:
Eloy Lafuente (stronk7)
2013-03-05 19:28:14 +01:00
7 changed files with 315 additions and 15 deletions
@@ -0,0 +1,65 @@
@tool_behat
Feature: Edit capabilities
In order to extend and restrict moodle features
As an admin or teacher
I need to allow/deny the existing capabilities at different levels
Background:
Given the following "users" exists:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@asd.com |
And the following "courses" exists:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exists:
| user | course | role |
| teacher1 | C1 | editingteacher |
@javascript
Scenario: Default system capabilities modification
Given I log in as "admin"
And I set the following system permissions of "Teacher" role:
| capability | permission |
| block/mnet_hosts:myaddinstance | Allow |
| moodle/community:add | Inherit |
| moodle/grade:managesharedforms | Prevent |
| moodle/course:request | Prohibit |
When I follow "Edit Teacher role"
Then the "block/mnet_hosts:myaddinstance" field should match "1" value
And the "moodle/community:add" field should match "0" value
And the "moodle/grade:managesharedforms" field should match "-1" value
And the "moodle/course:request" field should match "-1000" value
@javascript
Scenario: Course capabilities overrides
Given I log in as "teacher1"
And I follow "Course 1"
And I expand "Users" node
And I follow "Permissions"
And I override the system permissions of "Student" role with:
| mod/forum:deleteanypost | Prohibit |
| mod/forum:editanypost | Prevent |
| mod/forum:addquestion | Allow |
When I select "Student (3)" from "Advanced role override"
Then the "mod/forum:deleteanypost" field should match "-1000" value
And the "mod/forum:editanypost" field should match "-1" value
And the "mod/forum:addquestion" field should match "1" value
@javascript
Scenario: Module capabilities overrides
Given I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on
And I add a "Forum" to section "1" and I fill the form with:
| Forum name | I'm the name |
| Forum introduction | I'm the introduction |
And I follow "I'm the name"
And I follow "Permissions"
And I override the system permissions of "Student" role with:
| mod/forum:deleteanypost | Prohibit |
| mod/forum:editanypost | Prevent |
| mod/forum:addquestion | Allow |
When I select "Student (3)" from "Advanced role override"
Then the "mod/forum:deleteanypost" field should match "-1000" value
And the "mod/forum:editanypost" field should match "-1" value
And the "mod/forum:addquestion" field should match "1" value
@@ -0,0 +1,44 @@
@blocks
Feature: Allowed blocks controls
In order to prevent the use of some blocks
As an admin
I need to restrict some blocks to be used in courses
Background:
Given the following "users" exists:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@asd.com |
And the following "courses" exists:
| fullname | shortname | category |
| Course $NASTYSTRING1 | C1 | 0 |
And the following "course enrolments" exists:
| user | course | role |
| teacher1 | C1 | editingteacher |
@javascript
Scenario: Blocks can be added with the default permissions
Given I log in as "teacher1"
And I follow "Course $NASTYSTRING1"
And I turn editing mode on
When I add the "Course completion status" block
And I add the "Activities" block
Then I should see "Activities"
And I should see "Course completion status"
@javascript
Scenario: Blocks can not be added when the admin restricts the permissions
Given I log in as "admin"
And I set the following system permissions of "Teacher" role:
| block/activity_modules:addinstance | Prohibit |
And I am on homepage
And I follow "Course $NASTYSTRING1"
And I expand "Users" node
And I follow "Permissions"
And I override the system permissions of "Teacher" role with:
| block/completionstatus:addinstance | Prohibit |
And I log out
When I log in as "teacher1"
And I follow "Course $NASTYSTRING1"
And I turn editing mode on
Then the "Add a block" select box should not contain "Activities"
And the "Add a block" select box should not contain "Course completion status"
+15
View File
@@ -196,6 +196,21 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
);
}
/**
* Escapes the double quote character.
*
* Double quote is the argument delimiter, it can be escaped
* with a backslash, but we auto-remove this backslashes
* before the step execution, this method is useful when using
* arguments as arguments for other steps.
*
* @param string $string
* @return string
*/
public function escape($string) {
return str_replace('"', '\"', $string);
}
/**
* Executes the passed closure until returns true or time outs.
*
+1 -1
View File
@@ -29,7 +29,7 @@ use Behat\Mink\Session as Session,
Behat\Mink\Element\NodeElement as NodeElement;
/**
* Representation of a moodle field.
* Representation of a form field.
*
* Basically an interface with Mink session.
*
+45 -12
View File
@@ -219,13 +219,14 @@ class behat_forms extends behat_base {
$fieldnode = $this->find_field($locator);
// Gets the field instance.
// Get the field.
$field = $this->get_field($fieldnode, $locator);
$fieldvalue = $field->get_value();
// Checks if the provided value matches the current field value.
if ($value != $field->get_value()) {
if (trim($value) != trim($fieldvalue)) {
throw new ExpectationException(
'The \'' . $locator . '\' value is \'' . $field->get_value() . '\'' ,
'The \'' . $locator . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected' ,
$this->getSession()
);
}
@@ -299,7 +300,13 @@ class behat_forms extends behat_base {
}
/**
* Gets an instance of the form element field.
* Gets an instance of the form field.
*
* Not all the fields are part of a moodle form, in this
* cases it fallsback to the generic form field. Also note
* that this generic field type is using a generic setValue()
* method from the Behat API, which is not always good to set
* the value of form elements.
*
* @param NodeElement $fieldnode The current node
* @param string $locator Just to send an exception that makes sense for the user
@@ -308,8 +315,16 @@ class behat_forms extends behat_base {
protected function get_field(NodeElement $fieldnode, $locator) {
global $CFG;
// Get the field type.
$type = $this->get_node_type($fieldnode, $locator);
// Get the field type if is part of a moodleform.
if ($this->is_moodleform_field($fieldnode)) {
$type = $this->get_node_type($fieldnode, $locator);
}
// If is not a moodleforms field use the base field type.
if (empty($type)) {
$type = 'field';
}
$classname = 'behat_form_' . $type;
// Fallsback on the default form field if nothing specific exists.
@@ -324,16 +339,34 @@ class behat_forms extends behat_base {
return new $classname($this->getSession(), $fieldnode);
}
/**
* Detects when the field is a moodleform field type.
*
* Note that there are fields inside moodleforms that are not
* moodleform element; this method can not detect this, this will
* be managed by get_node_type, after failing to find the form
* element element type.
*
* @param NodeElement $fieldnode
* @return bool
*/
protected function is_moodleform_field(NodeElement $fieldnode) {
// We already waited when getting the NodeElement and we don't want an exception if it's not part of a moodleform.
$parentformfound = $fieldnode->find('xpath', "/ancestor::form[contains(concat(' ', normalize-space(@class), ' '), ' mform ')]/fieldset");
return ($parentformfound != false);
}
/**
* Recursive method to find the field type.
*
* Depending on the field the felement class node is a level or in another. We
* look recursively for a parent node with a 'felement' class to find the field type.
*
* @throws ExpectationException
* @param NodeElement $fieldnode The current node
* @param string $locator Just to send an exception that makes sense for the user
* @return mixed String or NodeElement depending if we have reached the felement node
* @param NodeElement $fieldnode The current node.
* @param string $locator Just to send an exception that makes sense for the user.
* @return mixed A NodeElement if we continue looking for the element type and String or false when we are done.
*/
protected function get_node_type(NodeElement $fieldnode, $locator) {
@@ -345,9 +378,9 @@ class behat_forms extends behat_base {
return substr($class, 10);
}
// Stop propagation through the DOM, something went wrong!.
// Stop propagation through the DOM, if it does not have a felement is not part of a moodle form.
if (strstr($class, 'fcontainer') != false) {
throw new ExpectationException('No field type for ' . $locator . ' found, ensure the field exists', $this->getSession());
return false;
}
}
+9 -2
View File
@@ -47,9 +47,16 @@ class behat_navigation extends behat_base {
public function i_expand_node($nodetext) {
$xpath = "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]
/child::li
/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]
/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]
|
//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]
/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed'))]
/descendant::li
/descendant::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]
/descendant::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]";
/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]
/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]
";
$node = $this->find('xpath', $xpath);
$node->click();
+136
View File
@@ -0,0 +1,136 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Steps definitions related with permissions.
*
* @package core
* @category test
* @copyright 2013 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../behat/behat_base.php');
use Behat\Mink\Exception\ExpectationException as ExpectationException,
Behat\Behat\Context\Step\Given as Given,
Behat\Gherkin\Node\TableNode as TableNode;
/**
* Steps definitions to set up permissions to capabilities.
*
* @package core
* @category test
* @copyright 2013 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_permissions extends behat_base {
/**
* Set system level permissions to the specified role. Expects a table with capability name and permission (Inherit/Allow/Prevent/Prohibit) columns.
* @Given /^I set the following system permissions of "(?P<rolefullname_string>(?:[^"]|\\")*)" role:$/
* @param string $rolename
* @param TableNode $table
* @return void Executes other steps
*/
public function i_set_the_following_system_permissions_of_role($rolename, $table) {
return array(
new Given('I am on homepage'),
new Given('I expand "Front page settings" node'),
new Given('I expand "Site administration" node'),
new Given('I expand "Users" node'),
new Given('I expand "Permissions" node'),
new Given('I follow "Define roles"'),
new Given('I follow "Edit ' . $this->escape($rolename) . ' role"'),
new Given('I fill the capabilities form with the following permissions:', $table),
new Given('I press "Save changes"')
);
}
/**
* Overrides system capabilities at category, course and module levels. This step begins after clicking 'Permissions' link. Expects a table with capability name and permission (Inherit/Allow/Prevent/Prohibit) columns.
* @Given /^I override the system permissions of "(?P<rolefullname_string>(?:[^"]|\\")*)" role with:$/
* @param string $rolename
* @param TableNode $table
* @return void Executes other steps
*/
public function i_override_the_system_permissions_of_role_with($rolename, $table) {
// We don't know the number of overrides so we have to get it to match the option contents.
$roleoption = $this->find('xpath', '//select[@name="roleid"]/option[contains(text(),"' . $this->escape($rolename) . '")]');
return array(
new Given('I select "' . $this->escape($roleoption->getText()) . '" from "Advanced role override"'),
new Given('I fill the capabilities form with the following permissions:', $table),
new Given('I press "Save changes"')
);
}
/**
* 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('Show advanced');
if ($advancedtoggle) {
$this->getSession()->getPage()->pressButton('Show advanced');
}
} 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 exists.
$radio = $this->find('xpath', '//input[@name="' . $capability . '" and @value="' . $permissionvalue . '"]');
$radio->click();
}
}
}