MDL-37046 behat: Use behat test env
authorDavid Monllao <davidm@moodle.com>
Thu, 17 Jan 2013 06:54:07 +0000 (14:54 +0800)
committerDavid Monllao <davidm@moodle.com>
Tue, 29 Jan 2013 00:40:38 +0000 (08:40 +0800)
Moving from phpunit test environment
to a specific behat test environment

17 files changed:
.gitignore
admin/tool/behat/cli/util.php
admin/tool/behat/lang/en/tool_behat.php
admin/tool/behat/locallib.php
admin/tool/behat/renderer.php
admin/tool/behat/settings.php
admin/tool/behat/steps_definitions_form.php
admin/tool/behat/styles.css
admin/tool/behat/tests/tool_behat_test.php
config-dist.php
lib/behat/classes/behat_command.php
lib/behat/classes/behat_config_manager.php
lib/behat/classes/behat_util.php [deleted file]
lib/behat/classes/util.php [new file with mode: 0644]
lib/behat/features/bootstrap/behat_init_context.php
lib/behat/lib.php [new file with mode: 0644]
lib/setup.php

index 2a50123..e1cc233 100644 (file)
@@ -30,4 +30,4 @@ phpunit.xml
 composer.phar
 composer.lock
 /vendor/
-behat.yml
+/behat.yml
index 5e580aa..4fd147f 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * CLI tool
+ * CLI tool with utilities to manage Behat integration in Moodle
+ *
+ * All CLI utilities uses $CFG->behat_dataroot and $CFG->prefix_dataroot as
+ * $CFG->dataroot and $CFG->prefix
  *
  * @package    tool_behat
  * @copyright  2012 David Monllaó
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-define('CLI_SCRIPT', true);
 
-require(__DIR__ . '/../../../../config.php');
-require_once($CFG->libdir . '/clilib.php');
-require_once($CFG->libdir . '/behat/behat_util.php');
+if (isset($_SERVER['REMOTE_ADDR'])) {
+    die(); // No access from web!.
+}
+
+// Basic functions.
+require_once(__DIR__ . '/../../../../lib/clilib.php');
+require_once(__DIR__ . '/../../../../lib/behat/lib.php');
+
 
 // CLI options.
 list($options, $unrecognized) = cli_get_params(
     array(
         'help'    => false,
+        'install' => false,
+        'drop'    => false,
         'enable'  => false,
         'disable' => false,
     ),
@@ -40,12 +49,16 @@ list($options, $unrecognized) = cli_get_params(
     )
 );
 
+
+// Checking util.php CLI script usage.
 $help = "
-Behat tool
+Behat utilities to manage the test environment
 
 Options:
---enable Enables test environment and updates tests list
---disable Disables test environment
+--install  Installs the test environment for acceptance tests
+--drop     Drops the database tables and the dataroot contents
+--enable   Enables test environment and updates tests list
+--disable  Disables test environment
 
 -h, --help     Print out this help
 
@@ -60,22 +73,110 @@ if (!empty($options['help'])) {
     exit(0);
 }
 
+
+// Checking $CFG->behat_* vars and values.
+define('BEHAT_UTIL', true);
+define('CLI_SCRIPT', true);
+define('ABORT_AFTER_CONFIG', true);
+define('NO_OUTPUT_BUFFERING', true);
+
+error_reporting(E_ALL | E_STRICT);
+ini_set('display_errors', '1');
+ini_set('log_errors', '1');
+
+require_once(__DIR__ . '/../../../../config.php');
+
+// CFG->behat_prefix must be set and with value different than CFG->prefix and phpunit_prefix.
+if (!isset($CFG->behat_prefix) ||
+   (isset($CFG->behat_prefix) &&
+       ($CFG->behat_prefix == $CFG->prefix ||
+       $CFG->behat_prefix == $CFG->phpunit_prefix))) {
+    behat_error(BEHAT_EXITCODE_CONFIG,
+        'Define $CFG->behat_prefix in config.php with a value different than $CFG->prefix and $CFG->phpunit_prefix');
+}
+
+// CFG->behat_dataroot must be set and with value different than CFG->dataroot and phpunit_dataroot.
+if (!isset($CFG->behat_dataroot) ||
+   (isset($CFG->behat_dataroot) &&
+       ($CFG->behat_dataroot == $CFG->dataroot ||
+       $CFG->behat_dataroot == $CFG->phpunit_dataroot))) {
+    behat_error(BEHAT_EXITCODE_CONFIG,
+        'Define $CFG->behat_dataroot in config.php with a value different than $CFG->dataroot and $CFG->phpunit_dataroot');
+}
+
+// Create behat_dataroot if it doesn't exists.
+if (!file_exists($CFG->behat_dataroot)) {
+    if (!mkdir($CFG->behat_dataroot, $CFG->directorypermissions)) {
+        behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory can not be created');
+    }
+}
+if (!is_dir($CFG->behat_dataroot) || !is_writable($CFG->behat_dataroot)) {
+    behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory has no permissions or is not a directory');
+}
+
+// Check that the directory does not contains other things.
+if (!file_exists("$CFG->behat_dataroot/behattestdir.txt")) {
+    if ($dh = opendir($CFG->behat_dataroot)) {
+        while (($file = readdir($dh)) !== false) {
+            if ($file === 'behat' or $file === '.' or $file === '..' or $file === '.DS_Store') {
+                continue;
+            }
+            behat_error(BEHAT_EXITCODE_CONFIG, '$CFG->behat_dataroot directory is not empty, ensure this is the directory where you want to install behat test dataroot');
+        }
+        closedir($dh);
+        unset($dh);
+        unset($file);
+    }
+
+    // Now we create dataroot directory structure for behat tests.
+    testing_initdataroot($CFG->behat_dataroot, 'behat');
+}
+
+// Overrides vars with behat-test ones.
+$vars = array('wwwroot', 'prefix', 'dataroot');
+foreach ($vars as $var) {
+    $CFG->{$var} = $CFG->{'behat_' . $var};
+}
+
+$CFG->noemailever = true;
+$CFG->passwordsaltmain = 'moodle';
+
+// Continues setup.
+define('ABORT_AFTER_CONFIG_CANCEL', true);
+require("$CFG->dirroot/lib/setup.php");
+
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/upgradelib.php');
+require_once($CFG->libdir.'/clilib.php');
+require_once($CFG->libdir.'/pluginlib.php');
+require_once($CFG->libdir.'/installlib.php');
+
 if ($unrecognized) {
     $unrecognized = implode("\n  ", $unrecognized);
     cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
 }
 
