mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 20:42:22 +02:00
Merge branch 'MDL-81888-main-v02' of https://github.com/ferranrecio/moodle
This commit is contained in:
commit
854296c210
@ -43,6 +43,13 @@ class featureimport extends moodleform {
|
||||
['accepted_types' => ['.feature']]
|
||||
);
|
||||
$mform->addRule('featurefile', null, 'required');
|
||||
|
||||
$options = [
|
||||
0 => get_string('execute_scenarios', 'tool_generator'),
|
||||
1 => get_string('execute_cleanup', 'tool_generator'),
|
||||
];
|
||||
$mform->addElement('select', 'executecleanup', get_string('execute', 'tool_generator'), $options);
|
||||
|
||||
$this->add_action_buttons(false, get_string('import'));
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@ namespace tool_generator\local\testscenario;
|
||||
use behat_admin;
|
||||
use behat_data_generators;
|
||||
use behat_base;
|
||||
use behat_course;
|
||||
use behat_user;
|
||||
use Behat\Gherkin\Parser;
|
||||
use Behat\Gherkin\Lexer;
|
||||
use Behat\Gherkin\Keywords\ArrayKeywords;
|
||||
@ -49,6 +51,7 @@ class runner {
|
||||
$this->include_composer_libraries();
|
||||
$this->include_behat_libraries();
|
||||
$this->load_generator();
|
||||
$this->load_cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,6 +80,9 @@ class runner {
|
||||
require_once($CFG->libdir . '/behat/behat_base.php');
|
||||
require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
|
||||
require_once("{$CFG->dirroot}/admin/tests/behat/behat_admin.php");
|
||||
require_once("{$CFG->dirroot}/course/lib.php");
|
||||
require_once("{$CFG->dirroot}/course/tests/behat/behat_course.php");
|
||||
require_once("{$CFG->dirroot}/user/tests/behat/behat_user.php");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -97,6 +103,27 @@ class runner {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all cleanup steps.
|
||||
*/
|
||||
private function load_cleanup() {
|
||||
$extra = $this->scan_method(
|
||||
new ReflectionMethod(behat_course::class, 'the_course_is_deleted'),
|
||||
new behat_course(),
|
||||
);
|
||||
if ($extra) {
|
||||
$this->validsteps[$extra->given] = $extra;
|
||||
}
|
||||
|
||||
$extra = $this->scan_method(
|
||||
new ReflectionMethod(behat_user::class, 'the_user_is_deleted'),
|
||||
new behat_user(),
|
||||
);
|
||||
if ($extra) {
|
||||
$this->validsteps[$extra->given] = $extra;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan a generator to get all valid steps.
|
||||
* @param behat_data_generators $generator the generator to scan.
|
||||
@ -159,6 +186,19 @@ class runner {
|
||||
* @return parsedfeature
|
||||
*/
|
||||
public function parse_feature(string $content): parsedfeature {
|
||||
return $this->parse_selected_scenarios($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all feature file scenarios.
|
||||
*
|
||||
* Note: if no filter is passed, it will execute only the scenarios that are not tagged.
|
||||
*
|
||||
* @param string $content the feature file content.
|
||||
* @param string $filtertag the tag to filter the scenarios.
|
||||
* @return parsedfeature
|
||||
*/
|
||||
private function parse_selected_scenarios(string $content, ?string $filtertag = null): parsedfeature {
|
||||
$result = new parsedfeature();
|
||||
|
||||
$parser = $this->get_parser();
|
||||
@ -170,6 +210,13 @@ class runner {
|
||||
if ($feature->hasScenarios()) {
|
||||
$scenarios = $feature->getScenarios();
|
||||
foreach ($scenarios as $scenario) {
|
||||
// By default, we only execute scenaros that are not tagged.
|
||||
if (empty($filtertag) && !empty($scenario->getTags())) {
|
||||
continue;
|
||||
}
|
||||
if ($filtertag && !in_array($filtertag, $scenario->getTags())) {
|
||||
continue;
|
||||
}
|
||||
if ($scenario->getNodeType() == 'Outline') {
|
||||
$this->parse_scenario_outline($scenario, $result);
|
||||
continue;
|
||||
@ -184,6 +231,15 @@ class runner {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a feature file using only the scenarios with cleanup tag.
|
||||
* @param string $content the feature file content.
|
||||
* @return parsedfeature
|
||||
*/
|
||||
public function parse_cleanup(string $content): parsedfeature {
|
||||
return $this->parse_selected_scenarios($content, 'cleanup');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a scenario outline.
|
||||
* @param OutlineNode $scenario the scenario outline to parse.
|
||||
@ -209,7 +265,6 @@ class runner {
|
||||
$keywords = new ArrayKeywords([
|
||||
'en' => [
|
||||
'feature' => 'Feature',
|
||||
// If in the future we have clean up steps, background will be renamed to "Clean up".
|
||||
'background' => 'Background',
|
||||
'scenario' => 'Scenario',
|
||||
'scenario_outline' => 'Scenario Outline|Scenario Template',
|
||||
|
@ -57,10 +57,12 @@ class parsingresult implements renderable, templatable {
|
||||
$haslines = false;
|
||||
foreach ($this->parsedfeature->get_scenarios() as $scenario) {
|
||||
$scenariodata = [
|
||||
'type' => $scenario->type,
|
||||
'name' => $scenario->name,
|
||||
'type' => ucfirst($scenario->type),
|
||||
'steps' => [],
|
||||
];
|
||||
if (!empty($scenario->name)) {
|
||||
$scenariodata['name'] = $scenario->name;
|
||||
}
|
||||
if (!empty($scenario->error)) {
|
||||
$scenariodata['scenarioerror'] = $scenario->error;
|
||||
}
|
||||
|
@ -43,10 +43,12 @@ list($options, $unrecognised) = cli_get_params(
|
||||
'disable-composer' => false,
|
||||
'composer-upgrade' => true,
|
||||
'composer-self-update' => true,
|
||||
'cleanup' => false,
|
||||
],
|
||||
[
|
||||
'h' => 'help',
|
||||
'f' => 'feature',
|
||||
'c' => 'cleanup',
|
||||
]
|
||||
);
|
||||
|
||||
@ -60,11 +62,13 @@ steps.
|
||||
Usage:
|
||||
php runtestscenario.php [--feature=\"value\"] [--help]
|
||||
[--no-composer-self-update] [--no-composer-upgrade]
|
||||
[--disable-composer]
|
||||
[--disable-composer] [--cleanup]
|
||||
|
||||
Options:
|
||||
-f, --feature Execute specified feature file (Absolute path of feature file).
|
||||
|
||||
-c, --cleanup Execute the scenarios with @cleanup tag.
|
||||
|
||||
--no-composer-self-update
|
||||
Prevent upgrade of the composer utility using its self-update command
|
||||
|
||||
@ -79,6 +83,7 @@ Note: Installation of composer and/or dependencies will still happen as required
|
||||
|
||||
Example from Moodle root directory:
|
||||
\$ php admin/tool/generator/cli/runtestscenario.php --feature=/path/to/some/testing/scenario.feature
|
||||
\$ php admin/tool/generator/cli/runtestscenario.php --feature=/path/to/some/testing/scenario.feature --cleanup
|
||||
";
|
||||
|
||||
if (!empty($options['help'])) {
|
||||
@ -139,7 +144,11 @@ if (empty($content)) {
|
||||
}
|
||||
|
||||
try {
|
||||
$parsedfeature = $runner->parse_feature($content);
|
||||
if (!empty($options['cleanup'])) {
|
||||
$parsedfeature = $runner->parse_cleanup($content);
|
||||
} else {
|
||||
$parsedfeature = $runner->parse_feature($content);
|
||||
}
|
||||
} catch (\Exception $error) {
|
||||
echo "Error parsing feature file: {$error->getMessage()}\n";
|
||||
echo "Use the web version of the tool to see the parsing details:\n";
|
||||
|
@ -64,6 +64,9 @@ $string['error_nonexistingcourse'] = 'The specified course does not exist';
|
||||
$string['error_nopageinstances'] = 'The selected course does not contain page module instances';
|
||||
$string['error_notdebugging'] = 'Not available on this server because debugging is not set to DEVELOPER';
|
||||
$string['error_nouserspassword'] = 'You need to set $CFG->tool_generator_users_password in config.php to generate the test plan';
|
||||
$string['execute'] = 'Execute';
|
||||
$string['execute_cleanup'] = 'Cleanup scenarios';
|
||||
$string['execute_scenarios'] = 'Testing scenarios';
|
||||
$string['fullname'] = 'Test course: {$a->size}';
|
||||
$string['maketestcourse'] = 'Make test course';
|
||||
$string['maketestplan'] = 'Make JMeter test plan';
|
||||
|
@ -79,7 +79,11 @@ if (empty($content)) {
|
||||
}
|
||||
|
||||
try {
|
||||
$parsedfeature = $runner->parse_feature($content);
|
||||
if ($data->executecleanup) {
|
||||
$parsedfeature = $runner->parse_cleanup($content);
|
||||
} else {
|
||||
$parsedfeature = $runner->parse_feature($content);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
echo $output->notification(get_string('testscenario_errorparsing', 'tool_generator', $th->getMessage()));
|
||||
echo $output->continue_button($currenturl);
|
||||
|
@ -27,7 +27,7 @@
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "Scenario",
|
||||
"title": "Scenario title",
|
||||
"name": "Scenario title",
|
||||
"hassteps": true,
|
||||
"steps": [
|
||||
{
|
||||
@ -53,7 +53,7 @@
|
||||
<p>{{#str}} testscenario_steps, tool_generator {{/str}}</p>
|
||||
{{/haslines}}
|
||||
{{#scenarios}}
|
||||
<h3>{{type}}: {{name}}</h3>
|
||||
<h3>{{type}}{{#name}}: {{name}} {{/name}}</h3>
|
||||
<div>
|
||||
{{#scenarioerror}}
|
||||
<div class="alert alert-danger mb-3" role="alert">
|
||||
|
@ -74,3 +74,25 @@ Feature: Create testing scenarios using generators
|
||||
And I should see "Course 2" in the "page-header" "region"
|
||||
And I am on the "C3" "Course" page
|
||||
And I should see "Course 3" in the "page-header" "region"
|
||||
|
||||
@javascript
|
||||
Scenario: Run cleanup steps after creating a testing scenario
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
And I upload "admin/tool/generator/tests/fixtures/testscenario/scenario_cleanup.feature" file to "Feature file" filemanager
|
||||
And I press "Import"
|
||||
And I should see "Scenario: Create course content to cleanup later"
|
||||
And I navigate to "Courses > Manage courses and categories" in site administration
|
||||
And I should see "Course cleanup" in the "course-listing" "region"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I should see "Teacher Test1"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
When I upload "admin/tool/generator/tests/fixtures/testscenario/scenario_cleanup.feature" file to "Feature file" filemanager
|
||||
And I set the field "Execute" to "Cleanup scenarios"
|
||||
And I press "Import"
|
||||
And I should see "the course \"Course cleanup\" is deleted"
|
||||
And I should see "the user \"cleanteacher\" is deleted"
|
||||
Then I navigate to "Courses > Manage courses and categories" in site administration
|
||||
And I should not see "Course cleanup" in the "course-listing" "region"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I should not see "Teacher Test1"
|
||||
|
@ -12,19 +12,33 @@ Feature: Fixture to prepare scenario for testing
|
||||
| activity | name | intro | course | idnumber | section | visible |
|
||||
| assign | Activity sample 1 | Test assignment description | C1 | sample1 | 1 | 1 |
|
||||
| assign | Activity sample 2 | Test assignment description | C1 | sample2 | 1 | 0 |
|
||||
|
||||
@cleanup
|
||||
Scenario: clean course from fixture to prepare scenario for testing
|
||||
Given the course "Course test" is deleted
|
||||
|
||||
Scenario: Create users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Test1 | sample@example.com |
|
||||
| username | firstname | lastname | email |
|
||||
| teachersample | Teacher | Test1 | sample@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| teachersample | C1 | editingteacher |
|
||||
And "5" "users" exist with the following data:
|
||||
| username | student[count] |
|
||||
| firstname | Student |
|
||||
| lastname | Test[count] |
|
||||
| email | student[count]@example.com |
|
||||
| username | studentsample[count] |
|
||||
| firstname | Student |
|
||||
| lastname | Test[count] |
|
||||
| email | studentsample[count]@example.com |
|
||||
And "5" "course enrolments" exist with the following data:
|
||||
| user | student[count] |
|
||||
| course | C1 |
|
||||
| role | student |
|
||||
| user | studentsample[count] |
|
||||
| course | C1 |
|
||||
| role | student |
|
||||
|
||||
@cleanup
|
||||
Scenario: clean users from fixture to prepare scenario for testing
|
||||
Given the user "teachersample" is deleted
|
||||
And the user "studentsample1" is deleted
|
||||
And the user "studentsample2" is deleted
|
||||
And the user "studentsample3" is deleted
|
||||
And the user "studentsample4" is deleted
|
||||
And the user "studentsample5" is deleted
|
||||
|
22
admin/tool/generator/tests/fixtures/testscenario/scenario_cleanup.feature
vendored
Normal file
22
admin/tool/generator/tests/fixtures/testscenario/scenario_cleanup.feature
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Feature: Fixture to test cleanup of a testing scenario
|
||||
|
||||
Scenario: Create course content to cleanup later
|
||||
Given the following config values are set as admin:
|
||||
| sendcoursewelcomemessage | 0 | enrol_manual |
|
||||
And the following "course" exists:
|
||||
| fullname | Course cleanup |
|
||||
| shortname | Cleanup |
|
||||
| category | 0 |
|
||||
| numsections | 3 |
|
||||
| initsections | 1 |
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| cleanteacher | Teacher | Test1 | samplecleanup@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| cleanteacher | Cleanup | editingteacher |
|
||||
|
||||
@cleanup
|
||||
Scenario: remove fixture to test cleanup of a testing scenario
|
||||
Given the course "Course cleanup" is deleted
|
||||
And the user "cleanteacher" is deleted
|
@ -12,3 +12,9 @@ Feature: Fixture to prepare scenario for testing from an outline
|
||||
| Course 1 | C1 |
|
||||
| Course 2 | C2 |
|
||||
| Course 3 | C3 |
|
||||
|
||||
@cleanup
|
||||
Scenario: clean up fixture to prepare scenario for testing from an outline
|
||||
Given the course "Course 1" is deleted
|
||||
And the course "Course 2" is deleted
|
||||
And the course "Course 3" is deleted
|
||||
|
@ -1138,6 +1138,17 @@ class behat_course extends behat_base {
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a course.
|
||||
*
|
||||
* @Given the course :coursefullname is deleted
|
||||
* @param string $coursefullname
|
||||
*/
|
||||
public function the_course_is_deleted($coursefullname) {
|
||||
delete_course($this->get_course_id($coursefullname), false);
|
||||
fix_course_sortorder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates the activity or resource specified by it's name. You should be in the course page with editing mode on.
|
||||
*
|
||||
|
@ -52,6 +52,21 @@ class behat_user extends behat_base {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a user.
|
||||
*
|
||||
* @Given the user :identifier is deleted
|
||||
* @param string $identifier
|
||||
*/
|
||||
public function the_user_is_deleted($identifier) {
|
||||
global $DB;
|
||||
$userid = $this->get_user_id_by_identifier($identifier);
|
||||
if (!$userid) {
|
||||
throw new moodle_exception('The specified user with username or email "' . $identifier . '" does not exist');
|
||||
}
|
||||
delete_user($DB->get_record('user', ['id' => $userid]));
|
||||
}
|
||||
|
||||
/**
|
||||
* The input field should have autocomplete set to this value.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user