SlideShare a Scribd company logo
1 of 81
Download to read offline
Booking.com
@thomas_shone
W
E
AR
E
H
IR
IN
G
Hoare Logic
{P} C {Q}
Hodor Logic
{P} C {Q}
I put on my
mink and
wizard behat
Questing in the world of
front end testing
Why?
What's the benefit?
Meet The Team
Don’t feed the druid after midnight
Task
Each test has a different approach
Barbarian
Quality Assurance
Ranger
Unit Test
Cleric
Continuous Integration
Wizard
Front End Test
Dreaded Bugbear
Teamwork
Wizards are squishy
The glue
Behat
(cucumber syntax)
Mink
(browser emulation)
Goutte
(web driver)
Selenium
(web driver)
Zombie
(web driver)
Guzzle
(curl)
Selenium RC
(java)
Zombie.js
(node.js)
Feature: Party harmony
As a leader, I want to ensure harmony and mutual trust, so that
we work as a team
Scenario: Teach members to respect others’ property
Given that the Wizard has 10 cookies
And the Bard eats 1 cookie
Then the Bard mysteriously catches fire
Cucumber Syntax
Readable testing language
class FeatureContext … {
/**
* @Given that the wizard has :num cookies
*/
public function wizardHasCookies($num) {
// $this->wizard is a pre-existing condition... like syphilis
$this->wizard->setNumberOfCookies($num);
}
}
and converts it into
FeatureContext.php
Feature: Party harmony
As a leader, I want to ensure harmony and mutual trust, so that
we work as a team
Scenario: Teach members to respect others’ property
Given that the Wizard has 10 cookies
And the Bard eats 1 cookie
Then the Bard mysteriously catches fire
Cucumber Syntax
What’s missing?
Scenario:
Given that the wizard has 10 cookies
And the Bard eats 1 cookie
Then the Bard mysteriously catches fire
Fire spell fizzled (OutOfManaException)
1 scenario (1 failed)
3 steps (2 passed, 1 failed)
0m0.03s (14.19Mb)
Remember {P} C {Q}
Set your starting states
Feature: Party harmony
As a leader, I want to ensure harmony and mutual trust, so that
we work as a team
Background:
The Wizard’s fire spell is fully charged
And the Bard is currently not on fire
Scenario: Teach members to respect others’ property
Given that the Wizard has 10 cookies
And the Bard eats 1 cookie
Then the Bard mysteriously catches fire
Remember {P} C {Q}
Set your starting states
???
As a leader, I want to ensure harmony and
mutual trust, so that we work as a team
User stories
As a <role>, I want to <desire> so that
<benefit>
Front end testing is code coverage for your user stories
User stories
Coverage
Features are your contract with the stakeholders
Contract
Scenarios are the use cases that outline the user story
Scenarios
Legend has it...
… that someone once convinced their PO to
write all their front end tests.
class MinkContext … {
/**
* Clicks link with specified id|title|alt|text.
*
* @When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/
*/
public function clickLink($link) {
$link = $this->fixStepArgument($link);
$this->getSession()->getPage()->clickLink($link);
}
}
Mink provides...
MinkContext.php
OK...
Lets drop the metaphor and get to actual
code
$ composer require behat/behat="~3.0,>=3.0.5"
Getting started
$ composer require behat/mink-extension="~2.0"
Behat (cucumber syntax)
Mink (browser emulator)
Web drivers
$ composer require behat/mink-goutte-driver="~1.0"
$ composer require behat/mink-selenium2-driver="~1.2"
$ ./vendor/bin/behat --init
+d features - place your *.feature files here
+d features/bootstrap - place your context classes here
+f features/bootstrap/FeatureContext.php - place your definitions,
transformations and hooks here
Initialize
Create a new test suite
use BehatMinkExtensionContextMinkContext;
class FeatureContext extends MinkContext … {
…
}
Context
FeatureContext.php
$ ./vendor/bin/behat -dl
Given /^(?:|I )am on "(?P<page>[^"]+)"$/
When /^(?:|I )reload the page$/
When /^(?:|I )move backward one page$/
When /^(?:|I )move forward one page$/
When /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/
When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/
When /^(?:|I )fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?:
[^"]|")*)"$/
Context
What does Mink bring to the table?
default:
suites:
default:
paths: [ %paths.base%/features/ ]
contexts: [ FeatureContext ]
extensions:
BehatMinkExtension:
base_url: "[your website]"
sessions:
default:
goutte: ~
Configuration
behat.yml
Feature: Authentication and authorisation
As a security conscious developer I wish to ensure that only
valid users can access our website.
Scenario: Attempt to login with invalid details
Given I am on "/login"
When I fill in "email" with "some@guy.com"
And I fill in "password" with "invalid"
And I press "Login"
Then I should see "Invalid Email or Password"
Our first feature
auth.feature
$ ./vendor/bin/behat --config behat.yml features/auth.feature
Scenario: Attempt to login with an invalid account
Given I am on "/login"
When I fill in "email" with "some@guy.com"
And I fill in "password" with "invalid"
And I press "Login"
Then I should see "Invalid Email or Password"
1 scenarios (1 passed)
5 steps (5 passed)
Victory
output
Feature: Authentication and authorisation
As a security conscious developer I wish to ensure that only
valid users can access our website.
Scenario: Attempt to login with invalid details
Given I login as "some@guy.com" with password "invalid"
Then I should see "Invalid Email or Password"
Simplify
auth.feature
Scenario: Attempt to login with an invalid account
Given I login as "bob@smith.com" with password "invalid"
Then I should see "Invalid Email or Password"
1 scenario (1 undefined)
/**
* @Given I login as :arg1 with password :arg2
*/
public function iLoginAsWithPassword($arg1, $arg2) {
throw new PendingException();
}
Simplify
output
class FeatureContext … {
/**
* @Given I login as :username with password :password
*/
public function iLoginAsWithPassword($username, $password) {
$this->visit("/login");
$this->fillField("email", $username);
$this->fillField("password", $password);
$this->pressButton("Login");
}
}
Simplify
FeatureContext.php
Scenario: Attempt to login with an invalid account
Given I login as "bob@smith.com" with password "invalid"
Then I should see "Invalid Email or Password"
1 scenarios (1 passed)
2 steps (2 passed)
Simplify
output
Feature: Authentication and authorisation
As a security conscious developer I wish to ensure that only
valid users can access our website.
Scenario: Attempt to register a new user
Given I am on "/signup"
When I fill in "email" with "some@guy.com"
And I fill in "password" with "valid"
And I fill in "password2" with "valid"
And I fill in "first_name" with "some"
And I fill in "last_name" with "guy"
And I press "Create my speaker profile"
Then I should see "You’ve successfully created your account"
Our first hurdle
This ones easy, you do…. oh….
Migration and seeding
Doctrine, Propel, Laravel, Phinx
$ composer require robmorgan/phinx="~0.4"
Phinx to the rescue
Install
$ php vendor/bin/phinx init
Phinx by Rob Morgan - https://phinx.org. version 0.4.3
Created ./phinx.xml
Configuration
$ php vendor/bin/phinx create InitialMigration
Creating
SID
E
N
O
TE
#!/usr/bin/env bash
DATABASE="opencfp"
mysql -e "DROP DATABASE IF EXISTS $DATABASE" -uroot -p123
mysql -e "CREATE DATABASE $DATABASE" -uroot -p123
vendor/bin/phinx migrate
vendor/bin/behat
But it’s a bit extreme
run-behat-test.sh
SAVEPOINT identifier;
# Run tests
ROLLBACK TO SAVEPOINT identifier;
RELEASE SAVEPOINT identifier;
Transaction/Rollback
Roll your own solution
Activation emails?
smtp-sink, FakeSMTP, etc
# Stop the currently running service
sudo service postfix stop
# Dumps outgoing emails to file as "day.hour.minute.second"
smtp-sink -d "%d.%H.%M.%S" localhost:2500 1000 &
vendor/bin/behat
smtp-sink
run-behat-test.sh
Or….
you could just read the activation code from
the database directly
class DatabaseContext {
public function __construct($dsn, $user, $pass) {
$this->dbh = new PDO($dsn, $user, $pass);
}
/**
* @When /^there is no user called :user$/
*/
public function removeUser($user) {
$this->dbh->prepare("DELETE FROM `users` WHERE username=?")
->query([$user]);
}
}
A new context
DatabaseContext.php
SID
E
N
O
TE
default:
suites:
default:
paths: [ %paths.base%/features/ ]
contexts:
- FeatureContext
- DatabaseContext:
- mysql:host=localhost;dbname=opencfp
- root
- 123
Configuration
behat.yml
SID
E
N
O
TE
Or….
actually send the email and read it via SMTP
How far is too far?
What are your priorities?
Taking it too far
True story
// Make sure your server and your behat client have the same time set
// Share the secret key between the two. The code should be valid for
// 30 second periods
$code = sha1($secret_key . floor(time() / 30));
if ($request->get("code") === $code) {
// Bypass captcha
}
Easier way
Simple but safe bypass
Our first talk
Set the stage
Feature: Manage paper submissions
In order to ensure that speakers can submit their papers
As an speaker I need to be able to manage my own submissions
Background:
There is a speaker registered as "some@guy.com" with a
password "secrets"
I login as "some@guy.com" with password "secrets"
Scenario: Add a new talk to our submissions
...
Our first talk
Talk submission in 3, 2, 1...
Scenario: Add a new talk to our submissions
Given I am on "talk/create"
And I fill in the following:
| title | Behat Talk |
| description | Awesome |
| type | regular |
| category | testing |
| level | mid |
And I check "desired"
And I press "Submit my talk!"
Then I should see "Success: Successfully added talk."
Tyranny of JavaScript
Deleting a talk
Well that won’t work
talks.feature
Feature: Manage paper submissions
In order to ensure that speakers can submit their papers
As an speaker I need to be able to manage my own submissions
Scenario: Delete a talk
Given create a talk called "Behat Talk"
And I am on "/dashboard"
When I follow "Delete"
And I should not see "Behat Talk Changed"
The text "Behat Talk Changed" appears in the text of this page,
but it should not. (BehatMinkExceptionResponseTextException)
// Guzzle using web scraper
behat/mink-goutte-driver
// Java-based distributed browser workers (support JavaScript)
behat/mink-selenium2-driver
behat/mink-sahi-driver
// node.js headless browser proxy (support JavaScript)
behat/mink-zombie-driver
Drivers
Some take the scenic route
default:
# …
extensions:
BehatMinkExtension:
base_url: "[your website]"
sessions:
default:
goutte: ~
javascript:
selenium2: ~
Configuration
Setting up for Selenium
$ java -jar selenium-server-standalone-2.*.jar
Selenium
@javascript # Or we could use @selenium2
Feature: Manage paper submissions
In order to ensure that speakers can submit their papers
As an speaker I need to be able to manage my own submissions
Start Selenium Server
Specify javascript requirement
$ ./vendor/bin/behat --tags speaker,talk
Tags
Run specific tags
@speaker
Feature: Manage paper submissions
In order to ensure that speakers can submit their papers
As an speaker I need to be able to manage my own submissions
@talk
Scenario: Create a new talk
Given I am logged in as a speaker ...
SID
E
N
O
TE
Feature: Submitting and managing talks
As a speaker I wish be able to submit talks so I can get a chance
to talk at a conference.
@javascript
Scenario: Delete a talk
Given create a talk called "Behat Talk"
And I am on "/dashboard"
When I fill "Delete"
And I accept alerts
And I should not see "Behat Talk"
Enable JavaScript
talks.feature
Run as JavaScript
talks.feature
Feature: Submitting and managing talks
As a speaker I wish be able to submit talks so I can get a chance
to talk at a conference.
Scenario: Delete a talk
Given create a talk called "Behat Talk"
And I am on "/dashboard"
When I follow "Delete"
And I accept alerts
And I should not see "Behat Talk"
class FeatureContext … {
public function takeAScreenshotCalled($filename) {
$driver = get_class($this->getSession()->getDriver());
if ($driver == 'BehatMinkDriverSelenium2Driver') {
$ss = $this->getSession()
->getDriver()
->getScreenshot();
file_put_contents($filename, $ss);
}
}
}
Screenshot
FeatureContext.php
Advanced Usage
with extra bells and whistles
use BehatBehatHookScopeAfterFeatureScope; // @AfterFeature
AfterScenarioScope; // @AfterScenario
AfterStepScope; // @AfterStep
BeforeFeatureScope; // @BeforeFeature
BeforeScenarioScope; // @BeforeScenario
BeforeStepScope; // @BeforeStep
FeatureScope; // @Feature
ScenarioScope; // @Scenario
StepScope; // @Step
Hooks
Listen in close
class FeatureContext … {
/**
* @AfterScenarioScope
*/
public function afterScenario(AfterScenarioScope $scope) {
$scenario = $scope->getScenario()->getTitle();
$filename = make_safe_filename($scenario);
// Take a screenshot and put it on a dashboard
// where people can see it
}
}
Hooks
FeatureContext.php
class FeatureContext … {
/**
* @AfterStep
*/
public function afterStep(AfterStepScope $scope) {
$code = $event->getTestResult()->getResultCode();
if ($code == TestResult::FAILED) {
// Take a screenshot
}
}
}
Hooks
FeatureContext.php
Some days everything is made of glass
Common Gotchas
Expect breakages
And that’s a good thing
Speed vs Coverage
Find the right balance
Keep Selenium updated
Browsers change faster than fashion trends
Behat documents
http://docs.behat.org points to v2.5 docs but
doesn’t tell you.
Use http://docs.behat.org/en/v3.0/
Questions?
or ask me later via @thomas_shone
Thank you
Photo from Flickr by John Morey, TrojanRat, Gerry Machen, USFS Region 5,
Peregrina Tyss and Thomas Hawk
Permutations
The reason why testing is painful
class MemoryContext {
/**
* @Transform /^memory:(.*)$/
*/
public function fromMemory($key) {
if (!isset($this->memory[$key])) {
throw new LogicException("Entry $key does not exist");
}
return $this->memory[$key];
}
}
Transformations
MemoryContext.php
default:
suites:
web:
paths: [ %paths.base%/features/web ]
contexts: [ BaseContext, WebContext ]
api:
paths: [ %paths.base%/features/api ]
contexts: [ BaseContext, ApiContext ]
Configuration
Multiple contexts
default:
suites:
admin:
paths: [ %paths.base%/features/web ]
contexts: [ BaseContext, AdminContext ]
filters:
role: admin
speaker:
paths: [ %paths.base%/features/web ]
contexts: [ BaseContext, SpeakerContext ]
filters:
tags: @speaker
Configuration
Grouping and filtering
$ ./vendor/bin/behat --suite admin
Suites
Run a specific suite
Feature: Managing the CFP
In order to ensure that speakers can submit their papers
As an admin
I need to be able to open the call for papers
$ ./vendor/bin/behat --suite speaker
Suites
Run a specific suite
@speaker
Feature: Submitting to the CFP
In order to ensure that the conference has papers
As an speaker
I need to be able to submit papers
$ java -jar selenium-server-standalone-2.*.jar -role hub
Selenium Grid
$ java -jar selenium-server-standalone-2.*.jar -role node -hub http://
[gridserver]:4444/grid/register
Start the grid
Add a node
default:
extensions:
BehatMinkExtension:
sessions:
javascript:
selenium2:
wd_host: "http://127.0.0.1:4444/wb/hub"
capabilities:
version: ""
Configuration
Because magic...

