MDL-80096 tool_generator: execute behat generators in current instance
This is a new feature in tool_generator to execute a feature file containing only generator steps. This new tool can be used to prepared testing scenarios for complex issues that requires manual testing.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
<?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/>.
|
||||
|
||||
namespace tool_generator\form;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use moodleform;
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/lib/formslib.php');
|
||||
|
||||
/**
|
||||
* Form for importting a testing scenario feature file.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class featureimport extends moodleform {
|
||||
public function definition(): void {
|
||||
$mform = &$this->_form;
|
||||
|
||||
// File upload.
|
||||
$mform->addElement(
|
||||
'filepicker',
|
||||
'featurefile',
|
||||
get_string('testscenario_file', 'tool_generator'),
|
||||
null,
|
||||
['accepted_types' => ['.feature']]
|
||||
);
|
||||
$mform->addRule('featurefile', null, 'required');
|
||||
$this->add_action_buttons(false, get_string('import'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the feature file contents.
|
||||
* @return string|null the feature file contents or null if not found.
|
||||
*/
|
||||
public function get_feature_contents(): ?string {
|
||||
$result = $this->get_file_content('featurefile');
|
||||
if (!$result) {
|
||||
return null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace tool_generator\local\testscenario;
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class with a scenario feature parsed.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class parsedfeature {
|
||||
/** @var int the number of steps. */
|
||||
private int $stepcount = 0;
|
||||
|
||||
/** @var bool if the parser is ok or fail. */
|
||||
private bool $isvalid = true;
|
||||
|
||||
/** @var stdClass[] the list of scenarios with all the steps.
|
||||
*
|
||||
* scenarionum => {type: string, title: string, steps: steprunner[]}.
|
||||
*/
|
||||
private array $scenarios = [];
|
||||
|
||||
/**
|
||||
* Get the general error, if any.
|
||||
* @return string
|
||||
*/
|
||||
public function get_general_error(): string {
|
||||
if (!$this->isvalid) {
|
||||
return get_string('testscenario_invalidfile', 'tool_generator');
|
||||
}
|
||||
if ($this->stepcount == 0) {
|
||||
return get_string('testscenario_nosteps', 'tool_generator');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the parsed feature is valid.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_valid(): bool {
|
||||
return $this->isvalid && $this->stepcount > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a line to the current scenario.
|
||||
* @param steprunner $step the step to add.
|
||||
*/
|
||||
public function add_step(steprunner $step) {
|
||||
if (empty($this->scenarios)) {
|
||||
$this->add_scenario('scenario', null);
|
||||
}
|
||||
$currentscenario = count($this->scenarios) - 1;
|
||||
$this->scenarios[$currentscenario]->steps[] = $step;
|
||||
$this->stepcount++;
|
||||
if (!$step->is_valid()) {
|
||||
$this->isvalid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new scenario.
|
||||
* @param string $type the type of the scenario.
|
||||
* @param string|null $name the name of the scenario.
|
||||
*/
|
||||
public function add_scenario(string $type, ?string $name) {
|
||||
$this->scenarios[] = (object) [
|
||||
'type' => $type,
|
||||
'name' => $name ?? '',
|
||||
'steps' => [],
|
||||
'error' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the current scenario.
|
||||
* @param string $error
|
||||
*/
|
||||
public function add_error(string $error) {
|
||||
$currentscenario = count($this->scenarios) - 1;
|
||||
$this->scenarios[$currentscenario]->error = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of scenarios.
|
||||
* @return stdClass[] array of scenarionum => {type: string, title: string, steps: steprunner[]}
|
||||
*/
|
||||
public function get_scenarios(): array {
|
||||
return $this->scenarios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the steps form all scenarios.
|
||||
* @return steprunner[]
|
||||
*/
|
||||
public function get_all_steps(): array {
|
||||
$result = [];
|
||||
foreach ($this->scenarios as $scenario) {
|
||||
foreach ($scenario->steps as $step) {
|
||||
$result[] = $step;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace tool_generator\local\testscenario;
|
||||
|
||||
use behat_data_generators;
|
||||
use Behat\Gherkin\Parser;
|
||||
use Behat\Gherkin\Lexer;
|
||||
use Behat\Gherkin\Keywords\ArrayKeywords;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
|
||||
/**
|
||||
* Class to process a scenario generator file.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class runner {
|
||||
|
||||
/** @var behat_data_generators the behat data generator instance. */
|
||||
private behat_data_generators $generator;
|
||||
|
||||
/** @var array of valid steps indexed by given expression tag. */
|
||||
private array $validsteps;
|
||||
|
||||
/**
|
||||
* Initi all composer, behat libraries and load the valid steps.
|
||||
*/
|
||||
public function init() {
|
||||
$this->include_composer_libraries();
|
||||
$this->include_behat_libraries();
|
||||
$this->load_generator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Include composer autload.
|
||||
*/
|
||||
public function include_composer_libraries() {
|
||||
global $CFG;
|
||||
if (!file_exists($CFG->dirroot . '/vendor/autoload.php')) {
|
||||
throw new \moodle_exception('Missing composer.');
|
||||
}
|
||||
require_once($CFG->dirroot . '/vendor/autoload.php');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include all necessary behat libraries.
|
||||
*/
|
||||
public function include_behat_libraries() {
|
||||
global $CFG;
|
||||
if (!class_exists('Behat\Gherkin\Lexer')) {
|
||||
throw new \moodle_exception('Missing behat classes.');
|
||||
}
|
||||
// Behat utilities.
|
||||
require_once($CFG->libdir . '/behat/classes/util.php');
|
||||
require_once($CFG->libdir . '/behat/classes/behat_command.php');
|
||||
require_once($CFG->libdir . '/behat/behat_base.php');
|
||||
require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all generators.
|
||||
*/
|
||||
private function load_generator() {
|
||||
$this->generator = new behat_data_generators();
|
||||
$this->validsteps = $this->scan_generator($this->generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan a generator to get all valid steps.
|
||||
* @param behat_data_generators $generator the generator to scan.
|
||||
* @return array the valid steps.
|
||||
*/
|
||||
private function scan_generator(behat_data_generators $generator): array {
|
||||
$result = [];
|
||||
$class = new ReflectionClass($generator);
|
||||
$methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||
foreach ($methods as $method) {
|
||||
$given = $this->get_method_given($method);
|
||||
if ($given) {
|
||||
$result[$given] = $method->getName();
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the given expression tag of a method.
|
||||
*
|
||||
* @param ReflectionMethod $method the method to get the given expression tag.
|
||||
* @return string|null the given expression tag or null if not found.
|
||||
*/
|
||||
private function get_method_given(ReflectionMethod $method): ?string {
|
||||
$doccomment = $method->getDocComment();
|
||||
$doccomment = str_replace("\r\n", "\n", $doccomment);
|
||||
$doccomment = str_replace("\r", "\n", $doccomment);
|
||||
$doccomment = explode("\n", $doccomment);
|
||||
foreach ($doccomment as $line) {
|
||||
$matches = [];
|
||||
if (preg_match('/.*\@(given|when|then)\s+(.+)$/i', $line, $matches)) {
|
||||
return $matches[2];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a feature file.
|
||||
* @param string $content the feature file content.
|
||||
* @return parsedfeature
|
||||
*/
|
||||
public function parse_feature(string $content): parsedfeature {
|
||||
$result = new parsedfeature();
|
||||
|
||||
$parser = $this->get_parser();
|
||||
$feature = $parser->parse($content);
|
||||
|
||||
// No need for background in testing scenarios because scenarios can only contain generators.
|
||||
// In the future the background can be used to define clean up steps (when clean up methods
|
||||
// are implemented).
|
||||
if ($feature->hasScenarios()) {
|
||||
$scenarios = $feature->getScenarios();
|
||||
foreach ($scenarios as $scenario) {
|
||||
if ($scenario->getNodeType() == 'Outline') {
|
||||
$result->add_scenario($scenario->getNodeType(), $scenario->getTitle());
|
||||
$result->add_error(get_string('testscenario_outline', 'tool_generator'));
|
||||
continue;
|
||||
}
|
||||
$result->add_scenario($scenario->getNodeType(), $scenario->getTitle());
|
||||
$steps = $scenario->getSteps();
|
||||
foreach ($steps as $step) {
|
||||
$result->add_step(new steprunner($this->generator, $this->validsteps, $step));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parser.
|
||||
* @return Parser
|
||||
*/
|
||||
private function get_parser(): Parser {
|
||||
$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',
|
||||
'examples' => 'Examples|Scenarios',
|
||||
'given' => 'Given',
|
||||
'when' => 'When',
|
||||
'then' => 'Then',
|
||||
'and' => 'And',
|
||||
'but' => 'But',
|
||||
],
|
||||
]);
|
||||
$lexer = new Lexer($keywords);
|
||||
$parser = new Parser($lexer);
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a parsed feature.
|
||||
* @param parsedfeature $parsedfeature the parsed feature to execute.
|
||||
* @return bool true if all steps were executed successfully.
|
||||
*/
|
||||
public function execute(parsedfeature $parsedfeature): bool {
|
||||
if (!$parsedfeature->is_valid()) {
|
||||
return false;
|
||||
}
|
||||
$result = true;
|
||||
$steps = $parsedfeature->get_all_steps();
|
||||
foreach ($steps as $step) {
|
||||
$result = $step->execute() && $result;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace tool_generator\local\testscenario;
|
||||
|
||||
use behat_data_generators;
|
||||
use Behat\Gherkin\Node\StepNode;
|
||||
|
||||
/**
|
||||
* Class to validate and process a scenario step.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class steprunner {
|
||||
/** @var behat_data_generators the behat data generator instance. */
|
||||
private behat_data_generators $generator;
|
||||
|
||||
/** @var array the valid steps indexed by given expression tag. */
|
||||
private array $validsteps;
|
||||
|
||||
/** @var StepNode the step node to process. */
|
||||
private StepNode $stepnode;
|
||||
|
||||
/** @var string|null the generator method to call. */
|
||||
private ?string $method = null;
|
||||
|
||||
/** @var array the parameters to pass to the generator method. */
|
||||
private array $params = [];
|
||||
|
||||
/** @var bool if the step is valid. */
|
||||
private bool $isvalid = false;
|
||||
|
||||
/** @var bool if the step has been executed. */
|
||||
private bool $executed = false;
|
||||
|
||||
/** @var string the error message if any. */
|
||||
private string $error = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param behat_data_generators $generator the behat data generator instance.
|
||||
* @param array $validsteps the valid steps indexed by given expression tag.
|
||||
* @param StepNode $stepnode the step node to process.
|
||||
*/
|
||||
public function __construct(behat_data_generators $generator, array $validsteps, StepNode $stepnode) {
|
||||
$this->generator = $generator;
|
||||
$this->validsteps = $validsteps;
|
||||
$this->stepnode = $stepnode;
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the step runner.
|
||||
*
|
||||
* This method will check if the step is valid and all the needed information
|
||||
* in case it is executed.
|
||||
*/
|
||||
private function init() {
|
||||
$matches = [];
|
||||
$linetext = $this->stepnode->getText();
|
||||
foreach ($this->validsteps as $pattern => $method) {
|
||||
if (!$this->match_given($pattern, $linetext, $matches)) {
|
||||
continue;
|
||||
}
|
||||
$this->method = $method;
|
||||
$this->params = $this->build_method_params($method, $matches);
|
||||
$this->isvalid = true;
|
||||
return;
|
||||
}
|
||||
$this->error = get_string('testscenario_invalidstep', 'tool_generator');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the method parameters.
|
||||
* @param string $methodname the method name.
|
||||
* @param array $matches the matches.
|
||||
* @return array the method parameters.
|
||||
*/
|
||||
private function build_method_params($methodname, $matches) {
|
||||
$method = new \ReflectionMethod($this->generator, $methodname);
|
||||
$params = [];
|
||||
foreach ($method->getParameters() as $param) {
|
||||
$paramname = $param->getName();
|
||||
if (isset($matches[$paramname])) {
|
||||
$params[] = $matches[$paramname];
|
||||
unset($matches[$paramname]);
|
||||
} else if (count($matches) > 0) {
|
||||
// If the param is not present means the regular expressions does not use
|
||||
// proper names. So we will try to find the param by position.
|
||||
$params[] = array_pop($matches);
|
||||
} else {
|
||||
// No more params to match.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array_merge($params, $this->stepnode->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the step is valid.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_valid(): bool {
|
||||
return $this->isvalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the step has been executed.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_executed(): bool {
|
||||
return $this->executed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the step text.
|
||||
* @return string
|
||||
*/
|
||||
public function get_text(): string {
|
||||
return $this->stepnode->getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the step error message.
|
||||
* @return string
|
||||
*/
|
||||
public function get_error(): string {
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the step arguments as string.
|
||||
* @return string
|
||||
*/
|
||||
public function get_arguments_string(): string {
|
||||
$result = '';
|
||||
foreach ($this->stepnode->getArguments() as $argument) {
|
||||
$result .= $argument->getTableAsString();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a given expression with a text.
|
||||
* @param string $pattern the given expression.
|
||||
* @param string $text the text to match.
|
||||
* @param array $matches the matches.
|
||||
* @return bool if the step matched the generator given expression.
|
||||
*/
|
||||
private function match_given(string $pattern, $text, array &$matches) {
|
||||
$internalmatcher = [];
|
||||
if (substr($pattern, 0, 1) === '/') {
|
||||
// Pattern is a regular expression.
|
||||
$result = preg_match($pattern, $text, $matches);
|
||||
foreach ($matches as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
unset($matches[$key]);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Patter is a string with parameters.
|
||||
$elementmatches = [];
|
||||
preg_match_all('/:([^ ]+)/', $pattern, $elementmatches, PREG_SET_ORDER, 0);
|
||||
|
||||
$pattern = preg_replace('/:([^ ]+)/', '(?P<$1>"[^"]+"|[^" ]+)', $pattern);
|
||||
$pattern = '/^' . $pattern . '$/';
|
||||
$result = preg_match($pattern, $text, $internalmatcher);
|
||||
if (!$result) {
|
||||
return false;
|
||||
}
|
||||
foreach ($elementmatches as $elementmatch) {
|
||||
// Remove any possible " at the beggining and end of $internalmatcher[$elementmatch[1]].
|
||||
$paramvalue = preg_replace('/^"(.*)"$/', '$1', $internalmatcher[$elementmatch[1]]);
|
||||
$matches[$elementmatch[1]] = $paramvalue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the step.
|
||||
* @return bool if the step is executed or not.
|
||||
*/
|
||||
public function execute(): bool {
|
||||
if (!$this->isvalid) {
|
||||
return false;
|
||||
}
|
||||
$this->executed = true;
|
||||
try {
|
||||
call_user_func_array(
|
||||
[$this->generator, $this->method],
|
||||
$this->params
|
||||
);
|
||||
} catch (\moodle_exception $exception) {
|
||||
$this->error = $exception->getMessage();
|
||||
$this->isvalid = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?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/>.
|
||||
|
||||
namespace tool_generator\output;
|
||||
|
||||
use renderable;
|
||||
use renderer_base;
|
||||
use templatable;
|
||||
use tool_generator\local\testscenario\parsedfeature;
|
||||
|
||||
/**
|
||||
* A report to show the feature file parsing process.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class parsingresult implements renderable, templatable {
|
||||
|
||||
/** @var parsedfeature the processed feature object. */
|
||||
protected $parsedfeature;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param parsedfeature $parsedfeature
|
||||
*/
|
||||
public function __construct(parsedfeature $parsedfeature) {
|
||||
$this->parsedfeature = $parsedfeature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export for template.
|
||||
*
|
||||
* @param renderer_base $output The renderer.
|
||||
* @return array
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): array {
|
||||
$data = [
|
||||
'scenarios' => [],
|
||||
'isvalid' => $this->parsedfeature->is_valid(),
|
||||
'generalerror' => $this->parsedfeature->get_general_error(),
|
||||
];
|
||||
$haslines = false;
|
||||
foreach ($this->parsedfeature->get_scenarios() as $scenario) {
|
||||
$scenariodata = [
|
||||
'type' => $scenario->type,
|
||||
'name' => $scenario->name,
|
||||
'steps' => [],
|
||||
];
|
||||
if (!empty($scenario->error)) {
|
||||
$scenariodata['scenarioerror'] = $scenario->error;
|
||||
}
|
||||
foreach ($scenario->steps as $step) {
|
||||
$scenariodata['steps'][] = [
|
||||
'text' => $step->get_text(),
|
||||
'arguments' => $step->get_arguments_string(),
|
||||
'hasarguments' => !empty($step->get_arguments_string()),
|
||||
'isvalid' => $step->is_valid(),
|
||||
'error' => $step->get_error(),
|
||||
'isexecuted' => $step->is_executed(),
|
||||
];
|
||||
$haslines = true;
|
||||
}
|
||||
if (!empty($scenariodata['steps'])) {
|
||||
$scenariodata['hassteps'] = true;
|
||||
}
|
||||
$data['scenarios'][] = $scenariodata;
|
||||
}
|
||||
if ($haslines) {
|
||||
$data['haslines'] = $haslines;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Run a test scenario generator feature file.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
if (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
die(); // No access from web!
|
||||
}
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require_once(__DIR__ . '/../../../../config.php');
|
||||
require_once(__DIR__ . '/../../../../lib/clilib.php');
|
||||
require_once(__DIR__ . '/../../../../lib/behat/classes/behat_config_manager.php');
|
||||
require_once(__DIR__ . '/../../../../lib/testing/lib.php');
|
||||
|
||||
ini_set('display_errors', '1');
|
||||
ini_set('log_errors', '1');
|
||||
|
||||
list($options, $unrecognised) = cli_get_params(
|
||||
[
|
||||
'help' => false,
|
||||
'feature' => '',
|
||||
'disable-composer' => false,
|
||||
'composer-upgrade' => true,
|
||||
'composer-self-update' => true,
|
||||
],
|
||||
[
|
||||
'h' => 'help',
|
||||
'f' => 'feature',
|
||||
]
|
||||
);
|
||||
|
||||
// Checking run.php CLI script usage.
|
||||
$help = "
|
||||
Run a feature file into the current Moodle instance. The feature file can only
|
||||
contains scenarios with core_data_generator steps. It is not yet compatible
|
||||
with scenario outlines. All scenarios will be executed at once, event background
|
||||
steps.
|
||||
|
||||
Usage:
|
||||
php runtestscenario.php [--feature=\"value\"] [--help]
|
||||
[--no-composer-self-update] [--no-composer-upgrade]
|
||||
[--disable-composer]
|
||||
|
||||
Options:
|
||||
-f, --feature Execute specified feature file (Absolute path of feature file).
|
||||
|
||||
--no-composer-self-update
|
||||
Prevent upgrade of the composer utility using its self-update command
|
||||
|
||||
--no-composer-upgrade
|
||||
Prevent update development dependencies using composer
|
||||
|
||||
--disable-composer
|
||||
A shortcut to disable composer self-update and dependency update
|
||||
Note: Installation of composer and/or dependencies will still happen as required
|
||||
|
||||
-h, --help Print out this help
|
||||
|
||||
Example from Moodle root directory:
|
||||
\$ php admin/tool/generator/cli/runtestscenario.php --feature=/path/to/some/testing/scenario.feature
|
||||
";
|
||||
|
||||
if (!empty($options['help'])) {
|
||||
echo $help;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// The command will install composer if not present. Usually composer libraries are
|
||||
// installed when behat or phpunit are installed, but we do not want to force users
|
||||
// to create all phpunit or behat databases tables just to run a test scenario locally.
|
||||
if (!file_exists($CFG->dirroot . '/vendor/autoload.php')) {
|
||||
// Force OPcache reset if used, we do not want any stale caches
|
||||
// when preparing test environment.
|
||||
if (function_exists('opcache_reset')) {
|
||||
opcache_reset();
|
||||
}
|
||||
|
||||
if ($options['disable-composer']) {
|
||||
// Disable self-update and upgrade easily.
|
||||
// Note: Installation will still occur regardless of this setting.
|
||||
$options['composer-self-update'] = false;
|
||||
$options['composer-upgrade'] = false;
|
||||
}
|
||||
|
||||
// Install and update composer and dependencies as required.
|
||||
testing_update_composer_dependencies($options['composer-self-update'], $options['composer-upgrade']);
|
||||
}
|
||||
|
||||
if (empty($options['feature'])) {
|
||||
echo "Missing feature file path.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$featurefile = $options['feature'];
|
||||
if (!file_exists($featurefile)) {
|
||||
echo "Feature file not found.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$runner = new tool_generator\local\testscenario\runner();
|
||||
|
||||
try {
|
||||
$runner->init();
|
||||
} catch (Exception $e) {
|
||||
echo "Something is wrong with the behat setup.\n";
|
||||
echo " Please,try running \"php admin/tool/behat/cli/init.php\" from your Moodle root directory.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$content = file_get_contents($featurefile);
|
||||
|
||||
if (empty($content)) {
|
||||
echo "The feature file is empty.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
try {
|
||||
$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";
|
||||
echo " Site administration -> development -> Create testing scenarios\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!$parsedfeature->is_valid()) {
|
||||
echo "The file is not valid: {$parsedfeature->get_general_error()}\n";
|
||||
echo "Use the web version of the tool to see the details:\n";
|
||||
echo " Site administration -> development -> Create testing scenarios\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$total = 0;
|
||||
$success = 0;
|
||||
|
||||
foreach ($parsedfeature->get_all_steps() as $step) {
|
||||
if ($step->execute()) {
|
||||
echo "\nOK: {$step->get_text()}\n";
|
||||
echo "{$step->get_arguments_string()}\n";
|
||||
$success++;
|
||||
} else {
|
||||
echo "\nFAIL: {$step->get_text()}\n";
|
||||
echo "{$step->get_arguments_string()}\n";
|
||||
echo "{$step->get_error()}\n";
|
||||
}
|
||||
$total++;
|
||||
}
|
||||
|
||||
echo "\n{$success}/{$total} steps executed successfully.\n";
|
||||
|
||||
if ($success < $total) {
|
||||
echo "\nSome steps failed.\n";
|
||||
exit(1);
|
||||
} else {
|
||||
echo "\nAll steps executed successfully.\n";
|
||||
exit(0);
|
||||
}
|
||||
@@ -95,6 +95,18 @@ $string['sitesize_5'] = 'XXL (~20GB; 4177 courses, created in ~10 hours)';
|
||||
$string['size'] = 'Size of course';
|
||||
$string['smallfiles'] = 'Small files';
|
||||
$string['targetcourse'] = 'Test target course';
|
||||
$string['testscenario'] = 'Create testing scenarios';
|
||||
$string['testscenario_description'] = 'Creating testing scenarios uses a limited feature files syntax to create all necessary elements to run a manual test.';
|
||||
$string['testscenario_filedesc'] = 'The upload feature files can only contain scenarios with core_data_generator steps. It is not yet compatible with scenario outlines. All scenarios will be executed at once but background will be ignored.';
|
||||
$string['testscenario_errorparsing'] = 'Error parsing feature file: {$a}';
|
||||
$string['testscenario_file'] = 'Feature file';
|
||||
$string['testscenario_invalidfile'] = 'The file format is not valid or contains invalid steps.';
|
||||
$string['testscenario_invalidstep'] = 'Unkown step. Create testing scenarios only accepts generator steps.';
|
||||
$string['testscenario_outline'] = 'Scenario outlines are not supported.';
|
||||
$string['testscenario_nosteps'] = 'There are no steps to execute in the file.';
|
||||
$string['testscenario_notready'] = 'Composer and behat libraries are not installed.<br><br>Please, execute this command to enable this tool: <strong>php admin/tool/generator/cli/runtestscenario.php</strong>';
|
||||
$string['testscenario_scenarionosteps'] = 'This scenario does not have any steps.';
|
||||
$string['testscenario_steps'] = 'Testing scenario steps:';
|
||||
$string['testplanexplanation'] = 'This tool creates a JMeter test plan file along with the user credentials file.
|
||||
|
||||
This test plan is designed to work along with {$a}, which makes easier to run the test plan in a specific Moodle environment, gathers information about the runs and compares the results, so you will need to download it and use it\'s test_runner.sh script or follow the installation and usage instructions.
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Web interface to list and filter steps
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use tool_generator\local\testscenario\runner;
|
||||
use tool_generator\form\featureimport;
|
||||
use tool_generator\output\parsingresult;
|
||||
|
||||
require(__DIR__ . '/../../../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
|
||||
|
||||
// Executing behat generator can take some time.
|
||||
core_php_time_limit::raise(300);
|
||||
|
||||
admin_externalpage_setup('toolgenerator_runtestscenario');
|
||||
|
||||
$currenturl = new moodle_url('/admin/tool/generator/runtestscenario.php');
|
||||
$runner = new runner();
|
||||
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
echo $output->header();
|
||||
echo $output->heading(get_string('testscenario', 'tool_generator'));
|
||||
|
||||
echo $output->paragraph(get_string('testscenario_description', 'tool_generator'));
|
||||
|
||||
try {
|
||||
$runner->init();
|
||||
} catch (Exception $e) {
|
||||
echo $output->notification(get_string('testscenario_notready', 'tool_generator'), null, false);
|
||||
echo $output->footer();
|
||||
die;
|
||||
}
|
||||
|
||||
echo $output->paragraph(get_string('testscenario_filedesc', 'tool_generator'));
|
||||
|
||||
$mform = new featureimport();
|
||||
|
||||
$data = null;
|
||||
if (!$mform->is_cancelled()) {
|
||||
$data = $mform->get_data();
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
$mform->display();
|
||||
echo $OUTPUT->footer();
|
||||
die;
|
||||
}
|
||||
|
||||
$content = $mform->get_feature_contents();
|
||||
|
||||
if (empty($content)) {
|
||||
echo $output->notification(get_string('testscenario_invalidfile', 'tool_generator'));
|
||||
echo $output->continue_button($currenturl);
|
||||
echo $output->footer();
|
||||
die;
|
||||
}
|
||||
|
||||
try {
|
||||
$parsedfeature = $runner->parse_feature($content);
|
||||
} catch (\Throwable $th) {
|
||||
echo $output->notification(get_string('testscenario_errorparsing', 'tool_generator', $th->getMessage()));
|
||||
echo $output->continue_button($currenturl);
|
||||
|
||||
echo $output->footer();
|
||||
die;
|
||||
}
|
||||
|
||||
$runner->execute($parsedfeature);
|
||||
|
||||
echo $output->render(new parsingresult($parsedfeature));
|
||||
echo $output->continue_button($currenturl);
|
||||
echo $output->footer();
|
||||
@@ -32,5 +32,13 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('development', new admin_externalpage('toolgeneratortestplan',
|
||||
get_string('maketestplan', 'tool_generator'),
|
||||
$CFG->wwwroot . '/' . $CFG->admin . '/tool/generator/maketestplan.php'));
|
||||
}
|
||||
|
||||
$ADMIN->add(
|
||||
'development',
|
||||
new admin_externalpage(
|
||||
'toolgenerator_runtestscenario',
|
||||
get_string('testscenario', 'tool_generator'),
|
||||
$CFG->wwwroot . '/' . $CFG->admin . '/tool/generator/runtestscenario.php'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
{{!
|
||||
This file is part of Moodle - https://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/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_generator/parsingresult
|
||||
|
||||
Display the result of parsing or executing a behat testing scenario.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"isvalid": true,
|
||||
"generalerror": "Error message",
|
||||
"haslines": true,
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "Scenario",
|
||||
"title": "Scenario title",
|
||||
"hassteps": true,
|
||||
"steps": [
|
||||
{
|
||||
"text": "Step text",
|
||||
"isvalid": true,
|
||||
"isexecuted": true,
|
||||
"hasarguments": true,
|
||||
"arguments": "Argument text",
|
||||
"error": "Error message"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{^isvalid}}
|
||||
<div class="alert alert-danger mb-3" role="alert">
|
||||
<span class="fa fa-times"></span>
|
||||
{{generalerror}}
|
||||
</div>
|
||||
{{/isvalid}}
|
||||
{{#haslines}}
|
||||
<p>{{#str}} testscenario_steps, tool_generator {{/str}}</p>
|
||||
{{/haslines}}
|
||||
{{#scenarios}}
|
||||
<h3>{{type}}: {{name}}</h3>
|
||||
<div>
|
||||
{{#scenarioerror}}
|
||||
<div class="alert alert-danger mb-3" role="alert">
|
||||
<span class="fa fa-times"></span>
|
||||
{{scenarioerror}}
|
||||
</div>
|
||||
{{/scenarioerror}}
|
||||
{{^hassteps}}
|
||||
<div class="alert alert-info mb-3" role="alert">
|
||||
<span class="fa fa-info-circle"></span>
|
||||
{{#str}} testscenario_scenarionosteps, tool_generator {{/str}}
|
||||
</div>
|
||||
{{/hassteps}}
|
||||
{{#hassteps}}
|
||||
<ul class="list-group mb-3">
|
||||
{{#steps}}
|
||||
<li class="list-group-item">
|
||||
<div>
|
||||
{{text}}
|
||||
{{^isvalid}}
|
||||
<span class="badge badge-pill badge-danger">
|
||||
<span class="fa fa-times"></span>
|
||||
{{#str}} error {{/str}}
|
||||
</span>
|
||||
{{/isvalid}}
|
||||
{{#isvalid}}
|
||||
{{#isexecuted}}
|
||||
<span class="badge badge-pill badge-success">
|
||||
<span class="fa fa-check "></span>
|
||||
{{#str}} success {{/str}}
|
||||
</span>
|
||||
{{/isexecuted}}
|
||||
{{/isvalid}}
|
||||
</div>
|
||||
{{#hasarguments}}
|
||||
<div class="alert alert-info mb-0 mt-2" role="alert" style="overflow: auto;">
|
||||
<pre class="mb-0">{{arguments}}</pre>
|
||||
</div>
|
||||
{{/hasarguments}}
|
||||
{{^isvalid}}
|
||||
<div class="alert alert-danger mb-0 mt-2" role="alert" style="overflow: auto;">
|
||||
{{error}}
|
||||
</div>
|
||||
{{/isvalid}}
|
||||
</li>
|
||||
{{/steps}}
|
||||
</ul>
|
||||
{{/hassteps}}
|
||||
</div>
|
||||
{{/scenarios}}
|
||||
@@ -0,0 +1,64 @@
|
||||
@tool @tool_generator @_file_upload
|
||||
Feature: Create testing scenarios using generators
|
||||
In order to execute manual tests
|
||||
As a developer
|
||||
I need to use a feature file to execute generators into the current instance
|
||||
|
||||
@javascript
|
||||
Scenario: Create a testing scenario with a course enrolled users and activities
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
When I upload "admin/tool/generator/tests/fixtures/testscenario/scenario.feature" file to "Feature file" filemanager
|
||||
And I press "Import"
|
||||
And I should see "Scenario: Create course content"
|
||||
Then I am on the "C1" "Course" page
|
||||
And I should see "Activity sample 1" in the "Topic 1" "section"
|
||||
And I should see "Activity sample 2" in the "Topic 1" "section"
|
||||
And I navigate to course participants
|
||||
And I should see "Teacher Test1"
|
||||
And I should see "Student Test1"
|
||||
And I should see "Student Test2"
|
||||
And I should see "Student Test3"
|
||||
And I should see "Student Test4"
|
||||
And I should see "Student Test5"
|
||||
|
||||
@javascript
|
||||
Scenario: Prevent creating a testing scenario with no steps to execute
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
When I upload "admin/tool/generator/tests/fixtures/testscenario/scenario_wrongempty.feature" file to "Feature file" filemanager
|
||||
And I press "Import"
|
||||
Then I should see "There are no steps to execute in the file."
|
||||
|
||||
@javascript
|
||||
Scenario: Prevent creating a testing scenario with only background steps to execute
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
When I upload "admin/tool/generator/tests/fixtures/testscenario/scenario_wrongonlybackground.feature" file to "Feature file" filemanager
|
||||
And I press "Import"
|
||||
Then I should see "There are no steps to execute in the file."
|
||||
|
||||
@javascript
|
||||
Scenario: Prevent creating a testing scenario with a wrong file format
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
When I upload "admin/tool/generator/tests/fixtures/testscenario/scenario_wrongformat.feature" file to "Feature file" filemanager
|
||||
And I press "Import"
|
||||
Then I should see "Error parsing feature file"
|
||||
|
||||
@javascript
|
||||
Scenario: Prevent creating a testing scenario with non generator steps
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
When I upload "admin/tool/generator/tests/fixtures/testscenario/scenario_wrongstep.feature" file to "Feature file" filemanager
|
||||
And I press "Import"
|
||||
Then I should see "The file format is not valid or contains invalid steps"
|
||||
|
||||
@javascript
|
||||
Scenario: Prevent creating a testing scenario from a scenario outline
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Development > Create testing scenarios" in site administration
|
||||
When I upload "admin/tool/generator/tests/fixtures/testscenario/scenario_wrongoutline.feature" file to "Feature file" filemanager
|
||||
And I press "Import"
|
||||
Then I should see "Scenario outlines are not supported"
|
||||
Then I should see "There are no steps to execute in the file"
|
||||
@@ -0,0 +1,27 @@
|
||||
Feature: Prepare scenario for testing
|
||||
Scenario: Create course content
|
||||
Given the following "course" exists:
|
||||
| fullname | Course test |
|
||||
| shortname | C1 |
|
||||
| category | 0 |
|
||||
| numsections | 3 |
|
||||
And the following "activities" exist:
|
||||
| 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 |
|
||||
Scenario: Create users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Test1 | sample@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And "5" "users" exist with the following data:
|
||||
| username | student[count] |
|
||||
| firstname | Student |
|
||||
| lastname | Test[count] |
|
||||
| email | student[count]@example.com |
|
||||
And "5" "course enrolments" exist with the following data:
|
||||
| user | student[count] |
|
||||
| course | C1 |
|
||||
| role | student |
|
||||
@@ -0,0 +1,4 @@
|
||||
Feature: Prepare scenario for testing
|
||||
Scenario: only empty scenario 1.
|
||||
Scenario: only empty scenario 2.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
This is not a valid feature file.
|
||||
|
||||
However: it has lines
|
||||
indented and stuff
|
||||
like if it was.
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Feature: Invalid texting because background is not compatible
|
||||
Background:
|
||||
Given the following "course" exists:
|
||||
| fullname | Course 1 |
|
||||
| shortname | C1 |
|
||||
| category | 0 |
|
||||
| numsections | 3 |
|
||||
And the following "activities" exist:
|
||||
| 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 |
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
Feature: Prepare scenario for testing
|
||||
|
||||
Scenario Outline: test outline scenarios are not supported yet
|
||||
Given the following "course" exists:
|
||||
| fullname | <name> |
|
||||
| shortname | <shortname> |
|
||||
| category | 0 |
|
||||
| numsections | 3 |
|
||||
|
||||
Examples:
|
||||
| name | shortname |
|
||||
| Course 1 | C1 |
|
||||
| Course 2 | C2 |
|
||||
| Course 3 | C3 |
|
||||
@@ -0,0 +1,13 @@
|
||||
Feature: Contains wrong steps
|
||||
Scenario: Scenario with non generator steps
|
||||
Given the following "course" exists:
|
||||
| fullname | Course test |
|
||||
| shortname | C1 |
|
||||
| category | 0 |
|
||||
| numsections | 3 |
|
||||
And the following "activities" exist:
|
||||
| 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 |
|
||||
And I click on "Tokens filter" "link"
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
<?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/>.
|
||||
|
||||
namespace tool_generator\local\testscenario;
|
||||
|
||||
/**
|
||||
* Tests for parsedfeature class.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \tool_generator\local\testscenario\parsedfeature
|
||||
*/
|
||||
class parsedfeature_test extends \advanced_testcase {
|
||||
/**
|
||||
* Get a parsed feature from a content.
|
||||
* @param string $content the feature content.
|
||||
* @return parsedfeature the parsed feature.
|
||||
*/
|
||||
private function get_feature_from_content(string $content): parsedfeature {
|
||||
$runner = new runner();
|
||||
$runner->init();
|
||||
return $runner->parse_feature($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for parse_feature.
|
||||
* @covers ::get_general_error
|
||||
* @covers ::add_scenario
|
||||
* @covers ::add_step
|
||||
*/
|
||||
public function test_general_error(): void {
|
||||
$nosteps = get_string('testscenario_nosteps', 'tool_generator');
|
||||
$invalidfile = get_string('testscenario_invalidfile', 'tool_generator');
|
||||
|
||||
$parsedfeature = new parsedfeature();
|
||||
$this->assertEquals($nosteps, $parsedfeature->get_general_error());
|
||||
|
||||
$parsedfeature->add_scenario('Scenario', 'Test scenario');
|
||||
$this->assertEquals($nosteps, $parsedfeature->get_general_error());
|
||||
|
||||
// Add some valid step.
|
||||
$extrafeature = $this->get_feature_from_content('Feature: Test feature
|
||||
Scenario: Create users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Test1 | [email protected] |
|
||||
');
|
||||
$step = $extrafeature->get_all_steps()[0];
|
||||
$parsedfeature->add_step($step);
|
||||
$this->assertEquals('', $parsedfeature->get_general_error());
|
||||
|
||||
// Only generator methods are allowed.
|
||||
$extrafeature = $this->get_feature_from_content('Feature: Test feature
|
||||
Scenario: Not generator
|
||||
Given I am in a course
|
||||
');
|
||||
$step = $extrafeature->get_all_steps()[0];
|
||||
$parsedfeature->add_step($step);
|
||||
$this->assertEquals($invalidfile, $parsedfeature->get_general_error());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for parse_feature.
|
||||
* @covers ::is_valid
|
||||
* @covers ::add_scenario
|
||||
* @covers ::add_step
|
||||
*/
|
||||
public function test_is_valid(): void {
|
||||
$parsedfeature = new parsedfeature();
|
||||
$this->assertFalse($parsedfeature->is_valid());
|
||||
|
||||
$parsedfeature->add_scenario('Scenario', 'Test scenario');
|
||||
$this->assertFalse($parsedfeature->is_valid());
|
||||
|
||||
// Add some valid step.
|
||||
$extrafeature = $this->get_feature_from_content('Feature: Test feature
|
||||
Scenario: Create users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Test1 | [email protected] |
|
||||
');
|
||||
$step = $extrafeature->get_all_steps()[0];
|
||||
$parsedfeature->add_step($step);
|
||||
$this->assertTrue($parsedfeature->is_valid());
|
||||
|
||||
// Only generator methods are allowed.
|
||||
$extrafeature = $this->get_feature_from_content('Feature: Test feature
|
||||
Scenario: Not generator
|
||||
Given I am in a course
|
||||
');
|
||||
$step = $extrafeature->get_all_steps()[0];
|
||||
$parsedfeature->add_step($step);
|
||||
$this->assertFalse($parsedfeature->is_valid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for ading steps into scenarios.
|
||||
* @covers ::add_step
|
||||
* @covers ::add_scenario
|
||||
* @covers ::get_all_steps
|
||||
* @covers ::get_scenarios
|
||||
*/
|
||||
public function test_add_step(): void {
|
||||
$parsedfeature = new parsedfeature();
|
||||
$this->assertEquals(0, count($parsedfeature->get_all_steps()));
|
||||
|
||||
$extrafeature = $this->get_feature_from_content('Feature: Test feature
|
||||
Scenario: Create users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Test1 | [email protected] |
|
||||
');
|
||||
$step = $extrafeature->get_all_steps()[0];
|
||||
$parsedfeature->add_step($step);
|
||||
$this->assertEquals(1, count($parsedfeature->get_all_steps()));
|
||||
|
||||
// Should create a default scenario.
|
||||
$scenarios = $parsedfeature->get_scenarios();
|
||||
$this->assertEquals(1, count($scenarios));
|
||||
$this->assertEquals('scenario', $scenarios[0]->type);
|
||||
$this->assertEquals('', $scenarios[0]->name);
|
||||
$this->assertEquals(1, count($scenarios[0]->steps));
|
||||
$this->assertEquals($step, $scenarios[0]->steps[0]);
|
||||
$this->assertEquals('', $scenarios[0]->error);
|
||||
|
||||
// Add a second step.
|
||||
$extrafeature = $this->get_feature_from_content('Feature: Test feature
|
||||
Scenario: Not generator
|
||||
Given I am in a course
|
||||
');
|
||||
$step2 = $extrafeature->get_all_steps()[0];
|
||||
$parsedfeature->add_step($step2);
|
||||
$scenarios = $parsedfeature->get_scenarios();
|
||||
$this->assertEquals(1, count($scenarios));
|
||||
$this->assertEquals('scenario', $scenarios[0]->type);
|
||||
$this->assertEquals('', $scenarios[0]->name);
|
||||
$this->assertEquals(2, count($scenarios[0]->steps));
|
||||
$this->assertEquals($step, $scenarios[0]->steps[0]);
|
||||
$this->assertEquals($step2, $scenarios[0]->steps[1]);
|
||||
$this->assertEquals('', $scenarios[0]->error);
|
||||
|
||||
// Create a new scenario.
|
||||
$parsedfeature->add_scenario('scenario', 'Test scenario 2');
|
||||
$parsedfeature->add_step($step2);
|
||||
$scenarios = $parsedfeature->get_scenarios();
|
||||
$this->assertEquals(2, count($scenarios));
|
||||
// Scenario 1.
|
||||
$this->assertEquals('scenario', $scenarios[0]->type);
|
||||
$this->assertEquals('', $scenarios[0]->name);
|
||||
$this->assertEquals(2, count($scenarios[0]->steps));
|
||||
$this->assertEquals($step, $scenarios[0]->steps[0]);
|
||||
$this->assertEquals($step2, $scenarios[0]->steps[1]);
|
||||
$this->assertEquals('', $scenarios[0]->error);
|
||||
// Scenario 2.
|
||||
$this->assertEquals('scenario', $scenarios[1]->type);
|
||||
$this->assertEquals('Test scenario 2', $scenarios[1]->name);
|
||||
$this->assertEquals(1, count($scenarios[1]->steps));
|
||||
$this->assertEquals($step2, $scenarios[1]->steps[0]);
|
||||
$this->assertEquals('', $scenarios[1]->error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for ading errors into scenarios.
|
||||
* @covers ::add_error
|
||||
* @covers ::add_scenario
|
||||
* @covers ::add_step
|
||||
* @covers ::get_scenarios
|
||||
*/
|
||||
public function test_add_error(): void {
|
||||
$parsedfeature = new parsedfeature();
|
||||
|
||||
// Add some valid step.
|
||||
$extrafeature = $this->get_feature_from_content('Feature: Test feature
|
||||
Scenario: Create users
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Test1 | [email protected] |
|
||||
');
|
||||
$step = $extrafeature->get_all_steps()[0];
|
||||
|
||||
$parsedfeature->add_scenario('scenario', 'Test scenario 1');
|
||||
$parsedfeature->add_step($step);
|
||||
$parsedfeature->add_error('Error message');
|
||||
$parsedfeature->add_scenario('scenario', 'Test scenario 2');
|
||||
$parsedfeature->add_step($step);
|
||||
|
||||
$scenarios = $parsedfeature->get_scenarios();
|
||||
$this->assertEquals(2, count($scenarios));
|
||||
// Scenario 1.
|
||||
$this->assertEquals('scenario', $scenarios[0]->type);
|
||||
$this->assertEquals('Test scenario 1', $scenarios[0]->name);
|
||||
$this->assertEquals(1, count($scenarios[0]->steps));
|
||||
$this->assertEquals($step, $scenarios[0]->steps[0]);
|
||||
$this->assertEquals('Error message', $scenarios[0]->error);
|
||||
// Scenario 2.
|
||||
$this->assertEquals('scenario', $scenarios[1]->type);
|
||||
$this->assertEquals('Test scenario 2', $scenarios[1]->name);
|
||||
$this->assertEquals(1, count($scenarios[1]->steps));
|
||||
$this->assertEquals($step, $scenarios[1]->steps[0]);
|
||||
$this->assertEquals('', $scenarios[1]->error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?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/>.
|
||||
|
||||
namespace tool_generator\local\testscenario;
|
||||
|
||||
/**
|
||||
* Tests for runner class.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \tool_generator\local\testscenario\runner
|
||||
*/
|
||||
class runner_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test for parse_feature.
|
||||
* @covers ::parse_feature
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_parse_and_execute_feature(): void {
|
||||
global $CFG, $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Call the init method to include all behat libraries and attributes.
|
||||
$runner = new runner();
|
||||
$runner->init();
|
||||
|
||||
$featurefile = $CFG->dirroot . '/admin/tool/generator/tests/fixtures/testscenario/scenario.feature';
|
||||
$contents = file_get_contents($featurefile);
|
||||
$feature = $runner->parse_feature($contents);
|
||||
|
||||
$this->assertEquals(2, count($feature->get_scenarios()));
|
||||
$this->assertEquals(6, count($feature->get_all_steps()));
|
||||
$this->assertTrue($feature->is_valid());
|
||||
|
||||
$result = $runner->execute($feature);
|
||||
$this->assertTrue($result);
|
||||
|
||||
// Validate everything is created.
|
||||
$this->assertEquals(
|
||||
1,
|
||||
$DB->count_records('course', ['shortname' => 'C1'])
|
||||
);
|
||||
$course = $DB->get_record('course', ['shortname' => 'C1']);
|
||||
$this->assertEquals(
|
||||
2,
|
||||
$DB->count_records('course_modules', ['course' => $course->id])
|
||||
);
|
||||
$this->assertEquals(
|
||||
1,
|
||||
$DB->count_records('user', ['firstname' => 'Teacher'])
|
||||
);
|
||||
$this->assertEquals(
|
||||
5,
|
||||
$DB->count_records('user', ['firstname' => 'Student'])
|
||||
);
|
||||
$context = \context_course::instance($course->id);
|
||||
$this->assertEquals(
|
||||
6,
|
||||
$DB->count_records('role_assignments', ['contextid' => $context->id])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for parse_feature.
|
||||
* @covers ::parse_feature
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_parse_and_execute_wrong_feature(): void {
|
||||
global $CFG, $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Call the init method to include all behat libraries and attributes.
|
||||
$runner = new runner();
|
||||
$runner->init();
|
||||
|
||||
$featurefile = $CFG->dirroot . '/admin/tool/generator/tests/fixtures/testscenario/scenario_wrongstep.feature';
|
||||
$contents = file_get_contents($featurefile);
|
||||
$feature = $runner->parse_feature($contents);
|
||||
|
||||
$this->assertEquals(1, count($feature->get_scenarios()));
|
||||
$this->assertEquals(3, count($feature->get_all_steps()));
|
||||
$this->assertFalse($feature->is_valid());
|
||||
|
||||
$result = $runner->execute($feature);
|
||||
$this->assertFalse($result);
|
||||
$this->assertEquals(0, $DB->count_records('course', ['shortname' => 'C1']));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
<?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/>.
|
||||
|
||||
namespace tool_generator\local\testscenario;
|
||||
|
||||
use behat_data_generators;
|
||||
use Behat\Gherkin\Parser;
|
||||
use Behat\Gherkin\Lexer;
|
||||
use Behat\Gherkin\Keywords\ArrayKeywords;
|
||||
use Behat\Gherkin\Node\StepNode;
|
||||
|
||||
/**
|
||||
* Tests for steprunner class.
|
||||
*
|
||||
* @package tool_generator
|
||||
* @copyright 2023 Ferran Recio <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \tool_generator\local\testscenario\steprunner
|
||||
*/
|
||||
class steprunner_test extends \advanced_testcase {
|
||||
public static function setUpBeforeClass(): void {
|
||||
// Call the init method to include all behat libraries and attributes.
|
||||
$runner = new runner();
|
||||
$runner->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a step node from a string.
|
||||
* @param string $step the step string.
|
||||
* @return StepNode the step node.
|
||||
*/
|
||||
private function get_step(string $step): StepNode {
|
||||
$content = 'Feature: Test feature
|
||||
Scenario: Test scenario
|
||||
' . $step . '
|
||||
';
|
||||
|
||||
$method = new \ReflectionMethod(runner::class, 'get_parser');
|
||||
$parser = $method->invoke(new runner());
|
||||
|
||||
$feature = $parser->parse($content);
|
||||
$scenario = $feature->getScenarios()[0];
|
||||
$steps = $scenario->getSteps();
|
||||
return $steps[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for parse_feature.
|
||||
* @covers ::is_valid
|
||||
* @param string $step the step to validate.
|
||||
* @param bool $expected if the step is expected to be valid.
|
||||
* @dataProvider execute_steps_provider
|
||||
*/
|
||||
public function test_is_valid(string $step, bool $expected): void {
|
||||
$generator = new behat_data_generators();
|
||||
$validsteps = [
|
||||
'/^the following "(?P<element_string>(?:[^"]|\\")*)" exist:$/' => 'the_following_entities_exist',
|
||||
':count :entitytype exist with the following data:' => 'the_following_repeated_entities_exist',
|
||||
'the following :entitytype exists:' => 'the_following_entity_exists',
|
||||
];
|
||||
|
||||
$step = $this->get_step($step);
|
||||
$steprunner = new steprunner($generator, $validsteps, $step);
|
||||
$this->assertEquals($expected, $steprunner->is_valid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for execute step.
|
||||
*
|
||||
* @covers ::is_executed
|
||||
* @covers ::execute
|
||||
* @param string $step the step to execute.
|
||||
* @param bool $expected if the step is expected to be executed.
|
||||
* @dataProvider execute_steps_provider
|
||||
*/
|
||||
public function test_execute(string $step, bool $expected): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$generator = new behat_data_generators();
|
||||
$validsteps = [
|
||||
'/^the following "(?P<element_string>(?:[^"]|\\")*)" exist:$/' => 'the_following_entities_exist',
|
||||
':count :entitytype exist with the following data:' => 'the_following_repeated_entities_exist',
|
||||
'the following :entitytype exists:' => 'the_following_entity_exists',
|
||||
];
|
||||
|
||||
$step = $this->get_step($step);
|
||||
$steprunner = new steprunner($generator, $validsteps, $step);
|
||||
|
||||
$this->assertFalse($steprunner->is_executed());
|
||||
|
||||
$result = $steprunner->execute();
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
$this->assertEquals($expected, $steprunner->is_executed());
|
||||
|
||||
if ($expected) {
|
||||
// Validate everything is created.
|
||||
$this->assertEquals(
|
||||
1,
|
||||
$DB->count_records('course', ['shortname' => 'C1'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_execute.
|
||||
* @return array the data.
|
||||
*/
|
||||
public static function execute_steps_provider(): array {
|
||||
return [
|
||||
'Following exists' => [
|
||||
'step' => 'Given the following "course" exists:
|
||||
| fullname | Course test |
|
||||
| shortname | C1 |
|
||||
| category | 0 |',
|
||||
'expected' => true,
|
||||
],
|
||||
'Following exist' => [
|
||||
'step' => 'Given the following "course" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course test | C1 | 0 |',
|
||||
'expected' => true,
|
||||
],
|
||||
'Repeated entities' => [
|
||||
'step' => 'Given "1" "courses" exist with the following data:
|
||||
| fullname | Course test |
|
||||
| shortname | C[count] |
|
||||
| category | 0 |
|
||||
| numsections | 3 |',
|
||||
'expected' => true,
|
||||
],
|
||||
'Invalid step' => [
|
||||
'step' => 'Given I click on "Tokens filter" "link"',
|
||||
'expected' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for execute step.
|
||||
* @covers ::is_executed
|
||||
* @covers ::execute
|
||||
* @covers ::get_error
|
||||
*/
|
||||
public function test_execute_duplicated(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$generator = new behat_data_generators();
|
||||
$validsteps = [
|
||||
'/^the following "(?P<element_string>(?:[^"]|\\")*)" exist:$/' => 'the_following_entities_exist',
|
||||
':count :entitytype exist with the following data:' => 'the_following_repeated_entities_exist',
|
||||
'the following :entitytype exists:' => 'the_following_entity_exists',
|
||||
];
|
||||
|
||||
$step = $this->get_step('Given the following "course" exists:
|
||||
| fullname | Course test |
|
||||
| shortname | C1 |
|
||||
| category | 0 |');
|
||||
$steprunner = new steprunner($generator, $validsteps, $step);
|
||||
|
||||
$this->assertFalse($steprunner->is_executed());
|
||||
|
||||
$result = $steprunner->execute();
|
||||
|
||||
$this->assertTrue($result);
|
||||
$this->assertTrue($steprunner->is_executed());
|
||||
$this->assertEquals('', $steprunner->get_error());
|
||||
|
||||
// Validate everything is created.
|
||||
$this->assertEquals(
|
||||
1,
|
||||
$DB->count_records('course', ['shortname' => 'C1'])
|
||||
);
|
||||
|
||||
// Execute the same course creation.
|
||||
$steprunner = new steprunner($generator, $validsteps, $step);
|
||||
$this->assertFalse($steprunner->is_executed());
|
||||
$result = $steprunner->execute();
|
||||
$this->assertFalse($result);
|
||||
$this->assertTrue($steprunner->is_executed());
|
||||
$this->assertEquals(get_string('shortnametaken', 'error', 'C1'), $steprunner->get_error());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for parse_feature.
|
||||
* @covers ::get_text
|
||||
* @covers ::get_arguments_string
|
||||
*/
|
||||
public function test_get_step_content(): void {
|
||||
$generator = new behat_data_generators();
|
||||
$validsteps = [
|
||||
'/^the following "(?P<element_string>(?:[^"]|\\")*)" exist:$/' => 'the_following_entities_exist',
|
||||
':count :entitytype exist with the following data:' => 'the_following_repeated_entities_exist',
|
||||
'the following :entitytype exists:' => 'the_following_entity_exists',
|
||||
];
|
||||
|
||||
$step = $this->get_step('Given the following "course" exists:
|
||||
| fullname | Course test |
|
||||
| shortname | C1 |
|
||||
| category | 0 |
|
||||
| numsections | 3 |');
|
||||
$steprunner = new steprunner($generator, $validsteps, $step);
|
||||
|
||||
$this->assertEquals(
|
||||
'the following "course" exists:',
|
||||
$steprunner->get_text()
|
||||
);
|
||||
|
||||
$data = [
|
||||
'| fullname | Course test |',
|
||||
'| shortname | C1 |',
|
||||
'| category | 0 |',
|
||||
'| numsections | 3 |',
|
||||
];
|
||||
$arguments = explode("\n", $steprunner->get_arguments_string());
|
||||
$this->assertEquals(
|
||||
$data,
|
||||
$arguments
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user