├── .travis.yml ├── README.md ├── behat.yml ├── circle.yml ├── composer.json ├── custom-greet.php ├── features ├── Bootstrap │ └── FeatureContext.php └── hello-world.feature ├── greet.php └── start-server.sh /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - '7.0' 4 | 5 | before_script: 6 | - composer install 7 | - "sh start-server.sh > /dev/null &" 8 | - "phantomjs --webdriver=4444 > /dev/null &" 9 | 10 | script: 11 | - vendor/bin/behat 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Behat & PhantomJS Example 2 | An example of using the Behat Selenium2 Mink Driver to power PhantomJS, and integrate with both CircleCI and TravisCI 3 | 4 | [![Build Status](https://travis-ci.org/jmauerhan/phantomjs-behat-selenium-example.svg?branch=master)](https://travis-ci.org/jmauerhan/phantomjs-behat-selenium-example) [![Circle CI](https://circleci.com/gh/jmauerhan/phantomjs-behat-selenium-example.svg?style=shield)](https://circleci.com/gh/jmauerhan/phantomjs-behat-selenium-example) 5 | 6 | ## Steps 7 | 8 | ### Install Dependencies 9 | - [PhantomJS](http://phantomjs.org/download.html) 10 | - PhantomJS has specific builds for your operating system - these do not work cross-platform. 11 | - Ensure you add the installed location to your PATH. 12 | - Behat, Mink, the Behat Mink Extension, and the Mink Selenium2 Driver (via Composer - see composer.json) 13 | - We will not *actually* be using Selenium, this is just the driver for Behat to interact with PhantomJS 14 | - This demo also requires `beberlei/assert` for assertions, but this is **not required** to get Behat & PhantomJS working, I just like using these assertions over writing my own all the time. 15 | 16 | ### Configure behat.yml 17 | Configure your behat.yml file to use the Behat MinkExtension, and set up the Javascript driver to be Selenium2 with PhantomJS as the browser. I have also configured Goutte as the default browser. Any tests with @javascript will use PhantomJS, the others will use Goutte (a fast, PHP headless browser powered by cURL) 18 | 19 | Example: 20 | ``` 21 | default: 22 | autoload: 23 | '': features/Bootstrap 24 | suites: 25 | default: 26 | contexts: 27 | - Features\Bootstrap\FeatureContext 28 | extensions: 29 | Behat\MinkExtension: 30 | #If you're running a server on a different port, or have a /etc/hosts file set up, change this. 31 | base_url: 'http://localhost:8000' 32 | sessions: 33 | default: 34 | goutte: ~ 35 | javascript: 36 | selenium2: 37 | browser: phantomjs 38 | ``` 39 | 40 | ### Write some features. 41 | Feel free to browse the Features directory of this repo to see the FeatureContext code, I have included some tests which require JS and some tests which do not, which use Goutte. 42 | 43 | ### Start PhantomJS 44 | In your terminal: 45 | ``` 46 | phantomjs --webdriver=4444 47 | ``` 48 | ***Note**: *This is a foreground process, so you'll need to open another terminal window to run Behat** 49 | 50 | ### Optional: Start up your local dev 51 | You can have your local development environment set up however you want, you might be using Docker containers, Vagrant, WAMP/MAMP, whatever. This demo has some PHP code you can run entirely on the built-in webserver. Open a new terminal and cd into the root of this project, then run: 52 | ``` 53 | php -S 127.0.0.1:8000 54 | ``` 55 | 56 | ### Run Behat 57 | In your terminal: 58 | ``` 59 | vendor/bin/behat 60 | ``` 61 | 62 | ## Integrating with CI 63 | 64 | Both CircleCI and Travis include PhantomJS, so there's no need to install or update. 65 | 66 | There's a one line script to start PHP's built-in server in this repository, so I'm starting that in the background in the ci build script. We'll also need to start the PhantomJS webdriver in the background. Then just run the Behat tests 67 | 68 | ### CircleCI 69 | ``` 70 | machine: 71 | php: 72 | version: 7.0.4 73 | 74 | test: 75 | pre: 76 | - sh start-server.sh: 77 | background: true 78 | - phantomjs --webdriver=4444: 79 | background: true 80 | override: 81 | - vendor/bin/behat -f junit -o $CIRCLE_TEST_REPORTS -f pretty -o std 82 | ``` 83 | 84 | ### TravisCI 85 | ``` 86 | language: php 87 | php: 88 | - '7.0' 89 | 90 | before_script: 91 | - composer install 92 | - "sh start-server.sh > /dev/null &" 93 | - "phantomjs --webdriver=4444 > /dev/null &" 94 | 95 | script: 96 | - vendor/bin/behat 97 | ``` 98 | -------------------------------------------------------------------------------- /behat.yml: -------------------------------------------------------------------------------- 1 | default: 2 | autoload: 3 | '': Features/Bootstrap 4 | suites: 5 | default: 6 | contexts: 7 | - Features\Bootstrap\FeatureContext 8 | extensions: 9 | Behat\MinkExtension: 10 | base_url: 'http://localhost:8000' 11 | sessions: 12 | default: 13 | goutte: ~ 14 | javascript: 15 | selenium2: 16 | browser: phantomjs 17 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | php: 3 | version: 7.0.4 4 | 5 | test: 6 | pre: 7 | - sh start-server.sh: 8 | background: true 9 | - phantomjs --webdriver=4444: 10 | background: true 11 | override: 12 | - vendor/bin/behat -f junit -o $CIRCLE_TEST_REPORTS -f pretty -o std 13 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jmauerhan/behat-phantomjs-example", 3 | "description": "Example of how to use PhantomJS with Behat", 4 | "type": "project", 5 | "require": { 6 | "php":">=5.4.0", 7 | "behat/behat": "^3.1", 8 | "behat/mink": "^1.7", 9 | "behat/mink-extension": "^2.2", 10 | "behat/mink-selenium2-driver": "^1.3", 11 | "behat/mink-goutte-driver": "^1.2", 12 | "beberlei/assert": "^2.5" 13 | }, 14 | "license": "MIT", 15 | "authors": [ 16 | { 17 | "name": "Jessica Mauerhan", 18 | "email": "jessicamauerhan@gmail.com" 19 | } 20 | ], 21 | "autoload": { 22 | "psr-4": { 23 | "Features\\": "features/" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /custom-greet.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 12 | 13 |
14 | {$_GET['greeting']} {$_GET['name']}!"; 17 | } 18 | ?> 19 | 27 | 28 | -------------------------------------------------------------------------------- /features/Bootstrap/FeatureContext.php: -------------------------------------------------------------------------------- 1 | getTestResult()->isPassed() === false) { 25 | $imageData = $this->getSession()->getDriver()->getScreenshot(); 26 | $imagePath = time() . '.png'; 27 | file_put_contents($imagePath, $imageData); 28 | } 29 | } 30 | 31 | /** 32 | * @Given I visit :path 33 | */ 34 | public function iVisit($path) 35 | { 36 | $this->visit($path); 37 | } 38 | 39 | /** 40 | * @When I enter :value in the :fieldName field 41 | */ 42 | public function iEnterInTheField($value, $fieldName) 43 | { 44 | $this->fillField($fieldName, $value); 45 | } 46 | 47 | /** 48 | * @When I select a greeting from the :label field 49 | */ 50 | public function iSelectAGreetingFromTheField($label) 51 | { 52 | $field = $this->getSession()->getPage()->findField($label); 53 | Assertion::notNull($field); 54 | $options = $field->findAll('css', 'option'); 55 | Assertion::notNull($options); 56 | Assertion::isArray($options); 57 | Assertion::notEmpty($options); 58 | $greetings = []; 59 | foreach ($options AS $option) { 60 | $value = $option->getValue(); 61 | //Exclude whatever is already selected, so we actually change it. 62 | if ($field->getValue() !== $value) { 63 | $greetings[] = $option->getValue(); 64 | } 65 | } 66 | shuffle($greetings); 67 | $this->chosenGreeting = array_pop($greetings); 68 | $field->selectOption($this->chosenGreeting); 69 | $this->getSession()->wait(1000); 70 | } 71 | 72 | /** 73 | * @Then I should see the submit button updates to the new greeting 74 | */ 75 | public function iShouldSeeTheSubmitButtonUpdatesToTheNewGreeting() 76 | { 77 | $expected = "Say {$this->chosenGreeting}!"; 78 | $submitButton = $this->getSession()->getPage()->findButton('submit'); 79 | Assertion::eq($submitButton->getText(), $expected); 80 | } 81 | 82 | /** 83 | * @Given I have entered a name in the :fieldLabel field 84 | */ 85 | public function iHaveEnteredANameInTheField($fieldLabel) 86 | { 87 | $this->name = 'Bob'; 88 | $this->fillField($fieldLabel, $this->name); 89 | } 90 | 91 | /** 92 | * @When I press the submit button 93 | */ 94 | public function iPressTheSubmitButton() 95 | { 96 | $this->pressButton('submit'); 97 | } 98 | 99 | /** 100 | * @Then I should see the greeting and my name 101 | */ 102 | public function iShouldSeeTheGreetingAndMyName() 103 | { 104 | $greeting = $this->chosenGreeting . ' ' . $this->name . '!'; 105 | $this->assertPageContainsText($greeting); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /features/hello-world.feature: -------------------------------------------------------------------------------- 1 | Feature: Hello World with Custom Greeting 2 | As a user 3 | I want to see a greeting with my name 4 | So I know the page is working 5 | 6 | Scenario: User Enters Their Name 7 | Given I visit "greet.php" 8 | When I enter "Jane" in the "Name" field 9 | And I press "Say Hello" 10 | Then I should see "Hello Jane!" 11 | 12 | @javascript 13 | Scenario: Change Greeting Button 14 | Given I visit "custom-greet.php" 15 | When I select a greeting from the "Greeting" field 16 | Then I should see the submit button updates to the new greeting 17 | 18 | @javascript 19 | Scenario: Get Custom Greeting 20 | Given I visit "custom-greet.php" 21 | And I have entered a name in the "Name" field 22 | And I select a greeting from the "Greeting" field 23 | When I press the submit button 24 | Then I should see the greeting and my name 25 | -------------------------------------------------------------------------------- /greet.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 |
6 | Hello ' . $_GET['name'] . '!'; 9 | } 10 | ?> 11 | 12 | -------------------------------------------------------------------------------- /start-server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | php -S 127.0.0.1:8000 3 | --------------------------------------------------------------------------------