Welcome to the Mink documentation!¶
One of the most important parts in the web is a browser. A browser is the window through which web users interact with web applications and other users. Users are always talking with web applications through browsers.
So, in order to test that our web application behaves correctly, we need a way to simulate this interaction between the browser and the web application in our tests. We need Mink.
Mink is an open source browser controller/emulator for web applications, written in PHP.
Read Mink at a Glance to learn more about Mink and why you need it.
Installation¶
Mink is a php library that you’ll use inside your test suites or project. Before you begin, ensure that you have at least PHP 5.4 installed.
The recommended way to install Mink with all its dependencies is through Composer:
$ composer require --dev behat/mink
Note
For local installations of composer you must call it like this:
$ php composer.phar require --dev behat/mink
.
In this case you must use the different call
php composer.phar
everywhere instead of the simple command composer
.
Everything will be installed inside the vendor
folder.
Finally, include the Composer autoloading script to your project:
require_once 'vendor/autoload.php';
Note
By default, Mink will be installed with no drivers. In order to be able to use additional drivers, you should install them (through composer). Require the appropriate dependencies:
- GoutteDriver -
behat/mink-goutte-driver
- Selenium2Driver -
behat/mink-selenium2-driver
- BrowserKitDriver -
behat/mink-browserkit-driver
- ChromeDriver -
dmore/chrome-mink-driver
- ZombieDriver -
behat/mink-zombie-driver
- SeleniumDriver -
behat/mink-selenium-driver
- SahiDriver -
behat/mink-sahi-driver
- WUnitDriver -
behat/mink-wunit-driver
If you’re a newcomer or just don’t know what to choose, you should probably start with the GoutteDriver and the Selenium2Driver (you will be able to tune it up later):
Guides¶
Learn Mink with the topical guides:
Mink at a Glance¶
There’s a huge number of browser emulators out there, like Goutte, Selenium, Sahi and others. They all do the same job, but do it very differently. They behave differently and have very different API’s. But, what’s more important, there are actually 2 completely different types of browser emulators out there:
- Headless browser emulators
- Browser controllers
The first type of browser emulators are simple pure HTTP specification implementations, like Goutte. Those browser emulators send real HTTP requests against an application and parse the response content. They are very simple to run and configure, because this type of emulator can be written in any available programming language and can be run through the console on servers without a GUI. Headless emulators have both advantages and disadvantages. Advantages are simplicity, speed and ability to run without the need of a real browser. But this type of browser emulator has one big disadvantage, it has no JS/AJAX support. So, you can’t test your rich GUI web applications with headless browsers.
The second type of browser emulators are browser controllers. Those emulators aim to control the real browser. That’s right, a program to control another program. Browser controllers simulate user interactions on the browser and are able to retrieve actual information from the current browser page. Selenium and Sahi are the two most famous browser controllers. The main advantage of using browser controllers is the support for JS/AJAX interactions on the page. The disadvantage is that such browser emulators require an installed browser, extra configuration and are usually much slower than headless counterparts.
So, the easy answer is to choose the best emulator for your project and use its API for testing. But as we’ve already seen, both browser emulator types have advantages and disadvantages. If you choose a headless browser emulator, you will not be able to test your JS/AJAX pages. And if you choose a browser controller, your overall test suite will become very slow at some point. So, in the real world we should use both! And that’s why you need Mink.
Mink removes API differences between different browser emulators providing different drivers (read in Drivers chapter) for every browser emulator and providing you with an easy way to control the browser (Controlling the Browser), traverse pages (Traversing Pages), manipulate page elements (Manipulating Pages) or interact with them (Interacting with Pages).
Controlling the Browser¶
In Mink, the entry point to the browser is called the session. Think about it as being your browser window (some drivers even let you switch tabs!).
First, start your session (it’s like opening your browser tab). Nothing can be done with it before starting it.
// Choose a Mink driver. More about it in later chapters.
$driver = new \Behat\Mink\Driver\GoutteDriver();
$session = new \Behat\Mink\Session($driver);
// start the session
$session->start();
Note
The first argument to the session constructor is a driver object. Drivers are the way the Mink abstraction layer works. You will discover more about the available drivers in a later chapter.
Caution
Although Mink does its best to remove differences between the different drivers, each driver has unique features and shortcomings. See the Driver Feature Support to see which features are supported by each driver.
Basic Browser Interaction¶
Now that your session is started, you’ll want to open a page with it. Just
after starting, the session is not on any page (in a real browser, you would
be on the about:blank
page), and calling any other action is likely to fail.
$session->visit('http://my_project.dev/some_page.php');
Note
Mink is primarily designed to be used for testing websites. To allow
you to browse and test error pages, the Session::visit
method does
not consider error status codes as invalid. It will not throw an exception
in this case. You will need to check the status code (or certain text
on the page) to know if the response was successful or not.
Interacting with the Page¶
The session gives you access to the page through the Session::getPage
method. This allows you to traverse the page,
manipulate page elements and
interact with them. The next chapters
cover the page API in depth. Most of what you’ll do with Mink will use this
object, but you can continue reading to learn more about the Session.
Using the Browser History¶
The session gives you access to the browser history:
// get the current page URL:
echo $session->getCurrentUrl();
// use history controls:
$session->reload();
$session->back();
$session->forward();
Cookie Management¶
The session can manipulate cookies available in the browser.
// set cookie:
$session->setCookie('cookie name', 'value');
// get cookie:
echo $session->getCookie('cookie name');
// delete cookie:
$session->setCookie('cookie name', null);
Note
With drivers that use JavaScript to control the browser - like Sahi - you may be restricted to accessing/setting all, but HttpOnly cookies .
Status Code Retrieval¶
The session lets you retrieve the HTTP status code of the response:
echo $session->getStatusCode();
Headers Management¶
The session lets you manipulate request headers and access response headers:
// setting browser language:
$session->setRequestHeader('Accept-Language', 'fr');
// retrieving response headers:
print_r($session->getResponseHeaders());
Note
Headers handling is only supported in headless drivers (e.g. Goutte). Browser controllers (e.g. Selenium2) cannot access that information.
HTTP Authentication¶
The session has a special method to perform HTTP Basic authentication:
$session->setBasicAuth($user, $password);
The method can also be used to reset a previous authentication:
$session->setBasicAuth(false);
Note
Automatic HTTP authentication is only supported in headless drivers. Because HTTP authentication in the browser requires manual user action, that can’t be done remotely for browser controllers.
Javascript Evaluation¶
The session allows you to execute or evaluate Javascript.
// Execute JS
$session->executeScript('document.body.firstChild.innerHTML = "";');
// evaluate JS expression:
echo $session->evaluateScript(
"return 'something from browser';"
);
Note
The difference between these methods is that Session::evaluateScript
returns the result of the expression. When you don’t need to get a return
value, using Session::executeScript
is better.
You can also wait until a given JS expression returns a truthy value or the timeout is reached:
// wait for n milliseconds or
// till JS expression becomes truthy:
$session->wait(
5000,
"$('.suggestions-results').children().length"
);
Note
The Session::wait
method returns true
when the evaluation becomes
truthy. It will return false
when the timeout is reached.
Resetting the Session¶
The primary aim for Mink is to provide a single consistent web browsing API for acceptance tests. But a very important part in testing is isolation.
Mink provides two very useful methods to isolate tests, which can be used
in your test’s teardown
methods:
// soft-reset:
$session->reset();
// hard-reset:
$session->stop();
// or if you want to start again at the same time
$session->restart();
Stopping the session is the best way to reset the session to its initial
state. It will close the browser entirely. To use the session again, you
need to start the session before any other action. The Session::restart
shortcut allows you to do these 2 steps in a single call.
The drawback of closing the browser and starting it again is that it takes
time. In many cases, a lower level of isolation is enough in favor of a faster
resetting. The Session::reset
method covers this use case. It will try
to clear the cookies and reset the request headers and the browser history
to the limit of the driver possibilities.
Taking all this into account, it is recommended to use Session::reset()
by default and to call Session::stop()
when you need really full isolation.
Traversing Pages¶
Most usages of Mink will involve working with the page opened in your browser. This is done thanks to the powerful Element API. This API allows to traverse the page (similar to the DOM in Javascript), manipulate page elements and to interact with them, which will be covered in the next chapters.
DocumentElement and NodeElement¶
The Element API consists of 2 main classes. The DocumentElement
instance
represents the page being displayed in the browser, while the NodeElement
class is used to represent any element inside the page. Both classes share
a common set of methods to traverse the page (defined in TraversableElement
).
The DocumentElement
instance is accessible through the Session::getPage
method:
$page = $session->getPage();
// You can now manipulate the page.
Note
The DocumentElement
instance represents the <html>
node in the
DOM. It is equivalent to document.documentElement
in the Javascript
DOM API.
Traversal Methods¶
Elements have 2 main traversal methods: ElementInterface::findAll
returns
an array of NodeElement
instances matching the provided selector
inside the current element while ElementInterface::find
returns the first
match or null
when there is none.
The TraversableElement
class also provides a bunch of shortcut methods
on top of find()
to make it easier to achieve many common use cases:
ElementInterface::has
- Checks whether a child element matches the given selector but without returning it.
TraversableElement::findById
- Looks for a child element with the given id.
TraversableElement::findLink
- Looks for a link with the given text, title, id or
alt
attribute (for images used inside links). TraversableElement::findButton
- Looks for a button with the given text, title, id,
name
attribute oralt
attribute (for images used inside links). TraversableElement::findField
- Looks for a field (
input
,textarea
orselect
) with the given label, placeholder, id orname
attribute.
Note
These shortcuts return a single element. If you need to find all
matches, you will need to use findAll
with the named selector.
Nested Traversing¶
Every find*()
method will return a Behat\Mink\Element\NodeElement
instance
and findAll()
will return an array of such instances. The fun part is
that you can use the same methods of traversing on such elements as well:
$registerForm = $page->find('css', 'form.register');
if (null === $registerForm) {
throw new \Exception('The element is not found');
}
// find some field INSIDE form with class="register"
$field = $registerForm->findField('Email');
Selectors¶
The ElementInterface::find
and ElementInterface::findAll
methods
support several kinds of selectors to find elements.
CSS Selector¶
The css
selector type lets you use CSS expressions to search for elements
on the page:
$title = $page->find('css', 'h1');
$buttonIcon = $page->find('css', '.btn > .icon');
XPath Selector¶
The xpath
selector type lets you use XPath queries to search for elements
on the page:
$anchorsWithoutUrl = $page->findAll('xpath', '//a[not(@href)]');
Caution
This selector searches for an element inside the current node (which
is <html>
for the page object). This means that trying to pass it
the XPath of an element retrieved with ElementInterface::getXpath
will not work (this query includes the query for the root node). To check
whether an element object still exists on the browser page, use ElementInterface::isValid
instead.
Named Selectors¶
Named selectors provide a set of reusable queries for common needs. For conditions
based on the content of elements, the named selector will try to find an
exact match first. It will then fallback to partial matching if there
is no result for the exact match. The named_exact
selector type can be
used to force using only exact matching. The named_partial
selector type
can be used to apply partial matching without preferring exact matches.
For the named selector type, the second argument of the find()
method
is an array with 2 elements: the name of the query to use and the value to
search with this query:
$topLink = $page->find('named', array('link', $escapedValue));
The following queries are supported by the named selector:
id
- Searches for an element by its id.
id_or_name
- Searches for an element by its id or name.
link
- Searches for a link by its id, title, img alt, rel or text.
button
- Searches for a button by its name, id, text, img alt or title.
link_or_button
- Searches for both links and buttons.
content
- Searches for a specific page content (text).
field
- Searches for a form field by its id, name, label or placeholder.
select
- Searches for a select field by its id, name or label.
checkbox
- Searches for a checkbox by its id, name, or label.
radio
- Searches for a radio button by its id, name, or label.
file
- Searches for a file input by its id, name, or label.
optgroup
- Searches for an optgroup by its label.
option
- Searches for an option by its content or value.
fieldset
- Searches for a fieldset by its id or legend.
table
- Searches for a table by its id or caption.
Custom Selector¶
Mink lets you register your own selector types through implementing the Behat\Mink\Selector\SelectorInterface
.
It should then be registered in the SelectorsHandler
which is the registry
of available selectors.
The recommended way to register a custom selector is to do it when building
your Session
:
$selector = new \App\MySelector();
$handler = new \Behat\Mink\Selector\SelectorsHandler();
$handler->registerSelector('mine', $selector);
$driver = // ...
$session = new \Behat\Mink\Session($driver, $handler);
Manipulating Pages¶
Once you get a page element, you will want to manipulate it. You can also interact with the page, which is covered in the next chapter.
Getting the tag name¶
The NodeElement::getTagName
method allows you to get the tag name of
the element. This tag name is always returned lowercased.
$el = $page->find('css', '.something');
// get tag name:
echo $el->getTagName(); // displays 'a'
Accessing HTML attributes¶
The NodeElement
class gives you access to HTML attributes of the element.
NodeElement::hasAttribute
- Checks whether the element has a given attribute.
NodeElement::getAttribute
- Gets the value of an attribute.
NodeElement::hasClass
- Checks whether the element has the given class (convenience wrapper around
getAttribute('class')
).
$el = $page->find('css', '.something');
if ($el->hasAttribute('href')) {
echo $el->getAttribute('href');
} else {
echo 'This anchor is not a link. It does not have an href.';
}
Element Content and Text¶
The Element
class provides access to the content of elements.
Element::getHtml
- Gets the inner HTML of the element, i.e. all children of the element.
Element::getOuterHtml
- Gets the outer HTML of the element, i.e. including the element itself.
Element::getText
- Gets the text of the element.
Note
getText()
will strip tags and unprinted characters out of the response,
including newlines. So it’ll basically return the text that the user sees
on the page.
Checking Element Visibility¶
The NodeElement::isVisible
method checks whether the element is visible.
Accessing Form State¶
The NodeElement
class allows access to the state of form elements:
NodeElement::getValue
- Gets the value of the element. See Interacting with Forms.
NodeElement::isChecked
- Checks whether the checkbox or radio button is checked.
NodeElement::isSelected
- Checks whether the
<option>
element is selected.
Shortcut methods¶
The TraversableElement
class provides a few shortcut methods that allow
finding a child element in the page and checking the state of it immediately:
TraversableElement::hasCheckedField
- Looks for a checkbox (see findField) and checks whether it is checked.
TraversableElement::hasUncheckedField
- Looks for a checkbox (see findField) and checks whether it is not checked.
Interacting with Pages¶
Most usages of Mink will involve working with the page opened in your browser. The Mink Element API lets you interact with elements of the page.
Interacting with Links and Buttons¶
The NodeElement::click
and NodeElement::press
methods let you click
the links and press the buttons on the page.
Note
These methods are actually equivalent internally (pressing a button involves clicking on it). Having both methods allows the code to be more readable.
Interacting with Forms¶
The NodeElement
class has a set of methods allowing interaction with
forms:
NodeElement::getValue
gets the value of a form field. The value depends on the type of field:
- the value of the selected option for single select boxes (or
null
when none are selected); - an array of selected option values for multiple select boxes;
- the value of the checkbox field when checked, or
null
when not checked; - the value of the selected radio button in the radio group for radio buttons;
- the value of the field for textual fields and textareas;
- an undefined value for file fields (because of browser limitations).
- the value of the selected option for single select boxes (or
NodeElement::setValue
sets the value of a form field
- for a file field, it should be the absolute path to the file;
- for a checkbox, it should be a boolean indicating whether it is checked;
- for other fields, it should match the behavior of
getValue
.
NodeElement::isChecked
- reports whether a radio button or a checkbox is checked.
NodeElement::isSelected
- reports whether an
<option>
element is selected. NodeElement::check
- checks a checkbox field.
NodeElement::uncheck
- unchecks a checkbox field.
NodeElement::selectOption
- select an option in a select box or in a radio group.
NodeElement::attachFile
- attaches a file in a file input.
NodeElement::submit
- submits the form.
Interacting with the Mouse¶
The NodeElement
class offers a set of methods allowing interaction with
the mouse:
NodeElement::click
- performs a click on the element.
NodeElement::doubleClick
- performs a double click on the element.
NodeElement::rightClick
- performs a right click on the element.
NodeElement::mouseOver
- moves the mouse over the element.
Interacting with the Keyboard¶
Mink lets you interact with the keyboard thanks to the NodeElement::keyDown
,
NodeElement::keyPress
and NodeElement::keyUp
methods.
Manipulating the Focus¶
The NodeElement
class lets you give and remove focus on the element thanks
to the NodeElement::focus
and NodeElement::blur
methods.
Drag’n’Drop¶
Mink supports drag’n’drop of one element onto another:
$dragged = $page->find(...);
$target = $page->find(...);
$dragged->dragTo($target);
Shortcut Methods¶
The TraversableElement
class provides a few shortcut methods that allow
finding a child element on the page and performing an action on it immediately:
TraversableElement::clickLink
- Looks for a link (see findLink) and clicks on it.
TraversableElement::pressButton
- Looks for a button (see findButton) and presses on it.
TraversableElement::fillField
- Looks for a field (see findField) and sets a value in it.
TraversableElement::checkField
- Looks for a checkbox (see findField) and checks it.
TraversableElement::uncheckField
- Looks for a checkbox (see findField) and unchecks it.
TraversableElement::selectFieldOption
- Looks for a select or radio group (see findField) and selects a choice in it.
TraversableElement::attachFileToField
- Looks for a file field (see findField) and attaches a file to it.
Note
All these shortcut methods throw an ElementNotFoundException
if the child element cannot be found.
Drivers¶
How does Mink provide a consistent API for very different browser library
types, often written in different languages? Through drivers! A Mink driver
is a simple class, that implements Behat\Mink\Driver\DriverInterface
.
This interface describes bridge methods between Mink and real browser emulators.
Mink always talks with browser emulators through its driver. It doesn’t know
anything about how to start/stop or traverse pages in that particular browser
emulator. It only knows what driver method it should call in order to do this.
Mink comes with six drivers out of the box:
GoutteDriver¶
GoutteDriver provides a bridge for the Goutte headless browser. Goutte is a classical pure-php headless browser, written by the creator of the Symfony framework Fabien Potencier.
Note
The GoutteDriver extends the BrowserKitDriver to fix a small edge case in the Goutte implementation of BrowserKit. It is also able to instantiate the Goutte client automatically.
Installation¶
GoutteDriver is a pure PHP library available through Composer:
$ composer require behat/mink-goutte-driver
Usage¶
In order to talk with Goutte, you should instantiate a
Behat\Mink\Driver\GoutteDriver
:
$driver = new \Behat\Mink\Driver\GoutteDriver();
Also, if you want to configure Goutte more precisely, you could do the full setup by hand:
$client = new \Goutte\Client();
// Do more configuration for the Goutte client
$driver = new \Behat\Mink\Driver\GoutteDriver($client);
BrowserKitDriver¶
BrowserKitDriver provides a bridge for the Symfony BrowserKit component. BrowserKit is a browser emulator provided by the Symfony project.
Installation¶
BrowserKitDriver is a pure PHP library available through Composer:
$ composer require behat/mink-browserkit-driver
Note
The BrowserKit component only provides an abstract implementation. The actual implementation is provided by other projects, like Goutte or the Symfony HttpKernel component.
If you are using Goutte, you should use the special GoutteDriver which ensures full compatibility for Goutte due to an edge case in Goutte.
Usage¶
In order to talk with BrowserKit, you should instantiate a
Behat\Mink\Driver\BrowserKitDriver
:
$browserkitClient = // ...
$driver = new \Behat\Mink\Driver\BrowserKitDriver($browserkitClient);
Selenium2Driver¶
Selenium2Driver provides a bridge for the Selenium2 (webdriver) tool. If you just love Selenium2, you can now use it right out of the box too.
Installation¶
Selenium2Driver is available through Composer:
$ composer require behat/mink-selenium2-driver
In order to talk with selenium server, you should install and configure it first:
Download the Selenium Server from the project website.
Run the server with the following command (update the version number to the one you downloaded):
$ java -jar selenium-server-standalone-2.44.0.jar
Tip
The Selenium2Driver actually relies on the WebDriver protocol defined by Selenium2. This means that it is possible to use it with other implementations of the protocol. Note however that other implementations may have some bugs.
The testsuite of the driver is run against the Phantom.js implementation but it still triggers some failures because of bugs in their implementation.
Usage¶
That’s it, now you can use Selenium2Driver:
$driver = new \Behat\Mink\Driver\Selenium2Driver('firefox');
ChromeDriver¶
ChromeDriver allows Mink to control Chrome without the overhead of Selenium.
It communicates directly with chrome over HTTP and WebSockets, which allows it to work at least twice as fast as Chrome with Selenium.
For Chrome 59+ it supports headless mode, eliminating the need to install a display server, and the overhead that comes with it.
Installation¶
ChromeDriver is available through Composer:
$ composer require dmore/chrome-mink-driver
Usage¶
Run Chromium or Google Chrome with remote debugging enabled:
$ google-chrome-stable --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222
or headless (59+):
$ google-chrome-stable --disable-gpu --headless --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222
Configure Mink to use ChromeDriver:
use Behat\Mink\Mink;
use Behat\Mink\Session;
use DMore\ChromeDriver\ChromeDriver;
$mink = new Mink(array(
'browser' => new Session(new ChromeDriver('http://localhost:9222', null, 'http://www.google.com'))
));
That’s it!
For more details, see the official documentation
ZombieDriver¶
ZombieDriver provides a bridge for the Zombie.js browser emulator. Zombie.js is a headless browser emulator, written in node.js. It supports all JS interactions that Selenium and Sahi do and works almost as fast as Goutte does. It is the best of both worlds actually, but still limited to only one browser type (Webkit). Also it is still slower than Goutte and requires node.js and npm to be installed on the system.
Installation¶
ZombieDriver is available through Composer:
$ composer require behat/mink-zombie-driver
In order to talk with a zombie.js server, you need to install and configure zombie.js first:
Install node.js by following instructions from the official site: http://nodejs.org/.
Install npm (node package manager) by following the instructions from http://npmjs.org/.
Install zombie.js with npm:
$ npm install -g zombie
After installing npm and zombie.js, you’ll need to add npm libs to your NODE_PATH
.
The easiest way to do this is to add:
export NODE_PATH="/PATH/TO/NPM/node_modules"
into your .bashrc
.
Usage¶
After that, you’ll be able to just use ZombieDriver without manual server setup. The driver will do all that for you automatically:
$driver = new \Behat\Mink\Driver\ZombieDriver(
new \Behat\Mink\Driver\NodeJS\Server\ZombieServer()
);
If you want more control during driver initialization, like for example if you want to configure the driver to init the server on a specific port, use the more verbose version:
$driver = new \Behat\Mink\Driver\ZombieDriver(
new \Behat\Mink\Driver\Zombie\Server($host, $port, $nodeBin, $script)
);
Note
$host
simply defines the host on which zombie.js will be started. It’s
127.0.0.1
by default.
$port
defines a zombie.js port. Default one is 8124
.
$nodeBin
defines full path to node.js binary. Default one is just node
.
$script
defines a node.js script to start zombie.js server. If you pass
a null
the default script will be used. Use this option carefully!
SahiDriver¶
SahiDriver provides a bridge for the Sahi browser controller. Sahi is a new JS browser controller, that fast replaced the old Selenium testing suite. It’s both easier to setup and to use than classical Selenium. It has a GUI installer for each popular operating system out there and is able to control every systems browser through a special bundled proxy server.
Installation¶
SahiDriver is available through Composer:
$ composer require behat/mink-sahi-driver
In order to talk with a real browser through Sahi, you should install and configure Sahi first:
Download and run the Sahi jar from the Sahi project website and run it. It will run the installer, which will guide you through the installation process.
Run Sahi proxy before your test suites (you can start this proxy during system startup):
cd $YOUR_PATH_TO_SAHI/bin ./sahi.sh
Usage¶
After installing Sahi and running the Sahi proxy server, you will be able
to control it with Behat\Mink\Driver\SahiDriver
:
$driver = new \Behat\Mink\Driver\SahiDriver('firefox');
Note
Notice, that the first argument of SahiDriver
is always a browser name,
supported by Sahi.
If you want more control during the driver initialization, like for example if you want to configure the driver to talk with a proxy on another machine, use the more verbose version with a second client argument:
$driver = new \Behat\Mink\Driver\SahiDriver(
'firefox',
new \Behat\SahiClient\Client(
new \Behat\SahiClient\Connection($sid, $host, $port)
)
);
Note
$sid
is a Sahi session ID. It’s a unique string, used by the driver
and the Sahi proxy in order to be able to talk with each other. You should
fill this with null
if you want Sahi to start your browser automatically
or with some unique string if you want to control an already started
browser.
$host
simply defines the host on which Sahi is started. It is localhost
by default.
$port
defines a Sahi proxy port. The default one is 9999
.
SeleniumDriver¶
SeleniumDriver provides a bridge for the famous Selenium tool. If you need legacy Selenium, you can use it right out of the box in your Mink test suites.
Caution
The SeleniumRC protocol used by this driver is deprecated and does not support all Mink features. For this reason, the SeleniumDriver is deprecated in favor of the Selenium2Driver, which is based on the new protocol and is more powerful.
Installation¶
SeleniumDriver is available through Composer:
$ composer require behat/mink-selenium-driver
In order to talk with the selenium server, you should install and configure it first:
Download the Selenium Server from the project website.
Run the server with the following command (update the version number to the one you downloaded):
$ java -jar selenium-server-standalone-2.44.0.jar
Usage¶
That’s it, now you can use SeleniumDriver:
$client = new \Selenium\Client($host, $port);
$driver = new \Behat\Mink\Driver\SeleniumDriver(
'firefox', 'base_url', $client
);
Driver Feature Support¶
Although Mink does its best to remove browser differences between different
browser emulators, it can’t do much in some cases. For example, BrowserKitDriver
cannot evaluate JavaScript and Selenium2Driver cannot get the response status
code. In such cases, the driver will always throw a meaningful
Behat\Mink\Exception\UnsupportedDriverActionException
.
Feature | BrowserKit/Goutte | Selenium2 | Chrome | Zombie | Selenium | Sahi |
---|---|---|---|---|---|---|
Page traversing | Yes | Yes | Yes | Yes | Yes | Yes |
Form manipulation | Yes | Yes | Yes | Yes | Yes | Yes |
HTTP Basic auth | Yes | No | Yes | Yes | No | No |
Windows management | No | Yes | Yes | No | Yes | Yes |
iFrames management | No | Yes | Yes | No | Yes | No |
Request headers access | Yes | No | Yes | Yes | No | No |
Response headers | Yes | No | Yes | Yes | No | No |
Cookie manipulation | Yes | Yes | Yes | Yes | Yes | Yes |
Status code access | Yes | No | Yes | Yes | No | No |
Mouse manipulation | No | Yes | Yes | Yes | Yes | Yes |
Drag’n Drop | No | Yes | Yes | No | Yes | Yes |
Keyboard actions | No | Yes | Yes | Yes | Yes | Yes |
Element visibility | No | Yes | Yes | No | Yes | Yes |
JS evaluation | No | Yes | Yes | Yes | Yes | Yes |
Window resizing | No | Yes | Yes | No | No | No |
Window maximizing | No | Yes | Yes | No | Yes | No |
Managing Sessions¶
Although the session object is already usable enough, it’s not as easy to write multisession (multidriver/multibrowser) code. Yep, you’ve heard right, with Mink you can manipulate multiple browser emulators simultaneously with a single consistent API:
// init sessions
$session1 = new \Behat\Mink\Session($driver1);
$session2 = new \Behat\Mink\Session($driver2);
// start sessions
$session1->start();
$session2->start();
$session1->visit('http://my_project.dev/chat.php');
$session2->visit('http://my_project.dev/chat.php');
Caution
The state of a session is actually managed by the driver. This means that each session must use a different driver instance.
Isn’t it cool? But Mink makes it even cooler:
$mink = new \Behat\Mink\Mink();
$mink->registerSession('goutte', $goutteSession);
$mink->registerSession('sahi', $sahiSession);
$mink->setDefaultSessionName('goutte');
With such configuration, you can talk with your sessions by name through one single container object:
$mink->getSession('goutte')->visit('http://my_project.dev/chat.php');
$mink->getSession('sahi')->visit('http://my_project.dev/chat.php');
Note
Mink will even lazy-start your sessions when needed (on the first getSession()
call). So, the browser will not be started until you really need it!
Or you could even omit the session name in default cases:
$mink->getSession()->visit('http://my_project.dev/chat.php');
This call is possible thanks to $mink->setDefaultSessionName('goutte')
setting previously. We’ve set the default session, that would be returned
on getSession()
call without arguments.
Tip
The Behat\Mink\Mink
class also provides an easy way to reset or restart
your started sessions (and only started ones):
// reset started sessions
$mink->resetSessions();
// restart started sessions
$mink->restartSessions();
Contributing¶
Reporting issues¶
If your issue affects only a single driver, it should be reported to the driver itself. Any other issues in the Mink abstraction layer and feature requests should be reported to the main Mink repository.
Contributing features¶
Contributions should be sent using GitHub pull requests.
Any contribution should be covered by tests to be accepted. Changes impacting drivers should include tests in the common driver testsuite to ensure consistency between implementations.
New features should always be contributed to the main Mink repository first. Features submitted only to a single driver without being part of the Mink abstraction won’t be accepted.
Testing Tools Integration¶
Mink has integrations for several testing tools:
- Behat through the Behat MinkExtension
- PHPUnit through the phpunit-mink package