first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
@core @core_admin
Feature: Staff can assign user roles
In order to assign users to roles at site or activity module level
As an admin
I can add and remove users from the roles
Background:
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | frog | Favourite frog |
And the following config values are set as admin:
| showuseridentity | email,profile_field_frog |
And the following "users" exist:
| username | firstname | lastname | email | profile_field_frog |
| user1 | User | One | one@example.com | Kermit |
| user2 | User | Two | two@example.com | Tree |
And the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | student |
And the following "activities" exist:
| activity | name | course | idnumber |
| page | TestPage | C1 | page1 |
@javascript
Scenario: Enrol at system level using custom field search
When I am on the "C1" "Course" page logged in as "admin"
And I navigate to "Users > Permissions > Assign system roles" in site administration
And I follow "Manager"
And I set the field "addselect_searchtext" to "Kermit"
# The Behat 'I should see' step doesn't work for optgroup labels.
Then "optgroup[label*='Potential users matching'][label*=' (1)']" "css_element" should exist
And I set the field "addselect" to "User One (one@example.com, Kermit)"
And I press "Add"
And I should see "User One" in the "#removeselect" "css_element"
@javascript
Scenario: Unenrol at system level using custom field search
Given the following "role assigns" exist:
| user | role | contextlevel | reference |
| user1 | manager | System | |
When I am on the "C1" "Course" page logged in as "admin"
And I navigate to "Users > Permissions > Assign system roles" in site administration
And I follow "Manager"
And I set the field "removeselect_searchtext" to "Kermit"
# The Behat 'I should see' step doesn't work for optgroup labels.
Then "optgroup[label*='Existing users matching'][label*=' (1)']" "css_element" should exist
And I set the field "removeselect" to "User One (one@example.com, Kermit)"
And I press "Remove"
And I should not see "User One" in the "#removeselect" "css_element"
@javascript
Scenario: Enrol at activity level using custom field search
When I am on the "page1" "Activity" page logged in as "admin"
And I navigate to "Permissions" in current page administration
And I set the field "Participants tertiary navigation" to "Locally assigned roles"
And I follow "Teacher"
And I set the field "addselect_searchtext" to "Kermit"
# The Behat 'I should see' step doesn't work for optgroup labels.
Then "optgroup[label*='Potential users matching'][label*=' (1)']" "css_element" should exist
And I set the field "addselect" to "User One (one@example.com, Kermit)"
And I press "Add"
And I should see "User One" in the "#removeselect" "css_element"
@javascript
Scenario: Unenrol at activity level using custom field search
Given the following "role assigns" exist:
| user | role | contextlevel | reference |
| user1 | editingteacher | Activity module | page1 |
When I am on the "page1" "Activity" page logged in as "admin"
And I navigate to "Permissions" in current page administration
And I set the field "Participants tertiary navigation" to "Locally assigned roles"
And I follow "Teacher"
And I set the field "removeselect_searchtext" to "Kermit"
# The Behat 'I should see' step doesn't work for optgroup labels.
Then "optgroup[label*='Users in this Activity module matching'][label*=' (1)']" "css_element" should exist
And I set the field "removeselect" to "User One (one@example.com, Kermit)"
And I press "Remove"
And I should not see "User One" in the "#removeselect" "css_element"
+132
View File
@@ -0,0 +1,132 @@
<?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 administration.
*
* @package core_admin
* @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__ . '/../../../lib/behat/behat_base.php');
require_once(__DIR__ . '/../../../lib/behat/behat_field_manager.php');
use Behat\Gherkin\Node\TableNode as TableNode,
Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
/**
* Site administration level steps definitions.
*
* @package core_admin
* @category test
* @copyright 2013 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_admin extends behat_base {
/**
* 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) {
// Navigate straight to the search results fo rthis label.
$this->execute('behat_general::i_visit', ["/admin/search.php?query=" . urlencode($label)]);
// 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);
} 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::*[self::input | self::textarea | self::select]" .
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
}
$this->execute('behat_forms::i_set_the_field_with_xpath_to', [$fieldxpath, $value]);
$this->execute("behat_general::i_click_on", [get_string('savechanges'), 'button']);
}
}
/**
* Sets the specified site settings. A table with | config | value | (optional)plugin | (optional)encrypted | is expected.
*
* @Given /^the following config values are set as admin:$/
* @param TableNode $table
*/
public function the_following_config_values_are_set_as_admin(TableNode $table) {
if (!$data = $table->getRowsHash()) {
return;
}
foreach ($data as $config => $value) {
// Default plugin value is null.
$plugin = null;
$encrypted = false;
if (is_array($value)) {
$plugin = $value[1];
if (array_key_exists(2, $value)) {
$encrypted = $value[2] === 'encrypted';
}
$value = $value[0];
}
if ($encrypted) {
$value = \core\encryption::encrypt($value);
}
set_config($config, $value, $plugin);
}
}
/**
* Waits with the provided params if we are running a JS session.
*
* @param int $timeout
* @param string $javascript
* @return void
*/
protected function wait($timeout, $javascript = false) {
if ($this->running_javascript()) {
$this->getSession()->wait($timeout, $javascript);
}
}
}
+223
View File
@@ -0,0 +1,223 @@
@core @core_admin @core_reportbuilder
Feature: An administrator can browse user accounts
In order to find the user accounts I am looking for
As an admin
I can browse users and see their basic information
Background:
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | frog | Favourite frog |
And the following "users" exist:
| username | firstname | lastname | email | department | profile_field_frog | firstnamephonetic |
| user1 | User | One | one@example.com | Attack | Kermit | Yewzer |
| user2 | User | Two | two@example.com | Defence | Tree | Yoozare |
And I log in as "admin"
Scenario: User accounts display default fields
When I navigate to "Users > Accounts > Browse list of users" in site administration
# Name field always present, email field is default for showidentity.
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
# Should not see other identity fields or non-default name fields.
And I should not see "Department" in the "reportbuilder-table" "table"
And I should not see "Attack" in the "reportbuilder-table" "table"
And I should not see "Favourite frog" in the "reportbuilder-table" "table"
And I should not see "Kermit" in the "reportbuilder-table" "table"
And I should not see "First name - phonetic" in the "reportbuilder-table" "table"
And I should not see "Yoozare" in the "reportbuilder-table" "table"
Scenario: User accounts with extra name fields
Given the following config values are set as admin:
| alternativefullnameformat | firstnamephonetic lastname |
When I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name - phonetic | Email address |
| Yewzer One | one@example.com |
| Yoozare Two | two@example.com |
Scenario: User accounts with specified identity fields
Given the following config values are set as admin:
| showuseridentity | department,profile_field_frog |
When I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Favourite frog | Department |
| User One | Kermit | Attack |
| User Two | Tree | Defence |
And I should not see "Email address" in the "table" "css_element"
And I should not see "one@example.com"
@javascript
Scenario: Sort user accounts by custom profile field
Given the following config values are set as admin:
| showuseridentity | profile_field_frog |
When I navigate to "Users > Accounts > Browse list of users" in site administration
And I follow "Favourite frog"
Then "Kermit" "text" should appear before "Tree" "text"
And I follow "Favourite frog"
Then "Tree" "text" should appear before "Kermi" "text"
@javascript
Scenario: Edit user information
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Edit" action in the "User One" report row
And I set the field "Last name" to "OneOne"
And I press "Update profile"
Then I should see "User OneOne"
@javascript
Scenario: Suspend and activate user account
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Suspend user account" action in the "User One" report row
And I should see "Suspended" in the "User One" "table_row"
And I press "Activate user account" action in the "User One" report row
Then I should not see "Suspended" in the "User One" "table_row"
@javascript
Scenario: Delete a user account
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Delete" action in the "User One" report row
And I should see "Are you absolutely sure you want to completely delete the user User One" in the "Delete user" "dialogue"
And I click on "Delete" "button" in the "Delete user" "dialogue"
Then I should see "Deleted user User One"
And I should not see "User One" in the "reportbuilder-table" "table"
@javascript
Scenario: Resend email and confirm a user account
Given the following "users" exist:
| username | firstname | lastname | email | confirmed |
| user3 | User | Three | three@example.com | 0 |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "Confirmation pending" in the "User Three" "table_row"
And I press "Resend confirmation email" action in the "User Three" report row
And I should see "Confirmation email sent successfully"
And I press "Confirm" action in the "User Three" report row
And I should not see "Confirmation pending" in the "User Three" "table_row"
@javascript
Scenario: User report filters
Given the following "users" exist:
| username | firstname | lastname | email | profile_field_frog |
| user3 | User | Three | three@example.com | Glass |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
| User Three | three@example.com |
And I click on "Filters" "button"
And I set the following fields in the "Last name" "core_reportbuilder > Filter" to these values:
| Last name operator | Is equal to |
| Last name value | Three |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
| Favourite frog operator | Is equal to |
| Favourite frog value | Kermit |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
@javascript
Scenario: User report enrolled in any course filter
Given the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
And the following "course enrolments" exist:
| user | course | role |
| user2 | C1 | student |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
And I click on "Filters" "button"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | Yes |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
@javascript
Scenario: User report system role and course role filters
Given the following "users" exist:
| username | firstname | lastname | email |
| user3 | User | Three | three@example.com |
And the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | editingteacher |
| user3 | C1 | student |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| user1 | coursecreator | system | |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
| User Three | three@example.com |
And I click on "Filters" "button"
And I set the following fields in the "System role" "core_reportbuilder > Filter" to these values:
| System role operator | Is equal to |
| System role value | Course creator |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
| Role name | Teacher |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
Scenario: Add a new user
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I click on "Add a new user" "link"
Then I should see "Username"
And I should see "User picture"
And I should see "Additional names"
@javascript
Scenario: Browse user list as a person with limited capabilities
Given the following "users" exist:
| username | firstname | lastname | email |
| manager | Max | Manager | manager@example.com |
And the following "roles" exist:
| name | shortname | description | archetype |
| Custom manager | custom1 | My custom role 1 | |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/site:configview | Allow | custom1 | System | |
| moodle/user:update | Allow | custom1 | System | |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| manager | custom1 | System | |
When I log in as "manager"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I click on "User One" "checkbox"
And the "Bulk user actions" select box should contain "Confirm"
And the "Bulk user actions" select box should not contain "Delete"
And I set the field "Bulk user actions" to "Force password change"
And I should see "Are you absolutely sure you want to force a password change to User One ?"
And I press "Yes"
And I press "Continue"
And I should see "Browse list of users"
+54
View File
@@ -0,0 +1,54 @@
@core @core_admin
Feature: Staff can check user permissions
In order to find out whether a user can or can't do something
As an admin
I can check their permissions in a particular context
Background:
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | frog | Favourite frog |
And the following config values are set as admin:
| showuseridentity | email,profile_field_frog |
And the following "users" exist:
| username | firstname | lastname | email | profile_field_frog |
| user1 | User | One | one@example.com | Kermit |
| user2 | User | Two | two@example.com | Tree |
| user3 | User | Three | thr@example.com | Kermit |
And the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
| C2 | Course 2 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | editingteacher |
| user2 | C1 | editingteacher |
| user3 | C2 | editingteacher |
@javascript
Scenario: Search for a user (enrolled on the course) by custom field and select them to see permissions
When I am on the "C1" "permissions" page logged in as "admin"
And I set the field "Participants tertiary navigation" to "Check permissions"
And I set the field "Search" to "Kermit"
# The Behat 'I should see' step doesn't work for optgroup labels.
Then "optgroup[label='Matching enrolled users (1)']" "css_element" should exist
And I should see "User One (one@example.com, Kermit)"
And I should not see "User Two"
And I set the field "reportuser" to "User One (one@example.com, Kermit)"
And I press "Show this user's permissions"
And I should see "Permissions for user User One"
And I should see "Yes" in the "Add a new forum" "table_row"
@javascript
Scenario: Search for a user (not enrolled on the course) by custom field and select them to see permissions
When I am on the "C1" "permissions" page logged in as "admin"
And I set the field "Participants tertiary navigation" to "Check permissions"
And I set the field "Search" to "Kermit"
# The Behat 'I should see' step doesn't work for optgroup labels.
Then "optgroup[label*='Potential users matching'][label*=' (1)']" "css_element" should exist
And I should see "User Three (thr@example.com, Kermit)"
And I should not see "User Two"
And I set the field "reportuser" to "User Three (thr@example.com, Kermit)"
And I press "Show this user's permissions"
Then I should see "Permissions for user User Three"
And I should see "No" in the "Add a new forum" "table_row"
@@ -0,0 +1,23 @@
@core @core_admin
Feature: Display extended course names
In order to display more info about the courses
As an admin
I need to display courses short names along with courses full names
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course fullname | C_shortname | 0 |
And I log in as "admin"
And I am on site homepage
Scenario: Courses list without extended course names (default value)
Then I should see "Course fullname"
And I should not see "C_shortname Course fullname"
Scenario: Courses list with extended course names
Given I navigate to "Appearance > Courses" in site administration
And I set the field "Display extended course names" to "1"
When I press "Save changes"
And I am on site homepage
Then I should see "C_shortname Course fullname"
@@ -0,0 +1,72 @@
@core @core_admin @core_user
Feature: Allowing multiple accounts to have the same email address
In order to manage user accounts
As an admin
I need to be able to set whether to allow multiple accounts with the same email or not
Scenario Outline: Create a user with the same email as an existing user
Given the following config values are set as admin:
| allowaccountssameemail | <allowsameemail> |
And the following "users" exist:
| username | firstname | lastname | email |
| s1 | John | Doe | s1@example.com |
When I log in as "admin"
And I navigate to "Users > Accounts > Add a new user" in site administration
And I set the following fields to these values:
| Username | s2 |
| First name | Jane |
| Last name | Doe |
| Email address | <email> |
| New password | test |
And I press "Create user"
Then I should <expect> "This email address is already registered."
Examples:
| allowsameemail | email | expect |
| 0 | s1@example.com | see |
| 0 | S1@EXAMPLE.COM | see |
| 1 | s1@example.com | not see |
| 1 | S1@EXAMPLE.COM | not see |
Scenario Outline: Update a user with the same email as an existing user
Given the following config values are set as admin:
| allowaccountssameemail | <allowsameemail> |
And the following "users" exist:
| username | firstname | lastname | email |
| s1 | John | Doe | s1@example.com |
| s2 | Jane | Doe | s2@example.com |
When I am on the "s2" "user > editing" page logged in as "admin"
And I set the field "Email address" to "<email>"
And I press "Update profile"
Then I should <expect> "This email address is already registered."
Examples:
| allowsameemail | email | expect |
| 0 | s1@example.com | see |
| 0 | S1@EXAMPLE.COM | see |
| 1 | s1@example.com | not see |
| 1 | S1@EXAMPLE.COM | not see |
| 0 | S2@EXAMPLE.COM | not see |
| 1 | S2@EXAMPLE.COM | not see |
Scenario Outline: Update own user profile with the same email as an existing user
Given the following config values are set as admin:
| allowaccountssameemail | <allowsameemail> |
And the following "users" exist:
| username | firstname | lastname | email |
| s1 | John | Doe | s1@example.com |
| s2 | Jane | Doe | s2@example.com |
When I log in as "s2"
And I open my profile in edit mode
And I set the field "Email address" to "<email>"
And I press "Update profile"
Then I should <expect> "This email address is already registered."
Examples:
| allowsameemail | email | expect |
| 0 | s1@example.com | see |
| 0 | S1@EXAMPLE.COM | see |
| 1 | s1@example.com | not see |
| 1 | S1@EXAMPLE.COM | not see |
| 0 | S2@EXAMPLE.COM | not see |
| 1 | S2@EXAMPLE.COM | not see |
+182
View File
@@ -0,0 +1,182 @@
@core @core_admin @core_reportbuilder
Feature: An administrator can filter user accounts by role, cohort and other profile fields
In order to find the user accounts I am looking for
As an admin
I need to filter the users account list using different filter
Background:
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | frog | Favourite frog |
| text | undead | Type of undead |
And the following "users" exist:
| username | firstname | lastname | email | auth | confirmed | lastip | institution | department | profile_field_frog | profile_field_undead |
| user1 | User | One | one@example.com | manual | 0 | 127.0.1.1 | moodle | red | Kermit | |
| user2 | User | Two | two@example.com | ldap | 1 | 0.0.0.0 | moodle | blue | Mr Toad | Zombie |
| user3 | User | Three | three@example.com | manual | 1 | 0.0.0.0 | | | | |
| user4 | User | Four | four@example.com | ldap | 0 | 127.0.1.2 | | | | |
And the following "cohorts" exist:
| name | idnumber |
| Cohort 1 | CH1 |
And the following "cohort members" exist:
| user | cohort |
| user2 | CH1 |
| user3 | CH1 |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | student |
| user3 | C1 | student |
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
@javascript
Scenario: Filter user accounts by role and cohort
When I click on "Filters" "button"
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
| Role name | Student |
| Course short name | C1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Cohort ID" "core_reportbuilder > Filter" to these values:
| Cohort ID operator | Is equal to |
| Cohort ID value | CH1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter user accounts by confirm and authentication method
When I click on "Filters" "button"
And I set the following fields in the "Confirmed" "core_reportbuilder > Filter" to these values:
| Confirmed operator | No |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Authentication" "core_reportbuilder > Filter" to these values:
| Authentication operator | Is equal to |
| Authentication value | Manual accounts |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter user accounts by enrolled in any course
When I click on "Filters" "button"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | Yes |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | No |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter user accounts by last IP address
When I click on "Filters" "button"
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
| Last IP address operator | Is equal to |
| Last IP address value | 127.0.1.1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
| Last IP address operator | Is equal to |
| Last IP address value | 127.0.1.2 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter users by institution and department
When I click on "Filters" "button"
And I set the following fields in the "Institution" "core_reportbuilder > Filter" to these values:
| Institution operator | Is equal to |
| Institution value | moodle |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Department" "core_reportbuilder > Filter" to these values:
| Department operator | Is equal to |
| Department value | red |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter users by custom profile field (specific or any)
When I click on "Filters" "button"
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
| Favourite frog operator | Is equal to |
| Favourite frog value | Kermit |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Type of undead" "core_reportbuilder > Filter" to these values:
| Type of undead operator | Is equal to |
| Type of undead value | Zombie |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter users by full name
When I click on "Filters" "button"
And I set the following fields in the "Full name" "core_reportbuilder > Filter" to these values:
| Full name operator | Is equal to |
| Full name value | User One |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Full name" "core_reportbuilder > Filter" to these values:
| Full name operator | Is equal to |
| Full name value | User Two |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
@@ -0,0 +1,29 @@
@core @core_admin
Feature: Administrator is warned and when trying to set invalid allcountrycodes value.
In order to avoid misconfiguration of the country selector fields
As an admin
I want to be warned when I try to set an invalid country code in the allcountrycodes field
Scenario: Attempting to set allcountrycodes field with valid country codes
Given I log in as "admin"
And I navigate to "Location > Location settings" in site administration
When I set the following administration settings values:
| All country codes | CZ,BE,GB,ES |
Then I should not see "Invalid country code"
Scenario: Attempting to set allcountrycodes field with invalid country code
Given I log in as "admin"
And I navigate to "Location > Location settings" in site administration
When I set the following administration settings values:
| All country codes | CZ,BE,FOOBAR,GB,ES |
Then I should see "Invalid country code: FOOBAR"
Scenario: Attempting to unset allcountrycodes field
Given I log in as "admin"
And I navigate to "Location > Location settings" in site administration
And I set the following administration settings values:
| All country codes | CZ,BE,GB,ES |
And I navigate to "Location > Location settings" in site administration
When I set the following administration settings values:
| All country codes | |
Then I should not see "Invalid country code"
@@ -0,0 +1,34 @@
@core @core_admin
Feature: Configure language settings for the site
In order to configure language settings for the site
As an admin
I want to set language settings relevant to my site users
Scenario: Set languages on language menu
Given I log in as "admin"
And I navigate to "Language > Language settings" in site administration
When I set the field "Languages on language menu" to "en"
And I press "Save changes"
Then I should not see "Invalid language code"
Scenario: Reset languages on language menu
Given I log in as "admin"
And I navigate to "Language > Language settings" in site administration
When I set the field "Languages on language menu" to ""
And I press "Save changes"
Then I should not see "Invalid language code"
Scenario Outline: Set languages on language menu with invalid language
Given I log in as "admin"
And I navigate to "Language > Language settings" in site administration
When I set the field "Languages on language menu" to "<fieldvalue>"
And I press "Save changes"
Then I should see "Invalid language code: <invalidlang>"
Examples:
| fieldvalue | invalidlang |
| xx | xx |
| xx\|Bad | xx |
| en,qq | qq |
| en,qq\|Bad | qq |
| en$$ | en$$ |
| en$$\|Bad | en$$ |
+59
View File
@@ -0,0 +1,59 @@
@core @core_admin
Feature: An administrator can manage Block plugins
In order to alter the user experience
As an admin
I can manage block plugins
@javascript
Scenario: An administrator can control the enabled state of block plugins using JavaScript
Given I am logged in as "admin"
And I navigate to "Plugins > Blocks > Manage blocks" in site administration
When I click on "Disable Latest badges" "link"
Then I should see "Latest badges disabled."
And "Disable Latest badges" "link" should not exist
But "Enable Latest badges" "link" should exist
When I click on "Enable Latest badges" "link"
Then I should see "Latest badges enabled."
And "Enable Latest badges" "link" should not exist
But "Disable Latest badges" "link" should exist
Scenario: An administrator can control the enabled state of block plugins without JavaScript
Given I am logged in as "admin"
And I navigate to "Plugins > Blocks > Manage blocks" in site administration
When I click on "Disable Latest badges" "link"
Then I should see "Latest badges disabled."
And "Disable Latest badges" "link" should not exist
But "Enable Latest badges" "link" should exist
When I click on "Enable Latest badges" "link"
Then I should see "Latest badges enabled."
And "Enable Latest badges" "link" should not exist
But "Disable Latest badges" "link" should exist
@javascript
Scenario: An administrator can control the protected state of block plugins using JavaScript
Given I am logged in as "admin"
And I navigate to "Plugins > Blocks > Manage blocks" in site administration
When I click on "Protect instances of Latest badges" "link"
Then I should see "Latest badges block instances are protected."
And "Protect instances of Latest badges" "link" should not exist
But "Unprotect instances of Latest badges" "link" should exist
And "Protect instances of Activities" "link" should exist
When I click on "Unprotect instances of Latest badges" "link"
Then I should see "Latest badges block instances are unprotected."
And "Unprotect instances of Activities" "link" should not exist
But "Protect instances of Latest badges" "link" should exist
And "Protect instances of Activities" "link" should exist
Scenario: An administrator can control the protected state of block plugins without JavaScript
Given I am logged in as "admin"
And I navigate to "Plugins > Blocks > Manage blocks" in site administration
When I click on "Protect instances of Latest badges" "link"
Then I should see "Latest badges block instances are protected."
And "Protect instances of Latest badges" "link" should not exist
But "Unprotect instances of Latest badges" "link" should exist
And "Protect instances of Activities" "link" should exist
When I click on "Unprotect instances of Latest badges" "link"
Then I should see "Latest badges block instances are unprotected."
And "Unprotect instances of Activities" "link" should not exist
But "Protect instances of Latest badges" "link" should exist
And "Protect instances of Activities" "link" should exist
+30
View File
@@ -0,0 +1,30 @@
@core @core_admin
Feature: An administrator can manage Media plugins
In order to alter the user experience
As an admin
I can manage media plugins
@javascript
Scenario: An administrator can control the enabled state of media plugins using JavaScript
Given I am logged in as "admin"
And I navigate to "Plugins > Media players > Manage media players" in site administration
When I click on "Disable YouTube" "link"
Then I should see "YouTube disabled."
And "Disable YouTube" "link" should not exist
But "Enable YouTube" "link" should exist
When I click on "Enable YouTube" "link"
Then I should see "YouTube enabled."
And "Enable YouTube" "link" should not exist
But "Disable YouTube" "link" should exist
Scenario: An administrator can control the enabled state of media plugins without JavaScript
Given I am logged in as "admin"
And I navigate to "Plugins > Media players > Manage media players" in site administration
When I click on "Disable YouTube" "link"
Then I should see "YouTube disabled."
And "Disable YouTube" "link" should not exist
But "Enable YouTube" "link" should exist
When I click on "Enable YouTube" "link"
Then I should see "YouTube enabled."
And "Enable YouTube" "link" should not exist
But "Disable YouTube" "link" should exist
+103
View File
@@ -0,0 +1,103 @@
@core @core_admin
Feature: Manage external services tokens
In order to manage external service usage
As an admin
I need to be able to create, filter and delete tokens
Background:
Given the following "users" exist:
| username | password | firstname | lastname |
| user1 | user1 | Firstname1 | Lastname1 |
| user2 | user2 | Firstname2 | Lastname2 |
| user3 | user3 | Firstname3 | Lastname3 |
| user4 | user4 | Firstname4 | Lastname4 |
And I change window size to "small"
@javascript
Scenario: Add a token to user identified by name and then delete that token
Given I log in as "admin"
And I am on site homepage
And I navigate to "Server > Web services > Manage tokens" in site administration
And I press "Create token"
And I set the field "Name" to "Webservice1"
And I set the field "User" to "Firstname1 Lastname1"
And I set the field "Service" to "Moodle mobile web service"
And I set the field "IP restriction" to "127.0.0.1"
When I press "Save changes"
Then the following should exist in the "generaltable" table:
| Name | First name | Service | IP restriction | Last access |
| Webservice1 | Firstname1 Lastname1 | Moodle mobile web service | 127.0.0.1 | Never |
# Verify the message and the "Copy to clipboard" button.
And I should see "Copy the token now. It won't be shown again once you leave this page."
And "Copy to clipboard" "button" should exist
# New token can only read once.
And I reload the page
And I should not see "Copy the token now. It won't be shown again once you leave this page."
And "Copy to clipboard" "button" should not exist
# Delete token.
And I click on "Delete" "link" in the "Webservice1" "table_row"
And I should see "Do you really want to delete this web service token for Firstname1 Lastname1 on the service Moodle mobile web service?"
And I press "Delete"
And "Webservice1" "table_row" should not exist
@javascript @skip_chrome_zerosize
Scenario: Tokens can be filtered by name (case-insensitive), by user and by service
Given the following "core_webservice > Service" exists:
| name | Site information |
| shortname | siteinfo |
| enabled | 1 |
And the following "core_webservice > Service function" exists:
| service | siteinfo |
| functions | core_webservice_get_site_info |
And the following "core_webservice > Tokens" exist:
| user | service | name |
| user2 | siteinfo | WEBservice1 |
| user3 | moodle_mobile_app | webservicE3 |
| user4 | siteinfo | New service2 |
When I log in as "admin"
And I navigate to "Server > Web services > Manage tokens" in site administration
# All created tokens are shown by default.
And "Firstname1 Lastname1" "table_row" should not exist
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
And I should see "Moodle mobile web service" in the "Firstname3 Lastname3" "table_row"
And I should see "Site information" in the "Firstname4 Lastname4" "table_row"
# Filter tokens by by name (case-insensitive).
And I click on "Tokens filter" "link"
And I set the field "Name" to "webservice"
And I press "Show only matching tokens"
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
And I should see "Moodle mobile web service" in the "Firstname3 Lastname3" "table_row"
And "Firstname4 Lastname4" "table_row" should not exist
# Reset the filter.
And I press "Show all tokens"
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
And I should see "Moodle mobile web service" in the "Firstname3 Lastname3" "table_row"
And I should see "Site information" in the "Firstname4 Lastname4" "table_row"
# Filter tokens by user (note we can select the user by the identity field here).
When I click on "Tokens filter" "link"
And I set the field "User" to "user2@example.com"
And I press "Show only matching tokens"
Then "Firstname3 Lastname3" "table_row" should not exist
And "Firstname4 Lastname4" "table_row" should not exist
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
# Reset the filter.
And I press "Show all tokens"
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
And I should see "Moodle mobile web service" in the "Firstname3 Lastname3" "table_row"
And I should see "Site information" in the "Firstname4 Lastname4" "table_row"
# Filter tokens by service.
And I click on "Tokens filter" "link"
And I set the field "Service" to "Site information"
And I press "Show only matching tokens"
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
And I should see "Site information" in the "Firstname4 Lastname4" "table_row"
And "Firstname3 Lastname3" "table_row" should not exist
@@ -0,0 +1,52 @@
@core @core_admin
Feature: MoodleNet outbound configuration
In order to send activity/resource to MoodleNet
As a Moodle administrator
I need to set outbound configuration
Background:
Given I log in as "admin"
Scenario: Share to MoodleNet experimental flag
Given I navigate to "Development > Experimental" in site administration
Then "Enable sharing to MoodleNet" "field" should exist
And the field "Enable sharing to MoodleNet" matches value "0"
Scenario: Outbound configuration without experimental flag enable yet
Given I navigate to "MoodleNet" in site administration
Then I should not see "MoodleNet outbound settings"
Scenario: Outbound configuration without OAuth 2 service setup yet
Given the following config values are set as admin:
| enablesharingtomoodlenet | 1 |
When I navigate to "MoodleNet" in site administration
Then I should see "MoodleNet outbound settings"
And I click on "MoodleNet outbound settings" "link"
And the field "OAuth 2 service" matches value "None"
And I should see "Select a MoodleNet OAuth 2 service to enable sharing to that MoodleNet site. If the service doesn't exist yet, you will need to create it."
And I click on "create" "link"
And I should see "OAuth 2 services"
Scenario: Outbound configuration with OAuth 2 service setup
Given a MoodleNet mock server is configured
And the following config values are set as admin:
| enablesharingtomoodlenet | 1 |
And I navigate to "Server > OAuth 2 services" in site administration
And I press "Custom"
And I should see "Create new service: Custom"
And I set the following fields to these values:
| Name | Testing custom service |
| Client ID | thisistheclientid |
| Client secret | supersecret |
And I press "Save changes"
When I navigate to "MoodleNet > MoodleNet outbound settings" in site administration
Then the field "OAuth 2 service" matches value "None"
And I navigate to "Server > OAuth 2 services" in site administration
And I press "MoodleNet"
And I should see "Create new service: MoodleNet"
And I change the MoodleNet field "Service base URL" to mock server
And I press "Save changes"
And I navigate to "MoodleNet > MoodleNet outbound settings" in site administration
And the "OAuth 2 service" "field" should be enabled
And I should see "MoodleNet" in the "OAuth 2 service" "select"
And I should not see "Testing custom service" in the "OAuth 2 service" "select"
+29
View File
@@ -0,0 +1,29 @@
@core @core_admin
Feature: Outgoing mail configuration
In order to send email from Moodle
As a Moodle administrator
I need to set mail configuration
Background:
Given I log in as "admin"
Scenario: SMTP Auth Type without OAuth 2 service setup yet
Given I navigate to "Server > Email > Outgoing mail configuration" in site administration
And I should not see "XOAUTH2" in the "SMTP Auth Type" "select"
And I should see "LOGIN" in the "SMTP Auth Type" "select"
And I should see "PLAIN" in the "SMTP Auth Type" "select"
Scenario: SMTP Auth Type with OAuth 2 service setup
Given I navigate to "Server > OAuth 2 services" in site administration
And I press "Google"
And I should see "Create new service: Google"
And I set the following fields to these values:
| Name | Testing service |
| Client ID | thisistheclientid |
| Client secret | supersecret |
And I press "Save changes"
When I navigate to "Server > Email > Outgoing mail configuration" in site administration
Then I should see "XOAUTH2" in the "SMTP Auth Type" "select"
And I should see "LOGIN" in the "SMTP Auth Type" "select"
And I should see "PLAIN" in the "SMTP Auth Type" "select"
And I should see "Testing service" in the "OAuth 2 service" "select"
+34
View File
@@ -0,0 +1,34 @@
@core @core_admin
Feature: Purge caches
In order to see changes to cached data
As a Moodle administrator
I want manually purge different data and file caches
Background:
Given I log in as "admin"
And I navigate to "Development > Purge caches" in site administration
Scenario: Purge all caches
Given I should not see "All caches were purged"
When I press "Purge all caches"
Then I should see "All caches were purged"
Scenario: Purge selected caches
Given I should not see "Selected caches were purged"
When I set the field "Themes" to "1"
And I click on "Purge selected caches" "button" in the "#fitem_id_purgeselectedcaches" "css_element"
Then I should see "The selected caches were purged"
Scenario: Purge selected caches without selecting any caches
Given I should not see "Select one or more caches to purge"
And I click on "Purge selected caches" "button" in the "#fitem_id_purgeselectedcaches" "css_element"
Then I should not see "The selected caches were purged"
And I should see "Select one or more caches to purge"
Scenario: Redirect back to the original page after following a Purge all caches link
Given I am on site homepage
And I should see "Available courses"
And I should not see "All caches were purged"
When I follow "Purge all caches"
Then I should see "All caches were purged"
And I should see "Available courses"
+113
View File
@@ -0,0 +1,113 @@
@core @core_admin @core_course @javascript
Feature: Reset course indentation
In order to reset indentation in course modules
As a admin
I want change indent value for all the modules of a course format courses in one go
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Sections Course 1 | T1 | topics |
| Sections Course 2 | T2 | topics |
| Weekly Course 1 | W1 | weeks |
| Weekly Course 2 | W2 | weeks |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| forum | Sections forum name | Sections forum description | T1 | forum1 |
| data | Sections database name | Sections database description | T1 | data1 |
| wiki | Sections wiki name | Sections wiki description | T2 | wiki1 |
| forum | Weekly forum name | Weekly forum description | W1 | forum2 |
| data | Weekly database name | Weekly database description | W1 | data2 |
| wiki | Weekly wiki name | Weekly wiki description | W2 | wiki2 |
And I log in as "admin"
And I am on "Sections Course 1" course homepage with editing mode on
And I open "Sections forum name" actions menu
And I click on "Move right" "link" in the "Sections forum name" activity
And I open "Sections forum name" actions menu
And "Move right" "link" in the "Sections forum name" "activity" should not be visible
And "Move left" "link" in the "Sections forum name" "activity" should be visible
And I press the escape key
And I open "Sections database name" actions menu
And "Move right" "link" in the "Sections database name" "activity" should be visible
And "Move left" "link" in the "Sections database name" "activity" should not be visible
And I am on "Sections Course 2" course homepage with editing mode on
And I open "Sections wiki name" actions menu
And I click on "Move right" "link" in the "Sections wiki name" activity
And I open "Sections wiki name" actions menu
And "Move right" "link" in the "Sections wiki name" "activity" should not be visible
And "Move left" "link" in the "Sections wiki name" "activity" should be visible
And I am on "Weekly Course 1" course homepage with editing mode on
And I open "Weekly forum name" actions menu
And I click on "Move right" "link" in the "Weekly forum name" activity
And I open "Weekly forum name" actions menu
And "Move right" "link" in the "Weekly forum name" "activity" should not be visible
And "Move left" "link" in the "Weekly forum name" "activity" should be visible
And I press the escape key
And I open "Weekly database name" actions menu
And "Move right" "link" in the "Weekly database name" "activity" should be visible
And "Move left" "link" in the "Weekly database name" "activity" should not be visible
And I am on "Weekly Course 2" course homepage with editing mode on
And I open "Weekly wiki name" actions menu
And I click on "Move right" "link" in the "Weekly wiki name" activity
And I open "Weekly wiki name" actions menu
And "Move right" "link" in the "Weekly wiki name" "activity" should not be visible
And "Move left" "link" in the "Weekly wiki name" "activity" should be visible
Scenario Outline: Apply course indentation reset
Given I navigate to "Plugins > Course formats > <format>" in site administration
And I wait "5" seconds
And "Reset indentation sitewide" "link" should exist
When I click on "Reset indentation sitewide" "link"
And I should see "Reset indentation sitewide"
And "Reset indentation sitewide" "button" should exist
And I click on "Reset indentation sitewide" "button"
Then I should see "Indentation reset."
And I am on "<prefix> Course 1" course homepage with editing mode on
And I open "<prefix> forum name" actions menu
And "Move right" "link" in the "<prefix> forum name" "activity" should be visible
And "Move left" "link" in the "<prefix> forum name" "activity" should not be visible
And I press the escape key
And I open "<prefix> database name" actions menu
And "Move right" "link" in the "<prefix> database name" "activity" should be visible
And "Move left" "link" in the "<prefix> database name" "activity" should not be visible
And I am on "<prefix> Course 2" course homepage with editing mode on
And I open "<prefix> wiki name" actions menu
And "Move right" "link" in the "<prefix> wiki name" "activity" should be visible
And "Move left" "link" in the "<prefix> wiki name" "activity" should not be visible
# Check other course formats had not been reset
And I am on "<other> Course 1" course homepage with editing mode on
And I open "<other> forum name" actions menu
And "Move right" "link" in the "<other> forum name" "activity" should not be visible
And "Move left" "link" in the "<other> forum name" "activity" should be visible
Examples:
| format | prefix | other |
| Custom sections | Sections | Weekly |
| Weekly sections | Weekly | Sections |
Scenario Outline: Cancel course indentation reset
Given I navigate to "Plugins > Course formats > <format>" in site administration
And "Reset indentation sitewide" "link" should exist
When I click on "Reset indentation sitewide" "link"
And I should see "Reset indentation sitewide"
And "Reset indentation sitewide" "button" should exist
And "Cancel" "button" should exist
And I click on "Cancel" "button"
Then I should not see "Indentation reset."
And I am on "<prefix> Course 1" course homepage with editing mode on
And I open "<prefix> forum name" actions menu
And "Move right" "link" in the "<prefix> forum name" "activity" should not be visible
And "Move left" "link" in the "<prefix> forum name" "activity" should be visible
And I press the escape key
And I open "<prefix> database name" actions menu
And "Move right" "link" in the "<prefix> database name" "activity" should be visible
And "Move left" "link" in the "<prefix> database name" "activity" should not be visible
And I am on "<prefix> Course 2" course homepage with editing mode on
And I open "<prefix> wiki name" actions menu
And "Move right" "link" in the "<prefix> wiki name" "activity" should not be visible
And "Move left" "link" in the "<prefix> wiki name" "activity" should be visible
Examples:
| format | prefix |
| Custom sections | Sections |
| Weekly sections | Weekly |
+21
View File
@@ -0,0 +1,21 @@
@core @core_admin
Feature: Use the search areas admin screen
In order to control search indexing
As an admin
I need to use the search areas admin screen
Background:
Given I log in as "admin"
And I navigate to "Plugins > Search > Search areas" in site administration
Scenario: Disable and enable a search area
When I click on "Disable" "link" in the "Book - resource information" "table_row"
Then I should see "Search area disabled" in the ".alert-success" "css_element"
And I should see "Search area disabled" in the "Book - resource information" "table_row"
When I click on "Enable" "link" in the "Book - resource information" "table_row"
Then I should see "Search area enabled" in the ".alert-success" "css_element"
And I should not see "Search area disabled" in the "Book - resource information" "table_row"
# Note: Other scenarios are not currently easy to implement in Behat because there is no mock
# search engine - we could add testing once Moodle has an internal database search engine.
@@ -0,0 +1,26 @@
@core @core_admin
Feature: Set admin settings value
In order to set admin settings value
As an admin
I need to set admin setting value and verify it is applied
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course fullname | C_shortname | 0 |
And I log in as "admin"
And I am on site homepage
And I should see "Course fullname"
And I should not see "C_shortname Course fullname"
Scenario: set admin value with full name
Given the following config values are set as admin:
| courselistshortnames | 1 |
And I am on site homepage
Then I should see "C_shortname Course fullname"
Scenario: set admin value with short name
Given the following config values are set as admin:
| courselistshortnames | 1 |
And I am on site homepage
Then I should see "C_shortname Course fullname"
@@ -0,0 +1,21 @@
@core @core_admin
Feature: Navigate site administration pages
In order to configure my site
As an admin
I need to be able to navigate the site administration pages
@javascript
Scenario: Navigate to an admin category page
Given I log in as "admin"
When I navigate to "Plugins > Activity modules > Assignment" in site administration
# Ensure secondary navigation is still present and "Plugins" is selected.
Then "//a[@aria-current = 'true' and normalize-space() = 'Plugins']" "xpath" should exist in the ".secondary-navigation" "css_element"
And I should see "Category: Assignment"
@javascript
Scenario: Navigate to an admin settings page
Given I log in as "admin"
When I navigate to "Plugins > Activity modules > Forum" in site administration
# Ensure secondary navigation is still present and "Plugins" is selected.
Then "//a[@aria-current = 'true' and normalize-space() = 'Plugins']" "xpath" should exist in the ".secondary-navigation" "css_element"
And I should see "Forum"
@@ -0,0 +1,31 @@
@core @core_admin @javascript
Feature: Verify the breadcrumbs in external webservice site administration pages
Whenever I navigate to external webservice page in site administration
As an admin
The breadcrumbs should be visible
Background:
Given I log in as "admin"
Scenario: Verify the breadcrumbs in external services page
Given I navigate to "Server > Web services > External services" in site administration
And "External services" "text" should exist in the ".breadcrumb" "css_element"
And "Web services" "link" should exist in the ".breadcrumb" "css_element"
When I click on "Edit" "link"
Then "Edit external service" "text" should exist in the ".breadcrumb" "css_element"
And "External services" "link" should exist in the ".breadcrumb" "css_element"
And "Web services" "link" should exist in the ".breadcrumb" "css_element"
And I press "Cancel"
And I click on "Add" "link"
And I set the field "Name" to "function to test"
And "Add external service" "text" should exist in the ".breadcrumb" "css_element"
And "External services" "link" should exist in the ".breadcrumb" "css_element"
And "Web services" "link" should exist in the ".breadcrumb" "css_element"
And I press "Add service"
And "Functions" "text" should exist in the ".breadcrumb" "css_element"
And "External services" "link" should exist in the ".breadcrumb" "css_element"
And "Web services" "link" should exist in the ".breadcrumb" "css_element"
And I navigate to "Server > Web services > External services" in site administration
And I click on "Delete" "link"
And "External services" "text" should exist in the ".breadcrumb" "css_element"
And "Web services" "link" should exist in the ".breadcrumb" "css_element"
@@ -0,0 +1,25 @@
@core @core_admin @javascript
Feature: Verify the breadcrumbs in webservice tokens site administration pages
Whenever I navigate to manage tokens page in site administration
As an admin
The breadcrumbs should be visible
Background:
Given I log in as "admin"
Scenario: Verify the breadcrumbs in manage tokens page as an admin
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | John | Doe | s1@example.com |
And I log in as "admin"
And I navigate to "Server > Web services > Manage tokens" in site administration
And I click on "Create token" "button"
And "Create token" "text" should exist in the ".breadcrumb" "css_element"
And "Manage tokens" "link" should exist in the ".breadcrumb" "css_element"
And "Web services" "link" should exist in the ".breadcrumb" "css_element"
And I set the field "User" to "John Doe"
And I press "Save changes"
When I click on "Delete" "link"
Then "Delete token" "text" should exist in the ".breadcrumb" "css_element"
And "Manage tokens" "link" should exist in the ".breadcrumb" "css_element"
And "Web services" "link" should exist in the ".breadcrumb" "css_element"
+50
View File
@@ -0,0 +1,50 @@
@core @core_admin @core_reportbuilder
Feature: View task logs report and use its filters
In order to view task logs report and use its filters
As an admin
I need to navigate to Server > Tasks > Task logs
Background:
# We need to run cron to populate the report.
Given I trigger cron
@javascript
Scenario Outline: Filter task logs by name
Given I log in as "admin"
And I change window size to "large"
And I navigate to "Server > Tasks > Task logs" in site administration
When I click on "Filters" "button"
And I set the following fields in the "Class name" "core_reportbuilder > Filter" to these values:
| Class name value | <name> |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "Filters applied"
And I should see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
And the following should exist in the "reportbuilder-table" table:
| Type | Name |
| Scheduled | <match> |
And the following should not exist in the "reportbuilder-table" table:
| Type | Name |
| Scheduled | <nonmatch> |
Examples:
| name | match | nonmatch |
| Cleanup event monitor events | Cleanup event monitor events | Incoming email pickup |
| Incoming email pickup | Incoming email pickup | Cleanup event monitor events |
@javascript
# Task duration is dependent on many factors, we are asserting here that no task has a duration >2 minutes.
Scenario Outline: Filter task logs by duration
Given I log in as "admin"
And I change window size to "large"
And I navigate to "Server > Tasks > Task logs" in site administration
When I click on "Filters" "button"
And I set the following fields in the "Duration" "core_reportbuilder > Filter" to these values:
| Duration operator | <operator> |
| Duration value | 2 |
| Duration unit | minute(s) |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "Filters applied"
And I <shouldornotsee> "Nothing to display"
Examples:
| operator | shouldornotsee |
| Less than | should not see |
| Greater than | should see |
@@ -0,0 +1,41 @@
@core @core_admin @core_webservice
Feature: Web service user settings
In order to configure authorised users for a web service
As an admin
I need to use the page that lets you do that
Background:
# Include a custom profile field so we can check it gets displayed
Given the following "custom profile fields" exist:
| datatype | shortname | name | param2 |
| text | frog | Favourite frog | 100 |
And the following config values are set as admin:
| showuseridentity | email,profile_field_frog |
And the following "users" exist:
| username | firstname | lastname | email | profile_field_frog |
| user1 | User | One | 1@example.org | Kermit |
And the following "core_webservice > Service" exists:
| name | Silly service |
| shortname | silly |
| restrictedusers | 1 |
| enabled | 1 |
Scenario: Add a user to a web service
When I log in as "admin"
And I navigate to "Server > Web services > External services" in site administration
And I click on "Authorised users" "link" in the "Silly service" "table_row"
And I set the field "Not authorised users" to "User One"
And I press "Add"
Then I should see "User One" in the ".alloweduserlist" "css_element"
And I should see "1@example.org" in the ".alloweduserlist" "css_element"
And I should see "Kermit" in the ".alloweduserlist" "css_element"
@javascript
Scenario: Add a function to a web service
When I log in as "admin"
And I navigate to "Server > Web services > External services" in site administration
And I click on "Functions" "link" in the "Silly service" "table_row"
And I follow "Add functions"
And I set the field "Name" to "core_blog_get_entries"
And I click on "Add functions" "button" in the "#fgroup_id_buttonar" "css_element"
Then I should see "core_blog_get_entries" in the "generaltable" "table"
+112
View File
@@ -0,0 +1,112 @@
<?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/>.
declare(strict_types=1);
namespace core_admin\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* Unit tests to test block protection changes.
*
* @package core
* @covers \core_admin\external\set_block_protection
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set_block_protection_test extends \externallib_advanced_testcase {
/**
* Test execute method with no login.
*/
public function test_execute_no_login(): void {
$this->expectException(\require_login_exception::class);
set_block_protection::execute('block_login', 1);
}
/**
* Test execute method with no login.
*/
public function test_execute_no_capability(): void {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->expectException(\required_capability_exception::class);
set_block_protection::execute('block_login', 1);
}
/**
* Test the execute function with a range of parameters.
*
* @dataProvider execute_provider
* @param string $block
* @param int $targetstate
* @param bool $isundeletable
*/
public function test_execute(
string $block,
int $targetstate,
bool $isundeletable,
): void {
$this->resetAfterTest();
$this->setAdminUser();
set_block_protection::execute($block, $targetstate);
$undeletable = \block_manager::get_undeletable_block_types();
[, $pluginname] = explode('_', $block, 2);
if ($isundeletable) {
$this->assertNotFalse(array_search($pluginname, $undeletable));
} else {
$this->assertFalse(array_search($pluginname, $undeletable));
}
$this->assertCount(1, \core\notification::fetch());
}
/**
* Data provider for test_execute.
*
* @return array
*/
public function execute_provider(): array {
return [
[
'block_login',
1,
true,
],
[
'block_login',
0,
false,
],
];
}
/**
* Assert that an exception is thrown when the block does not exist.
*/
public function execute_block_does_not_exist(): void {
$this->expectException(\dml_missing_record_exception::class);
set_block_protection::execute('fake_block', 1);
$this->assertDebuggingCalledCount(1);
}
}
+172
View File
@@ -0,0 +1,172 @@
<?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/>.
declare(strict_types=1);
namespace core_admin\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* Unit tests to configure the plugin order.
*
* Note: Not all plugins can be ordered, so this test is limited to those which support it.
*
* @package core
* @covers \core_admin\external\set_plugin_state
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set_plugin_order_test extends \externallib_advanced_testcase {
/**
* Text execute method for editor plugins, which support ordering.
*
* @dataProvider execute_editor_provider
* @param string $initialstate The initial state of the plugintype
* @param string $plugin The name of the plugin
* @param int $direction
* @param array $neworder
* @param string $newstate
*/
public function test_execute_editors(
string $initialstate,
string $plugin,
int $direction,
array $neworder,
string $newstate,
): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$CFG->texteditors = $initialstate;
set_plugin_order::execute($plugin, $direction);
$this->assertSame(
$neworder,
array_keys(\core\plugininfo\editor::get_sorted_plugins()),
);
$this->assertSame($newstate, $CFG->texteditors);
}
/**
* Data provider for base tests of the execute method.
*
* @return array
*/
public function execute_editor_provider(): array {
$pluginmanager = \core_plugin_manager::instance();
$allplugins = array_keys($pluginmanager->get_plugins_of_type('editor'));
// Disabled editors are listed alphabetically at the end.
$getorder = function (array $plugins) use ($allplugins) {
return array_merge(
$plugins,
array_diff($allplugins, array_values($plugins)),
);
};
return [
[
'initialstate' => 'textarea,tiny',
'pluginname' => 'editor_textarea',
'direction' => 1, // DOWN.
'expected' => $getorder([
'tiny',
'textarea',
]),
'newtexteditors' => 'tiny,textarea',
],
[
'initialstate' => 'textarea,tiny',
'pluginname' => 'editor_textarea',
'direction' => -1, // UP.
'expected' => $getorder([
'textarea',
'tiny',
]),
'newtexteditors' => 'textarea,tiny',
],
[
'initialstate' => 'textarea,tiny',
'pluginname' => 'editor_tiny',
'direction' => 1, // DOWN.
// Tiny is already at the bottom of the list of enabled plugins.
'expected' => $getorder([
'textarea',
'tiny',
]),
'newtexteditors' => 'textarea,tiny',
],
[
'initialstate' => 'textarea,tiny',
'pluginname' => 'editor_atto',
'direction' => 1, // DOWN.
// Atto is not enabled. Disabled editors are listed lexically after enabled editors.
'expected' => $getorder([
'textarea',
'tiny',
]),
'newtexteditors' => 'textarea,tiny',
],
];
}
/**
* Text execute method for plugins which do not support ordering.
*
* @dataProvider execute_non_orderable_provider
* @param string $plugin
*/
public function test_execute_editors_non_orderable(string $plugin): void {
$this->resetAfterTest();
$this->setAdminUser();
$this->assertIsArray(set_plugin_order::execute($plugin, 1));
}
public function execute_non_orderable_provider(): array {
return [
// Activities do not support ordering.
['mod_assign'],
// Nor to blocks.
['block_login'],
];
}
/**
* Test execute method with no login.
*/
public function test_execute_no_login(): void {
$this->expectException(\require_login_exception::class);
set_plugin_order::execute('editor_tiny', 1);
}
/**
* Test execute method with no login.
*/
public function test_execute_no_capability(): void {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->expectException(\required_capability_exception::class);
set_plugin_order::execute('editor_tiny', 1);
}
}
+131
View File
@@ -0,0 +1,131 @@
<?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/>.
declare(strict_types=1);
namespace core_admin\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* Unit tests to configure the enabled/disabled state of a plugin.
*
* @package core
* @covers \core_admin\external\set_plugin_state
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set_plugin_state_test extends \externallib_advanced_testcase {
/**
* Text execute method.
*
* @dataProvider execute_standard_provider
* @param string $plugin The name of the plugin
* @param int|null $initialstate The initial state of the plugin
* @param int $newstate The target state
* @param int $notificationcount The number of notifications expected
*/
public function test_execute(
string $plugin,
?int $initialstate,
int $newstate,
int $notificationcount,
): void {
$this->resetAfterTest();
$this->setAdminUser();
if ($initialstate !== null) {
[$plugintype, $pluginname] = \core_component::normalize_component($plugin);
$manager = \core_plugin_manager::resolve_plugininfo_class($plugintype);
$manager::enable_plugin($pluginname, $initialstate);
\core\notification::fetch();
}
set_plugin_state::execute($plugin, $newstate);
$this->assertCount($notificationcount, \core\notification::fetch());
}
/**
* Data provider for base tests of the execute method.
*
* @return array
*/
public function execute_standard_provider(): array {
$generatetestsfor = function (string $plugin): array {
return [
[
'plugin' => $plugin,
'initialstate' => null,
'newstate' => 0,
'notificationcount' => 1,
],
[
'plugin' => $plugin,
'initialstate' => 1,
'newstate' => 0,
'notificationcount' => 1,
],
[
'plugin' => $plugin,
'initialstate' => 1,
'newstate' => 1,
'notificationcount' => 0,
],
[
'plugin' => $plugin,
'initialstate' => 0,
'newstate' => 0,
'notificationcount' => 0,
],
[
'plugin' => $plugin,
'initialstate' => 0,
'newstate' => 1,
'notificationcount' => 1,
],
];
};
return array_merge(
$generatetestsfor('mod_assign'),
$generatetestsfor('editor_tiny'),
$generatetestsfor('tiny_h5p'),
$generatetestsfor('block_badges'),
);
}
/**
* Test execute method with no login.
*/
public function test_execute_no_login(): void {
$this->expectException(\require_login_exception::class);
set_plugin_state::execute('mod_assign', 1);
}
/**
* Test execute method with no login.
*/
public function test_execute_no_capability(): void {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->expectException(\required_capability_exception::class);
set_plugin_state::execute('mod_assign', 1);
}
}
@@ -0,0 +1,285 @@
<?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/>.
declare(strict_types=1);
namespace core_admin\reportbuilder\datasource;
use core\task\database_logger;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
use core_reportbuilder\local\filters\{boolean_select, date, duration, number, select, text};
use core_reportbuilder\task\send_schedules;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
/**
* Unit tests for task logs datasource
*
* @package core_admin
* @covers \core_admin\reportbuilder\datasource\task_logs
* @copyright 2022 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class task_logs_test extends core_reportbuilder_testcase {
/**
* Test default datasource
*/
public function test_datasource_default(): void {
$this->resetAfterTest();
$this->generate_task_log_data(true, 3, 2, 1654038000, 1654038060);
$this->generate_task_log_data(false, 5, 1, 1654556400, 1654556700);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Tasks', 'source' => task_logs::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(2, $content);
// Default columns are name, start time, duration, result. Sorted by start time descending.
[$name, $timestart, $duration, $result] = array_values($content[0]);
$this->assertStringContainsString(send_schedules::class, $name);
$this->assertEquals('7/06/22, 07:00:00', $timestart);
$this->assertEquals('5 mins', $duration);
$this->assertEquals('Fail', $result);
[$name, $timestart, $duration, $result] = array_values($content[1]);
$this->assertStringContainsString(send_schedules::class, $name);
$this->assertEquals('1/06/22, 07:00:00', $timestart);
$this->assertEquals('1 min', $duration);
$this->assertEquals('Success', $result);
}
/**
* Test datasource columns that aren't added by default
*/
public function test_datasource_non_default_columns(): void {
$this->resetAfterTest();
$this->generate_task_log_data(true, 3, 2, 1654038000, 1654038060, 'hi', 'core_reportbuilder', 'test', 43);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Tasks', 'source' => task_logs::class, 'default' => 0]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:component']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:type']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:endtime']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:hostname']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:pid']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:database']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:dbreads']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:dbwrites']);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(1, $content);
$this->assertEquals([
'core_reportbuilder',
'Scheduled',
'1/06/22, 07:01:00',
'test',
'43',
'<div>3 reads</div><div>2 writes</div>',
'3',
'2',
], array_values($content[0]));
}
/**
* Data provider for {@see test_datasource_filters}
*
* @return array[]
*/
public function datasource_filters_provider(): array {
return [
'Filter name' => ['task_log:name', [
'task_log:name_values' => [send_schedules::class],
], true],
'Filter name (no match)' => ['task_log:name', [
'task_log:name_values' => ['invalid'],
], false],
'Filter component' => ['task_log:component', [
'task_log:component_operator' => select::EQUAL_TO,
'task_log:component_value' => 'core_reportbuilder',
], true],
'Filter component (no match)' => ['task_log:component', [
'task_log:component_operator' => select::NOT_EQUAL_TO,
'task_log:component_value' => 'core_reportbuilder',
], false],
'Filter type' => ['task_log:type', [
'task_log:type_operator' => select::EQUAL_TO,
'task_log:type_value' => database_logger::TYPE_SCHEDULED,
], true],
'Filter type (no match)' => ['task_log:type', [
'task_log:type_operator' => select::EQUAL_TO,
'task_log:type_value' => database_logger::TYPE_ADHOC,
], false],
'Filter output' => ['task_log:output', [
'task_log:output_operator' => text::IS_NOT_EMPTY,
], true],
'Filter output (no match)' => ['task_log:output', [
'task_log:output_operator' => text::IS_EMPTY,
], false],
'Filter result' => ['task_log:result', [
'task_log:result_operator' => boolean_select::CHECKED,
], true],
'Filter result (no match)' => ['task_log:result', [
'task_log:result_operator' => boolean_select::NOT_CHECKED,
], false],
'Filter time start' => ['task_log:timestart', [
'task_log:timestart_operator' => date::DATE_RANGE,
'task_log:timestart_from' => 1622502000,
], true],
'Filter time start (no match)' => ['task_log:timestart', [
'task_log:timestart_operator' => date::DATE_RANGE,
'task_log:timestart_to' => 1622502000,
], false],
'Filter time end' => ['task_log:timeend', [
'task_log:timeend_operator' => date::DATE_RANGE,
'task_log:timeend_from' => 1622502000,
], true],
'Filter time end (no match)' => ['task_log:timeend', [
'task_log:timeend_operator' => date::DATE_RANGE,
'task_log:timeend_to' => 1622502000,
], false],
'Filter duration' => ['task_log:duration', [
'task_log:duration_operator' => duration::DURATION_MAXIMUM,
'task_log:duration_unit' => MINSECS,
'task_log:duration_value' => 2,
], true],
'Filter duration (no match)' => ['task_log:duration', [
'task_log:duration_operator' => duration::DURATION_MINIMUM,
'task_log:duration_unit' => MINSECS,
'task_log:duration_value' => 2,
], false],
'Filter database reads' => ['task_log:dbreads', [
'task_log:dbreads_operator' => number::LESS_THAN,
'task_log:dbreads_value1' => 4,
], true],
'Filter database reads (no match)' => ['task_log:dbreads', [
'task_log:dbreads_operator' => number::GREATER_THAN,
'task_log:dbreads_value1' => 4,
], false],
'Filter database writes' => ['task_log:dbwrites', [
'task_log:dbwrites_operator' => number::LESS_THAN,
'task_log:dbwrites_value1' => 4,
], true],
'Filter database writes (no match)' => ['task_log:dbwrites', [
'task_log:dbwrites_operator' => number::GREATER_THAN,
'task_log:dbwrites_value1' => 4,
], false],
];
}
/**
* Test datasource filters
*
* @param string $filtername
* @param array $filtervalues
* @param bool $expectmatch
*
* @dataProvider datasource_filters_provider
*/
public function test_datasource_filters(
string $filtername,
array $filtervalues,
bool $expectmatch
): void {
$this->resetAfterTest();
$this->generate_task_log_data(true, 3, 2, 1654038000, 1654038060, 'hi', 'core_reportbuilder', 'test', 43);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
// Create report containing single component column, and given filter.
$report = $generator->create_report(['name' => 'Tasks', 'source' => task_logs::class, 'default' => 0]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'task_log:component']);
// Add filter, set it's values.
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
$content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
if ($expectmatch) {
$this->assertCount(1, $content);
$this->assertEquals('core_reportbuilder', reset($content[0]));
} else {
$this->assertEmpty($content);
}
}
/**
* Stress test datasource
*
* In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
*/
public function test_stress_datasource(): void {
if (!PHPUNIT_LONGTEST) {
$this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
}
$this->resetAfterTest();
$this->generate_task_log_data(true, 3, 2, 1654038000, 1654038060, 'hi', 'core_reportbuilder', 'test', 43);
$this->datasource_stress_test_columns(task_logs::class);
$this->datasource_stress_test_columns_aggregation(task_logs::class);
$this->datasource_stress_test_conditions(task_logs::class, 'task_log:name');
}
/**
* Helper to generate some task logs data
*
* @param bool $success
* @param int $dbreads
* @param int $dbwrites
* @param float $timestart
* @param float $timeend
* @param string $logoutput
* @param string $component
* @param string $hostname
* @param int $pid
*/
private function generate_task_log_data(
bool $success,
int $dbreads,
int $dbwrites,
float $timestart,
float $timeend,
string $logoutput = 'hello',
string $component = 'moodle',
string $hostname = 'phpunit',
int $pid = 42
): void {
$logpath = make_request_directory() . '/log.txt';
file_put_contents($logpath, $logoutput);
$task = new send_schedules();
$task->set_component($component);
$task->set_hostname($hostname);
$task->set_pid($pid);
database_logger::store_log_for_task($task, $logpath, !$success, $dbreads, $dbwrites, $timestart, $timeend);
}
}
@@ -0,0 +1,114 @@
<?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/>.
declare(strict_types=1);
namespace core_admin\reportbuilder\local\filters;
use advanced_testcase;
use lang_string;
use core_reportbuilder\local\report\filter;
/**
* Unit tests for course role report filter
*
* @package core_admin
* @covers \core_admin\reportbuilder\local\filters\courserole
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class courserole_test extends advanced_testcase {
/**
* Data provider for {@see test_get_sql_filter}
*
* @return array[]
*/
public static function get_sql_filter_provider(): array {
return [
'Empty filter' => ['', '', '', ['admin', 'guest', 'user1', 'user2', 'user3', 'user4']],
'Filter by role' => ['editingteacher', '', '', ['user1', 'user3', 'user4']],
'Filter by role in category' => ['editingteacher', 'cat2', '', ['user1', 'user3']],
'Filter by role in category and course' => ['editingteacher', 'cat2', 'course2', ['user1']],
'Filter by role in course' => ['student', '', 'course2', ['user2']],
'Filter by category' => ['', 'cat2', '', ['user1', 'user2', 'user3']],
'Filter by category and course' => ['', 'cat2', 'course2', ['user1', 'user2']],
'Filter by course' => ['', '', 'course3', ['user3']],
'Filter by course (ensure whitespace is trimmed)' => ['', '', ' course3 ', ['user3']],
];
}
/**
* Test getting filter SQL
*
* @param string $rolename
* @param string $categoryname
* @param string $course
* @param string[] $expectedusers
*
* @dataProvider get_sql_filter_provider
*/
public function test_get_sql_filter(
string $rolename,
string $categoryname,
string $course,
array $expectedusers,
): void {
global $DB;
$this->resetAfterTest();
// Create categories/course structure (categoryone: courseone; categorytwo: coursetwo/coursethree).
$categoryone = $this->getDataGenerator()->create_category(['name' => 'cat1']);
$courseone = $this->getDataGenerator()->create_course(['category' => $categoryone->id, 'shortname' => 'course1']);
$categorytwo = $this->getDataGenerator()->create_category(['name' => 'cat2']);
$coursetwo = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course2']);
$coursethree = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course3']);
// User one is a teacher in courseone/coursetwo.
$userone = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user1']);
$this->getDataGenerator()->enrol_user($userone->id, $coursetwo->id, 'editingteacher');
// User two is a student in coursetwo.
$usertwo = $this->getDataGenerator()->create_and_enrol($coursetwo, 'student', ['username' => 'user2']);
// User three is a teacher in courseone/coursethree.
$userthree = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user3']);
$this->getDataGenerator()->enrol_user($userthree->id, $coursethree->id, 'editingteacher');
// User four is a teacher in courseone.
$userfour = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user4']);
$filter = new filter(
courserole::class,
'test',
new lang_string('yes'),
'testentity',
'id',
);
// Create instance of our filter, passing given operators (with lookups for role/category).
[$select, $params] = courserole::create($filter)->get_sql_filter([
$filter->get_unique_identifier() . '_role' => $DB->get_field('role', 'id', ['shortname' => $rolename]),
$filter->get_unique_identifier() . '_category' => $DB->get_field('course_categories', 'id', ['name' => $categoryname]),
$filter->get_unique_identifier() . '_course' => $course,
]);
$users = $DB->get_fieldset_select('user', 'username', $select, $params);
$this->assertEqualsCanonicalizing($expectedusers, $users);
}
}