diff --git a/README.md b/README.md index c62223d..b274380 100644 --- a/README.md +++ b/README.md @@ -38,27 +38,21 @@ Note: The extension has only been tested with the `selenium2` Mink driver. ## Installation -Simply [install Silverstripe through Composer](http://doc.silverstripe.org/framework/en/installation/composer). -Skip this step if adding the module to an existing project. +In a Silverstripe CMS project (see [getting started docs](https://docs.silverstripe.org/en/getting_started/)) add the Silverstripe Behat extension via Composer. - composer create-project silverstripe/installer my-test-project 4.x-dev +```sh +composer require --dev silverstripe/behat-extension +``` -Switch to the newly created webroot, and add the Silverstripe Behat extension. +Download the standalone [Google Chrome WebDriver](https://chromedriver.storage.googleapis.com/index.html) - cd my-test-project - composer require --dev silverstripe/behat-extension - -Download the standalone [Google Chrome WebDriver](http://chromedriver.storage.googleapis.com/index.html?path=2.8/) - -Now install the Silverstripe project as usual by opening it in a browser and following the instructions. -Protip: You can skip this step by using `[SS_DATABASE_CHOOSE_NAME]` in a global -[`.env`](https://docs.silverstripe.org/en/getting_started/environment_management/) file one level above the webroot. - -Unless you have [`SS_BASE_URL`](http://doc.silverstripe.org/framework/en/topics/commandline#configuration) set up, +Unless you have [`SS_BASE_URL`](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/" +```sh +export BEHAT_PARAMS="extensions[SilverStripe\BehatExtension\MinkExtension][base_url]=http://localhost/" +``` ## Usage @@ -66,17 +60,23 @@ in your project root, or set is as an environment variable in your terminal sess You can run the server locally in a separate Terminal session: - chromedriver +```sh +chromedriver +``` ### Running the Tests Now you can run the tests (for example for the `framework` module): - vendor/bin/behat @framework +```sh +vendor/bin/behat @framework +``` Or even run a single scenario by it's name (supports regular expressions): - vendor/bin/behat --name 'My scenario title' @framework +```sh +vendor/bin/behat --name 'My scenario title' @framework +``` This will start a Chrome browser by default. Other browsers and profiles can be configured in `behat.yml`. @@ -85,7 +85,9 @@ This will start a Chrome browser by default. Other browsers and profiles can be If running with `silverstripe/serve` and `chromedriver`, you can also use the following command which will automatically start and stop these services for individual tests. - vendor/bin/behat-ss @framework +```sh +vendor/bin/behat-ss @framework +``` This automates: - starting server @@ -128,30 +130,32 @@ number that failed. Example: behat.yml - default: - suites: - framework: - paths: - - %paths.modules.framework%/tests/behat/features - contexts: - - SilverStripe\Framework\Tests\Behaviour\FeatureContext - - SilverStripe\Framework\Tests\Behaviour\CmsFormsContext - - SilverStripe\Framework\Tests\Behaviour\CmsUiContext - - SilverStripe\BehatExtension\Context\BasicContext - - SilverStripe\BehatExtension\Context\EmailContext - - SilverStripe\BehatExtension\Context\LoginContext - - - SilverStripe\BehatExtension\Context\FixtureContext: - - %paths.modules.framework%/tests/behat/features/files/ - extensions: - SilverStripe\BehatExtension\MinkExtension: - default_session: facebook_web_driver - javascript_session: facebook_web_driver - facebook_web_driver: - browser: chrome - wd_host: "http://127.0.0.1:9515" #chromedriver port - SilverStripe\BehatExtension\Extension: - screenshot_path: %paths.base%/artifacts/screenshots +```yml +default: + suites: + framework: + paths: + - '%paths.modules.framework%/tests/behat/features' + contexts: + - SilverStripe\Framework\Tests\Behaviour\FeatureContext + - SilverStripe\Framework\Tests\Behaviour\CmsFormsContext + - SilverStripe\Framework\Tests\Behaviour\CmsUiContext + - SilverStripe\BehatExtension\Context\BasicContext + - SilverStripe\BehatExtension\Context\EmailContext + - SilverStripe\BehatExtension\Context\LoginContext + - + SilverStripe\BehatExtension\Context\FixtureContext: + - '%paths.modules.framework%/tests/behat/features/files/' + extensions: + SilverStripe\BehatExtension\MinkExtension: + default_session: facebook_web_driver + javascript_session: facebook_web_driver + facebook_web_driver: + browser: chrome + wd_host: "http://127.0.0.1:9515" #chromedriver port + SilverStripe\BehatExtension\Extension: + screenshot_path: '%paths.base%/artifacts/screenshots' +``` ## Module Initialisation @@ -167,9 +171,11 @@ Since step definitions are quite domain specific, its likely that you'll need yo The Silverstripe Behat extension provides an initializer script which generates a template in the recommended folder structure: - vendor/bin/behat --init @mymodule --namespace="MyVendor\MyModule" +```sh +vendor/bin/behat --init @mymodule --namespace="MyVendor\MyModule" +``` - Note: namespace is mandatory +**Note: namespace is mandatory** You'll now have a class located in `mymodule/tests/behat/src/FeatureContext.php`, which will have a psr-4 class mapping added to composer.json by default. @@ -182,7 +188,9 @@ The extension comes with several `BehatContext` subclasses come with some extra Some of them are just helpful in general website testing, other's are specific to SilverStripe. To find out all available steps (and the files they are defined in), run the following: - vendor/bin/behat @mymodule --definitions=i +```sh +vendor/bin/behat @mymodule --definitions=i +``` Note: There are more specific step definitions in the Silverstripe `framework` module for interacting with the CMS interfaces (see `framework/tests/behat/features/bootstrap`). @@ -207,38 +215,40 @@ scenario automatically. If you need more flexibility and transparency about which records are being created, use the inline definition syntax. The following example shows some syntax variations: - Feature: Do something with pages - As an site owner - I want to manage pages +```cucumber +Feature: Do something with pages + As an site owner + I want to manage pages - Background: - # Creates a new page without data. Can be accessed later under this identifier - Given a "page" "Page 1" - # Uses a custom RegistrationPage type - And an "error page" "Register" - # Creates a page with inline properties - And a "page" "Page 2" with "URLSegment"="page-1" and "Content"="my page 1" - # Field names can be tabular, and based on DataObject::$field_labels - And the "page" "Page 3" has the following data - | Content | | - | My Property | foo | - | My Boolean | bar | - # Pages are published by default, can be explicitly unpublished - And the "page" "Page 1" is not published - # Create a hierarchy, and reference a record created earlier - And the "page" "Page 1.1" is a child of a "page" "Page 1" - # Specific page type step - And a "page" "My Redirect" which redirects to a "page" "Page 1" - And a "member" "Website User" with "FavouritePage"="=>Page.Page 1" + Background: + # Creates a new page without data. Can be accessed later under this identifier + Given a "page" "Page 1" + # Uses a custom RegistrationPage type + And an "error page" "Register" + # Creates a page with inline properties + And a "page" "Page 2" with "URLSegment"="page-1" and "Content"="my page 1" + # Field names can be tabular, and based on DataObject::$field_labels + And the "page" "Page 3" has the following data + | Content | | + | My Property | foo | + | My Boolean | bar | + # Pages are published by default, can be explicitly unpublished + And the "page" "Page 1" is not published + # Create a hierarchy, and reference a record created earlier + And the "page" "Page 1.1" is a child of a "page" "Page 1" + # Specific page type step + And a "page" "My Redirect" which redirects to a "page" "Page 1" + And a "member" "Website User" with "FavouritePage"="=>Page.Page 1" - @javascript - Scenario: View a page in the tree - Given I am logged in with "ADMIN" permissions - And I go to "/admin/pages" - Then I should see "Page 1" in CMS Tree + @javascript + Scenario: View a page in the tree + Given I am logged in with "ADMIN" permissions + And I go to "/admin/pages" + Then I should see "Page 1" in CMS Tree +``` * Fixtures are created where you defined them. If you want the fixtures to be created - before every scenario, define them in + before every scenario, define them in [Background](http://docs.behat.org/en/latest/user_guide/writing_scenarios.html#backgrounds). If you want them to be created only when a particular scenario runs, define them there. * Fixtures are cleared between scenarios. @@ -259,8 +269,10 @@ use the inline definition syntax. The following example shows some syntax variat As a convention, Silverstripe Behat tests live in a `tests/behat` subfolder of your module. You can create it with the following commands: - mkdir -p mymodule/tests/behat/features/ - mkdir -p mymodule/tests/behat/src/ +```sh +mkdir -p mymodule/tests/behat/features/ +mkdir -p mymodule/tests/behat/src/ +``` ### FeatureContext @@ -269,16 +281,17 @@ 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/src/FeatureContext.php +Example: `mymodule/tests/behat/src/FeatureContext.php` - get(TestSessionEnvironment::class); - $state = $env->getState(); - if(isset($state->session['loggedInAs'])) { - $member = \Member::get()->byID($state->session['loggedInAs']); - } else { - $member = null; - } +$env = Injector::inst()->get(TestSessionEnvironment::class); +$state = $env->getState(); + +if (isset($state->session['loggedInAs'])) { + $member = \Member::get()->byID($state->session['loggedInAs']); +} else { + $member = null; +} +``` ## FAQ @@ -387,19 +405,23 @@ otherwise you'll always have an active debugging session in CLI, never in the br Then you can choose to enable XDebug for the current CLI run: - XDEBUG_CONFIG="idekey=macgdbp" vendor/bin/behat +```sh +XDEBUG_CONFIG="idekey=macgdbp" vendor/bin/behat +``` Or you can use the `TESTSESSION_PARAMS` environment variable to pass additional parameters to `dev/testsession/start`, and debug in the browser instead. - TESTSESSION_PARAMS="XDEBUG_SESSION_START=macgdbp" vendor/bin/behat @app +```sh +TESTSESSION_PARAMS="XDEBUG_SESSION_START=macgdbp" vendor/bin/behat @app +``` The `macgdbp` IDE key needs to match your `xdebug.idekey` php.ini setting. ### How do I set up continuous integration through Travis? Check out the [travis.yml](https://github.com/silverstripe/silverstripe-framework/blob/master/.travis.yml) -in `silverstripe/framework` for a good example on how to set up Behat tests through +in `silverstripe/framework` for a good example on how to set up Behat tests through [travis-ci.org](http://travis-ci.org). ## Cheatsheet @@ -410,6 +432,7 @@ It's based on the `vendor/bin/behat -di @cms` output. ### Basics +```cucumber Then /^(?:|I )should see "(?P(?:[^"]|\\")*)"$/ - Checks, that page contains specified text. @@ -473,9 +496,11 @@ It's based on the `vendor/bin/behat -di @cms` output. Then /^the "([^"]*)" table should not contain "([^"]*)"$/ Given /^I click on "([^"]*)" in the "([^"]*)" table$/ +``` ### Navigation +```cucumber Given /^(?:|I )am on homepage$/ - Opens homepage. @@ -496,9 +521,11 @@ It's based on the `vendor/bin/behat -di @cms` output. When /^(?:|I )move forward one page$/ - Moves forward one page in history +``` ### Forms +```cucumber When /^(?:|I )press "(?P