More Related Content

Similar to I put on my mink and wizard behat

Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsKonstantin Kudryashov
 
Behat - Drupal South 2018
Behat  - Drupal South 2018Behat  - Drupal South 2018
Behat - Drupal South 2018Berend de Boer
 
PHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source ProjectPHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source Projectxsist10
 
Transformando os pepinos do cliente no código de testes da sua aplicação
Transformando os pepinos do cliente no código de testes da sua aplicaçãoTransformando os pepinos do cliente no código de testes da sua aplicação
Transformando os pepinos do cliente no código de testes da sua aplicaçãoRodrigo Urubatan
 
Software Testing
Software TestingSoftware Testing
Software Testingsuperphly
 
Integration Testing With Cucumber How To Test Anything J A O O 2009
Integration Testing With  Cucumber    How To Test Anything    J A O O 2009Integration Testing With  Cucumber    How To Test Anything    J A O O 2009
Integration Testing With Cucumber How To Test Anything J A O O 2009Dr Nic Williams
 
How to build twitter bot using golang from scratch
How to build twitter bot using golang from scratchHow to build twitter bot using golang from scratch
How to build twitter bot using golang from scratchKaty Slemon
 
Bdd, cucumber and freinds
Bdd, cucumber and freindsBdd, cucumber and freinds
Bdd, cucumber and freindsFrank Duan
 
