diff --git a/admin/tool/behat/cli/util.php b/admin/tool/behat/cli/util.php index 93c5914d8b1..a83b6639836 100644 --- a/admin/tool/behat/cli/util.php +++ b/admin/tool/behat/cli/util.php @@ -32,9 +32,7 @@ require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/locallib.php'); list($options, $unrecognized) = cli_get_params( array( 'help' => false, - 'stepsdefinitions' => false, 'runtests' => false, - 'filter' => false, 'tags' => false, 'extra' => false, 'with-javascript' => false, @@ -51,7 +49,6 @@ Behat tool Ensure the user who executes the action has permissions over behat installation Options: ---stepsdefinitions Displays the available steps definitions (accepts --filter=\"\" option to restrict the list to the matching definitions) --runtests Runs the tests (accepts --with-javascript option, --tags=\"\" option to execute only the matching tests and --extra=\"\" to specify extra behat options) --testenvironment Allows the test environment to be accesses through the built-in server (accepts value 'enable' or 'disable') @@ -73,7 +70,7 @@ if ($unrecognized) { cli_error(get_string('cliunknowoption', 'admin', $unrecognized)); } -$commands = array('stepsdefinitions', 'runtests', 'testenvironment'); +$commands = array('runtests', 'testenvironment'); foreach ($commands as $command) { if ($options[$command]) { $action = $command; @@ -88,10 +85,6 @@ if (empty($action)) { switch ($action) { - case 'stepsdefinitions': - tool_behat::stepsdefinitions($options['filter']); - break; - case 'runtests': tool_behat::runtests($options['with-javascript'], $options['tags'], $options['extra']); break; diff --git a/admin/tool/behat/index.php b/admin/tool/behat/index.php index f1c7b5f1b9e..31653c42a19 100644 --- a/admin/tool/behat/index.php +++ b/admin/tool/behat/index.php @@ -26,8 +26,29 @@ require(__DIR__ . '/../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/locallib.php'); -$action = optional_param('action', 'info', PARAM_ALPHAEXT); +$filter = optional_param('filter', '', PARAM_ALPHANUMEXT); +$type = optional_param('type', false, PARAM_ALPHAEXT); +$component = optional_param('component', '', PARAM_ALPHAEXT); admin_externalpage_setup('toolbehat'); -call_user_func('tool_behat::' . $action); +// Getting available steps definitions from behat. +$steps = tool_behat::stepsdefinitions($type, $component, $filter); + +// Form. +$componentswithsteps = array( + '' => get_string('allavailablesteps', 'tool_behat'), + 'nomoodle' => get_string('nomoodlesteps', 'tool_behat'), +); +$components = tool_behat::get_components_steps_definitions(); +if ($components) { + foreach ($components as $component => $filepath) { + $componentswithsteps[$component] = 'Moodle ' . substr($component, 6); + } +} +$form = new steps_definitions_form(null, array('components' => $componentswithsteps)); + +// Output contents. +$renderer = $PAGE->get_renderer('tool_behat'); +echo $renderer->render_stepsdefinitions($steps, $form); + diff --git a/admin/tool/behat/lang/en/tool_behat.php b/admin/tool/behat/lang/en/tool_behat.php index 33a5a051f13..1f43264fe05 100644 --- a/admin/tool/behat/lang/en/tool_behat.php +++ b/admin/tool/behat/lang/en/tool_behat.php @@ -23,15 +23,26 @@ */ $string['actionnotsupported'] = 'Action not supported'; +$string['allavailablesteps'] = 'All the available steps'; $string['commandinfo'] = 'Info'; $string['commandruntests'] = 'Run tests'; $string['commandstepsdefinitions'] = 'Steps definitions list'; $string['commandswitchenvironment'] = 'Switch environment'; $string['finished'] = 'Process finished'; -$string['nobehatpath'] = 'You must specify the path to moodle-acceptance-tests.'; +$string['giveninfo'] = 'Given. Processes to set up the environment'; +$string['installinfo'] = 'for installation and tests execution info'; +$string['moreinfoin'] = 'More info in'; +$string['newstepsinfo'] = 'for info about adding new steps definitions'; +$string['newtestsinfo'] = 'for info about writting new tests'; +$string['nobehatpath'] = 'Behat path not found, use \'behatpath\' setting to specify it'; +$string['nomoodlesteps'] = 'Generic web application steps'; $string['nostepsdefinitions'] = 'There aren\'t steps definitions matching this filter'; $string['pluginname'] = 'Acceptance testing'; -$string['stepsdefinitions'] = 'Steps definitions which contains'; -$string['stepsdefinitionsemptyfilter'] = 'all steps definitions if empty'; -$string['viewsteps'] = 'View available steps definitions'; -$string['wrongbehatsetup'] = 'Something is wrong with the setup, check moodle-acceptance-tests runs well on CLI and check your \'behatpath\' setting value is pointing to the right directory'; \ No newline at end of file +$string['stepsdefinitionscomponent'] = 'Area'; +$string['stepsdefinitionscontains'] = 'Contains'; +$string['stepsdefinitionsfilters'] = 'Steps definitions'; +$string['stepsdefinitionstype'] = 'Type'; +$string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones'; +$string['viewsteps'] = 'Filter'; +$string['wheninfo'] = 'When. Actions that provokes an event'; +$string['wrongbehatsetup'] = 'Something is wrong with the setup, check moodle-acceptance-tests runs well on CLI and check your \'behatpath\' setting value is pointing to the right directory'; diff --git a/admin/tool/behat/locallib.php b/admin/tool/behat/locallib.php index 2b5cc767b1a..237f26233e0 100644 --- a/admin/tool/behat/locallib.php +++ b/admin/tool/behat/locallib.php @@ -26,6 +26,8 @@ require_once($CFG->libdir . '/filestorage/file_exceptions.php'); require_once($CFG->libdir . '/phpunit/bootstraplib.php'); require_once($CFG->libdir . '/phpunit/classes/tests_finder.php'); +require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/steps_definitions_form.php'); + /** * Behat commands manager * @@ -35,84 +37,60 @@ require_once($CFG->libdir . '/phpunit/classes/tests_finder.php'); */ class tool_behat { + /** + * Path where each component's tests are stored + * @var string + */ private static $behat_tests_path = '/tests/behat'; /** - * Displays basic info about acceptance tests + * Steps types + * @var array */ - public static function info() { + private static $steps_types = array('given', 'when', 'then'); - $html = self::get_header(); - $html .= self::get_info(); - $html .= self::get_steps_definitions_form(); - $html .= self::get_footer(); - - echo $html; - } + public static $docsurl = 'http://docs.moodle.org/dev/Acceptance_testing'; /** * Lists the available steps definitions - * @param string $filter Keyword to filter the list of steps definitions availables + * + * @param string $type + * @param string $component + * @param string $filter + * @return string */ - public static function stepsdefinitions($filter = false) { + public static function stepsdefinitions($type, $component, $filter) { global $CFG; self::check_behat_setup(); - self::update_config_file(); + // The loaded steps depends on the component specified. + self::update_config_file($component); - // Priority to the one specified as argument. - if (!$filter) { - $filter = optional_param('filter', false, PARAM_ALPHANUMEXT); + if ($type) { + $filter .= '&&' . $type; } if ($filter) { - $filteroption = ' -d ' . $filter; + $filteroption = ' -d "' . $filter . '"'; } else { $filteroption = ' -di'; } - $color = ''; - if (CLI_SCRIPT) { - $color = '--ansi '; - } - $currentcwd = getcwd(); chdir($CFG->behatpath); - exec('bin/behat ' . $color . ' --config="' . self::get_behat_config_filepath() . '" ' . $filteroption, $steps, $code); + exec('bin/behat --config="' . self::get_behat_config_filepath() . '" ' . $filteroption, $steps, $code); chdir($currentcwd); - // Outputing steps. - - $content = ''; if ($steps) { - foreach ($steps as $line) { - - // Skipping the step definition context. - if (strpos($line, '#') == 0) { - if (CLI_SCRIPT) { - $content .= $line . PHP_EOL; - } else { - $content .= htmlentities($line) . '
'; - } - - } - } + $stepshtml = implode('', $steps); } - if ($content === '') { - $content = get_string('nostepsdefinitions', 'tool_behat'); + if (!isset($stepshtml) || $stepshtml == '') { + $stepshtml = get_string('nostepsdefinitions', 'tool_behat'); } - if (!CLI_SCRIPT) { - $html = self::get_header(); - $html .= self::get_steps_definitions_form($filter); - $html .= html_writer::tag('div', $content, array('id' => 'steps-definitions')); - $html .= self::get_footer(); - echo $html; - } else { - echo $content; - } + return $stepshtml; } /** @@ -149,7 +127,7 @@ class tool_behat { public static function runtests($withjavascript = false, $tags = false, $extra = false) { global $CFG; - // Checks that the behat reference is properly set up + // Checks that the behat reference is properly set up. self::check_behat_setup(); // Check that PHPUnit test environment is correctly set up. @@ -159,7 +137,7 @@ class tool_behat { @set_time_limit(0); - // No javascript by default + // No javascript by default. if (!$withjavascript && strstr($tags, 'javascript') == false) { $jsstr = '~javascript'; } @@ -181,7 +159,7 @@ class tool_behat { $extra = ''; } - // Starts built-in server and inits test mode + // Starts built-in server and inits test mode. self::start_test_mode(); $server = self::start_test_server(); @@ -194,30 +172,38 @@ class tool_behat { ob_end_clean(); chdir($currentcwd); - // Stops built-in server and stops test mode + // Stops built-in server and stops test mode. self::stop_test_server($server[0], $server[1]); self::stop_test_mode(); // Output. - echo self::get_header(); echo $output; - echo self::get_footer(); } /** * Updates the config file + * @param string $component Restricts the obtained steps definitions to the specified component * @throws file_exception */ - private static function update_config_file() { + private static function update_config_file($component = '') { global $CFG; $behatpath = rtrim($CFG->behatpath, '/'); + // Not extra contexts when component is specified. + $loadbuiltincontexts = '0'; + if ($component == '' || $component == 'nomoodle') { + $loadbuiltincontexts = '1'; + } + // Basic behat dependencies. $contents = 'default: paths: features: ' . $behatpath . '/features bootstrap: ' . $behatpath . '/features/bootstrap + context: + parameters: + loadbuiltincontexts: ' . $loadbuiltincontexts . ' extensions: Behat\MinkExtension\Extension: base_url: ' . $CFG->test_wwwroot . ' @@ -245,19 +231,14 @@ class tool_behat { $contents .= ' features:' . implode(PHP_EOL . ' - ', $featurespaths) . PHP_EOL; } - // Gets all the components with steps definitions. - $components = tests_finder::get_components_with_tests('stepsdefinitions'); - if ($components) { - $stepsdefinitions = array(''); - foreach ($components as $componentname => $componentpath) { - $componentpath = self::clean_path($componentpath); - $diriterator = new DirectoryIterator($componentpath . self::$behat_tests_path); - $regite = new RegexIterator($diriterator, '|behat_.*\.php$|'); - // All behat_*.php inside self::$behat_tests_path are added as steps definitions files - foreach ($regite as $file) { - $key = $file->getBasename('.php'); - $stepsdefinitions[$key] = $key . ': ' . $file->getPathname(); + // Gets all the components with steps definitions. + $steps = self::get_components_steps_definitions(); + if ($steps && $component != 'nomoodle') { + $stepsdefinitions = array(''); + foreach ($steps as $key => $filepath) { + if ($component == '' || $component === $key) { + $stepsdefinitions[$key] = $key . ': ' . $filepath; } } $contents .= ' steps_definitions:' . implode(PHP_EOL . ' ', $stepsdefinitions) . PHP_EOL; @@ -271,6 +252,40 @@ class tool_behat { } + /** + * Gets the list of Moodle steps definitions + * + * Class name as a key and the filepath as value + * + * Externalized from update_config_file() to use + * it from the steps definitions web interface + * + * @return array + */ + public static function get_components_steps_definitions() { + + $components = tests_finder::get_components_with_tests('stepsdefinitions'); + if (!$components) { + return false; + } + + $stepsdefinitions = array(); + foreach ($components as $componentname => $componentpath) { + $componentpath = self::clean_path($componentpath); + $diriterator = new DirectoryIterator($componentpath . self::$behat_tests_path); + $regite = new RegexIterator($diriterator, '|behat_.*\.php$|'); + + // All behat_*.php inside self::$behat_tests_path are added as steps definitions files. + foreach ($regite as $file) { + $key = $file->getBasename('.php'); + $stepsdefinitions[$key] = $file->getPathname(); + } + } + + return $stepsdefinitions; + } + + /** * Cleans the path returned by get_components_with_tests() to standarize it * @@ -323,11 +338,15 @@ class tool_behat { // Moodle setting. if (empty($CFG->behatpath)) { $msg = get_string('nobehatpath', 'tool_behat'); - $url = $CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=systempaths'; + // With HTML. + $docslink = tool_behat::$docsurl; if (!CLI_SCRIPT) { - $msg .= ' ' . html_writer::tag('a', get_string('systempaths', 'admin'), array('href' => $url)); + $docslink = html_writer::tag('a', $docslink, array('href' => $docslink, 'target' => '_blank')); + $systempathsurl = $CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=systempaths'; + $msg .= ' (' . html_writer::tag('a', get_string('systempaths', 'admin'), array('href' => $systempathsurl)) . ')'; } + $msg .= '. ' . get_string('moreinfoin', 'tool_behat') . ' ' . $docslink; notice($msg); } @@ -362,7 +381,8 @@ class tool_behat { $behatdir = self::get_behat_dir(); - $contents = '$CFG->phpunit_prefix and $CFG->phpunit_dataroot are currently used as $CFG->prefix and $CFG->dataroot'; + $contents = '$CFG->test_wwwroot, $CFG->phpunit_prefix and $CFG->phpunit_dataroot' . + ' are currently used as $CFG->wwwroot, $CFG->prefix and $CFG->dataroot'; $filepath = $behatdir . '/test_environment_enabled.txt'; if (!file_put_contents($filepath, $contents)) { throw new file_exception('cannotcreatefile', $filepath); @@ -386,6 +406,8 @@ class tool_behat { $server = str_replace('http://', '', $CFG->test_wwwroot); $process = proc_open('php -S ' . $server, $descriptorspec, $pipes, $CFG->dirroot); + // TODO If it's already started close pipes. + if (!is_resource($process)) { print_error('testservercantrun'); } @@ -510,109 +532,4 @@ class tool_behat { return self::get_behat_dir() . '/behat.yml'; } - /** - * Returns header output - * @return string - */ - private static function get_header() { - global $OUTPUT; - - $action = optional_param('action', 'info', PARAM_ALPHAEXT); - - if (CLI_SCRIPT) { - return ''; - } - - $title = get_string('pluginname', 'tool_behat') . ' - ' . get_string('command' . $action, 'tool_behat'); - $html = $OUTPUT->header(); - $html .= $OUTPUT->heading($title); - - return $html; - } - - /** - * Returns footer output - * @return string - */ - private static function get_footer() { - global $OUTPUT; - - if (CLI_SCRIPT) { - return ''; - } - - return $OUTPUT->footer(); - } - - /** - * Returns a message and a button to continue if web execution - * @param string $html - * @param string $url - * @return string - */ - private static function output_success($html, $url = false) { - global $CFG, $OUTPUT; - - if (!$url) { - $url = $CFG->wwwroot . '/' . $CFG->admin . '/tool/behat/index.php'; - } - - if (!CLI_SCRIPT) { - $html = $OUTPUT->box($html, 'generalbox', 'notice'); - $html .= $OUTPUT->continue_button($url); - } - - return $html; - } - - /** - * Returns the installation instructions - * - * (hardcoded in English) - * - * @return string - */ - private static function get_info() { - global $OUTPUT; - - $url = 'http://docs.moodle.org/dev/Acceptance_testing'; - - $html = $OUTPUT->box_start(); - $html .= html_writer::tag('h1', 'Info'); - $html .= html_writer::tag('div', 'Follow ' . $url . ' instructions for info about installation and tests execution'); - $html .= $OUTPUT->box_end(); - - return $html; - } - - /** - * Returns the steps definitions form - * @param string $filter To filter the steps definitions list by keyword - * @return string - */ - private static function get_steps_definitions_form($filter = false) { - global $OUTPUT; - - if ($filter === false) { - $filter = ''; - } else { - $filter = s($filter); - } - - $html = $OUTPUT->box_start(); - $html .= '
'; - $html .= '
'; - $html .= ' '; - $html .= ' (' . get_string('stepsdefinitionsemptyfilter', 'tool_behat') . ')'; - $html .= '

'; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= '
'; - $html .= '
'; - $html .= $OUTPUT->box_end(); - - return $html; - } - } diff --git a/admin/tool/behat/renderer.php b/admin/tool/behat/renderer.php new file mode 100644 index 00000000000..6bba742b257 --- /dev/null +++ b/admin/tool/behat/renderer.php @@ -0,0 +1,83 @@ +. + +/** + * Behat tool renderer + * + * @package tool_behat + * @copyright 2012 David Monllaó + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); +} + +/** + * Renderer for behat tool web features + * + * @package tool_behat + * @copyright 2012 David Monllaó + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tool_behat_renderer extends plugin_renderer_base { + + /** + * Renders the list of available steps according to the submitted filters + * + * @param string $stepsdefinitions HTML from behat with the available steps + * @param moodleform $form + * @return string HTML code + */ + public function render_stepsdefinitions($stepsdefinitions, $form) { + + $title = get_string('pluginname', 'tool_behat'); + + // Header. + $html = $this->output->header(); + $html .= $this->output->heading($title); + + // Info. + $installurl = tool_behat::$docsurl . '#Installation'; + $installlink = html_writer::tag('a', $installurl, array('href' => $installurl, 'target' => '_blank')); + $writetestsurl = tool_behat::$docsurl . '#Writting_features'; + $writetestslink = html_writer::tag('a', $writetestsurl, array('href' => $writetestsurl, 'target' => '_blank')); + $writestepsurl = tool_behat::$docsurl . '#Adding_steps_definitions'; + $writestepslink = html_writer::tag('a', $writestepsurl, array('href' => $writestepsurl, 'target' => '_blank')); + $infos = array( + 'Read ' . $installlink . ' ' . get_string('installinfo', 'tool_behat'), + 'Read ' . $writetestslink . ' ' . get_string('newtestsinfo', 'tool_behat'), + 'Read ' . $writestepslink . ' ' . get_string('newstepsinfo', 'tool_behat') + ); + $html .= $this->output->box_start(); + $html .= html_writer::tag('h1', 'Info'); + $html .= html_writer::tag('div', ''); + $html .= $this->output->box_end(); + + // Form. + ob_start(); + $form->display(); + $html .= ob_get_contents(); + ob_end_clean(); + + // Steps definitions. + $html .= html_writer::tag('div', $stepsdefinitions, array('id' => 'steps-definitions')); + + $html .= $this->output->footer(); + + return $html; + } +} diff --git a/admin/tool/behat/steps_definitions_form.php b/admin/tool/behat/steps_definitions_form.php new file mode 100644 index 00000000000..c7c0d772de5 --- /dev/null +++ b/admin/tool/behat/steps_definitions_form.php @@ -0,0 +1,60 @@ +. + +/** + * Steps definitions form + * + * @package tool_behat + * @copyright 2012 David Monllaó + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once($CFG->libdir.'/formslib.php'); + + +/** + * Form to display the available steps definitions + * + * @package tool_behat + * @copyright 2012 David Monllaó + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class steps_definitions_form extends moodleform { + + /** + * Form definition + */ + function definition() { + + $mform =& $this->_form; + + $mform->addElement('header', 'filters', get_string('stepsdefinitionsfilters', 'tool_behat')); + + $types = array( + '' => get_string('allavailablesteps', 'tool_behat'), + 'given' => get_string('giveninfo', 'tool_behat'), + 'when' => get_string('wheninfo', 'tool_behat'), + 'then' => get_string('theninfo', 'tool_behat') + ); + $mform->addElement('select', 'type', get_string('stepsdefinitionstype', 'tool_behat'), $types); + + $mform->addElement('select', 'component', get_string('stepsdefinitionscomponent', 'tool_behat'), $this->_customdata['components']); + + $mform->addElement('text', 'filter', get_string('stepsdefinitionscontains', 'tool_behat')); + + $mform->addElement('submit', 'submit', get_string('viewsteps', 'tool_behat')); + } +} diff --git a/admin/tool/behat/styles.css b/admin/tool/behat/styles.css index e0581b72548..5cb0815277d 100644 --- a/admin/tool/behat/styles.css +++ b/admin/tool/behat/styles.css @@ -1,3 +1,7 @@ #region-main-box #behat .summary { position: relative;} +#page-admin-tool-behat-index{padding-top: 0px;} div#steps-definitions{border-style:solid;border-width:1px;border-color:#BBB;padding:5px;margin:auto;width:50%;} -#page-admin-tool-behat-index{padding-top: 0px;} \ No newline at end of file +div#steps-definitions .step{margin: 10px 0px 10px 0px;} +div#steps-definitions .stepdescription{color:#bf8c12;} +div#steps-definitions .steptype{color:#1467a6;margin-right: 5px;} +div#steps-definitions .stepregex{color:#060;} \ No newline at end of file