mirror of
https://github.com/silverstripe/silverstripe-behat-extension
synced 2024-10-22 17:05:32 +02:00
NEW Auto-detect base_url from FILE_TO_URL_MAPPING
Removed framework_host since its no longer necessary due to the changed execution logic. Unfortunately had to subclass the existing Mink Extension class since we can't influence its config persistence from our own extensions (with a completely separate ContainerBuilder). Also restructured README to be more focused on execution rather than diving into deep config concerns early on.
This commit is contained in:
parent
3a34c204c1
commit
e98233db65
222
README.md
222
README.md
@ -25,7 +25,7 @@ It provides the following helpers:
|
||||
* Captures JavaScript errors and logs them through Selenium
|
||||
* Saves screenshots to filesystem whenever an assertion error is detected
|
||||
|
||||
In order to achieve this, the extension makes on basic assumption:
|
||||
In order to achieve this, the extension makes one basic assumption:
|
||||
Your Behat tests are run from the same application as the tested
|
||||
SilverStripe codebase, on a locally hosted website from the same codebase.
|
||||
This is important because we need access to the underlying SilverStripe
|
||||
@ -33,88 +33,84 @@ PHP classes. You can of course use a remote browser to do the actual testing.
|
||||
|
||||
Note: The extension has only been tested with the `selenium2` Mink driver.
|
||||
|
||||
## Quick Start
|
||||
|
||||
The following commands install the SilverStripe CMS including all
|
||||
required dependencies, configure it, start a Selenium server in the background,
|
||||
and run the tests.
|
||||
|
||||
composer create-project silverstripe/installer my-test-project 3.1.x-dev
|
||||
cd my-test-project
|
||||
composer require silverstripe/behat-extension:*
|
||||
php framework/cli-script.php dev/generatesecuretoken path=mysite/_config/behat.yml
|
||||
wget http://selenium.googlecode.com/files/selenium-server-standalone-2.31.0.jar
|
||||
java -jar selenium-server-standalone-2.31.0.jar > /dev/null &
|
||||
vendor/bin/behat @framework
|
||||
vendor/bin/behat @cms
|
||||
|
||||
This setup assumes you have [$_FILE_TO_URL_MAPPING](http://doc.silverstripe.org/framework/en/topics/commandline#configuration) configured to auto-detect
|
||||
the URL for your webroots.
|
||||
|
||||
## Installation
|
||||
|
||||
Simply [install SilverStripe through Composer](http://doc.silverstripe.org/framework/en/installation/composer)
|
||||
with the `--dev` flag, which loads the required dependencies automatically.
|
||||
Simply [install SilverStripe through Composer](http://doc.silverstripe.org/framework/en/installation/composer).
|
||||
|
||||
composer create-project --keep-vcs --dev silverstripe/installer test 3.0.x-dev
|
||||
composer create-project silverstripe/installer my-test-project 3.1.x-dev
|
||||
|
||||
And get the latest Selenium2 server (requires Java):
|
||||
Switch to the newly created webroot, and add the SilverStripe Behat extension.
|
||||
|
||||
cd my-test-project
|
||||
composer require silverstripe/behat-extension:*
|
||||
|
||||
Now get the latest Selenium2 server (requires Java):
|
||||
|
||||
wget http://selenium.googlecode.com/files/selenium-server-standalone-2.31.0.jar
|
||||
|
||||
Alternatively, you can require this extension manually on an existing Composer project.
|
||||
Please note that we do require a Composer-based installation due to class autoloading concerns.
|
||||
We need to generate a token so the browser and commandline calls can interact with a "shared secret":
|
||||
|
||||
composer require silverstripe/behat-extension:*
|
||||
php framework/cli-script.php dev/generatesecuretoken path=mysite/_config/behat.yml
|
||||
|
||||
Unless you have [$_FILE_TO_URL_MAPPING](http://doc.silverstripe.org/framework/en/topics/commandline#configuration)
|
||||
set up, you also need to specify the URL for your webroot. Either add it to the existing `behat.yml` configuration file
|
||||
in your project root, or set is as an environment variable in your terminal session:
|
||||
|
||||
export BEHAT_PARAMS="extensions[SilverStripe\BehatExtension\MinkExtension][base_url]=http://localhost/"
|
||||
|
||||
## Usage
|
||||
|
||||
### Starting the Selenium Server
|
||||
|
||||
You can either run the server in a separate Terminal tab:
|
||||
|
||||
java -jar selenium-server-standalone-2.31.0.jar
|
||||
|
||||
Or you can run it in the background:
|
||||
|
||||
java -jar selenium-server-standalone-2.31.0.jar > /dev/null &
|
||||
|
||||
### Running the Tests
|
||||
|
||||
Now you can run the tests (for example for the `framework` module):
|
||||
|
||||
vendor/bin/behat @framework
|
||||
|
||||
In order to run specific tests only, use their feature file name:
|
||||
|
||||
vendor/bin/behat @framework/login.feature
|
||||
|
||||
This will start a Firefox browser by default. Other browsers and profiles can be configured in `behat.yml`.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Session::start()
|
||||
|
||||
Please add a `Session::start()` invocation to your own `_config.php`.
|
||||
This is a temporary measure until we hvae resolved the database vs. session initialization conflicts.
|
||||
|
||||
### Directory Structure
|
||||
|
||||
As a convention, SilverStripe Behat tests live in a `tests/behat` subfolder
|
||||
of your module. You can create it with the following command:
|
||||
|
||||
mkdir -p mymodule/tests/behat/features/bootstrap/MyModule/Test/Behaviour
|
||||
|
||||
### FeatureContext
|
||||
|
||||
The generic [Behat usage instructions](http://docs.behat.org/) apply
|
||||
here as well. The only major difference is the base class from which
|
||||
to extend your own `FeatureContext`: It should be `SilverStripeContext`
|
||||
rather than `BehatContext`.
|
||||
|
||||
Example: mymodule/tests/behat/features/bootstrap/MyModule/Test/Behaviour/FeatureContext.php
|
||||
|
||||
<?php
|
||||
namespace MyModule\Test\Behaviour;
|
||||
|
||||
use SilverStripe\BehatExtension\Context\SilverStripeContext,
|
||||
SilverStripe\BehatExtension\Context\BasicContext,
|
||||
SilverStripe\BehatExtension\Context\LoginContext;
|
||||
|
||||
require_once 'PHPUnit/Autoload.php';
|
||||
require_once 'PHPUnit/Framework/Assert/Functions.php';
|
||||
|
||||
class FeatureContext extends SilverStripeContext
|
||||
{
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
$this->useContext('BasicContext', new BasicContext($parameters));
|
||||
$this->useContext('LoginContext', new LoginContext($parameters));
|
||||
|
||||
parent::__construct($parameters);
|
||||
}
|
||||
}
|
||||
|
||||
### behat.yml
|
||||
|
||||
The SilverStripe installer already comes with a YML configuration
|
||||
which is ready to run tests on a locally hosted Selenium server.
|
||||
which is ready to run tests on a locally hosted Selenium server,
|
||||
located in the project root as `behat.yml`.
|
||||
|
||||
You'll need to customize at least the `base_url` setting to match the URL where
|
||||
the tested SilverStripe instance is hosted locally.
|
||||
the tested SilverStripe instance is hosted locally. This
|
||||
|
||||
Example: behat.yml
|
||||
|
||||
default:
|
||||
context:
|
||||
class: SilverStripe\MyModule\Test\Behaviour\FeatureContext
|
||||
extensions:
|
||||
SilverStripe\BehatExtension\Extension: ~
|
||||
Behat\MinkExtension\Extension:
|
||||
# Adjust this to your local environment
|
||||
base_url: http://localhost/
|
||||
default_session: selenium2
|
||||
javascript_session: selenium2
|
||||
goutte: ~
|
||||
selenium2:
|
||||
browser: firefox
|
||||
Generic Mink configuration settings are placed in `SilverStripe\BehatExtension\MinkExtension`,
|
||||
which is a subclass of `Behat\MinkExtension\Extension`.
|
||||
|
||||
Overview of settings (all in the `extensions.SilverStripe\BehatExtension\Extension` path):
|
||||
|
||||
@ -134,31 +130,21 @@ of a failed step. It defaults to whatever is returned by PHP's `sys_get_temp_dir
|
||||
Screenshot names within that directory consist of feature file filename and line
|
||||
number that failed.
|
||||
|
||||
## Usage
|
||||
Example: behat.yml
|
||||
|
||||
### Starting the selenium server
|
||||
|
||||
You can either run the server in a separate Terminal tab:
|
||||
|
||||
java -jar selenium-server-standalone-2.31.0.jar
|
||||
|
||||
Or you can run it in the background:
|
||||
|
||||
java -jar selenium-server-standalone-2.31.0.jar > /dev/null &
|
||||
|
||||
|
||||
### Running the tests
|
||||
|
||||
You will have Behat binary located in `bin` directory in your project root (or where `composer.json` is located).
|
||||
|
||||
By default, Behat will use Selenium2 driver.
|
||||
Selenium will also try to use chrome browser. Refer to `behat.yml` for details.
|
||||
|
||||
# Run all "mymodule" tests
|
||||
vendor/bin/behat @mymodule
|
||||
|
||||
# Run a specific feature test
|
||||
vendor/bin/behat @mymodule/my-steps.feature
|
||||
default:
|
||||
context:
|
||||
class: SilverStripe\MyModule\Test\Behaviour\FeatureContext
|
||||
extensions:
|
||||
SilverStripe\BehatExtension\Extension: ~
|
||||
SilverStripe\BehatExtension\MinkExtension:
|
||||
# Adjust this to your local environment
|
||||
base_url: http://localhost/
|
||||
default_session: selenium2
|
||||
javascript_session: selenium2
|
||||
goutte: ~
|
||||
selenium2:
|
||||
browser: firefox
|
||||
|
||||
### Available Step Definitions
|
||||
|
||||
@ -223,24 +209,44 @@ The module runner empties the database before each scenario tagged with
|
||||
`@database-defaults` and populates it with default records (usually a set of
|
||||
default pages).
|
||||
|
||||
## Howto
|
||||
## Writing Behat Tests
|
||||
|
||||
### Additional profiles
|
||||
### Directory Structure
|
||||
|
||||
By default, `MinkExtension` is using `FirefoxDriver`.
|
||||
Let's say you want to use `ChromeDriver` too.
|
||||
As a convention, SilverStripe Behat tests live in a `tests/behat` subfolder
|
||||
of your module. You can create it with the following command:
|
||||
|
||||
You can either override the `selenium2` setting in default profile or add another
|
||||
profile that can be run using `bin/behat --profile=PROFILE_NAME`, where `PROFILE_NAME`
|
||||
could be `chrome`.
|
||||
mkdir -p mymodule/tests/behat/features/bootstrap/MyModule/Test/Behaviour
|
||||
|
||||
chrome:
|
||||
extensions:
|
||||
Behat\MinkExtension\Extension:
|
||||
selenium2:
|
||||
capabilities:
|
||||
browserName: chrome
|
||||
version: ANY
|
||||
### FeatureContext
|
||||
|
||||
The generic [Behat usage instructions](http://docs.behat.org/) apply
|
||||
here as well. The only major difference is the base class from which
|
||||
to extend your own `FeatureContext`: It should be `SilverStripeContext`
|
||||
rather than `BehatContext`.
|
||||
|
||||
Example: mymodule/tests/behat/features/bootstrap/MyModule/Test/Behaviour/FeatureContext.php
|
||||
|
||||
<?php
|
||||
namespace MyModule\Test\Behaviour;
|
||||
|
||||
use SilverStripe\BehatExtension\Context\SilverStripeContext,
|
||||
SilverStripe\BehatExtension\Context\BasicContext,
|
||||
SilverStripe\BehatExtension\Context\LoginContext;
|
||||
|
||||
require_once 'PHPUnit/Autoload.php';
|
||||
require_once 'PHPUnit/Framework/Assert/Functions.php';
|
||||
|
||||
class FeatureContext extends SilverStripeContext
|
||||
{
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
$this->useContext('BasicContext', new BasicContext($parameters));
|
||||
$this->useContext('LoginContext', new LoginContext($parameters));
|
||||
|
||||
parent::__construct($parameters);
|
||||
}
|
||||
}
|
||||
|
||||
## FAQ
|
||||
|
||||
@ -310,7 +316,7 @@ Here's a sample profile for your `behat.yml`:
|
||||
# Saucelabs.com sample setup, use with "vendor/bin/behat --profile saucelabs"
|
||||
saucelabs:
|
||||
extensions:
|
||||
Behat\MinkExtension\Extension:
|
||||
SilverStripe\BehatExtension\MinkExtension:
|
||||
selenium2:
|
||||
browser: firefox
|
||||
# Add your own username and API token here
|
||||
|
@ -5,18 +5,10 @@ namespace SilverStripe\BehatExtension\Compiler;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder,
|
||||
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
||||
/*
|
||||
* This file is part of the SilverStripe\BehatExtension
|
||||
*
|
||||
* (c) Michał Ochman <ochman.d.michal@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behat\SilverStripe container compilation pass.
|
||||
* Passes Base URL available in MinkExtension config.
|
||||
* Used for the {@link \SilverStripe\BehatExtension\MinkExtension} subclass.
|
||||
*
|
||||
* @author Michał Ochman <ochman.d.michal@gmail.com>
|
||||
*/
|
||||
@ -29,16 +21,84 @@ class MinkExtensionBaseUrlPass implements CompilerPassInterface
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('behat.mink')) {
|
||||
throw new \Exception('MinkExtension not defined');
|
||||
}
|
||||
if (!$container->hasParameter('behat.mink.base_url')) {
|
||||
throw new \Exception('MinkExtension improperly configured. Missing base_url parameter.');
|
||||
}
|
||||
$baseUrl = $container->getParameter('behat.mink.base_url');
|
||||
if (empty($baseUrl)) {
|
||||
throw new \Exception('MinkExtension improperly configured. Missing or empty base_url parameter.');
|
||||
}
|
||||
$container->setParameter('behat.silverstripe_extension.framework_host', $baseUrl);
|
||||
$frameworkPath = $container->getParameter('behat.silverstripe_extension.framework_path');
|
||||
|
||||
global $_FILE_TO_URL_MAPPING;
|
||||
if($container->getParameter('behat.mink.base_url')) {
|
||||
// If base_url is already defined, also set it in the SilverStripe mapping
|
||||
$_FILE_TO_URL_MAPPING[dirname($frameworkPath)] = $container->getParameter('behat.mink.base_url');
|
||||
} else if($envPath = $this->findEnvironmentConfigFile($frameworkPath)) {
|
||||
// Otherwise try to retrieve it from _ss_environment
|
||||
include_once $envPath;
|
||||
if(
|
||||
isset($_FILE_TO_URL_MAPPING)
|
||||
&& !($container->hasParameter('behat.mink.base_url') && $container->getParameter('behat.mink.base_url'))
|
||||
) {
|
||||
$baseUrl = $this->findBaseUrlFromMapping(dirname($frameworkPath), $_FILE_TO_URL_MAPPING);
|
||||
if($baseUrl) $container->setParameter('behat.mink.base_url', $baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$container->getParameter('behat.mink.base_url')) {
|
||||
throw new \InvalidArgumentException(
|
||||
'"base_url" not configured. Please specify it in your behat.yml configuration, ' .
|
||||
'or in your _ss_environment.php configuration through $_FILE_TO_URL_MAPPING'
|
||||
);
|
||||
}
|
||||
|
||||
// The Behat\MinkExtension\Extension class copies configuration into an internal hash,
|
||||
// we need to follow this pattern to propagate our changes.
|
||||
$parameters = $container->getParameter('behat.mink.parameters');
|
||||
$parameters['base_url'] = $container->getParameter('behat.mink.base_url');
|
||||
$container->setParameter('behat.mink.parameters', $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to auto-detect host for webroot based on _ss_environment.php data (unless explicitly set in behat.yml)
|
||||
* Copied logic from Core.php, because it needs to be executed prior to {@link SilverStripeAwareInitializer}.
|
||||
*
|
||||
* @param String Absolute start path to search upwards from
|
||||
* @return Boolean Absolute path to environment file
|
||||
*/
|
||||
protected function findEnvironmentConfigFile($path) {
|
||||
$envPath = null;
|
||||
$envFile = '_ss_environment.php'; //define the name of the environment file
|
||||
$path = '.'; //define the dir to start scanning from (have to add the trailing slash)
|
||||
|
||||
//check this dir and every parent dir (until we hit the base of the drive)
|
||||
do {
|
||||
$path = realpath($path) . '/';
|
||||
//if the file exists, then we include it, set relevant vars and break out
|
||||
if (file_exists($path . $envFile)) {
|
||||
$envPath = $path . $envFile;
|
||||
break;
|
||||
}
|
||||
// here we need to check that the real path of the last dir and the next one are
|
||||
// not the same, if they are, we have hit the root of the drive
|
||||
} while (realpath($path) != realpath($path .= '../'));
|
||||
|
||||
return $envPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied logic from Core.php, because it needs to be executed prior to {@link SilverStripeAwareInitializer}.
|
||||
*
|
||||
* @param String Absolute start path to search upwards from
|
||||
* @param Array Map of paths to host names
|
||||
* @return String URL
|
||||
*/
|
||||
protected function findBaseUrlFromMapping($path, $mapping) {
|
||||
$fullPath = $path;
|
||||
$url = null;
|
||||
while($path && $path != "/" && !preg_match('/^[A-Z]:\\\\$/', $path)) {
|
||||
if(isset($mapping[$path])) {
|
||||
$url = $mapping[$path] . str_replace(DIRECTORY_SEPARATOR, '/', substr($fullPath,strlen($path)));
|
||||
break;
|
||||
} else {
|
||||
$path = dirname($path); // traverse up
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
/**
|
||||
* Initializes initializer.
|
||||
*/
|
||||
public function __construct($frameworkPath, $frameworkHost)
|
||||
public function __construct($frameworkPath)
|
||||
{
|
||||
$this->bootstrap($frameworkPath, $frameworkHost);
|
||||
$this->bootstrap($frameworkPath);
|
||||
$this->databaseName = $this->initializeTempDb();
|
||||
}
|
||||
|
||||
@ -143,14 +143,13 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
return $this->screenshotPath;
|
||||
}
|
||||
|
||||
protected function bootstrap($frameworkPath, $frameworkHost)
|
||||
/**
|
||||
* @param String Absolute path to 'framework' module
|
||||
*/
|
||||
protected function bootstrap($frameworkPath)
|
||||
{
|
||||
file_put_contents('php://stderr', 'Bootstrapping' . PHP_EOL);
|
||||
|
||||
// Set file to URL mappings
|
||||
global $_FILE_TO_URL_MAPPING;
|
||||
$_FILE_TO_URL_MAPPING[dirname($frameworkPath)] = $frameworkHost;
|
||||
|
||||
// Connect to database and build manifest
|
||||
$_GET['flush'] = 1;
|
||||
require_once $frameworkPath . '/core/Core.php';
|
||||
|
@ -61,15 +61,11 @@ class Extension implements ExtensionInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns compiler passes used by SilverStripe extension.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCompilerPasses()
|
||||
{
|
||||
return array(
|
||||
new Compiler\MinkExtensionBaseUrlPass(),
|
||||
);
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,7 +78,7 @@ class Extension implements ExtensionInterface
|
||||
$builder->
|
||||
children()->
|
||||
scalarNode('framework_path')->
|
||||
defaultValue('../../../framework')->
|
||||
defaultValue('framework')->
|
||||
end()->
|
||||
scalarNode('screenshot_path')->
|
||||
defaultNull()->
|
||||
|
20
src/SilverStripe/BehatExtension/MinkExtension.php
Normal file
20
src/SilverStripe/BehatExtension/MinkExtension.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\BehatExtension;
|
||||
|
||||
/**
|
||||
* Subclass the main extension in order to get a say in the config compilation.
|
||||
* We need to intercept setting the base_url to auto-detect it from SilverStripe configuration.
|
||||
*/
|
||||
class MinkExtension extends \Behat\MinkExtension\Extension
|
||||
{
|
||||
|
||||
public function getCompilerPasses()
|
||||
{
|
||||
return array_merge(
|
||||
array(new Compiler\MinkExtensionBaseUrlPass()),
|
||||
parent::getCompilerPasses()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -16,7 +16,6 @@ services:
|
||||
class: %behat.silverstripe_extension.context.initializer.class%
|
||||
arguments:
|
||||
- %behat.silverstripe_extension.framework_path%
|
||||
- %behat.silverstripe_extension.framework_host%
|
||||
calls:
|
||||
- [setAjaxSteps, [%behat.silverstripe_extension.ajax_steps%]]
|
||||
- [setAjaxTimeout, [%behat.silverstripe_extension.ajax_timeout%]]
|
||||
|
Loading…
Reference in New Issue
Block a user