Automated Testing
Automated TestingAutomated Testing
Automated TestingSpeed FC
 
A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...
A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...
A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...Ho Chi Minh City Software Testing Club
 
Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2Rob Fuller
 
Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2Chris Gates
 
Getting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
Getting Started with Test Automation: Introduction to Cucumber with Lapis LazuliGetting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
Getting Started with Test Automation: Introduction to Cucumber with Lapis LazuliRebecca Eloise Hogg
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I thinkWim Godden
 
Php vulnerability presentation
Php vulnerability presentationPhp vulnerability presentation
Php vulnerability presentationSqa Enthusiast
 
Persona: in your browsers, killing your passwords
Persona: in your browsers, killing your passwordsPersona: in your browsers, killing your passwords
Persona: in your browsers, killing your passwordsFrancois Marier
 

Similar to I put on my mink and wizard behat (20)

Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projects
 
Behat - Drupal South 2018
Behat  - Drupal South 2018Behat  - Drupal South 2018
Behat - Drupal South 2018
 
PHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source ProjectPHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source Project
 
Cucumber & BDD
Cucumber & BDDCucumber & BDD
Cucumber & BDD
 
Transformando os pepinos do cliente no código de testes da sua aplicação
Transformando os pepinos do cliente no código de testes da sua aplicaçãoTransformando os pepinos do cliente no código de testes da sua aplicação
Transformando os pepinos do cliente no código de testes da sua aplicação
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
Integration Testing With Cucumber How To Test Anything J A O O 2009
Integration Testing With  Cucumber    How To Test Anything    J A O O 2009Integration Testing With  Cucumber    How To Test Anything    J A O O 2009
Integration Testing With Cucumber How To Test Anything J A O O 2009
 