-// Run command.
-if ($options['enable']) {
-    $action = 'enable';
+// Behat utilities.
+require_once($CFG->libdir . '/behat/classes/util.php');
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
+
+// Run command (only one per time).
+if ($options['install']) {
+    behat_util::install_site();
+    mtrace("Acceptance tests site installed");
+} else if ($options['drop']) {
+    behat_util::drop_site();
+    mtrace("Acceptance tests site dropped");
+} else if ($options['enable']) {
+    behat_util::start_test_mode();
+    $runtestscommand = behat_command::get_behat_command() . ' --config '
+        . $CFG->behat_dataroot . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR . 'behat.yml';
+    mtrace("Acceptance tests environment enabled, to run the tests use:\n " . $runtestscommand);
 } else if ($options['disable']) {
-    $action = 'disable';
+    behat_util::stop_test_mode();
+    mtrace("Acceptance tests environment disabled");
 } else {
     echo $help;
-    exit(0);
 }
 
-behat_util::switchenvironment($action);
-
-mtrace(get_string('testenvironment' . $action, 'tool_behat'));
-
+exit(0);
index abe5b87..d890976 100644 (file)
@@ -30,15 +30,11 @@ $string['newstepsinfo'] = 'Read {$a} for info about how to add new steps definit
 $string['newtestsinfo'] = 'Read {$a} for info about how to write new tests';
 $string['nostepsdefinitions'] = 'There aren\'t steps definitions matching this filters';
 $string['pluginname'] = 'Acceptance testing';
-$string['phpunitenvproblem'] = 'PHPUnit environment problem';
 $string['stepsdefinitionscomponent'] = 'Area';
 $string['stepsdefinitionscontains'] = 'Contains';
 $string['stepsdefinitionsfilters'] = 'Steps definitions';
 $string['stepsdefinitionstype'] = 'Type';
-$string['testenvironmentenable'] = 'Test environment enabled';
-$string['testenvironmentdisable'] = 'Test environment disabled';
 $string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones';
 $string['viewsteps'] = 'Filter';
 $string['wheninfo'] = 'When. Actions that provokes an event';
-$string['wrongphpversion'] = 'PHP 5.4 or higher is required to run acceptance tests. See config-dist.php for alternatives.';
 $string['wrongbehatsetup'] = 'Something is wrong with the setup, ensure you ran the composer installer and vendor/bin/behat file has execution permissions';
index fd1ba30..33a5fd8 100644 (file)
@@ -22,6 +22,8 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+defined('MOODLE_INTERNAL') || die();
+
 global $CFG;
 require_once($CFG->libdir . '/behat/classes/behat_command.php');
 require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
@@ -45,8 +47,9 @@ class tool_behat {
      * @return string
      */
     public static function stepsdefinitions($type, $component, $filter) {
-        global $CFG;
 
+        // We don't require the test environment to be enabled to list the steps definitions
+        // so test writers can more easily set up the environment.
         behat_command::check_behat_setup();
 
         // The loaded steps depends on the component specified.
@@ -63,16 +66,15 @@ class tool_behat {
             $filteroption = ' -di';
         }
 
-        $currentcwd = getcwd();
-        chdir($CFG->dirroot);
-        exec(behat_command::get_behat_command() . ' --config="'.behat_config_manager::get_steps_list_config_filepath(). '" '.$filteroption, $steps, $code);
-        chdir($currentcwd);
+        // Get steps definitions from Behat.
+        $options = ' --config="'.behat_config_manager::get_steps_list_config_filepath(). '" '.$filteroption;
+        list($steps, $code) = behat_command::run($options);
 
         if ($steps) {
             $stepshtml = implode('', $steps);
         }
 
-        if (!isset($stepshtml) || $stepshtml == '') {
+        if (empty($stepshtml)) {
             $stepshtml = get_string('nostepsdefinitions', 'tool_behat');
         }
 
index e927ca1..1a70fce 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-defined('MOODLE_INTERNAL') || die;
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
 
 /**
  * Renderer for behat tool web features
@@ -33,11 +36,6 @@ defined('MOODLE_INTERNAL') || die;
  */
 class tool_behat_renderer extends plugin_renderer_base {
 
-    /**
-     * @var string Docs url
-     */
-    protected $docsurl = 'http://docs.moodle.org/dev/Acceptance_testing';
-
     /**
      * Renders the list of available steps according to the submitted filters
      *
@@ -54,20 +52,28 @@ class tool_behat_renderer extends plugin_renderer_base {
         $html .= $this->output->heading($title);
 
         // Info.
-        $installurl = $this->docsurl . '#Installation';
+        $installurl = behat_command::DOCS_URL . '#Installation';
         $installlink = html_writer::tag('a', $installurl, array('href' => $installurl, 'target' => '_blank'));
-        $writetestsurl = $this->docsurl . '#Writting_features';
+        $writetestsurl = behat_command::DOCS_URL . '#Writting_features';
         $writetestslink = html_writer::tag('a', $writetestsurl, array('href' => $writetestsurl, 'target' => '_blank'));
-        $writestepsurl = $this->docsurl . '#Adding_steps_definitions';
+        $writestepsurl = behat_command::DOCS_URL . '#Adding_steps_definitions';
         $writestepslink = html_writer::tag('a', $writestepsurl, array('href' => $writestepsurl, 'target' => '_blank'));
         $infos = array(
             get_string('installinfo', 'tool_behat', $installlink),
             get_string('newtestsinfo', 'tool_behat', $writetestslink),
             get_string('newstepsinfo', 'tool_behat', $writestepslink)
         );
+
+        // List of steps
         $html .= $this->output->box_start();
         $html .= html_writer::tag('h1', 'Info');
-        $html .= html_writer::tag('div', '<ul><li>' . implode('</li><li>', $infos) . '</li></ul>');
+        $html .= html_writer::empty_tag('div');
+        $html .= html_writer::empty_tag('ul');
+        $html .= html_writer::empty_tag('li');
+        $html .= implode(html_writer::end_tag('li') . html_writer::empty_tag('li'), $infos);
+        $html .= html_writer::end_tag('li');
+        $html .= html_writer::end_tag('ul');
+        $html .= html_writer::end_tag('div');
         $html .= $this->output->box_end();
 
         // Form.
@@ -77,7 +83,7 @@ class tool_behat_renderer extends plugin_renderer_base {
         ob_end_clean();
 
         // Steps definitions.
-        $html .= html_writer::tag('div', $stepsdefinitions, array('id' => 'steps-definitions'));
+        $html .= html_writer::tag('div', $stepsdefinitions, array('class' => 'steps-definitions'));
 
         $html .= $this->output->footer();
 
index 8939cdd..7f4b5a0 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 
-defined('MOODLE_INTERNAL') || die;
+defined('MOODLE_INTERNAL') || die();
 
 if ($hassiteconfig) {
     $url = $CFG->wwwroot . '/' . $CFG->admin . '/tool/behat/index.php';
index 788a3fb..c6b06f3 100644 (file)
@@ -37,6 +37,7 @@ class steps_definitions_form extends moodleform {
 
     /**
      * Form definition
+     * @return void
      */
     public function definition() {
 
index 9f9bb96..d7ca4d1 100644 (file)
@@ -1,5 +1,5 @@
-div#steps-definitions{border-style:solid;border-width:1px;border-color:#BBB;padding:5px;margin:auto;width:50%;}
-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;}
+.steps-definitions{border-style:solid;border-width:1px;border-color:#BBB;padding:5px;margin:auto;width:50%;}
+.steps-definitions .step{margin: 10px 0px 10px 0px;}
+.steps-definitions .stepdescription{color:#bf8c12;}
+.steps-definitions .steptype{color:#1467a6;margin-right: 5px;}
+.steps-definitions .stepregex{color:#060;}
index 00ebcce..12db2e0 100644 (file)
@@ -15,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Unit tests for admin/tool/behat
+ * Unit tests for admin/tool/behat.
  *
  * @package   tool_behat
  * @copyright  2012 David Monllaó
@@ -26,11 +26,11 @@ defined('MOODLE_INTERNAL') || die();
 
 global $CFG;
 require_once($CFG->dirroot . '/' . $CFG->admin .'/tool/behat/locallib.php');
-require_once($CFG->libdir . '/behat/classes/behat_util.php');
+require_once($CFG->libdir . '/behat/classes/util.php');
 require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
 
 /**
- * Allows access to internal methods without exposing them
+ * Allows access to internal methods without exposing them.
  *
  * @package    tool_behat
  * @copyright  2012 David Monllaó
@@ -57,13 +57,13 @@ class testable_behat_config_manager extends behat_config_manager {
      * @param array $stepsdefinitions
      * @return string
      */
-    public static function get_config_file_contents($prefix, $features, $stepsdefinitions) {
-        return parent::get_config_file_contents($prefix, $features, $stepsdefinitions);
+    public static function get_config_file_contents($features, $stepsdefinitions) {
+        return parent::get_config_file_contents($features, $stepsdefinitions);
     }
 }
 
 /**
- * Tool behat tests
+ * Tool behat tests.
  *
  * @package    tool_behat
  * @copyright  2012 David Monllaó
@@ -72,37 +72,7 @@ class testable_behat_config_manager extends behat_config_manager {
 class tool_behat_testcase extends advanced_testcase {
 
     /**
-     * behat_util tests
-     */
-    public function test_switch_environment() {
-
-        // Only run the tests if behat dependencies are installed.
-        // We don't need to pre-check PHPUnit initialisation because we are running on it.
-        if (version_compare(PHP_VERSION, '5.4.0', '>=') && behat_command::are_behat_dependencies_installed()) {
-             behat_util::switchenvironment('enable');
-             $this->assertTrue(behat_util::is_test_mode_enabled());
-             $this->assertFalse(behat_util::is_test_environment_running());
-
-             // We trigger a debugging() if it's already enabled.
-             behat_util::switchenvironment('enable');
-             $this->assertDebuggingCalled();
-
-             behat_util::switchenvironment('disable');
-             $this->assertFalse(behat_util::is_test_mode_enabled());
-             $this->assertFalse(behat_util::is_test_environment_running());
-
-             // We trigger a debugging() if it's already enabled.
-             behat_util::switchenvironment('disable');
-             $this->assertDebuggingCalled();
-
-             // Ensure all continues disabled.
-             $this->assertFalse(behat_util::is_test_mode_enabled());
-             $this->assertFalse(behat_util::is_test_environment_running());
-        }
-    }
-
-    /**
-     * behat_config_manager tests
+     * behat_config_manager tests.
      */
     public function test_merge_configs() {
 
@@ -170,11 +140,12 @@ class tool_behat_testcase extends advanced_testcase {
     }
 
     /**
-     * behat_config_manager tests
+     * behat_config_manager tests.
      */
     public function test_config_file_contents() {
         global $CFG;
 
+        // To avoid user value at config.php level.
         unset($CFG->behat_config);
 
         // List.
@@ -190,9 +161,9 @@ class tool_behat_testcase extends advanced_testcase {
             'anoche' => '/cuando/yo/dormia'
         );
 
-        $contents = testable_behat_config_manager::get_config_file_contents('/i/am/a/prefix/', $features, $stepsdefinitions);
+        $contents = testable_behat_config_manager::get_config_file_contents($features, $stepsdefinitions);
 
-        $this->assertContains('features: /i/am/a/prefix/lib/behat/features', $contents);
+        $this->assertContains('features: ' . $CFG->dirroot . '/lib/behat/features', $contents);
         $this->assertContains('micarro: /me/lo/robaron', $contents);
         $this->assertContains('base_url: \'' . $CFG->behat_wwwroot . '\'', $contents);
         $this->assertContains('class: behat_init_context', $contents);
index aac3a62..3cd7b3e 100644 (file)
@@ -552,8 +552,8 @@ $CFG->admin = 'admin';
 //
 // You can override default Moodle configuration for Behat and add your own
 // params; here you can add more profiles, use different Mink drivers than Selenium...
-// This params would be merged with the default Moodle behat.yml, giving priority
-// to the ones specified here. The array format is YAML, following the behat
+// These params would be merged with the default Moodle behat.yml, giving priority
+// to the ones specified here. The array format is YAML, following the Behat
 // params hierarchy. More info: http://docs.behat.org/guides/7.config.html
 // Example:
 //   $CFG->behat_config = array(
@@ -568,7 +568,7 @@ $CFG->admin = 'admin';
 //       )
 //   );
 //
-// You can completely switch to test environment when "php admin/tool/behatcli/util --enable",
+// You can completely switch to test environment when "php admin/tool/behat/cli/util --enable",
 // this means that all the site accesses will be routed to the test environment instead of
 // the regular one, so NEVER USE THIS SETTING IN PRODUCTION SITES. This setting is useful
 // when working with cloud CI (continous integration) servers which requires public sites to run the
index ece8039..5ef2199 100644 (file)
@@ -23,7 +23,9 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-require_once(__DIR__ . '/../../filestorage/file_exceptions.php');
+defined('MOODLE_INTERNAL') || die();
+
+require_once(__DIR__ . '/../lib.php');
 
 /**
  * Behat command related utils
@@ -35,24 +37,28 @@ require_once(__DIR__ . '/../../filestorage/file_exceptions.php');
  */
 class behat_command {
 
+    /**
+     * Docs url
+     */
+    const DOCS_URL = 'http://docs.moodle.org/dev/Acceptance_testing';
+
     /**
      * Ensures the behat dir exists in moodledata
-     * @throws file_exception
      * @return string Full path
      */
     public static function get_behat_dir() {
         global $CFG;
 
-        $behatdir = $CFG->dataroot . '/behat';
+        $behatdir = $CFG->behat_dataroot . '/behat';
 
         if (!is_dir($behatdir)) {
             if (!mkdir($behatdir, $CFG->directorypermissions, true)) {
-                throw new file_exception('storedfilecannotcreatefiledirs');
+                behat_error(BEHAT_EXITCODE_PERMISSIONS, 'Directory ' . $behatdir . ' can not be created');
             }
         }
 
         if (!is_writable($behatdir)) {
-            throw new file_exception('storedfilecannotcreatefiledirs');
+            behat_error(BEHAT_EXITCODE_PERMISSIONS, 'Directory ' . $behatdir . ' is not writable');
         }
 
         return $behatdir;
@@ -66,21 +72,44 @@ class behat_command {
         return 'vendor' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'behat';
     }
 
+    /**
+     * Runs behat command with provided options
+     *
+     * Execution continues when the process finishes
+     *
+     * @param  string $options  Defaults to '' so tests would be executed
+     * @return array            CLI command outputs [0] => string, [1] => integer
+     */
+    public final static function run($options = '') {
+        global $CFG;
+
+        $currentcwd = getcwd();
+        chdir($CFG->dirroot);
+        exec(self::get_behat_command() . ' ' . $options, $output, $code);
+        chdir($currentcwd);
+
+        return array($output, $code);
+    }
+
     /**
      * Checks if behat is set up and working
      *
+     * Uses notice() instead of behat_error() because is
+     * also called from web interface
+     *
      * It checks behat dependencies have been installed and runs
      * the behat help command to ensure it works as expected
      *
-     * @throw  Exception
-     * @param  boolean $checkphp Extra check for the PHP version
+     * @param  bool $checkphp Extra check for the PHP version
+     * @return void
      */
     public static function check_behat_setup($checkphp = false) {
         global $CFG;
 
         // We don't check the PHP version if $CFG->behat_switchcompletely has been enabled.
+        // Here we are in CLI.
         if (empty($CFG->behat_switchcompletely) && $checkphp && version_compare(PHP_VERSION, '5.4.0', '<')) {
-            throw new Exception(get_string('wrongphpversion', 'tool_behat'));
+            behat_error(BEHAT_EXITCODE_REQUIREMENT, 'PHP 5.4 is required. See config-dist.php for possible alternatives');
         }
 
         // Moodle setting.
@@ -89,7 +118,7 @@ class behat_command {
             $msg = get_string('wrongbehatsetup', 'tool_behat');
 
             // With HTML.
-            $docslink = 'http://docs.moodle.org/dev/Acceptance_testing#Installation';
+            $docslink = self::DOCS_URL . '#Installation';
             if (!CLI_SCRIPT) {
                 $docslink = html_writer::tag('a', $docslink, array('href' => $docslink, 'target' => '_blank'));
             }
@@ -98,10 +127,7 @@ class behat_command {
         }
 
         // Behat test command.
-        $currentcwd = getcwd();
-        chdir($CFG->dirroot);
-        exec(self::get_behat_command() . ' --help', $output, $code);
-        chdir($currentcwd);
+        list($output, $code) = self::run(' --help');
 
         if ($code != 0) {
             notice(get_string('wrongbehatsetup', 'tool_behat'));
@@ -110,7 +136,7 @@ class behat_command {
 
     /**
      * Has the site installed composer with --dev option
-     * @return boolean
+     * @return bool
      */
     public static function are_behat_dependencies_installed() {
         if (!is_dir(__DIR__ . '/../../../vendor/behat')) {
index 53bdbef..1c45dbd 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+defined('MOODLE_INTERNAL') || die();
+
+require_once(__DIR__ . '/../lib.php');
 require_once(__DIR__ . '/behat_command.php');
-require_once(__DIR__ . '/../../filestorage/file_exceptions.php');
 require_once(__DIR__ . '/../../testing/classes/tests_finder.php');
 
 /**
@@ -47,24 +49,21 @@ class behat_config_manager {
      * config files to avoid problems with concurrent executions.
      *
      * The steps definitions list can be filtered by component so it's
-     * behat.yml can be different from the dirroot one.
+     * behat.yml is different from the $CFG->dirroot one.
      *
-     * @param string $component Restricts the obtained steps definitions to the specified component
-     * @param string $testsrunner If the config file will be used to run tests
-     * @throws file_exception
+     * @param  string $component Restricts the obtained steps definitions to the specified component
+     * @param  string $testsrunner If the config file will be used to run tests
+     * @return void
      */
     public static function update_config_file($component = '', $testsrunner = true) {
         global $CFG;
 
-        // Behat must run with the whole set of features and steps definitions.
+        // Behat must have a separate behat.yml to have access to the whole set of features and steps definitions.
         if ($testsrunner === true) {
-            $prefix = '';
-            $configfilepath = $CFG->dirroot . '/behat.yml';
-
-            // Alternative for steps definitions filtering.
+            $configfilepath = behat_command::get_behat_dir() . '/behat.yml';
         } else {
+            // Alternative for steps definitions filtering, one for each user.
             $configfilepath = self::get_steps_list_config_filepath();
-            $prefix = $CFG->dirroot .'/';
         }
 
         // Gets all the components with features.
@@ -74,6 +73,8 @@ class behat_config_manager {
             foreach ($components as $componentname => $path) {
                 $path = self::clean_path($path) . self::get_behat_tests_path();
                 if (empty($featurespaths[$path]) && file_exists($path)) {
+
+                    // Standarizes separator (some dirs. comes with OS-dependant separator).
                     $uniquekey = str_replace('\\', '/', $path);
                     $featurespaths[$uniquekey] = $path;
                 }
@@ -94,11 +95,11 @@ class behat_config_manager {
 
         // Behat config file specifing the main context class,
         // the required Behat extensions and Moodle test wwwroot.
-        $contents = self::get_config_file_contents($prefix, $features, $stepsdefinitions);
+        $contents = self::get_config_file_contents($features, $stepsdefinitions);
 
         // Stores the file.
         if (!file_put_contents($configfilepath, $contents)) {
-            throw new file_exception('cannotcreatefile', $configfilepath);
+            behat_error(BEHAT_EXITCODE_PERMISSIONS, 'File ' . $configfilepath . ' can not be created');
         }
 
     }
@@ -138,32 +139,42 @@ class behat_config_manager {
 
     /**
      * Returns the behat config file path used by the steps definition list
+     *
+     * Note this can only be called from web-based scripts so it will return the
+     * production dataroot not behat_dataroot. With this the steps definitions
+     * list is accessible without having to install the behat test site.
+     *
      * @return string
      */
     public static function get_steps_list_config_filepath() {
-        return behat_command::get_behat_dir() . '/behat.yml';
+        global $USER;
+
+        $userdir = behat_command::get_behat_dir() . '/users/' . $USER->id;
+        make_writable_directory($userdir);
+
+        return $userdir . '/behat.yml';
     }
 
     /**
      * Behat config file specifing the main context class,
      * the required Behat extensions and Moodle test wwwroot.
      *
-     * @param string $prefix The filesystem prefix
      * @param array $features The system feature files
      * @param array $stepsdefinitions The system steps definitions
      * @return string
      */
-    protected static function get_config_file_contents($prefix, $features, $stepsdefinitions) {
+    protected static function get_config_file_contents($features, $stepsdefinitions) {
         global $CFG;
 
         // We require here when we are sure behat dependencies are available.
         require_once($CFG->dirroot . '/vendor/autoload.php');
 
+        $basedir = $CFG->dirroot . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'behat';
         $config = array(
             'default' => array(
                 'paths' => array(
-                    'features' => $prefix . 'lib/behat/features',
-                    'bootstrap' => $prefix . 'lib/behat/features/bootstrap',
+                    'features' => $basedir . DIRECTORY_SEPARATOR . 'features',
+                    'bootstrap' => $basedir . DIRECTORY_SEPARATOR . 'features' . DIRECTORY_SEPARATOR . 'bootstrap',
                 ),
                 'context' => array(
                     'class' => 'behat_init_context'
diff --git a/lib/behat/classes/behat_util.php b/lib/behat/classes/behat_util.php
deleted file mode 100644 (file)
index ec47b61..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-<?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/>.
-
-/**
- * Utils for behat-related stuff
- *
- * @package    core
- * @category   test
- * @copyright  2012 David Monllaó
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-require_once(__DIR__ . '/../../testing/classes/util.php');
-
-require_once(__DIR__ . '/behat_command.php');
-require_once(__DIR__ . '/behat_config_manager.php');
-
-require_once(__DIR__ . '/../../filestorage/file_exceptions.php');
-require_once(__DIR__ . '/../../phpunit/bootstraplib.php');
-
-/**
- * Init/reset utilities for Behat database and dataroot
- *
- * @package   core
- * @category  test
- * @copyright 2013 David Monllaó
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class behat_util extends testing_util {
-
-    /**
-     * Allows / disables the test environment to be accessed through the built-in server
-     *
-     * Built-in server must be started separately
-     *
-     * @param string $testenvironment enable|disable
-     */
-    public static function switchenvironment($testenvironment) {
-        if ($testenvironment == 'enable') {
-            self::start_test_mode();
-        } else if ($testenvironment == 'disable') {
-            self::stop_test_mode();
-        }
-    }
-
-    /**
-     * Checks if $CFG->behat_wwwroot is available
-     *
-     * @return boolean
-     */
-    public static function is_server_running() {
-        global $CFG;
-
-        $request = new curl();
-        $request->get($CFG->behat_wwwroot);
-        return (true && !$request->get_errno());
-    }
-
-    /**
-     * Checks whether the test database and dataroot is ready
-     * Stops execution if something went wrong
-     */
-    protected static function test_environment_problem() {
-        global $CFG;
-
-        // PHPUnit --diag returns nothing if the test environment is set up correctly.
-        exec('php ' . $CFG->dirroot . '/' . $CFG->admin . '/tool/phpunit/cli/util.php --diag', $output, $code);
-
-        // If something is not ready stop execution and display the CLI command output.
-        if ($code != 0) {
-            notice(get_string('phpunitenvproblem', 'tool_behat') . ': ' . implode(' ', $output));
-        }
-    }
-
-    /**
-     * Enables test mode
-     *
-     * Starts the test mode checking the composer installation and
-     * the phpunit test environment and updating the available
-     * features and steps definitions.
-     *
-     * Stores a file in dataroot/behat to allow Moodle to switch
-     * to the test environment when using cli-server (or $CFG->behat_switchcompletely)
-     *
-     * @throws file_exception
-     */
-    protected static function start_test_mode() {
-        global $CFG;
-
-        // Checks the behat set up and the PHP version.
-        behat_command::check_behat_setup(true);
-
-        // Check that PHPUnit test environment is correctly set up.
-        self::test_environment_problem();
-
-        // Updates all the Moodle features and steps definitions.
-        behat_config_manager::update_config_file();
-
-        if (self::is_test_mode_enabled()) {
-            debugging('Test environment was already enabled');
-            return;
-        }
-
-        $behatdir = behat_command::get_behat_dir();
-
-        $contents = '$CFG->behat_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);
-        }
-        chmod($filepath, $CFG->directorypermissions);
-    }
-
-    /**
-     * Disables test mode
-     * @throws file_exception
-     */
-    protected static function stop_test_mode() {
-
-        $testenvfile = self::get_test_filepath();
-
-        if (!self::is_test_mode_enabled()) {
-            debugging('Test environment was already disabled');
-        } else {
-            if (!unlink($testenvfile)) {
-                throw new file_exception('cannotdeletetestenvironmentfile');
-            }
-        }
-    }
-
-    /**
-     * Checks whether test environment is enabled or disabled
-     *
-     * To check is the current script is running in the test
-     * environment
-     *
-     * @see tool_behat::is_test_environment_running()
-     * @return bool
-     */
-    public static function is_test_mode_enabled() {
-
-        $testenvfile = self::get_test_filepath();
-        if (file_exists($testenvfile)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns true if Moodle is currently running with the test database and dataroot
-     * @return bool
-     */
-    public static function is_test_environment_running() {
-        global $CFG;
-
-        if (!empty($CFG->originaldataroot)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the path to the file which specifies if test environment is enabled
-     *
-     * The file is in dataroot/behat/ but we need to
-     * know if test mode is running because then we swap
-     * it to phpunit_dataroot and we need the original value
-     *
-     * @return string
-     */
-    protected final static function get_test_filepath() {
-        global $CFG;
-
-        if (self::is_test_environment_running()) {
-            $prefix = $CFG->originaldataroot;
-        } else {
-            $prefix = $CFG->dataroot;
-        }
-
-        return $prefix . '/behat/test_environment_enabled.txt';
-    }
-
-}
diff --git a/lib/behat/classes/util.php b/lib/behat/classes/util.php
new file mode 100644 (file)
index 0000000..828f452
--- /dev/null
@@ -0,0 +1,258 @@
+<?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/>.
+
+/**
+ * Utils for behat-related stuff
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once(__DIR__ . '/../lib.php');
+require_once(__DIR__ . '/../../testing/classes/util.php');
+require_once(__DIR__ . '/behat_command.php');
+require_once(__DIR__ . '/behat_config_manager.php');
+
+require_once(__DIR__ . '/../../filelib.php');
+
+/**
+ * Init/reset utilities for Behat database and dataroot
+ *
+ * @package   core
+ * @category  test
+ * @copyright 2013 David Monllaó
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_util extends testing_util {
+
+    /**
+     * @var array Files to skip when resetting dataroot folder
+     */
+    protected static $datarootskiponreset = array('.', '..', 'behat', 'behattestdir.txt');
+
+    /**
+     * @var array Files to skip when dropping dataroot folder
+     */
+    protected static $datarootskipondrop = array('.', '..', 'lock');
+
+    /**
+     * Installs a site using $CFG->dataroot and $CFG->prefix
+     * @throws coding_exception
+     * @return void
+     */
+    public static function install_site() {
+        global $DB;
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        // New dataroot.
+        self::reset_dataroot();
+
+        $options = array();
+        $options['adminuser'] = 'admin';
+        $options['adminpass'] = 'admin';
+        $options['fullname'] = 'Acceptance test site';
+
+        install_cli_database($options, false);
+
+        // Update admin user info.
+        $user = $DB->get_record('user', array('username' => 'admin'));
+        $user->email = 'moodle@moodlemoodle.com';
+        $user->firstname = 'Admin';
+        $user->lastname = 'User';
+        $user->city = 'Perth';
+        $user->country = 'AU';
+        $DB->update_record('user', $user);
+
+        // Sets maximum debug level.
+        set_config('debug', DEBUG_DEVELOPER);
+        set_config('debugdisplay', true);
+
+        // Keeps the current version of database and dataroot.
+        self::store_versions_hash();
+
+        // Stores the database contents for fast reset.
+        self::store_database_state();
+    }
+
+    /**
+     * Drops dataroot and remove test database tables
+     * @throws coding_exception
+     * @return void
+     */
+    public static function drop_site() {
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        self::reset_dataroot();
+        self::drop_dataroot();
+        self::drop_database(true);
+    }
+
+    /**
+     * Checks if $CFG->behat_wwwroot is available
+     *
+     * @return bool
+     */
+    public static function is_server_running() {
+        global $CFG;
+
+        $request = new curl();
+        $request->get($CFG->behat_wwwroot);
+        return (true && !$request->get_errno());
+    }
+
+    /**
+     * Checks whether the test database and dataroot is ready
+     * Stops execution if something went wrong
+     * @throws coding_exception
+     * @return void
+     */
+    protected static function test_environment_problem() {
+        global $CFG, $DB;
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        if (!self::is_test_site()) {
+            behat_error(1, 'This is not a behat test site!');
+        }
+
+        $tables = $DB->get_tables(false);
+        if (empty($tables)) {
+            behat_error(BEHAT_EXITCODE_INSTALL, '');
+        }
+
+        if (!self::is_test_data_updated()) {
+            behat_error(BEHAT_EXITCODE_REINSTALL, 'The test environment was initialised for a different version');
+        }
+    }
+
+    /**
+     * Enables test mode
+     *
+     * It uses CFG->behat_dataroot
+     *
+     * Starts the test mode checking the composer installation and
+     * the test environment and updating the available
+     * features and steps definitions.
+     *
+     * Stores a file in dataroot/behat to allow Moodle to switch
+     * to the test environment when using cli-server (or $CFG->behat_switchcompletely)
+     * @throws coding_exception
+     * @return void
+     */
+    public static function start_test_mode() {
+        global $CFG;
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        // Checks the behat set up and the PHP version.
+        behat_command::check_behat_setup(true);
+
+        // Check that test environment is correctly set up.
+        self::test_environment_problem();
+
+        // Updates all the Moodle features and steps definitions.
+        behat_config_manager::update_config_file();
+
+        if (self::is_test_mode_enabled()) {
+            return;
+        }
+
+        $contents = '$CFG->behat_wwwroot, $CFG->behat_prefix and $CFG->behat_dataroot' .
+            ' are currently used as $CFG->wwwroot, $CFG->prefix and $CFG->dataroot';
+        $filepath = self::get_test_file_path();
+        if (!file_put_contents($filepath, $contents)) {
+            behat_error(BEHAT_EXITCODE_PERMISSIONS, 'File ' . $filepath . ' can not be created');
+        }
+    }
+
+    /**
+     * Disables test mode
+     * @throws coding_exception
+     * @return void
+     */
+    public static function stop_test_mode() {
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        $testenvfile = self::get_test_file_path();
+
+        if (!self::is_test_mode_enabled()) {
+            echo "Test environment was already disabled\n";
+        } else {
+            if (!unlink($testenvfile)) {
+                behat_error(BEHAT_EXITCODE_PERMISSIONS, 'Can not delete test environment file');
+            }
+        }
+    }
+
+    /**
+     * Checks whether test environment is enabled or disabled
+     *
+     * To check is the current script is running in the test
+     * environment
+     *
+     * @see tool_behat::is_using_test_environment()
+     * @return bool
+     */
+    public static function is_test_mode_enabled() {
+
+        $testenvfile = self::get_test_file_path();
+        if (file_exists($testenvfile)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns true if Moodle is currently running with the test database and dataroot
+     * @return bool
+     */
+    public static function is_using_test_environment() {
+        global $CFG;
+
+        if (!empty($CFG->originaldataroot)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the path to the file which specifies if test environment is enabled
+     * @return string
+     */
+    protected final static function get_test_file_path() {
+        return behat_command::get_behat_dir() . '/test_environment_enabled.txt';
+    }
+
+}
index c1830b6..01a0d18 100644 (file)
@@ -17,7 +17,8 @@
 /**
  * Contexts initializer class
  *
- * @package    tool_behat
+ * @package    core
+ * @category   test
  * @copyright  2012 David Monllaó
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -34,7 +35,8 @@ use Behat\Behat\Context\BehatContext,
  * Renamed from behat FeatureContext class according
  * to Moodle coding styles conventions
  *
- * @package    tool_behat
+ * @package    core
+ * @category   test
  * @copyright  2012 David Monllaó
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -43,7 +45,8 @@ class behat_init_context extends BehatContext {
     /**
      * Initializes subcontexts
      *
-     * @param array $parameters context parameters (set them up through behat.yml)
+     * @param  array $parameters context parameters (set them up through behat.yml)
+     * @return void
      */
     public function __construct(array $parameters) {
         $this->useContext('moodle', new MoodleContext($parameters));
diff --git a/lib/behat/lib.php b/lib/behat/lib.php
new file mode 100644 (file)
index 0000000..dda2deb
--- /dev/null
@@ -0,0 +1,71 @@
+<?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/>.
+
+/**
+ * Behat basic functions
+ *
+ * It does not include MOODLE_INTERNAL because is part of the bootstrap
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../testing/lib.php');
+
+define('BEHAT_EXITCODE_CONFIG', 250);
+define('BEHAT_EXITCODE_REQUIREMENT', 251);
+define('BEHAT_EXITCODE_PERMISSIONS', 252);
+define('BEHAT_EXITCODE_REINSTALL', 253);
+define('BEHAT_EXITCODE_INSTALL', 254);
+
+/**
+ * Exits with an error code
+ *
+ * @param  mixed $errorcode
+ * @param  string $text
+ * @return void Stops execution with error code
+ */
+function behat_error($errorcode, $text = '') {
+
+    // Adding error prefixes.
+    switch ($errorcode) {
+        case BEHAT_EXITCODE_CONFIG:
+            $text = 'Behat config error: ' . $text;
+            break;
+        case BEHAT_EXITCODE_REQUIREMENT:
+            $text = 'Behat requirement not satisfied: ' . $text;
+            break;
+        case BEHAT_EXITCODE_PERMISSIONS:
+            $text = 'Behat permissions problem: ' . $text . ', check the permissions';
+            break;
+        case BEHAT_EXITCODE_REINSTALL:
+            $path = testing_cli_argument_path('/admin/tool/behat/cli/util.php');
+            $text = "Reinstall Behat: ".$text.", use:\n php ".$path." --drop \n php ".$path." --install";
+            break;
+        case BEHAT_EXITCODE_INSTALL:
+            $path = testing_cli_argument_path('/admin/tool/behat/cli/util.php');
+            $text = "Install Behat before enabling it, use:\n php ".$path." --install";
+            break;
+        default:
+            $text = 'Unknown error ' . $errorcode . ' ' . $text;
+            break;
+    }
+
+    testing_error($errorcode, $text);
+}
+
index 2c19eda..9ceabed 100644 (file)
@@ -90,7 +90,7 @@ if (!isset($CFG->wwwroot) or $CFG->wwwroot === 'http://example.com/moodle') {
     exit(1);
 }
 
-// Ignore $CFG->behat_wwwroot and use the same wwwroot in case test env. is enabled.
+// Ignore $CFG->behat_wwwroot and use the same wwwroot.
 if (isset($CFG->behat_switchcompletely)) {
     $CFG->behat_wwwroot = $CFG->wwwroot;
 
@@ -99,19 +99,28 @@ if (isset($CFG->behat_switchcompletely)) {
     $CFG->behat_wwwroot = 'http://localhost:8000';
 }
 
-// Test environment is requested if: Behat is running, if we are accessing though cli-server
-// or if $CFG->behat_switchcompletely has been set (maintains CLI scripts behaviour).
-$testenvironmentrequested = (isset($CFG->behat_switchcompletely) && php_sapi_name() !== 'cli') ||
-    php_sapi_name() === 'cli-server' ||
-    defined('BEHAT_RUNNING');
-// Only switch to test environment if it has been enabled.
-$testenvironmentenabled = file_exists($CFG->dataroot . '/behat/test_environment_enabled.txt');
-if ($testenvironmentenabled && $testenvironmentrequested) {
-    $CFG->wwwroot = $CFG->behat_wwwroot;
-    $CFG->passwordsaltmain = 'phpunit';
-    $CFG->originaldataroot = $CFG->dataroot;
-    $CFG->prefix = $CFG->phpunit_prefix;
-    $CFG->dataroot = $CFG->phpunit_dataroot;
+
+// Test environment is requested if:
+// * Behat is running (constant set hooking the behat init process before requiring config.php).
+// * If we are accessing though the built-in web server (cli-server).
+// * If $CFG->behat_switchcompletely has been set (maintains CLI scripts behaviour, which ATM is only preventive).
+// Test environment is enabled if:
+// * User has previously enabled through admin/tool/behat/cli/util.php --enable.
+// Both are required to switch to test mode
+if (isset($CFG->behat_dataroot) && isset($CFG->behat_prefix) && file_exists($CFG->behat_dataroot)) {
+    $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
+    $testenvironmentrequested = (isset($CFG->behat_switchcompletely) && php_sapi_name() !== 'cli') ||
+        php_sapi_name() === 'cli-server' ||
+        defined('BEHAT_RUNNING');
+    // Only switch to test environment if it has been enabled.
+    $testenvironmentenabled = file_exists($CFG->behat_dataroot . '/behat/test_environment_enabled.txt');
+    if ($testenvironmentenabled && $testenvironmentrequested) {
+        $CFG->wwwroot = $CFG->behat_wwwroot;
+        $CFG->passwordsaltmain = 'moodle';
+        $CFG->originaldataroot = $CFG->dataroot;
+        $CFG->prefix = $CFG->behat_prefix;
+        $CFG->dataroot = $CFG->behat_dataroot;
+    }
 }
 
 // Define admin directory