How to build twitter bot using golang from scratch
How to build twitter bot using golang from scratchHow to build twitter bot using golang from scratch
How to build twitter bot using golang from scratch
 
Bdd, cucumber and freinds
Bdd, cucumber and freindsBdd, cucumber and freinds
Bdd, cucumber and freinds
 
Automated Testing
Automated TestingAutomated Testing
Automated Testing
 
BDD with cucumber
BDD with cucumberBDD with cucumber
BDD with cucumber
 
Webauthn Tutorial
Webauthn TutorialWebauthn Tutorial
Webauthn Tutorial
 
A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...
A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...
A Universal Automation Framework based on BDD Cucumber and Ruby on Rails - Ph...
 
Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2
 
Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2Dirty Little Secrets They Didn't Teach You In Pentest Class v2
Dirty Little Secrets They Didn't Teach You In Pentest Class v2
 
Getting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
Getting Started with Test Automation: Introduction to Cucumber with Lapis LazuliGetting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
Getting Started with Test Automation: Introduction to Cucumber with Lapis Lazuli
 
End-to-end testing with geb
End-to-end testing with gebEnd-to-end testing with geb
End-to-end testing with geb
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
Php vulnerability presentation
Php vulnerability presentationPhp vulnerability presentation
Php vulnerability presentation
 
Persona: in your browsers, killing your passwords
Persona: in your browsers, killing your passwordsPersona: in your browsers, killing your passwords
Persona: in your browsers, killing your passwords
 

More from xsist10

Security theatre (Scotland php)
Security theatre (Scotland php)Security theatre (Scotland php)
Security theatre (Scotland php)xsist10
 
Security Theatre (PHP Leuven)
Security Theatre (PHP Leuven)Security Theatre (PHP Leuven)
Security Theatre (PHP Leuven)xsist10
 
Security Theatre - Confoo
Security Theatre - ConfooSecurity Theatre - Confoo
Security Theatre - Confooxsist10
 
Security Theatre - PHP UK Conference
Security Theatre - PHP UK ConferenceSecurity Theatre - PHP UK Conference
Security Theatre - PHP UK Conferencexsist10
 
Security Theatre - Benelux
Security Theatre - BeneluxSecurity Theatre - Benelux
Security Theatre - Beneluxxsist10
 
Security Theatre - AmsterdamPHP
Security Theatre - AmsterdamPHPSecurity Theatre - AmsterdamPHP
Security Theatre - AmsterdamPHPxsist10
 
PHP SA 2013 - The weak points in our PHP projects
PHP SA 2013 - The weak points in our PHP projectsPHP SA 2013 - The weak points in our PHP projects
PHP SA 2013 - The weak points in our PHP projectsxsist10
 

More from xsist10 (7)

Security theatre (Scotland php)
Security theatre (Scotland php)Security theatre (Scotland php)
Security theatre (Scotland php)
 
Security Theatre (PHP Leuven)
Security Theatre (PHP Leuven)Security Theatre (PHP Leuven)
Security Theatre (PHP Leuven)
 
Security Theatre - Confoo
Security Theatre - ConfooSecurity Theatre - Confoo
Security Theatre - Confoo
 
Security Theatre - PHP UK Conference
Security Theatre - PHP UK ConferenceSecurity Theatre - PHP UK Conference
Security Theatre - PHP UK Conference
 
Security Theatre - Benelux
Security Theatre - BeneluxSecurity Theatre - Benelux
Security Theatre - Benelux
 
Security Theatre - AmsterdamPHP
Security Theatre - AmsterdamPHPSecurity Theatre - AmsterdamPHP
Security Theatre - AmsterdamPHP
 
PHP SA 2013 - The weak points in our PHP projects
PHP SA 2013 - The weak points in our PHP projectsPHP SA 2013 - The weak points in our PHP projects
PHP SA 2013 - The weak points in our PHP projects
 

Recently uploaded

Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Recently uploaded (20)

Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

I put on my mink and wizard behat

  • 4. I put on my mink and wizard behat Questing in the world of front end testing
  • 6. Meet The Team Don’t feed the druid after midnight
  • 7. Task Each test has a different approach
  • 12.
  • 15. The glue Behat (cucumber syntax) Mink (browser emulation) Goutte (web driver) Selenium (web driver) Zombie (web driver) Guzzle (curl) Selenium RC (java) Zombie.js (node.js)
  • 16. Feature: Party harmony As a leader, I want to ensure harmony and mutual trust, so that we work as a team Scenario: Teach members to respect others’ property Given that the Wizard has 10 cookies And the Bard eats 1 cookie Then the Bard mysteriously catches fire Cucumber Syntax Readable testing language
  • 17. class FeatureContext … { /** * @Given that the wizard has :num cookies */ public function wizardHasCookies($num) { // $this->wizard is a pre-existing condition... like syphilis $this->wizard->setNumberOfCookies($num); } } and converts it into FeatureContext.php
  • 18. Feature: Party harmony As a leader, I want to ensure harmony and mutual trust, so that we work as a team Scenario: Teach members to respect others’ property Given that the Wizard has 10 cookies And the Bard eats 1 cookie Then the Bard mysteriously catches fire Cucumber Syntax What’s missing?
  • 19. Scenario: Given that the wizard has 10 cookies And the Bard eats 1 cookie Then the Bard mysteriously catches fire Fire spell fizzled (OutOfManaException) 1 scenario (1 failed) 3 steps (2 passed, 1 failed) 0m0.03s (14.19Mb) Remember {P} C {Q} Set your starting states
  • 20. Feature: Party harmony As a leader, I want to ensure harmony and mutual trust, so that we work as a team Background: The Wizard’s fire spell is fully charged And the Bard is currently not on fire Scenario: Teach members to respect others’ property Given that the Wizard has 10 cookies And the Bard eats 1 cookie Then the Bard mysteriously catches fire Remember {P} C {Q} Set your starting states
  • 21. ??? As a leader, I want to ensure harmony and mutual trust, so that we work as a team
  • 22. User stories As a <role>, I want to <desire> so that <benefit>
  • 23. Front end testing is code coverage for your user stories User stories Coverage Features are your contract with the stakeholders Contract Scenarios are the use cases that outline the user story Scenarios
  • 24. Legend has it... … that someone once convinced their PO to write all their front end tests.
  • 25. class MinkContext … { /** * Clicks link with specified id|title|alt|text. * * @When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/ */ public function clickLink($link) { $link = $this->fixStepArgument($link); $this->getSession()->getPage()->clickLink($link); } } Mink provides... MinkContext.php
  • 26. OK... Lets drop the metaphor and get to actual code
  • 27. $ composer require behat/behat="~3.0,>=3.0.5" Getting started $ composer require behat/mink-extension="~2.0" Behat (cucumber syntax) Mink (browser emulator) Web drivers $ composer require behat/mink-goutte-driver="~1.0" $ composer require behat/mink-selenium2-driver="~1.2"
  • 28. $ ./vendor/bin/behat --init +d features - place your *.feature files here +d features/bootstrap - place your context classes here +f features/bootstrap/FeatureContext.php - place your definitions, transformations and hooks here Initialize Create a new test suite
  • 29. use BehatMinkExtensionContextMinkContext; class FeatureContext extends MinkContext … { … } Context FeatureContext.php
  • 30. $ ./vendor/bin/behat -dl Given /^(?:|I )am on "(?P<page>[^"]+)"$/ When /^(?:|I )reload the page$/ When /^(?:|I )move backward one page$/ When /^(?:|I )move forward one page$/ When /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/ When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/ When /^(?:|I )fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?: [^"]|")*)"$/ Context What does Mink bring to the table?
  • 31. default: suites: default: paths: [ %paths.base%/features/ ] contexts: [ FeatureContext ] extensions: BehatMinkExtension: base_url: "[your website]" sessions: default: goutte: ~ Configuration behat.yml
  • 32. Feature: Authentication and authorisation As a security conscious developer I wish to ensure that only valid users can access our website. Scenario: Attempt to login with invalid details Given I am on "/login" When I fill in "email" with "some@guy.com" And I fill in "password" with "invalid" And I press "Login" Then I should see "Invalid Email or Password" Our first feature auth.feature
  • 33. $ ./vendor/bin/behat --config behat.yml features/auth.feature Scenario: Attempt to login with an invalid account Given I am on "/login" When I fill in "email" with "some@guy.com" And I fill in "password" with "invalid" And I press "Login" Then I should see "Invalid Email or Password" 1 scenarios (1 passed) 5 steps (5 passed) Victory output
  • 34. Feature: Authentication and authorisation As a security conscious developer I wish to ensure that only valid users can access our website. Scenario: Attempt to login with invalid details Given I login as "some@guy.com" with password "invalid" Then I should see "Invalid Email or Password" Simplify auth.feature
  • 35. Scenario: Attempt to login with an invalid account Given I login as "bob@smith.com" with password "invalid" Then I should see "Invalid Email or Password" 1 scenario (1 undefined) /** * @Given I login as :arg1 with password :arg2 */ public function iLoginAsWithPassword($arg1, $arg2) { throw new PendingException(); } Simplify output
  • 36. class FeatureContext … { /** * @Given I login as :username with password :password */ public function iLoginAsWithPassword($username, $password) { $this->visit("/login"); $this->fillField("email", $username); $this->fillField("password", $password); $this->pressButton("Login"); } } Simplify FeatureContext.php
  • 37. Scenario: Attempt to login with an invalid account Given I login as "bob@smith.com" with password "invalid" Then I should see "Invalid Email or Password" 1 scenarios (1 passed) 2 steps (2 passed) Simplify output
  • 38. Feature: Authentication and authorisation As a security conscious developer I wish to ensure that only valid users can access our website. Scenario: Attempt to register a new user Given I am on "/signup" When I fill in "email" with "some@guy.com" And I fill in "password" with "valid" And I fill in "password2" with "valid" And I fill in "first_name" with "some" And I fill in "last_name" with "guy" And I press "Create my speaker profile" Then I should see "You’ve successfully created your account" Our first hurdle This ones easy, you do…. oh….
  • 39. Migration and seeding Doctrine, Propel, Laravel, Phinx
  • 40. $ composer require robmorgan/phinx="~0.4" Phinx to the rescue Install $ php vendor/bin/phinx init Phinx by Rob Morgan - https://phinx.org. version 0.4.3 Created ./phinx.xml Configuration $ php vendor/bin/phinx create InitialMigration Creating SID E N O TE
  • 41. #!/usr/bin/env bash DATABASE="opencfp" mysql -e "DROP DATABASE IF EXISTS $DATABASE" -uroot -p123 mysql -e "CREATE DATABASE $DATABASE" -uroot -p123 vendor/bin/phinx migrate vendor/bin/behat But it’s a bit extreme run-behat-test.sh
  • 42. SAVEPOINT identifier; # Run tests ROLLBACK TO SAVEPOINT identifier; RELEASE SAVEPOINT identifier; Transaction/Rollback Roll your own solution
  • 44. # Stop the currently running service sudo service postfix stop # Dumps outgoing emails to file as "day.hour.minute.second" smtp-sink -d "%d.%H.%M.%S" localhost:2500 1000 & vendor/bin/behat smtp-sink run-behat-test.sh
  • 45. Or…. you could just read the activation code from the database directly
  • 46. class DatabaseContext { public function __construct($dsn, $user, $pass) { $this->dbh = new PDO($dsn, $user, $pass); } /** * @When /^there is no user called :user$/ */ public function removeUser($user) { $this->dbh->prepare("DELETE FROM `users` WHERE username=?") ->query([$user]); } } A new context DatabaseContext.php SID E N O TE
  • 47. default: suites: default: paths: [ %paths.base%/features/ ] contexts: - FeatureContext - DatabaseContext: - mysql:host=localhost;dbname=opencfp - root - 123 Configuration behat.yml SID E N O TE
  • 48. Or…. actually send the email and read it via SMTP
  • 49. How far is too far? What are your priorities?
  • 50. Taking it too far True story
  • 51. // Make sure your server and your behat client have the same time set // Share the secret key between the two. The code should be valid for // 30 second periods $code = sha1($secret_key . floor(time() / 30)); if ($request->get("code") === $code) { // Bypass captcha } Easier way Simple but safe bypass
  • 52. Our first talk Set the stage Feature: Manage paper submissions In order to ensure that speakers can submit their papers As an speaker I need to be able to manage my own submissions Background: There is a speaker registered as "some@guy.com" with a password "secrets" I login as "some@guy.com" with password "secrets" Scenario: Add a new talk to our submissions ...
  • 53. Our first talk Talk submission in 3, 2, 1... Scenario: Add a new talk to our submissions Given I am on "talk/create" And I fill in the following: | title | Behat Talk | | description | Awesome | | type | regular | | category | testing | | level | mid | And I check "desired" And I press "Submit my talk!" Then I should see "Success: Successfully added talk."
  • 55. Well that won’t work talks.feature Feature: Manage paper submissions In order to ensure that speakers can submit their papers As an speaker I need to be able to manage my own submissions Scenario: Delete a talk Given create a talk called "Behat Talk" And I am on "/dashboard" When I follow "Delete" And I should not see "Behat Talk Changed" The text "Behat Talk Changed" appears in the text of this page, but it should not. (BehatMinkExceptionResponseTextException)
  • 56. // Guzzle using web scraper behat/mink-goutte-driver // Java-based distributed browser workers (support JavaScript) behat/mink-selenium2-driver behat/mink-sahi-driver // node.js headless browser proxy (support JavaScript) behat/mink-zombie-driver Drivers Some take the scenic route
  • 57. default: # … extensions: BehatMinkExtension: base_url: "[your website]" sessions: default: goutte: ~ javascript: selenium2: ~ Configuration Setting up for Selenium
  • 58. $ java -jar selenium-server-standalone-2.*.jar Selenium @javascript # Or we could use @selenium2 Feature: Manage paper submissions In order to ensure that speakers can submit their papers As an speaker I need to be able to manage my own submissions Start Selenium Server Specify javascript requirement
  • 59. $ ./vendor/bin/behat --tags speaker,talk Tags Run specific tags @speaker Feature: Manage paper submissions In order to ensure that speakers can submit their papers As an speaker I need to be able to manage my own submissions @talk Scenario: Create a new talk Given I am logged in as a speaker ... SID E N O TE
  • 60. Feature: Submitting and managing talks As a speaker I wish be able to submit talks so I can get a chance to talk at a conference. @javascript Scenario: Delete a talk Given create a talk called "Behat Talk" And I am on "/dashboard" When I fill "Delete" And I accept alerts And I should not see "Behat Talk" Enable JavaScript talks.feature
  • 61. Run as JavaScript talks.feature Feature: Submitting and managing talks As a speaker I wish be able to submit talks so I can get a chance to talk at a conference. Scenario: Delete a talk Given create a talk called "Behat Talk" And I am on "/dashboard" When I follow "Delete" And I accept alerts And I should not see "Behat Talk"
  • 62. class FeatureContext … { public function takeAScreenshotCalled($filename) { $driver = get_class($this->getSession()->getDriver()); if ($driver == 'BehatMinkDriverSelenium2Driver') { $ss = $this->getSession() ->getDriver() ->getScreenshot(); file_put_contents($filename, $ss); } } } Screenshot FeatureContext.php
  • 63. Advanced Usage with extra bells and whistles
  • 64. use BehatBehatHookScopeAfterFeatureScope; // @AfterFeature AfterScenarioScope; // @AfterScenario AfterStepScope; // @AfterStep BeforeFeatureScope; // @BeforeFeature BeforeScenarioScope; // @BeforeScenario BeforeStepScope; // @BeforeStep FeatureScope; // @Feature ScenarioScope; // @Scenario StepScope; // @Step Hooks Listen in close
  • 65. class FeatureContext … { /** * @AfterScenarioScope */ public function afterScenario(AfterScenarioScope $scope) { $scenario = $scope->getScenario()->getTitle(); $filename = make_safe_filename($scenario); // Take a screenshot and put it on a dashboard // where people can see it } } Hooks FeatureContext.php
  • 66. class FeatureContext … { /** * @AfterStep */ public function afterStep(AfterStepScope $scope) { $code = $event->getTestResult()->getResultCode(); if ($code == TestResult::FAILED) { // Take a screenshot } } } Hooks FeatureContext.php
  • 67. Some days everything is made of glass Common Gotchas
  • 69. Speed vs Coverage Find the right balance
  • 70. Keep Selenium updated Browsers change faster than fashion trends
  • 71. Behat documents http://docs.behat.org points to v2.5 docs but doesn’t tell you. Use http://docs.behat.org/en/v3.0/
  • 72. Questions? or ask me later via @thomas_shone
  • 73. Thank you Photo from Flickr by John Morey, TrojanRat, Gerry Machen, USFS Region 5, Peregrina Tyss and Thomas Hawk
  • 74. Permutations The reason why testing is painful
  • 75. class MemoryContext { /** * @Transform /^memory:(.*)$/ */ public function fromMemory($key) { if (!isset($this->memory[$key])) { throw new LogicException("Entry $key does not exist"); } return $this->memory[$key]; } } Transformations MemoryContext.php
  • 76. default: suites: web: paths: [ %paths.base%/features/web ] contexts: [ BaseContext, WebContext ] api: paths: [ %paths.base%/features/api ] contexts: [ BaseContext, ApiContext ] Configuration Multiple contexts
  • 77. default: suites: admin: paths: [ %paths.base%/features/web ] contexts: [ BaseContext, AdminContext ] filters: role: admin speaker: paths: [ %paths.base%/features/web ] contexts: [ BaseContext, SpeakerContext ] filters: tags: @speaker Configuration Grouping and filtering
  • 78. $ ./vendor/bin/behat --suite admin Suites Run a specific suite Feature: Managing the CFP In order to ensure that speakers can submit their papers As an admin I need to be able to open the call for papers
  • 79. $ ./vendor/bin/behat --suite speaker Suites Run a specific suite @speaker Feature: Submitting to the CFP In order to ensure that the conference has papers As an speaker I need to be able to submit papers
  • 80. $ java -jar selenium-server-standalone-2.*.jar -role hub Selenium Grid $ java -jar selenium-server-standalone-2.*.jar -role node -hub http:// [gridserver]:4444/grid/register Start the grid Add a node