Issue #2433009 by hussainweb, grom358, neclimdul, daffie, larowlan, alexpott, pcambra, benjy, jibran, phenaproxima, moshe weitzman, nick_schuch: Add Mink, with Goutte driver, to core

8.0.x
webchick 2015-02-25 19:49:58 -08:00
parent 3eafd2d1dc
commit ddbb2c7999
239 changed files with 24917 additions and 3 deletions

View File

@ -27,7 +27,10 @@
"zendframework/zend-feed": "2.3.*",
"mikey179/vfsStream": "1.*",
"stack/builder": "1.0.*",
"egulias/email-validator": "1.2.*"
"egulias/email-validator": "1.2.*",
"behat/mink": "~1.6",
"behat/mink-goutte-driver": "~1.1",
"fabpot/goutte": "dev-master"
},
"autoload": {
"psr-4": {

325
core/composer.lock generated
View File

@ -4,8 +4,170 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "c977649e8e1a8b93301fa83283672a06",
"hash": "71958cc676a2780e738e9a7d95a3b78b",
"packages": [
{
"name": "behat/mink",
"version": "v1.6.1",
"source": {
"type": "git",
"url": "https://github.com/minkphp/Mink.git",
"reference": "8b68523a339ec991bcd638b39dc8f04f808da88a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/minkphp/Mink/zipball/8b68523a339ec991bcd638b39dc8f04f808da88a",
"reference": "8b68523a339ec991bcd638b39dc8f04f808da88a",
"shasum": ""
},
"require": {
"php": ">=5.3.1",
"symfony/css-selector": "~2.0"
},
"suggest": {
"behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
"behat/mink-goutte-driver": "fast headless driver for any app without JS emulation",
"behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
"behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-4": {
"Behat\\Mink\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
}
],
"description": "Browser controller/emulator abstraction for PHP",
"homepage": "http://mink.behat.org/",
"keywords": [
"browser",
"testing",
"web"
],
"time": "2015-02-04 17:02:06"
},
{
"name": "behat/mink-browserkit-driver",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/minkphp/MinkBrowserKitDriver.git",
"reference": "aed8f4a596b79014a75254c3e337511c33e38cbd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/aed8f4a596b79014a75254c3e337511c33e38cbd",
"reference": "aed8f4a596b79014a75254c3e337511c33e38cbd",
"shasum": ""
},
"require": {
"behat/mink": "~1.6@dev",
"php": ">=5.3.1",
"symfony/browser-kit": "~2.0",
"symfony/dom-crawler": "~2.0"
},
"require-dev": {
"silex/silex": "~1.2"
},
"type": "mink-driver",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-0": {
"Behat\\Mink\\Driver": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
}
],
"description": "Symfony2 BrowserKit driver for Mink framework",
"homepage": "http://mink.behat.org/",
"keywords": [
"Mink",
"Symfony2",
"browser",
"testing"
],
"time": "2014-09-26 11:35:19"
},
{
"name": "behat/mink-goutte-driver",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/minkphp/MinkGoutteDriver.git",
"reference": "2bf327b4166694ecaa8ae7f956cb6ae252ecf03e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/2bf327b4166694ecaa8ae7f956cb6ae252ecf03e",
"reference": "2bf327b4166694ecaa8ae7f956cb6ae252ecf03e",
"shasum": ""
},
"require": {
"behat/mink": "~1.6@dev",
"behat/mink-browserkit-driver": "~1.2@dev",
"fabpot/goutte": "~1.0.4|~2.0",
"php": ">=5.3.1"
},
"type": "mink-driver",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-0": {
"Behat\\Mink\\Driver": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
}
],
"description": "Goutte driver for Mink framework",
"homepage": "http://mink.behat.org/",
"keywords": [
"browser",
"goutte",
"headless",
"testing"
],
"time": "2014-10-09 09:21:12"
},
{
"name": "doctrine/annotations",
"version": "v1.2.1",
@ -570,6 +732,55 @@
],
"time": "2014-11-06 08:59:44"
},
{
"name": "fabpot/goutte",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/FriendsOfPHP/Goutte.git",
"reference": "65ab61eae03d670b93a9044ad2328eb81aa1bde5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/65ab61eae03d670b93a9044ad2328eb81aa1bde5",
"reference": "65ab61eae03d670b93a9044ad2328eb81aa1bde5",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": ">=4,<6",
"php": ">=5.4.0",
"symfony/browser-kit": "~2.1",
"symfony/css-selector": "~2.1",
"symfony/dom-crawler": "~2.1"
},
"type": "application",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Goutte\\": "Goutte"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "A simple PHP Web Scraper",
"homepage": "https://github.com/FriendsOfPHP/Goutte",
"keywords": [
"scraper"
],
"time": "2014-11-28 09:48:17"
},
{
"name": "guzzlehttp/guzzle",
"version": "5.0.3",
@ -1693,6 +1904,61 @@
],
"time": "2014-10-20 20:55:17"
},
{
"name": "symfony/browser-kit",
"version": "v2.6.4",
"target-dir": "Symfony/Component/BrowserKit",
"source": {
"type": "git",
"url": "https://github.com/symfony/BrowserKit.git",
"reference": "2ecec44ed5047020c65dd6e4a4b2f3cf13ae3c04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/BrowserKit/zipball/2ecec44ed5047020c65dd6e4a4b2f3cf13ae3c04",
"reference": "2ecec44ed5047020c65dd6e4a4b2f3cf13ae3c04",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"symfony/dom-crawler": "~2.0,>=2.0.5"
},
"require-dev": {
"symfony/css-selector": "~2.0,>=2.0.5",
"symfony/process": "~2.0,>=2.0.5"
},
"suggest": {
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\BrowserKit\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony BrowserKit Component",
"homepage": "http://symfony.com",
"time": "2015-01-03 08:01:59"
},
{
"name": "symfony/class-loader",
"version": "v2.6.4",
@ -1914,6 +2180,59 @@
"homepage": "http://symfony.com",
"time": "2015-01-25 04:39:26"
},
{
"name": "symfony/dom-crawler",
"version": "v2.6.4",
"target-dir": "Symfony/Component/DomCrawler",
"source": {
"type": "git",
"url": "https://github.com/symfony/DomCrawler.git",
"reference": "26a9eb302decd828990e1015afaa11b78b016073"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/DomCrawler/zipball/26a9eb302decd828990e1015afaa11b78b016073",
"reference": "26a9eb302decd828990e1015afaa11b78b016073",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/css-selector": "~2.3"
},
"suggest": {
"symfony/css-selector": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\DomCrawler\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony DomCrawler Component",
"homepage": "http://symfony.com",
"time": "2015-01-03 08:01:59"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.6.4",
@ -2651,7 +2970,9 @@
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"fabpot/goutte": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {

View File

@ -0,0 +1,3 @@
vendor
composer.lock
/phpunit.xml

View File

@ -0,0 +1,20 @@
language: php
php: [5.3, 5.4, 5.5, 5.6, hhvm]
matrix:
include:
- php: 5.5
env: SYMFONY_VERSION='2.3.*'
- php: 5.5
env: SYMFONY_VERSION='2.5.*@dev'
before_script:
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require -n --no-update symfony/symfony=$SYMFONY_VERSION; fi;'
- composer install -n --prefer-source
script: phpunit -v --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover

View File

@ -0,0 +1,33 @@
1.2.0 / 2014-09-26
==================
BC break:
* Changed the behavior of `getValue` for checkboxes according to the BC break in Mink 1.6
New features:
* Implemented `getOuterHtml`
* Added the support of manipulating forms without submit buttons
* Added support of any request headers instead of supporting only a few hardcoded ones
* Added support of any BrowserKit client using `filterResponse` when using BrowserKit 2.3+
* Added the support of reset buttons
* Implemented `submitForm`
* Implemented `isSelected`
Bug fixes:
* Fixed the support of options without value attribute in `isSelected` and `getValue`
* Added the support of radio buttons in `isChecked`
* Fixed the submission of empty textarea fields
* Refactored the handling of request headers to ensure they are reset when resetting the driver
* Fixed the handling of buttons to submit only for submit buttons rather than all buttons
* Fixed the code to throw exceptions rather than triggering a fatal error for invalid usages of the driver
* Fixed the removal of cookies
* Fixed the submission of form fields with same name and without id
* Fixed `getAttribute` to return `null` for missing attributes rather than an empty string
Testing:
* Updated the testsuite to use the new Mink 1.6 driver testsuite
* Added testing on HHVM

View File

@ -0,0 +1,22 @@
Copyright (c) 2012-2013 Konstantin Kudryashov <ever.zet@gmail.com>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,54 @@
Mink BrowserKit Driver
======================
[![Latest Stable Version](https://poser.pugx.org/behat/mink-browserkit-driver/v/stable.png)](https://packagist.org/packages/behat/mink-browserkit-driver)
[![Latest Unstable Version](https://poser.pugx.org/behat/mink-browserkit-driver/v/unstable.svg)](https://packagist.org/packages/behat/mink-browserkit-driver)
[![Total Downloads](https://poser.pugx.org/behat/mink-browserkit-driver/downloads.png)](https://packagist.org/packages/behat/mink-browserkit-driver)
[![Build Status](https://travis-ci.org/Behat/MinkBrowserKitDriver.svg?branch=master)](https://travis-ci.org/Behat/MinkBrowserKitDriver)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/badges/quality-score.png?s=0443d284940e099ea560eb39b6b2fcdc5d4e7f29)](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/)
[![Code Coverage](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/badges/coverage.png?s=48960c4495488ab0b7d310b62322f017497f5bfa)](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/)
[![License](https://poser.pugx.org/behat/mink-browserkit-driver/license.svg)](https://packagist.org/packages/behat/mink-browserkit-driver)
Usage Example
-------------
``` php
<?php
use Behat\Mink\Mink,
Behat\Mink\Session,
Behat\Mink\Driver\BrowserKitDriver;
use Symfony\Component\HttpKernel\Client;
$app = require_once(__DIR__.'/app.php'); // Silex app
$mink = new Mink(array(
'silex' => new Session(new BrowserKitDriver(new Client($app))),
));
$mink->getSession('silex')->getPage()->findLink('Chat')->click();
```
Installation
------------
``` json
{
"require": {
"behat/mink": "~1.5",
"behat/mink-browserkit-driver": "~1.1"
}
}
```
``` bash
$> curl -sS https://getcomposer.org/installer | php
$> php composer.phar install
```
Maintainers
-----------
* Konstantin Kudryashov [everzet](http://github.com/everzet)
* Other [awesome developers](https://github.com/Behat/MinkBrowserKitDriver/graphs/contributors)

View File

@ -0,0 +1,45 @@
{
"name": "behat/mink-browserkit-driver",
"description": "Symfony2 BrowserKit driver for Mink framework",
"keywords": ["Symfony2", "Mink", "testing", "browser"],
"homepage": "http://mink.behat.org/",
"type": "mink-driver",
"license": "MIT",
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
}
],
"require": {
"php": ">=5.3.1",
"behat/mink": "~1.6@dev",
"symfony/browser-kit": "~2.0",
"symfony/dom-crawler": "~2.0"
},
"require-dev": {
"silex/silex": "~1.2"
},
"autoload": {
"psr-0": {
"Behat\\Mink\\Driver": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Behat\\Mink\\Tests\\Driver\\": "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="vendor/behat/mink/driver-testsuite/bootstrap.php">
<php>
<var name="driver_config_factory" value="Behat\Mink\Tests\Driver\BrowserKitConfig::getInstance" />
</php>
<testsuites>
<testsuite name="Driver test suite">
<directory>tests</directory>
<directory>vendor/behat/mink/driver-testsuite/tests/Basic</directory>
<directory>vendor/behat/mink/driver-testsuite/tests/Form</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/Behat/Mink/Driver</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,949 @@
<?php
/*
* This file is part of the Behat\Mink.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Mink\Driver;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\DriverException;
use Behat\Mink\Exception\UnsupportedDriverActionException;
use Behat\Mink\Session;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\DomCrawler\Field\ChoiceFormField;
use Symfony\Component\DomCrawler\Field\FileFormField;
use Symfony\Component\DomCrawler\Field\FormField;
use Symfony\Component\DomCrawler\Field\InputFormField;
use Symfony\Component\DomCrawler\Field\TextareaFormField;
use Symfony\Component\DomCrawler\Form;
use Symfony\Component\HttpFoundation\Request as HttpFoundationRequest;
use Symfony\Component\HttpFoundation\Response as HttpFoundationResponse;
use Symfony\Component\HttpKernel\Client as HttpKernelClient;
/**
* Symfony2 BrowserKit driver.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class BrowserKitDriver extends CoreDriver
{
private $session;
private $client;
/**
* @var Form[]
*/
private $forms = array();
private $serverParameters = array();
private $started = false;
private $removeScriptFromUrl = false;
private $removeHostFromUrl = false;
/**
* Initializes BrowserKit driver.
*
* @param Client $client BrowserKit client instance
* @param string|null $baseUrl Base URL for HttpKernel clients
*/
public function __construct(Client $client, $baseUrl = null)
{
$this->client = $client;
$this->client->followRedirects(true);
if ($baseUrl !== null && $client instanceof HttpKernelClient) {
$client->setServerParameter('SCRIPT_FILENAME', parse_url($baseUrl, PHP_URL_PATH));
}
}
/**
* Returns BrowserKit HTTP client instance.
*
* @return Client
*/
public function getClient()
{
return $this->client;
}
/**
* {@inheritdoc}
*/
public function setSession(Session $session)
{
$this->session = $session;
}
/**
* Tells driver to remove hostname from URL.
*
* @param Boolean $remove
*
* @deprecated Deprecated as of 1.2, to be removed in 2.0. Pass the base url in the constructor instead.
*/
public function setRemoveHostFromUrl($remove = true)
{
trigger_error(
'setRemoveHostFromUrl() is deprecated as of 1.2 and will be removed in 2.0. Pass the base url in the constructor instead.',
E_USER_DEPRECATED
);
$this->removeHostFromUrl = (bool) $remove;
}
/**
* Tells driver to remove script name from URL.
*
* @param Boolean $remove
*
* @deprecated Deprecated as of 1.2, to be removed in 2.0. Pass the base url in the constructor instead.
*/
public function setRemoveScriptFromUrl($remove = true)
{
trigger_error(
'setRemoveScriptFromUrl() is deprecated as of 1.2 and will be removed in 2.0. Pass the base url in the constructor instead.',
E_USER_DEPRECATED
);
$this->removeScriptFromUrl = (bool) $remove;
}
/**
* {@inheritdoc}
*/
public function start()
{
$this->started = true;
}
/**
* {@inheritdoc}
*/
public function isStarted()
{
return $this->started;
}
/**
* {@inheritdoc}
*/
public function stop()
{
$this->reset();
$this->started = false;
}
/**
* {@inheritdoc}
*/
public function reset()
{
// Restarting the client resets the cookies and the history
$this->client->restart();
$this->forms = array();
$this->serverParameters = array();
}
/**
* {@inheritdoc}
*/
public function visit($url)
{
$this->client->request('GET', $this->prepareUrl($url), array(), array(), $this->serverParameters);
$this->forms = array();
}
/**
* {@inheritdoc}
*/
public function getCurrentUrl()
{
if (method_exists($this->client, 'getInternalRequest')) {
$request = $this->client->getInternalRequest();
} else {
// BC layer for BrowserKit 2.2.x and older
$request = $this->client->getRequest();
if (null !== $request && !$request instanceof Request && !$request instanceof HttpFoundationRequest) {
throw new DriverException(sprintf(
'The BrowserKit client returned an unsupported request implementation: %s. Please upgrade your BrowserKit package to 2.3 or newer.',
get_class($request)
));
}
}
if ($request === null) {
throw new DriverException('Unable to access the request before visiting a page');
}
return $request->getUri();
}
/**
* {@inheritdoc}
*/
public function reload()
{
$this->client->reload();
$this->forms = array();
}
/**
* {@inheritdoc}
*/
public function forward()
{
$this->client->forward();
$this->forms = array();
}
/**
* {@inheritdoc}
*/
public function back()
{
$this->client->back();
$this->forms = array();
}
/**
* {@inheritdoc}
*/
public function setBasicAuth($user, $password)
{
if (false === $user) {
unset($this->serverParameters['PHP_AUTH_USER'], $this->serverParameters['PHP_AUTH_PW']);
return;
}
$this->serverParameters['PHP_AUTH_USER'] = $user;
$this->serverParameters['PHP_AUTH_PW'] = $password;
}
/**
* {@inheritdoc}
*/
public function setRequestHeader($name, $value)
{
$contentHeaders = array('CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true);
$name = str_replace('-', '_', strtoupper($name));
// CONTENT_* are not prefixed with HTTP_ in PHP when building $_SERVER
if (!isset($contentHeaders[$name])) {
$name = 'HTTP_' . $name;
}
$this->serverParameters[$name] = $value;
}
/**
* {@inheritdoc}
*/
public function getResponseHeaders()
{
return $this->getResponse()->getHeaders();
}
/**
* {@inheritdoc}
*/
public function setCookie($name, $value = null)
{
if (null === $value) {
$this->deleteCookie($name);
return;
}
$jar = $this->client->getCookieJar();
$jar->set(new Cookie($name, $value));
}
/**
* Deletes a cookie by name.
*
* @param string $name Cookie name.
*/
private function deleteCookie($name)
{
$path = $this->getCookiePath();
$jar = $this->client->getCookieJar();
do {
if (null !== $jar->get($name, $path)) {
$jar->expire($name, $path);
}
$path = preg_replace('/.$/', '', $path);
} while ($path);
}
/**
* Returns current cookie path.
*
* @return string
*/
private function getCookiePath()
{
$path = dirname(parse_url($this->getCurrentUrl(), PHP_URL_PATH));
if ('\\' === DIRECTORY_SEPARATOR) {
$path = str_replace('\\', '/', $path);
}
return $path;
}
/**
* {@inheritdoc}
*/
public function getCookie($name)
{
// Note that the following doesn't work well because
// Symfony\Component\BrowserKit\CookieJar stores cookies by name,
// path, AND domain and if you don't fill them all in correctly then
// you won't get the value that you're expecting.
//
// $jar = $this->client->getCookieJar();
//
// if (null !== $cookie = $jar->get($name)) {
// return $cookie->getValue();
// }
$allValues = $this->client->getCookieJar()->allValues($this->getCurrentUrl());
if (isset($allValues[$name])) {
return $allValues[$name];
}
return null;
}
/**
* {@inheritdoc}
*/
public function getStatusCode()
{
return $this->getResponse()->getStatus();
}
/**
* {@inheritdoc}
*/
public function getContent()
{
return $this->getResponse()->getContent();
}
/**
* {@inheritdoc}
*/
public function find($xpath)
{
$nodes = $this->getCrawler()->filterXPath($xpath);
$elements = array();
foreach ($nodes as $i => $node) {
$elements[] = new NodeElement(sprintf('(%s)[%d]', $xpath, $i + 1), $this->session);
}
return $elements;
}
/**
* {@inheritdoc}
*/
public function getTagName($xpath)
{
return $this->getCrawlerNode($this->getFilteredCrawler($xpath))->nodeName;
}
/**
* {@inheritdoc}
*/
public function getText($xpath)
{
$text = $this->getFilteredCrawler($xpath)->text();
$text = str_replace("\n", ' ', $text);
$text = preg_replace('/ {2,}/', ' ', $text);
return trim($text);
}
/**
* {@inheritdoc}
*/
public function getHtml($xpath)
{
// cut the tag itself (making innerHTML out of outerHTML)
return preg_replace('/^\<[^\>]+\>|\<[^\>]+\>$/', '', $this->getOuterHtml($xpath));
}
/**
* {@inheritdoc}
*/
public function getOuterHtml($xpath)
{
$node = $this->getCrawlerNode($this->getFilteredCrawler($xpath));
return $node->ownerDocument->saveXML($node);
}
/**
* {@inheritdoc}
*/
public function getAttribute($xpath, $name)
{
$node = $this->getFilteredCrawler($xpath);
if ($this->getCrawlerNode($node)->hasAttribute($name)) {
return $node->attr($name);
}
return null;
}
/**
* {@inheritdoc}
*/
public function getValue($xpath)
{
if (in_array($this->getAttribute($xpath, 'type'), array('submit', 'image', 'button'))) {
return $this->getAttribute($xpath, 'value');
}
$node = $this->getCrawlerNode($this->getFilteredCrawler($xpath));
if ('option' === $node->tagName) {
return $this->getOptionValue($node);
}
try {
$field = $this->getFormField($xpath);
} catch (\InvalidArgumentException $e) {
return $this->getAttribute($xpath, 'value');
}
return $field->getValue();
}
/**
* {@inheritdoc}
*/
public function setValue($xpath, $value)
{
$this->getFormField($xpath)->setValue($value);
}
/**
* {@inheritdoc}
*/
public function check($xpath)
{
$this->getCheckboxField($xpath)->tick();
}
/**
* {@inheritdoc}
*/
public function uncheck($xpath)
{
$this->getCheckboxField($xpath)->untick();
}
/**
* {@inheritdoc}
*/
public function selectOption($xpath, $value, $multiple = false)
{
$field = $this->getFormField($xpath);
if (!$field instanceof ChoiceFormField) {
throw new DriverException(sprintf('Impossible to select an option on the element with XPath "%s" as it is not a select or radio input', $xpath));
}
if ($multiple) {
$oldValue = (array) $field->getValue();
$oldValue[] = $value;
$value = $oldValue;
}
$field->select($value);
}
/**
* {@inheritdoc}
*/
public function isSelected($xpath)
{
$optionValue = $this->getOptionValue($this->getCrawlerNode($this->getFilteredCrawler($xpath)));
$selectField = $this->getFormField('(' . $xpath . ')/ancestor-or-self::*[local-name()="select"]');
$selectValue = $selectField->getValue();
return is_array($selectValue) ? in_array($optionValue, $selectValue) : $optionValue == $selectValue;
}
/**
* {@inheritdoc}
*/
public function click($xpath)
{
$node = $this->getFilteredCrawler($xpath);
$crawlerNode = $this->getCrawlerNode($node);
$tagName = $crawlerNode->nodeName;
if ('a' === $tagName) {
$this->client->click($node->link());
$this->forms = array();
} elseif ($this->canSubmitForm($crawlerNode)) {
$this->submit($node->form());
} elseif ($this->canResetForm($crawlerNode)) {
$this->resetForm($crawlerNode);
} else {
$message = sprintf('%%s supports clicking on links and buttons only. But "%s" provided', $tagName);
throw new UnsupportedDriverActionException($message, $this);
}
}
/**
* {@inheritdoc}
*/
public function isChecked($xpath)
{
$field = $this->getFormField($xpath);
if (!$field instanceof ChoiceFormField || 'select' === $field->getType()) {
throw new DriverException(sprintf('Impossible to get the checked state of the element with XPath "%s" as it is not a checkbox or radio input', $xpath));
}
if ('checkbox' === $field->getType()) {
return $field->hasValue();
}
$radio = $this->getCrawlerNode($this->getFilteredCrawler($xpath));
return $radio->getAttribute('value') === $field->getValue();
}
/**
* {@inheritdoc}
*/
public function attachFile($xpath, $path)
{
$field = $this->getFormField($xpath);
if (!$field instanceof FileFormField) {
throw new DriverException(sprintf('Impossible to attach a file on the element with XPath "%s" as it is not a file input', $xpath));
}
$field->upload($path);
}
/**
* {@inheritdoc}
*/
public function submitForm($xpath)
{
$crawler = $this->getFilteredCrawler($xpath);
$this->submit($crawler->form());
}
/**
* @return Response
*
* @throws DriverException If there is not response yet
*/
protected function getResponse()
{
if (!method_exists($this->client, 'getInternalResponse')) {
$implementationResponse = $this->client->getResponse();
if (null === $implementationResponse) {
throw new DriverException('Unable to access the response before visiting a page');
}
return $this->convertImplementationResponse($implementationResponse);
}
$response = $this->client->getInternalResponse();
if (null === $response) {
throw new DriverException('Unable to access the response before visiting a page');
}
return $response;
}
/**
* Gets the BrowserKit Response for legacy BrowserKit versions.
*
* Before 2.3.0, there was no Client::getInternalResponse method, and the
* return value of Client::getResponse can be anything when the implementation
* uses Client::filterResponse because of a bad choice done in BrowserKit and
* kept for BC reasons (the Client::getInternalResponse method has been added
* to solve it).
*
* This implementation supports client which don't rely Client::filterResponse
* and clients which use an HttpFoundation Response (like the HttpKernel client).
*
* @param object $response the response specific to the BrowserKit implementation
*
* @return Response
*
* @throws DriverException If the response cannot be converted to a BrowserKit response
*/
private function convertImplementationResponse($response)
{
if ($response instanceof Response) {
return $response;
}
// due to a bug, the HttpKernel client implementation returns the HttpFoundation response
// The conversion logic is copied from Symfony\Component\HttpKernel\Client::filterResponse
if ($response instanceof HttpFoundationResponse) {
$headers = $response->headers->all();
if ($response->headers->getCookies()) {
$cookies = array();
foreach ($response->headers->getCookies() as $cookie) {
$cookies[] = new Cookie(
$cookie->getName(),
$cookie->getValue(),
$cookie->getExpiresTime(),
$cookie->getPath(),
$cookie->getDomain(),
$cookie->isSecure(),
$cookie->isHttpOnly()
);
}
$headers['Set-Cookie'] = $cookies;
}
// this is needed to support StreamedResponse
ob_start();
$response->sendContent();
$content = ob_get_clean();
return new Response($content, $response->getStatusCode(), $headers);
}
throw new DriverException(sprintf(
'The BrowserKit client returned an unsupported response implementation: %s. Please upgrade your BrowserKit package to 2.3 or newer.',
get_class($response)
));
}
/**
* Prepares URL for visiting.
* Removes "*.php/" from urls and then passes it to BrowserKitDriver::visit().
*
* @param string $url
*
* @return string
*/
protected function prepareUrl($url)
{
$replacement = ($this->removeHostFromUrl ? '' : '$1') . ($this->removeScriptFromUrl ? '' : '$2');
return preg_replace('#(https?\://[^/]+)(/[^/\.]+\.php)?#', $replacement, $url);
}
/**
* Returns form field from XPath query.
*
* @param string $xpath
*
* @return FormField
*
* @throws DriverException
*/
protected function getFormField($xpath)
{
$fieldNode = $this->getCrawlerNode($this->getFilteredCrawler($xpath));
$fieldName = str_replace('[]', '', $fieldNode->getAttribute('name'));
$formNode = $this->getFormNode($fieldNode);
$formId = $this->getFormNodeId($formNode);
if (!isset($this->forms[$formId])) {
$this->forms[$formId] = new Form($formNode, $this->getCurrentUrl());
}
if (is_array($this->forms[$formId][$fieldName])) {
return $this->forms[$formId][$fieldName][$this->getFieldPosition($fieldNode)];
}
return $this->forms[$formId][$fieldName];
}
/**
* Returns the checkbox field from xpath query, ensuring it is valid.
*
* @param string $xpath
*
* @return ChoiceFormField
*
* @throws DriverException when the field is not a checkbox
*/
private function getCheckboxField($xpath)
{
$field = $this->getFormField($xpath);
if (!$field instanceof ChoiceFormField) {
throw new DriverException(sprintf('Impossible to check the element with XPath "%s" as it is not a checkbox', $xpath));
}
return $field;
}
/**
* @param \DOMElement $element
*
* @return \DOMElement
*
* @throws DriverException if the form node cannot be found
*/
private function getFormNode(\DOMElement $element)
{
if ($element->hasAttribute('form')) {
$formId = $element->getAttribute('form');
$formNode = $element->ownerDocument->getElementById($formId);
if (null === $formNode || 'form' !== $formNode->nodeName) {
throw new DriverException(sprintf('The selected node has an invalid form attribute (%s).', $formId));
}
return $formNode;
}
$formNode = $element;
do {
// use the ancestor form element
if (null === $formNode = $formNode->parentNode) {
throw new DriverException('The selected node does not have a form ancestor.');
}
} while ('form' !== $formNode->nodeName);
return $formNode;
}
/**
* Gets the position of the field node among elements with the same name
*
* BrowserKit uses the field name as index to find the field in its Form object.
* When multiple fields have the same name (checkboxes for instance), it will return
* an array of elements in the order they appear in the DOM.
*
* @param \DOMElement $fieldNode
*
* @return integer
*/
private function getFieldPosition(\DOMElement $fieldNode)
{
$elements = $this->getCrawler()->filterXPath('//*[@name=\''.$fieldNode->getAttribute('name').'\']');
if (count($elements) > 1) {
// more than one element contains this name !
// so we need to find the position of $fieldNode
foreach ($elements as $key => $element) {
/** @var \DOMElement $element */
if ($element->getNodePath() === $fieldNode->getNodePath()) {
return $key;
}
}
}
return 0;
}
private function submit(Form $form)
{
$formId = $this->getFormNodeId($form->getFormNode());
if (isset($this->forms[$formId])) {
$this->mergeForms($form, $this->forms[$formId]);
}
// remove empty file fields from request
foreach ($form->getFiles() as $name => $field) {
if (empty($field['name']) && empty($field['tmp_name'])) {
$form->remove($name);
}
}
foreach ($form->all() as $field) {
// Add a fix for https://github.com/symfony/symfony/pull/10733 to support Symfony versions which are not fixed
if ($field instanceof TextareaFormField && null === $field->getValue()) {
$field->setValue('');
}
}
$this->client->submit($form);
$this->forms = array();
}
private function resetForm(\DOMElement $fieldNode)
{
$formNode = $this->getFormNode($fieldNode);
$formId = $this->getFormNodeId($formNode);
unset($this->forms[$formId]);
}
/**
* Determines if a node can submit a form.
*
* @param \DOMElement $node Node.
*
* @return boolean
*/
private function canSubmitForm(\DOMElement $node)
{
$type = $node->hasAttribute('type') ? $node->getAttribute('type') : null;
if ('input' == $node->nodeName && in_array($type, array('submit', 'image'))) {
return true;
}
return 'button' == $node->nodeName && (null === $type || 'submit' == $type);
}
/**
* Determines if a node can reset a form.
*
* @param \DOMElement $node Node.
*
* @return boolean
*/
private function canResetForm(\DOMElement $node)
{
$type = $node->hasAttribute('type') ? $node->getAttribute('type') : null;
return in_array($node->nodeName, array('input', 'button')) && 'reset' == $type;
}
/**
* Returns form node unique identifier.
*
* @param \DOMElement $form
*
* @return string
*/
private function getFormNodeId(\DOMElement $form)
{
return md5($form->getLineNo() . $form->getNodePath() . $form->nodeValue);
}
/**
* Gets the value of an option element
*
* @param \DOMElement $option
*
* @return string
*
* @see \Symfony\Component\DomCrawler\Field\ChoiceFormField::buildOptionValue
*/
private function getOptionValue(\DOMElement $option)
{
if ($option->hasAttribute('value')) {
return $option->getAttribute('value');
}
if (!empty($option->nodeValue)) {
return $option->nodeValue;
}
return '1'; // DomCrawler uses 1 by default if there is no text in the option
}
/**
* Merges second form values into first one.
*
* @param Form $to merging target
* @param Form $from merging source
*/
private function mergeForms(Form $to, Form $from)
{
foreach ($from->all() as $name => $field) {
$fieldReflection = new \ReflectionObject($field);
$nodeReflection = $fieldReflection->getProperty('node');
$valueReflection = $fieldReflection->getProperty('value');
$nodeReflection->setAccessible(true);
$valueReflection->setAccessible(true);
if (!($field instanceof InputFormField && in_array(
$nodeReflection->getValue($field)->getAttribute('type'),
array('submit', 'button', 'image')
))) {
$valueReflection->setValue($to[$name], $valueReflection->getValue($field));
}
}
}
/**
* Returns DOMElement from crawler instance.
*
* @param Crawler $crawler
*
* @return \DOMElement
*
* @throws DriverException when the node does not exist
*/
private function getCrawlerNode(Crawler $crawler)
{
$crawler->rewind();
$node = $crawler->current();
if (null !== $node) {
return $node;
}
throw new DriverException('The element does not exist');
}
/**
* Returns a crawler filtered for the given XPath, requiring at least 1 result.
*
* @param string $xpath
*
* @return Crawler
*
* @throws DriverException when no matching elements are found
*/
private function getFilteredCrawler($xpath)
{
if (!count($crawler = $this->getCrawler()->filterXPath($xpath))) {
throw new DriverException(sprintf('There is no element matching XPath "%s"', $xpath));
}
return $crawler;
}
/**
* Returns crawler instance (got from client).
*
* @return Crawler
*
* @throws DriverException
*/
private function getCrawler()
{
$crawler = $this->client->getCrawler();
if (null === $crawler) {
throw new DriverException('Unable to access the response content before visiting a page');
}
return $crawler;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Behat\Mink\Tests\Driver;
use Behat\Mink\Driver\BrowserKitDriver;
use Symfony\Component\HttpKernel\Client;
class BrowserKitConfig extends AbstractConfig
{
public static function getInstance()
{
return new self();
}
/**
* {@inheritdoc}
*/
public function createDriver()
{
$client = new Client(require(__DIR__.'/app.php'));
return new BrowserKitDriver($client);
}
/**
* {@inheritdoc}
*/
public function getWebFixturesUrl()
{
return 'http://localhost';
}
protected function supportsJs()
{
return false;
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Behat\Mink\Tests\Driver\Custom;
use Behat\Mink\Driver\BrowserKitDriver;
use Behat\Mink\Session;
use Symfony\Component\HttpKernel\Client;
/**
* @group functional
*/
class BaseUrlTest extends \PHPUnit_Framework_TestCase
{
public function testBaseUrl()
{
$client = new Client(require(__DIR__.'/../app.php'));
$driver = new BrowserKitDriver($client, 'http://localhost/foo/');
$session = new Session($driver);
$session->visit('http://localhost/foo/index.html');
$this->assertEquals(200, $session->getStatusCode());
$this->assertEquals('http://localhost/foo/index.html', $session->getCurrentUrl());
}
}

View File

@ -0,0 +1,181 @@
<?php
namespace Behat\Mink\Tests\Driver\Custom;
use Behat\Mink\Driver\BrowserKitDriver;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Response;
class ErrorHandlingTest extends \PHPUnit_Framework_TestCase
{
/**
* @var TestClient
*/
private $client;
protected function setUp()
{
$this->client = new TestClient();
}
public function testGetClient()
{
$this->assertSame($this->client, $this->getDriver()->getClient());
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Unable to access the response before visiting a page
*/
public function testGetResponseHeaderWithoutVisit()
{
$this->getDriver()->getResponseHeaders();
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Unable to access the response content before visiting a page
*/
public function testFindWithoutVisit()
{
$this->getDriver()->find('//html');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Unable to access the request before visiting a page
*/
public function testGetCurrentUrlWithoutVisit()
{
$this->getDriver()->getCurrentUrl();
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage The selected node has an invalid form attribute (foo)
*/
public function testNotMatchingHtml5FormId()
{
$html = <<<'HTML'
<html>
<body>
<form id="test">
<input name="test" value="foo" form="foo">
<input type="submit">
</form>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->setValue('//input[./@name="test"]', 'bar');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage The selected node has an invalid form attribute (foo)
*/
public function testInvalidHtml5FormId()
{
$html = <<<'HTML'
<html>
<body>
<form id="test">
<input name="test" value="foo" form="foo">
<input type="submit">
</form>
<div id="foo"></div>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->setValue('//input[./@name="test"]', 'bar');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage The selected node does not have a form ancestor.
*/
public function testManipulateInputWithoutForm()
{
$html = <<<'HTML'
<html>
<body>
<form id="test">
<input type="submit">
</form>
<div id="foo">
<input name="test" value="foo">
</div>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->setValue('//input[./@name="test"]', 'bar');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Behat\Mink\Driver\BrowserKitDriver supports clicking on links and buttons only. But "div" provided
*/
public function testClickOnUnsupportedElement()
{
$html = <<<'HTML'
<html>
<body>
<div></div>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->click('//div');
}
private function getDriver()
{
return new BrowserKitDriver($this->client);
}
}
class TestClient extends Client
{
protected $nextResponse = null;
protected $nextScript = null;
public function setNextResponse(Response $response)
{
$this->nextResponse = $response;
}
public function setNextScript($script)
{
$this->nextScript = $script;
}
protected function doRequest($request)
{
if (null === $this->nextResponse) {
return new Response();
}
$response = $this->nextResponse;
$this->nextResponse = null;
return $response;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace app;
$app = new \Silex\Application();
$app->register(new \Silex\Provider\SessionServiceProvider());
$def = realpath(__DIR__.'/../vendor/behat/mink/driver-testsuite/web-fixtures');
$ovr = realpath(__DIR__.'/web-fixtures');
$cbk = function ($file) use ($app, $def, $ovr) {
$file = str_replace('.file', '.php', $file);
$path = file_exists($ovr.'/'.$file) ? $ovr.'/'.$file : $def.'/'.$file;
$resp = null;
ob_start();
include($path);
$content = ob_get_clean();
if ($resp) {
if ('' === $resp->getContent()) {
$resp->setContent($content);
}
return $resp;
}
return $content;
};
$app->get('/{file}', $cbk)->assert('file', '.*');
$app->post('/{file}', $cbk)->assert('file', '.*');
$app['debug'] = true;
$app['exception_handler']->disable();
$app['session.test'] = true;
return $app;

View File

@ -0,0 +1,3 @@
<?php
$resp = new Symfony\Component\HttpFoundation\Response('Sorry, page not found', 404);

View File

@ -0,0 +1,3 @@
<?php
$resp = new Symfony\Component\HttpFoundation\Response('Sorry, a server error happened', 500);

View File

@ -0,0 +1,32 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Advanced form save</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
</head>
<body>
<?php
error_reporting(0);
$request = $app['request'];
$POST = $request->request->all();
$FILES = $request->files->all();
if (isset($POST['select_multiple_numbers']) && false !== strpos($POST['select_multiple_numbers'][0], ',')) {
$POST['select_multiple_numbers'] = explode(',', $POST['select_multiple_numbers'][0]);
}
// checkbox can have any value and will be successful in case "on"
// http://www.w3.org/TR/html401/interact/forms.html#checkbox
$POST['agreement'] = isset($POST['agreement']) ? 'on' : 'off';
ksort($POST);
echo str_replace('>', '', var_export($POST, true)) . "\n";
if (isset($FILES['about']) && file_exists($FILES['about']->getPathname())) {
echo $FILES['about']->getClientOriginalName() . "\n";
echo file_get_contents($FILES['about']->getPathname());
} else {
echo "no file";
}
?>
</body>
</html>

View File

@ -0,0 +1,15 @@
<?php
$SERVER = $app['request']->server->all();
$username = isset($SERVER['PHP_AUTH_USER']) ? $SERVER['PHP_AUTH_USER'] : false;
$password = isset($SERVER['PHP_AUTH_PW']) ? $SERVER['PHP_AUTH_PW'] : false;
if ($username == 'mink-user' && $password == 'mink-password') {
echo 'is authenticated';
} else {
$resp = new \Symfony\Component\HttpFoundation\Response();
$resp->setStatusCode(401);
$resp->headers->set('WWW-Authenticate', 'Basic realm="Mink Testing Area"');
echo 'is not authenticated';
}

View File

@ -0,0 +1,14 @@
<?php ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Basic Form Saving</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Anket for <?php echo $app['request']->request->get('first_name') ?></h1>
<span id="first">Firstname: <?php echo $app['request']->request->get('first_name') ?></span>
<span id="last">Lastname: <?php echo $app['request']->request->get('last_name') ?></span>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Basic Get Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Basic Get Form Page</h1>
<div id="serach">
<?php
$GET = $app['request']->query->all();
echo isset($GET['q']) && $GET['q'] ? $GET['q'] : 'No search query'
?>
</div>
<form>
<input name="q" value="" type="text" />
<input type="submit" value="Find" />
</form>
</body>
</html>

View File

@ -0,0 +1,17 @@
<?php
$resp = new Symfony\Component\HttpFoundation\Response();
$cook = new Symfony\Component\HttpFoundation\Cookie('srvr_cookie', 'srv_var_is_set', 0, '/');
$resp->headers->setCookie($cook);
?>
<!doctype html public "-//w3c//dtd xhtml 1.1//en" "http://www.w3.org/tr/xhtml11/dtd/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>basic form</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<script>
</script>
</head>
<body>
basic page with cookie set from server side
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Basic Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<script>
</script>
</head>
<body>
Previous cookie: <?php
echo $app['request']->cookies->has('srvr_cookie') ? $app['request']->cookies->get('srvr_cookie') : 'NO';
?>
</body>
</html>

View File

@ -0,0 +1,20 @@
<?php
$hasCookie = $app['request']->cookies->has('foo');
$resp = new Symfony\Component\HttpFoundation\Response();
$cook = new Symfony\Component\HttpFoundation\Cookie('foo', 'bar');
$resp->headers->setCookie($cook);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>HttpOnly Cookie Test</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<script>
</script>
</head>
<body>
<div id="cookie-status">Has Cookie: <?php echo json_encode($hasCookie) ?></div>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Headers page</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<?php print_r($app['request']->server->all()); ?>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<body>
<?php
if ('1' === $app['request']->query->get('p')) {
echo '<a href="/issue130.php?p=2">Go to 2</a>';
} else {
echo '<strong>'.$app['request']->headers->get('referer').'</strong>';
}
?>
</body>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<body>
<?php if ($app['request']->isMethod('POST')) {
$resp = new Symfony\Component\HttpFoundation\Response();
$cook = new Symfony\Component\HttpFoundation\Cookie('tc', $app['request']->request->get('cookie_value'));
$resp->headers->setCookie($cook);
} elseif ($app['request']->query->has('show_value')) {
echo $app['request']->cookies->get('tc');
return;
}
?>
<form method="post">
<input name="cookie_value">
<input type="submit" value="Set cookie">
</form>
</body>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Cookies page</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<?php
$cookies = $app['request']->cookies->all();
unset($cookies['MOCKSESSID']);
if (isset($cookies['srvr_cookie'])) {
$srvrCookie = $cookies['srvr_cookie'];
unset($cookies['srvr_cookie']);
$cookies['_SESS'] = '';
$cookies['srvr_cookie'] = $srvrCookie;
}
foreach ($cookies as $name => $val) {
$cookies[$name] = (string)$val;
}
echo str_replace(array('>'), '', var_export($cookies, true));
?>
</body>
</html>

View File

@ -0,0 +1,3 @@
<?php
$resp = new Symfony\Component\HttpFoundation\RedirectResponse('/redirect_destination.html');

View File

@ -0,0 +1,15 @@
<?php
$resp = new Symfony\Component\HttpFoundation\Response();
$resp->headers->set('X-Mink-Test', 'response-headers');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Response headers</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>Response headers</h1>
</body>
</html>

View File

@ -0,0 +1,19 @@
<?php
$session = $app['request']->getSession();
if ($app['request']->query->has('login')) {
$session->migrate();
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Session Test</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<script>
</script>
</head>
<body>
<div id="session-id"><?php echo $session->getId() ?></div>
</body>
</html>

View File

@ -0,0 +1,18 @@
<?php
$requestUri = $app['request']->server->get('REQUEST_URI');
$resp = new Symfony\Component\HttpFoundation\Response();
$cook = new Symfony\Component\HttpFoundation\Cookie('srvr_cookie', 'srv_var_is_set_sub_folder', 0, dirname($requestUri));
$resp->headers->setCookie($cook);
?>
<!doctype html public "-//w3c//dtd xhtml 1.1//en" "http://www.w3.org/tr/xhtml11/dtd/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>basic form</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<script>
</script>
</head>
<body>
basic page with cookie set from server side
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Basic Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<script>
</script>
</head>
<body>
Previous cookie: <?php
if ($app['request']->cookies->has('srvr_cookie')) {
echo $app['request']->cookies->get('srvr_cookie');
} else {
echo 'NO';
}
?>
</body>
</html>

View File

@ -0,0 +1,4 @@
vendor
composer.phar
composer.lock
phpunit.xml

View File

@ -0,0 +1,19 @@
language: php
php: [5.3, 5.4, 5.5, 5.6, hhvm]
before_script:
- export WEB_FIXTURES_HOST=http://localhost
- composer install --dev --prefer-source
- sudo apt-get update
- sudo apt-get install -y --force-yes apache2 libapache2-mod-php5
- sudo sed -i -e "s,/var/www,$(pwd)/vendor/behat/mink/driver-testsuite/web-fixtures,g" /etc/apache2/sites-available/default
- sudo /etc/init.d/apache2 restart
script: phpunit -v --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover

View File

@ -0,0 +1,20 @@
1.1.0 / 2014-10-09
==================
The driver now relies on BrowserKitDriver 1.2.x, so all changes of this driver are relevant.
The changes below only describe the changes related to GoutteDriver specifically.
New features:
* Added the possibility to use a normal Goutte client instead of requiring to use an extended one
* Added the support of Goutte 2.0 as well
Bug fixes:
* Fixed the support of disabling basic auth
* Fixed the resetting of the driver to reset the basic auth
Testing:
* Updated the testsuite to use the new Mink 1.6 driver testsuite
* Added testing on HHVM

View File

@ -0,0 +1,22 @@
Copyright (c) 2012-2013 Konstantin Kudryashov <ever.zet@gmail.com>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,53 @@
Mink Goutte Driver
==================
[![Latest Stable Version](https://poser.pugx.org/behat/mink-goutte-driver/v/stable.svg)](https://packagist.org/packages/behat/mink-goutte-driver)
[![Latest Unstable Version](https://poser.pugx.org/behat/mink-goutte-driver/v/unstable.svg)](https://packagist.org/packages/behat/mink-goutte-driver)
[![Total Downloads](https://poser.pugx.org/behat/mink-goutte-driver/downloads.svg)](https://packagist.org/packages/behat/mink-goutte-driver)
[![Build Status](https://travis-ci.org/Behat/MinkGoutteDriver.svg?branch=master)](https://travis-ci.org/Behat/MinkGoutteDriver)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Behat/MinkGoutteDriver/badges/quality-score.png?s=ca141bb2cad18e74cf3d3b132b1a6aa0f3f004a5)](https://scrutinizer-ci.com/g/Behat/MinkGoutteDriver/)
[![Code Coverage](https://scrutinizer-ci.com/g/Behat/MinkGoutteDriver/badges/coverage.png?s=ca2d17a948660bfaeb4a95bf1a709644305c54f3)](https://scrutinizer-ci.com/g/Behat/MinkGoutteDriver/)
[![License](https://poser.pugx.org/behat/mink-goutte-driver/license.svg)](https://packagist.org/packages/behat/mink-goutte-driver)
Usage Example
-------------
``` php
<?php
use Behat\Mink\Mink,
Behat\Mink\Session,
Behat\Mink\Driver\GoutteDriver,
Behat\Mink\Driver\Goutte\Client as GoutteClient;
$startUrl = 'http://example.com';
$mink = new Mink(array(
'goutte' => new Session(new GoutteDriver(new GoutteClient($startUrl))),
));
$mink->getSession('goutte')->getPage()->findLink('Chat')->click();
```
Installation
------------
``` json
{
"require": {
"behat/mink": "~1.5",
"behat/mink-goutte-driver": "~1.0"
}
}
```
``` bash
$> curl -sS https://getcomposer.org/installer | php
$> php composer.phar install
```
Maintainers
-----------
* Konstantin Kudryashov [everzet](http://github.com/everzet)
* Other [awesome developers](https://github.com/Behat/MinkGoutteDriver/graphs/contributors)

View File

@ -0,0 +1,41 @@
{
"name": "behat/mink-goutte-driver",
"description": "Goutte driver for Mink framework",
"keywords": ["goutte", "headless", "testing", "browser"],
"homepage": "http://mink.behat.org/",
"type": "mink-driver",
"license": "MIT",
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
}
],
"require": {
"php": ">=5.3.1",
"behat/mink": "~1.6@dev",
"behat/mink-browserkit-driver": "~1.2@dev",
"fabpot/goutte": "~1.0.4|~2.0"
},
"autoload": {
"psr-0": {
"Behat\\Mink\\Driver": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Behat\\Mink\\Tests\\Driver\\": "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
}
}

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="vendor/behat/mink/driver-testsuite/bootstrap.php">
<testsuites>
<testsuite name="Driver test suite">
<directory>tests</directory>
<directory>vendor/behat/mink/driver-testsuite/tests/Basic</directory>
<directory>vendor/behat/mink/driver-testsuite/tests/Form</directory>
</testsuite>
</testsuites>
<php>
<var name="driver_config_factory" value="Behat\Mink\Tests\Driver\GoutteConfig::getInstance" />
<!--server name="WEB_FIXTURES_HOST" value="http://test.mink.dev" /-->
</php>
<filter>
<whitelist>
<directory>./src/Behat/Mink/Driver</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Behat\Mink.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Mink\Driver\Goutte;
use Goutte\Client as BaseClient;
use Symfony\Component\BrowserKit\Response;
/**
* Client overrides to support Mink functionality.
*/
class Client extends BaseClient
{
/**
* Reads response meta tags to guess content-type charset.
*
* @param Response $response
*
* @return Response
*/
protected function filterResponse($response)
{
$contentType = $response->getHeader('Content-Type');
if (!$contentType || false === strpos($contentType, 'charset=')) {
if (preg_match('/\<meta[^\>]+charset *= *["\']?([a-zA-Z\-0-9]+)/i', $response->getContent(), $matches)) {
$headers = $response->getHeaders();
$headers['Content-Type'] = $contentType.';charset='.$matches[1];
$response = new Response($response->getContent(), $response->getStatus(), $headers);
}
}
return parent::filterResponse($response);
}
}

View File

@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Behat\Mink.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Mink\Driver;
use Behat\Mink\Driver\Goutte\Client as ExtendedClient;
use Goutte\Client;
/**
* Goutte driver.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class GoutteDriver extends BrowserKitDriver
{
/**
* Initializes Goutte driver.
*
* @param Client $client Goutte client instance
*/
public function __construct(Client $client = null)
{
parent::__construct($client ?: new ExtendedClient());
}
/**
* {@inheritdoc}
*/
public function setBasicAuth($user, $password)
{
if (false === $user) {
$this->getClient()->resetAuth();
return;
}
$this->getClient()->setAuth($user, $password);
}
/**
* Gets the Goutte client.
*
* The method is overwritten only to provide the appropriate return type hint.
*
* @return Client
*/
public function getClient()
{
return parent::getClient();
}
/**
* {@inheritdoc}
*/
public function reset()
{
parent::reset();
$this->getClient()->resetAuth();
}
/**
* {@inheritdoc}
*/
protected function prepareUrl($url)
{
return $url;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Behat\Mink\Tests\Driver\Custom;
use Behat\Mink\Driver\GoutteDriver;
class InstantiationTest extends \PHPUnit_Framework_TestCase
{
public function testInstantiateWithClient()
{
$client = $this->getMockBuilder('Goutte\Client')->disableOriginalConstructor()->getMock();
$client->expects($this->once())
->method('followRedirects')
->with(true);
$driver = new GoutteDriver($client);
$this->assertSame($client, $driver->getClient());
}
public function testInstantiateWithoutClient()
{
$driver = new GoutteDriver();
$this->assertInstanceOf('Behat\Mink\Driver\Goutte\Client', $driver->getClient());
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Behat\Mink\Tests\Driver;
use Behat\Mink\Driver\GoutteDriver;
class GoutteConfig extends AbstractConfig
{
public static function getInstance()
{
return new self();
}
/**
* {@inheritdoc}
*/
public function createDriver()
{
return new GoutteDriver();
}
protected function supportsJs()
{
return false;
}
}

5
core/vendor/behat/mink/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.tgz
*.phar
phpunit.xml
composer.lock
vendor

17
core/vendor/behat/mink/.travis.yml vendored Normal file
View File

@ -0,0 +1,17 @@
language: php
sudo: false
php: [5.3, 5.4, 5.5, 5.6, hhvm]
cache:
directories:
- $HOME/.composer/cache
install:
- composer install
script: phpunit -v --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover

255
core/vendor/behat/mink/CHANGES.md vendored Normal file
View File

@ -0,0 +1,255 @@
1.6.1 / 2015-02-04
==================
Bug fixes:
* Added a check for empty path in `WebAssert::cleanUrl()`
Driver testsuite:
* Added an extra test to ensure the right behavior for traversal
Misc:
* Changed the description in the composer.json
* Switched the repository structure to use PSR-4
* Updated URLs for the move to the new Github organization
1.6.0 / 2014-09-26
==================
* [BC break] Changed the named selector to prefer exact matches over partial matches
* [BC break] Changed `NodeElement::getValue` for checkboxes to return the value rather than the checked state (use `isChecked` for that)
* Fixed the XPath prefixing when searching inside an existing element
* Refactored the driver testsuite entirely and expand it to cover drivers entirely (covering many more cases for consistency)
* Changed `NodeElement::setValue` to support any fields rather than only input elements
* Removed the wrapping of any driver-level exception in a MinkException on invalid usage as it was making the code too complex
* Fixed the matching of the input type in the named selector to be case insensitive according to the HTML spec
* Introduced `Behat\Mink\Selector\Xpath\Escaper` to allow reusing the XPath escaping
* Deprecated `Element::getSession`. Code needing the session should get it from outside rather than the element
* Changed ElementNotFoundException to extend from ExpectationException
* Added `Element::getOuterHtml` to get the HTML code of the element including itself
* Fixed the name selectors to match on the `placeholder` only for textual inputs
* Enforced consistent behavior for drivers on 4xx and 5xx response to return the response rather than throwing an exception
* Added `Element::waitFor` to allow retrying some code until it succeeds or the timeout is reached
* Added `Element::isValid` to check whether an element still exists in the page
* Made `Session::executeScript` compatible across drivers by ensuring they all support the same syntaxes for the JS expression
* Made `Session::evaluateScript` compatible across drivers by ensuring they all support the same syntaxes for the JS expression
* Removed `hasClass` from `DocumentElement` (instead of triggering a fatal error)
* Added testing on HHVM to ensure consistency
* Fixed `NodeElement::getTagName` to ensure that the tag name is lowercase for all drivers
* Fixed `Element::hasAttribute` to ensure it supports attributes with an empty value
* Fixed the `field` selector to avoid matching inputs with the type `submit` or `reset`
* Changed the button XPath selection to accept `reset` buttons as well
* Changed `Session::wait` to return the condition value rather than nothing
* Added `Session::getWindowName` and `Session::getWindowNames` to get the name of the current and of all windows
* Added `Session::maximizeWindow` to maximize the window
* Added `NodeElement::isSelected` to check whether an `<option>` is selected
* Added `NodeElement::submitForm` to allow submitting a form without using a button
* Added assertions about the value of an attribute
* Added the anchor in the assertion on the URL in `WebAssert`
1.5.0 / 2013-04-14
==================
* Add `CoreDriver` to simplify future drivers improvements
* Add `Mink::isSessionStarted()` method
* Fix multibite string `preg_replace` bugs
* Fix handling of whitespaces in `WebAssert::pageText...()` methods
1.4.3 / 2013-03-02
==================
* Bump dependencies constraints
1.4.2 / 2013-02-13
==================
* Fix wrong test case to ensure that core drivers work as expected
1.4.1 / 2013-02-10
==================
* Update dependencies
* Add ElementException to element actions
* Rel attribute support for named selectors
* Add hasClass() helper to traversable elements
* Add getScreenshot() method to session
* Name attr support in named selector for button
* Fix for bunch of bugs
1.4.0 / 2012-05-40
==================
* New `Session::selectWindow()` and `Session::selectIFrame()` methods
* New built-in `WebAssert` class
* Fixed DocBlocks (autocompletion in any IDE now should just work)
* Moved Behat-related code into `Behat\MinkExtension`
* Removed PHPUnit test case class
* Updated composer dependencies to not require custom repository anymore
* All drivers moved into separate packages
1.3.3 / 2012-03-23
==================
* Prevent exceptions in `__toString()`
* Added couple of useful step definitions for Behat
* Fixed issues #168, #211, #212, #208
* Lot of small bug fixes and improvements
* Fixed dependencies and composer installation routine
1.3.2 / 2011-12-21
==================
* Fixed webdriver registration in MinkContext
1.3.1 / 2011-12-21
==================
* Fixed Composer package
1.3.0 / 2011-12-21
==================
* Brand new Selenium2Driver (webdriver session)
* Multiselect bugfixes
* ZombieDriver back in the business
* Composer now manages dependencies
* Some MinkContext steps got fixes
* Lots of bug fixes and cleanup
1.2.0 / 2011-11-04
==================
* Brand new SeleniumDriver (thanks @alexandresalome)
* Multiselect support (multiple options selection), including new Behat steps
* Ability to select option by it's text (in addition to value)
* ZombieDriver updates
* Use SuiteHooks to populate parameters (no need to call parent __construct anymore)
* Updated Goutte and all vendors
* Lot of bugfixes and new tests
1.1.1 / 2011-08-12
==================
* Fixed Zombie.js server termination on Linux
* Fixed base_url usage for external URLs
1.1.0 / 2011-08-08
==================
* Added Zombie.js driver (thanks @b00giZm)
* Added pt translation (thanks Daniel Gomes)
* Refactored MinkContext and MinkTestCase
1.0.3 / 2011-08-02
==================
* File uploads for empty fields fixed (GoutteDriver)
* Lazy sessions restart
* `show_tmp_dir` option in MinkContext
* Updated to stable Symfony2 components
* SahiClient connection limit bumped to 60 seconds
* Dutch language support
1.0.2 / 2011-07-22
==================
* ElementHtmlException fixed (thanks @Stof)
1.0.1 / 2011-07-21
==================
* Fixed buggy assertions in MinkContext
1.0.0 / 2011-07-20
==================
* Added missing tests for almost everything
* Hude speedup for SahiDriver
* Support for Behat 2.0 contexts
* Bundled PHPUnit TestCase
* Deep element traversing
* Correct behavior of getText() method
* New getHtml() method
* Basic HTTP auth support
* Soft and hard session resetting
* Cookies management
* Browser history interactions (reload(), back(), forward())
* Weaverryan'd exception messages
* Huge amount of bugfixes and small additions
0.3.2 / 2011-06-20
==================
* Fixed file uploads in Goutte driver
* Fixed setting of long texts into fields
* Added getPlainText() (returns text without tags and whitespaces) method to the element's API
* Start_url is now optional parameter
* Default session (if needed) name now need to be always specified by hands with setDefaultSessionName()
* default_driver => default_session
* Updated Symfony Components
0.3.1 / 2011-05-17
==================
* Small SahiClient update (it generates SID now if no provided)
* setActiveSessionName => setDefaultSessionName method rename
0.3.0 / 2011-05-17
==================
* Rewritten from scratch Mink drivers handler. Now it's sessions handler. And Mink now
sessions-centric tool. See examples in readme. Much cleaner API now.
0.2.4 / 2011-05-12
==================
* Fixed wrong url locator function
* Fixed wrong regex in `should see` step
* Fixed delimiters use in `should see` step
* Added url-match step for checking urls against regex
0.2.3 / 2011-05-01
==================
* Updated SahiClient with new version, which is faster and cleaner with it's exceptions
0.2.2 / 2011-05-01
==================
* Ability to use already started browser as SahiDriver aim
* Added japanese translation for bundled steps (thanks @hidenorigoto)
* 10 seconds limit for browser connection in SahiDriver
0.2.1 / 2011-04-21
==================
* Fixed some bundled step definitions
0.2.0 / 2011-04-21
==================
* Additional step definitions
* Support for extended drivers configuration through behat.yml environment parameters
* Lots of new named selectors
* Bug fixes
* Small improvements
0.1.2 / 2011-04-08
==================
* Fixed Sahi url escaping
0.1.1 / 2011-04-06
==================
* Fixed should/should_not steps
* Added spanish translation
* Fixed forms to use <base> element
* Fixed small UnsupportedByDriverException issue
0.1.0 / 2011-04-04
==================
* Initial release

22
core/vendor/behat/mink/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,22 @@
# Contributing
Mink is an open source, community-driven project. If you'd like to contribute, feel free to do this, but remember to follow these few simple rules:
## Submitting an issues
- __Driver-related__ issues must be reported in the corresponding driver repository
- A reproducible example is required for every bug report, otherwise it will most probably be __closed without warning__
- If you are going to make a big, substantial change, let's discuss it first
## Working with Pull Requests
1. Create your feature addition or a bug fix branch based on `master` branch in your repository's fork.
2. Make necessary changes, but __don't mix__ code reformatting with code changes on topic.
3. Add tests for those changes (please look into `tests/` folder for some examples). This is important so we don't break it in a future version unintentionally.
4. Commit your code, but do not mess with `CHANGES.md`.
5. Squash your commits by topic to preserve a clean and readable log.
6. Create Pull Request.
# Running tests
Make sure that you don't break anything with your changes by running:
```bash
$> phpunit
```

22
core/vendor/behat/mink/LICENSE vendored Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2011-2013 Konstantin Kudryashov <ever.zet@gmail.com>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

74
core/vendor/behat/mink/README.md vendored Normal file
View File

@ -0,0 +1,74 @@
Mink
====
[![Latest Stable Version](https://poser.pugx.org/behat/mink/v/stable.svg)](https://packagist.org/packages/behat/mink)
[![Latest Unstable Version](https://poser.pugx.org/behat/mink/v/unstable.svg)](https://packagist.org/packages/behat/mink)
[![Total Downloads](https://poser.pugx.org/behat/mink/downloads.svg)](https://packagist.org/packages/behat/mink)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/minkphp/Mink/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/minkphp/Mink/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/minkphp/Mink/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/minkphp/Mink/)
[![Build Status](https://travis-ci.org/minkphp/Mink.svg?branch=master)](https://travis-ci.org/minkphp/Mink)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/5bb8fab0-978f-428a-ae23-44ee4e129fbc/mini.png)](https://insight.sensiolabs.com/projects/5bb8fab0-978f-428a-ae23-44ee4e129fbc)
[![License](https://poser.pugx.org/behat/mink/license.svg)](https://packagist.org/packages/behat/mink)
Useful Links
------------
- The main website with documentation is at [http://mink.behat.org](http://mink.behat.org)
- Official Google Group is at [http://groups.google.com/group/behat](http://groups.google.com/group/behat)
- IRC channel on [#freenode](http://freenode.net/) is `#behat`
- [Note on Patches/Pull Requests](CONTRIBUTING.md)
Usage Example
-------------
``` php
<?php
use Behat\Mink\Mink,
Behat\Mink\Session,
Behat\Mink\Driver\GoutteDriver,
Behat\Mink\Driver\Goutte\Client as GoutteClient;
$startUrl = 'http://example.com';
// init Mink and register sessions
$mink = new Mink(array(
'goutte1' => new Session(new GoutteDriver(new GoutteClient())),
'goutte2' => new Session(new GoutteDriver(new GoutteClient())),
'custom' => new Session(new MyCustomDriver($startUrl))
));
// set the default session name
$mink->setDefaultSessionName('goutte2');
// visit a page
$mink->getSession()->visit($startUrl);
// call to getSession() without argument will always return a default session if has one (goutte2 here)
$mink->getSession()->getPage()->findLink('Downloads')->click();
echo $mink->getSession()->getPage()->getContent();
// call to getSession() with argument will return session by its name
$mink->getSession('custom')->getPage()->findLink('Downloads')->click();
echo $mink->getSession('custom')->getPage()->getContent();
// this all is done to make possible mixing sessions
$mink->getSession('goutte1')->getPage()->findLink('Chat')->click();
$mink->getSession('goutte2')->getPage()->findLink('Chat')->click();
```
Install Dependencies
--------------------
``` bash
$> curl -sS https://getcomposer.org/installer | php
$> php composer.phar install
```
Contributors
------------
* Konstantin Kudryashov [everzet](https://github.com/everzet) [lead developer]
* Christophe Coevoet [stof](https://github.com/stof) [lead developer]
* Alexander Obuhovich [aik099](https://github.com/aik099) [lead developer]
* Other [awesome developers](https://github.com/minkphp/Mink/graphs/contributors)

46
core/vendor/behat/mink/composer.json vendored Normal file
View File

@ -0,0 +1,46 @@
{
"name": "behat/mink",
"description": "Browser controller/emulator abstraction for PHP",
"keywords": ["web", "testing", "browser"],
"homepage": "http://mink.behat.org/",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
}
],
"require": {
"php": ">=5.3.1",
"symfony/css-selector": "~2.0"
},
"suggest": {
"behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
"behat/mink-goutte-driver": "fast headless driver for any app without JS emulation",
"behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
"behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)"
},
"autoload": {
"psr-4": {
"Behat\\Mink\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Behat\\Mink\\Tests\\": "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
}
}

View File

@ -0,0 +1,96 @@
Mink Driver testsuite
=====================
This is the common testsuite for Mink drivers to ensure consistency among implementations.
Usage
-----
The testsuite of a driver should be based as follow:
```json
{
"require": {
"behat/mink": "~1.6@dev"
},
"autoload-dev": {
"psr-4": {
"Acme\\MyDriver\\Tests\\": "tests"
}
}
}
```
```xml
<!-- phpunit.xml.dist -->
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="vendor/behat/mink/driver-testsuite/bootstrap.php">
<php>
<var name="driver_config_factory" value="Acme\MyDriver\Tests\Config::getInstance" />
<server name="WEB_FIXTURES_HOST" value="http://test.mink.dev" />
</php>
<testsuites>
<testsuite name="Functional tests">
<directory>vendor/behat/mink/driver-testsuite/tests</directory>
</testsuite>
<!-- if needed to add more tests -->
<testsuite name="Driver tests">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src</directory>
</whitelist>
</filter>
</phpunit>
```
Then create the driver config for the testsuite:
```php
// tests/Config.php
namespace Acme\MyDriver\Tests;
use Behat\Mink\Tests\Driver\AbstractConfig;
class Config extends AbstractConfig
{
/**
* Creates an instance of the config.
*
* This is the callable registered as a php variable in the phpunit.xml config file.
* It could be outside the class but this is convenient.
*/
public static function getInstance()
{
return new self();
}
/**
* Creates driver instance.
*
* @return \Behat\Mink\Driver\DriverInterface
*/
public function createDriver()
{
return new \Acme\MyDriver\MyDriver();
}
}
```
Some other methods are available in the AbstractConfig which can be overwritten to adapt the testsuite to
the needs of the driver (skipping some tests for instance).
Adding Driver-specific Tests
----------------------------
When adding extra test cases specific to the driver, either use your own namespace or put them in the
``Behat\Mink\Tests\Driver\Custom`` subnamespace to ensure that you will not create conflicts with test cases
added in the driver testsuite in the future.

View File

@ -0,0 +1,28 @@
<?php
$file = __DIR__.'/../../../autoload.php';
if (!file_exists($file)) {
echo PHP_EOL.'The Mink driver testsuite expects Mink to be installed as a composer dependency of your project'.PHP_EOL;
exit(1);
}
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require $file;
$loader->addPsr4('Behat\Mink\Tests\Driver\\', __DIR__.'/tests');
// Clean the global variables
unset($file);
unset($loader);
// Check the definition of the driverLoaderFactory
if (!isset($GLOBALS['driver_config_factory'])) {
echo PHP_EOL.'The "driver_config_factory" global variable must be set.'.PHP_EOL;
exit(1);
}
if (!is_callable($GLOBALS['driver_config_factory'])) {
echo PHP_EOL.'The "driver_config_factory" global variable must be a callable.'.PHP_EOL;
exit(1);
}

View File

@ -0,0 +1,83 @@
<?php
namespace Behat\Mink\Tests\Driver;
use Behat\Mink\Driver\DriverInterface;
abstract class AbstractConfig
{
/**
* Creates driver instance.
*
* @return DriverInterface
*/
abstract public function createDriver();
/**
* Map remote file path.
*
* @param string $file File path.
*
* @return string
*/
public function mapRemoteFilePath($file)
{
if (!isset($_SERVER['TEST_MACHINE_BASE_PATH']) || !isset($_SERVER['DRIVER_MACHINE_BASE_PATH'])) {
return $file;
}
$pattern = '/^'.preg_quote($_SERVER['TEST_MACHINE_BASE_PATH'], '/').'/';
$basePath = $_SERVER['DRIVER_MACHINE_BASE_PATH'];
return preg_replace($pattern, $basePath, $file, 1);
}
/**
* Gets the base url to the fixture folder
*
* @return string
*/
public function getWebFixturesUrl()
{
return $_SERVER['WEB_FIXTURES_HOST'];
}
/**
* @param string $testCase The name of the TestCase class
* @param string $test The name of the test method
*
* @return string|null A message explaining why the test should be skipped, or null to run the test.
*/
public function skipMessage($testCase, $test)
{
if (!$this->supportsCss() && 0 === strpos($testCase, 'Behat\Mink\Tests\Driver\Css\\')) {
return 'This driver does not support CSS.';
}
if (!$this->supportsJs() && 0 === strpos($testCase, 'Behat\Mink\Tests\Driver\Js\\')) {
return 'This driver does not support JavaScript.';
}
return null;
}
/**
* Whether the JS tests should run or no.
*
* @return bool
*/
protected function supportsJs()
{
return true;
}
/**
* Whether the CSS tests should run or no.
*
* @return bool
*/
protected function supportsCss()
{
return false;
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class BasicAuthTest extends TestCase
{
/**
* @dataProvider setBasicAuthDataProvider
*/
public function testSetBasicAuth($user, $pass, $pageText)
{
$session = $this->getSession();
$session->setBasicAuth($user, $pass);
$session->visit($this->pathTo('/basic_auth.php'));
$this->assertContains($pageText, $session->getPage()->getContent());
}
public function setBasicAuthDataProvider()
{
return array(
array('mink-user', 'mink-password', 'is authenticated'),
array('', '', 'is not authenticated'),
);
}
public function testResetBasicAuth()
{
$session = $this->getSession();
$session->setBasicAuth('mink-user', 'mink-password');
$session->visit($this->pathTo('/basic_auth.php'));
$this->assertContains('is authenticated', $session->getPage()->getContent());
$session->setBasicAuth(false);
$session->visit($this->pathTo('/headers.php'));
$this->assertNotContains('PHP_AUTH_USER', $session->getPage()->getContent());
}
public function testResetWithBasicAuth()
{
$session = $this->getSession();
$session->setBasicAuth('mink-user', 'mink-password');
$session->visit($this->pathTo('/basic_auth.php'));
$this->assertContains('is authenticated', $session->getPage()->getContent());
$session->reset();
$session->visit($this->pathTo('/headers.php'));
$this->assertNotContains('PHP_AUTH_USER', $session->getPage()->getContent());
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class ContentTest extends TestCase
{
public function testOuterHtml()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$element = $this->getAssertSession()->elementExists('css', '.travers');
$this->assertEquals(
"<div class=\"travers\">\n <div class=\"sub\">el1</div>\n".
" <div class=\"sub\">el2</div>\n <div class=\"sub\">\n".
" <a href=\"some_url\">some <strong>deep</strong> url</a>\n".
" </div>\n </div>",
$element->getOuterHtml()
);
}
/**
* @dataProvider getAttributeDataProvider
*/
public function testGetAttribute($attributeName, $attributeValue)
{
$this->getSession()->visit($this->pathTo('/index.html'));
$element = $this->getSession()->getPage()->findById('attr-elem['.$attributeName.']');
$this->assertNotNull($element);
$this->assertSame($attributeValue, $element->getAttribute($attributeName));
}
public function getAttributeDataProvider()
{
return array(
array('with-value', 'some-value'),
array('without-value', ''),
array('with-empty-value', ''),
array('with-missing', null),
);
}
public function testJson()
{
$this->getSession()->visit($this->pathTo('/json.php'));
$this->assertContains(
'{"key1":"val1","key2":234,"key3":[1,2,3]}',
$this->getSession()->getPage()->getContent()
);
}
public function testHtmlDecodingNotPerformed()
{
$session = $this->getSession();
$webAssert = $this->getAssertSession();
$session->visit($this->pathTo('/html_decoding.html'));
$page = $session->getPage();
$span = $webAssert->elementExists('css', 'span');
$input = $webAssert->elementExists('css', 'input');
$expectedHtml = '<span custom-attr="&amp;">some text</span>';
$this->assertContains($expectedHtml, $page->getHtml(), '.innerHTML is returned as-is');
$this->assertContains($expectedHtml, $page->getContent(), '.outerHTML is returned as-is');
$this->assertEquals('&', $span->getAttribute('custom-attr'), '.getAttribute value is decoded');
$this->assertEquals('&', $input->getAttribute('value'), '.getAttribute value is decoded');
$this->assertEquals('&', $input->getValue(), 'node value is decoded');
}
}

View File

@ -0,0 +1,167 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class CookieTest extends TestCase
{
/**
* test cookie decoding
* @group issue140
*/
public function testIssue140()
{
$this->getSession()->visit($this->pathTo('/issue140.php'));
$this->getSession()->getPage()->fillField('cookie_value', 'some:value;');
$this->getSession()->getPage()->pressButton('Set cookie');
$this->getSession()->visit($this->pathTo('/issue140.php?show_value'));
$this->assertEquals('some:value;', $this->getSession()->getCookie('tc'));
$this->assertEquals('some:value;', $this->getSession()->getPage()->getText());
}
public function testCookie()
{
$this->getSession()->visit($this->pathTo('/cookie_page2.php'));
$this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
$this->assertNull($this->getSession()->getCookie('srvr_cookie'));
$this->getSession()->setCookie('srvr_cookie', 'client cookie set');
$this->getSession()->reload();
$this->assertContains('Previous cookie: client cookie set', $this->getSession()->getPage()->getText());
$this->assertEquals('client cookie set', $this->getSession()->getCookie('srvr_cookie'));
$this->getSession()->setCookie('srvr_cookie', null);
$this->getSession()->reload();
$this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
$this->getSession()->visit($this->pathTo('/cookie_page1.php'));
$this->getSession()->visit($this->pathTo('/cookie_page2.php'));
$this->assertContains('Previous cookie: srv_var_is_set', $this->getSession()->getPage()->getText());
$this->getSession()->setCookie('srvr_cookie', null);
$this->getSession()->reload();
$this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
}
/**
* @dataProvider cookieWithPathsDataProvider
*/
public function testCookieWithPaths($cookieRemovalMode)
{
// start clean
$session = $this->getSession();
$session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
$this->assertContains('Previous cookie: NO', $session->getPage()->getText());
// cookie from root path is accessible in sub-folder
$session->visit($this->pathTo('/cookie_page1.php'));
$session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
$this->assertContains('Previous cookie: srv_var_is_set', $session->getPage()->getText());
// cookie from sub-folder overrides cookie from root path
$session->visit($this->pathTo('/sub-folder/cookie_page1.php'));
$session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
$this->assertContains('Previous cookie: srv_var_is_set_sub_folder', $session->getPage()->getText());
if ($cookieRemovalMode == 'session_reset') {
$session->reset();
} elseif ($cookieRemovalMode == 'cookie_delete') {
$session->setCookie('srvr_cookie', null);
}
// cookie is removed from all paths
$session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
$this->assertContains('Previous cookie: NO', $session->getPage()->getText());
}
public function cookieWithPathsDataProvider()
{
return array(
array('session_reset'),
array('cookie_delete'),
);
}
public function testReset()
{
$this->getSession()->visit($this->pathTo('/cookie_page1.php'));
$this->getSession()->visit($this->pathTo('/cookie_page2.php'));
$this->assertContains('Previous cookie: srv_var_is_set', $this->getSession()->getPage()->getText());
$this->getSession()->reset();
$this->getSession()->visit($this->pathTo('/cookie_page2.php'));
$this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
$this->getSession()->setCookie('srvr_cookie', 'test_cookie');
$this->getSession()->visit($this->pathTo('/cookie_page2.php'));
$this->assertContains('Previous cookie: test_cookie', $this->getSession()->getPage()->getText());
$this->getSession()->reset();
$this->getSession()->visit($this->pathTo('/cookie_page2.php'));
$this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
$this->getSession()->setCookie('client_cookie1', 'some_val');
$this->getSession()->setCookie('client_cookie2', 123);
$this->getSession()->visit($this->pathTo('/session_test.php'));
$this->getSession()->visit($this->pathTo('/cookie_page1.php'));
$this->getSession()->visit($this->pathTo('/print_cookies.php'));
$this->assertContains(
"'client_cookie1' = 'some_val'",
$this->getSession()->getPage()->getText()
);
$this->assertContains(
"'client_cookie2' = '123'",
$this->getSession()->getPage()->getText()
);
$this->assertContains(
"_SESS' = ",
$this->getSession()->getPage()->getText()
);
$this->assertContains(
" 'srvr_cookie' = 'srv_var_is_set'",
$this->getSession()->getPage()->getText()
);
$this->getSession()->reset();
$this->getSession()->visit($this->pathTo('/print_cookies.php'));
$this->assertContains('array ( )', $this->getSession()->getPage()->getText());
}
public function testHttpOnlyCookieIsDeleted()
{
$this->getSession()->restart();
$this->getSession()->visit($this->pathTo('/cookie_page3.php'));
$this->assertEquals('Has Cookie: false', $this->findById('cookie-status')->getText());
$this->getSession()->reload();
$this->assertEquals('Has Cookie: true', $this->findById('cookie-status')->getText());
$this->getSession()->restart();
$this->getSession()->visit($this->pathTo('/cookie_page3.php'));
$this->assertEquals('Has Cookie: false', $this->findById('cookie-status')->getText());
}
public function testSessionPersistsBetweenRequests()
{
$this->getSession()->visit($this->pathTo('/session_test.php'));
$webAssert = $this->getAssertSession();
$node = $webAssert->elementExists('css', '#session-id');
$sessionId = $node->getText();
$this->getSession()->visit($this->pathTo('/session_test.php'));
$node = $webAssert->elementExists('css', '#session-id');
$this->assertEquals($sessionId, $node->getText());
$this->getSession()->visit($this->pathTo('/session_test.php?login'));
$node = $webAssert->elementExists('css', '#session-id');
$this->assertNotEquals($sessionId, $newSessionId = $node->getText());
$this->getSession()->visit($this->pathTo('/session_test.php'));
$node = $webAssert->elementExists('css', '#session-id');
$this->assertEquals($newSessionId, $node->getText());
}
}

View File

@ -0,0 +1,262 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class ErrorHandlingTest extends TestCase
{
const NOT_FOUND_XPATH = '//html/./invalid';
const NOT_FOUND_EXCEPTION = 'Exception';
const INVALID_EXCEPTION = 'Exception';
public function testVisitErrorPage()
{
$this->getSession()->visit($this->pathTo('/500.php'));
$this->assertContains(
'Sorry, a server error happened',
$this->getSession()->getPage()->getContent(),
'Drivers allow loading pages with a 500 status code'
);
}
public function testCheckInvalidElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$element = $this->findById('user-name');
$this->setExpectedException(self::INVALID_EXCEPTION);
$this->getSession()->getDriver()->check($element->getXpath());
}
public function testCheckNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->check(self::NOT_FOUND_XPATH);
}
public function testUncheckInvalidElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$element = $this->findById('user-name');
$this->setExpectedException(self::INVALID_EXCEPTION);
$this->getSession()->getDriver()->uncheck($element->getXpath());
}
public function testUncheckNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->uncheck(self::NOT_FOUND_XPATH);
}
public function testSelectOptionInvalidElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$element = $this->findById('user-name');
$this->setExpectedException(self::INVALID_EXCEPTION);
$this->getSession()->getDriver()->selectOption($element->getXpath(), 'test');
}
public function testSelectOptionNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->selectOption(self::NOT_FOUND_XPATH, 'test');
}
public function testAttachFileInvalidElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$element = $this->findById('user-name');
$this->setExpectedException(self::INVALID_EXCEPTION);
$this->getSession()->getDriver()->attachFile($element->getXpath(), __FILE__);
}
public function testAttachFileNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->attachFile(self::NOT_FOUND_XPATH, __FILE__);
}
public function testSubmitFormInvalidElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$element = $this->findById('core');
$this->setExpectedException(self::INVALID_EXCEPTION);
$this->getSession()->getDriver()->submitForm($element->getXpath());
}
public function testSubmitFormNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->submitForm(self::NOT_FOUND_XPATH);
}
public function testGetTagNameNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->getTagName(self::NOT_FOUND_XPATH);
}
public function testGetTextNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->getText(self::NOT_FOUND_XPATH);
}
public function testGetHtmlNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->getHtml(self::NOT_FOUND_XPATH);
}
public function testGetOuterHtmlNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->getOuterHtml(self::NOT_FOUND_XPATH);
}
public function testGetValueNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->getValue(self::NOT_FOUND_XPATH);
}
public function testSetValueNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->setValue(self::NOT_FOUND_XPATH, 'test');
}
public function testIsSelectedNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->isSelected(self::NOT_FOUND_XPATH);
}
public function testIsCheckedNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->isChecked(self::NOT_FOUND_XPATH);
}
public function testIsVisibleNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->isVisible(self::NOT_FOUND_XPATH);
}
public function testClickNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->click(self::NOT_FOUND_XPATH);
}
public function testDoubleClickNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->doubleClick(self::NOT_FOUND_XPATH);
}
public function testRightClickNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->rightClick(self::NOT_FOUND_XPATH);
}
public function testGetAttributeNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->getAttribute(self::NOT_FOUND_XPATH, 'id');
}
public function testMouseOverNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->mouseOver(self::NOT_FOUND_XPATH);
}
public function testFocusNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->focus(self::NOT_FOUND_XPATH);
}
public function testBlurNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->blur(self::NOT_FOUND_XPATH);
}
public function testKeyPressNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->keyPress(self::NOT_FOUND_XPATH, 'a');
}
public function testKeyDownNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->keyDown(self::NOT_FOUND_XPATH, 'a');
}
public function testKeyUpNotFoundElement()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->setExpectedException(self::NOT_FOUND_EXCEPTION);
$this->getSession()->getDriver()->keyUp(self::NOT_FOUND_XPATH, 'a');
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class HeaderTest extends TestCase
{
/**
* test referrer
* @group issue130
*/
public function testIssue130()
{
$this->getSession()->visit($this->pathTo('/issue130.php?p=1'));
$page = $this->getSession()->getPage();
$page->clickLink('Go to 2');
$this->assertEquals($this->pathTo('/issue130.php?p=1'), $page->getText());
}
public function testHeaders()
{
$this->getSession()->setRequestHeader('Accept-Language', 'fr');
$this->getSession()->visit($this->pathTo('/headers.php'));
$this->assertContains('[HTTP_ACCEPT_LANGUAGE] => fr', $this->getSession()->getPage()->getContent());
}
public function testSetUserAgent()
{
$session = $this->getSession();
$session->setRequestHeader('user-agent', 'foo bar');
$session->visit($this->pathTo('/headers.php'));
$this->assertContains('[HTTP_USER_AGENT] => foo bar', $session->getPage()->getContent());
}
public function testResetHeaders()
{
$session = $this->getSession();
$session->setRequestHeader('X-Mink-Test', 'test');
$session->visit($this->pathTo('/headers.php'));
$this->assertContains(
'[HTTP_X_MINK_TEST] => test',
$session->getPage()->getContent(),
'The custom header should be sent',
true
);
$session->reset();
$session->visit($this->pathTo('/headers.php'));
$this->assertNotContains(
'[HTTP_X_MINK_TEST] => test',
$session->getPage()->getContent(),
'The custom header should not be sent after resetting',
true
);
}
public function testResponseHeaders()
{
$this->getSession()->visit($this->pathTo('/response_headers.php'));
$headers = $this->getSession()->getResponseHeaders();
$lowercasedHeaders = array();
foreach ($headers as $name => $value) {
$lowercasedHeaders[str_replace('_', '-', strtolower($name))] = $value;
}
$this->assertArrayHasKey('x-mink-test', $lowercasedHeaders);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class IFrameTest extends TestCase
{
public function testIFrame()
{
$this->getSession()->visit($this->pathTo('/iframe.html'));
$webAssert = $this->getAssertSession();
$el = $webAssert->elementExists('css', '#text');
$this->assertSame('Main window div text', $el->getText());
$this->getSession()->switchToIFrame('subframe');
$el = $webAssert->elementExists('css', '#text');
$this->assertSame('iFrame div text', $el->getText());
$this->getSession()->switchToIFrame();
$el = $webAssert->elementExists('css', '#text');
$this->assertSame('Main window div text', $el->getText());
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class NavigationTest extends TestCase
{
public function testRedirect()
{
$this->getSession()->visit($this->pathTo('/redirector.php'));
$this->assertEquals($this->pathTo('/redirect_destination.html'), $this->getSession()->getCurrentUrl());
}
public function testPageControlls()
{
$this->getSession()->visit($this->pathTo('/randomizer.php'));
$number1 = $this->getSession()->getPage()->find('css', '#number')->getText();
$this->getSession()->reload();
$number2 = $this->getSession()->getPage()->find('css', '#number')->getText();
$this->assertNotEquals($number1, $number2);
$this->getSession()->visit($this->pathTo('/links.html'));
$this->getSession()->getPage()->clickLink('Random number page');
$this->assertEquals($this->pathTo('/randomizer.php'), $this->getSession()->getCurrentUrl());
$this->getSession()->back();
$this->assertEquals($this->pathTo('/links.html'), $this->getSession()->getCurrentUrl());
$this->getSession()->forward();
$this->assertEquals($this->pathTo('/randomizer.php'), $this->getSession()->getCurrentUrl());
}
public function testLinks()
{
$this->getSession()->visit($this->pathTo('/links.html'));
$page = $this->getSession()->getPage();
$link = $page->findLink('Redirect me to');
$this->assertNotNull($link);
$this->assertRegExp('/redirector\.php$/', $link->getAttribute('href'));
$link->click();
$this->assertEquals($this->pathTo('/redirect_destination.html'), $this->getSession()->getCurrentUrl());
$this->getSession()->visit($this->pathTo('/links.html'));
$page = $this->getSession()->getPage();
$link = $page->findLink('basic form image');
$this->assertNotNull($link);
$this->assertRegExp('/basic_form\.html$/', $link->getAttribute('href'));
$link->click();
$this->assertEquals($this->pathTo('/basic_form.html'), $this->getSession()->getCurrentUrl());
$this->getSession()->visit($this->pathTo('/links.html'));
$page = $this->getSession()->getPage();
$link = $page->findLink("Link with a ");
$this->assertNotNull($link);
$this->assertRegExp('/links\.html\?quoted$/', $link->getAttribute('href'));
$link->click();
$this->assertEquals($this->pathTo('/links.html?quoted'), $this->getSession()->getCurrentUrl());
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class ScreenshotTest extends TestCase
{
public function testScreenshot()
{
if (!extension_loaded('gd')) {
$this->markTestSkipped('Testing screenshots requires the GD extension');
}
$this->getSession()->visit($this->pathTo('/index.html'));
$screenShot = $this->getSession()->getScreenshot();
$this->assertInternalType('string', $screenShot);
$this->assertFalse(base64_decode($screenShot, true), 'The returned screenshot should not be base64-encoded');
$img = imagecreatefromstring($screenShot);
if (false === $img) {
$this->fail('The screenshot should be a valid image');
}
imagedestroy($img);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class StatusCodeTest extends TestCase
{
public function testStatuses()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->assertEquals(200, $this->getSession()->getStatusCode());
$this->assertEquals($this->pathTo('/index.html'), $this->getSession()->getCurrentUrl());
$this->getSession()->visit($this->pathTo('/404.php'));
$this->assertEquals($this->pathTo('/404.php'), $this->getSession()->getCurrentUrl());
$this->assertEquals(404, $this->getSession()->getStatusCode());
$this->assertEquals('Sorry, page not found', $this->getSession()->getPage()->getContent());
}
}

View File

@ -0,0 +1,139 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class TraversingTest extends TestCase
{
/**
* find by label
* @group issue211
*/
public function testIssue211()
{
$this->getSession()->visit($this->pathTo('/issue211.html'));
$field = $this->getSession()->getPage()->findField('Téléphone');
$this->assertNotNull($field);
}
public function testElementsTraversing()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$page = $this->getSession()->getPage();
$this->assertNotNull($page->find('css', 'h1'));
$this->assertEquals('Extremely useless page', $page->find('css', 'h1')->getText());
$this->assertEquals('h1', $page->find('css', 'h1')->getTagName());
$this->assertNotNull($page->find('xpath', '//div/strong[3]'));
$this->assertEquals('pariatur', $page->find('xpath', '//div/strong[3]')->getText());
$this->assertEquals('super-duper', $page->find('xpath', '//div/strong[3]')->getAttribute('class'));
$this->assertTrue($page->find('xpath', '//div/strong[3]')->hasAttribute('class'));
$this->assertNotNull($page->find('xpath', '//div/strong[2]'));
$this->assertEquals('veniam', $page->find('xpath', '//div/strong[2]')->getText());
$this->assertEquals('strong', $page->find('xpath', '//div/strong[2]')->getTagName());
$this->assertNull($page->find('xpath', '//div/strong[2]')->getAttribute('class'));
$this->assertFalse($page->find('xpath', '//div/strong[2]')->hasAttribute('class'));
$strongs = $page->findAll('css', 'div#core > strong');
$this->assertCount(3, $strongs);
$this->assertEquals('Lorem', $strongs[0]->getText());
$this->assertEquals('pariatur', $strongs[2]->getText());
$element = $page->find('css', '#some-element');
$this->assertEquals('some very interesting text', $element->getText());
$this->assertEquals(
"\n some <div>very\n </div>\n".
"<em>interesting</em> text\n ",
$element->getHtml()
);
$this->assertTrue($element->hasAttribute('data-href'));
$this->assertFalse($element->hasAttribute('data-url'));
$this->assertEquals('http://mink.behat.org', $element->getAttribute('data-href'));
$this->assertNull($element->getAttribute('data-url'));
$this->assertEquals('div', $element->getTagName());
}
public function testVeryDeepElementsTraversing()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$page = $this->getSession()->getPage();
$footer = $page->find('css', 'footer');
$this->assertNotNull($footer);
$searchForm = $footer->find('css', 'form#search-form');
$this->assertNotNull($searchForm);
$this->assertEquals('search-form', $searchForm->getAttribute('id'));
$searchInput = $searchForm->findField('Search site...');
$this->assertNotNull($searchInput);
$this->assertEquals('text', $searchInput->getAttribute('type'));
$searchInput = $searchForm->findField('Search site...');
$this->assertNotNull($searchInput);
$this->assertEquals('text', $searchInput->getAttribute('type'));
$profileForm = $footer->find('css', '#profile');
$this->assertNotNull($profileForm);
$profileFormDiv = $profileForm->find('css', 'div');
$this->assertNotNull($profileFormDiv);
$profileFormDivLabel = $profileFormDiv->find('css', 'label');
$this->assertNotNull($profileFormDivLabel);
$profileFormDivParent = $profileFormDivLabel->getParent();
$this->assertNotNull($profileFormDivParent);
$profileFormDivParent = $profileFormDivLabel->getParent();
$this->assertEquals('something', $profileFormDivParent->getAttribute('data-custom'));
$profileFormInput = $profileFormDivLabel->findField('user-name');
$this->assertNotNull($profileFormInput);
$this->assertEquals('username', $profileFormInput->getAttribute('name'));
}
public function testDeepTraversing()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$traversDiv = $this->getSession()->getPage()->findAll('css', 'div.travers');
$this->assertCount(1, $traversDiv);
$traversDiv = $traversDiv[0];
$subDivs = $traversDiv->findAll('css', 'div.sub');
$this->assertCount(3, $subDivs);
$this->assertTrue($subDivs[2]->hasLink('some deep url'));
$this->assertFalse($subDivs[2]->hasLink('come deep url'));
$subUrl = $subDivs[2]->findLink('some deep url');
$this->assertNotNull($subUrl);
$this->assertRegExp('/some_url$/', $subUrl->getAttribute('href'));
$this->assertEquals('some deep url', $subUrl->getText());
$this->assertEquals('some <strong>deep</strong> url', $subUrl->getHtml());
$this->assertTrue($subUrl->has('css', 'strong'));
$this->assertFalse($subUrl->has('css', 'em'));
$this->assertEquals('deep', $subUrl->find('css', 'strong')->getText());
}
public function testFindingChild()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$form = $this->getSession()->getPage()->find('css', 'footer form');
$this->assertNotNull($form);
$this->assertCount(1, $form->findAll('css', 'input'), 'Elements are searched only in the element, not in all previous matches');
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Behat\Mink\Tests\Driver\Basic;
use Behat\Mink\Tests\Driver\TestCase;
class VisibilityTest extends TestCase
{
public function testVisibility()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$webAssert = $this->getAssertSession();
$clicker = $webAssert->elementExists('css', '.elements div#clicker');
$invisible = $webAssert->elementExists('css', '#invisible');
$this->assertFalse($invisible->isVisible());
$this->assertTrue($clicker->isVisible());
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Behat\Mink\Tests\Driver\Css;
use Behat\Mink\Tests\Driver\TestCase;
class HoverTest extends TestCase
{
/**
* @group mouse-events
*/
public function testMouseOverHover()
{
$this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
$this->findById('reset-square')->mouseOver();
$this->assertActionSquareHeight(100);
$this->findById('action-square')->mouseOver();
$this->assertActionSquareHeight(200);
}
/**
* @group mouse-events
* @depends testMouseOverHover
*/
public function testClickHover()
{
$this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
$this->findById('reset-square')->mouseOver();
$this->assertActionSquareHeight(100);
$this->findById('action-square')->click();
$this->assertActionSquareHeight(200);
}
/**
* @group mouse-events
* @depends testMouseOverHover
*/
public function testDoubleClickHover()
{
$this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
$this->findById('reset-square')->mouseOver();
$this->assertActionSquareHeight(100);
$this->findById('action-square')->doubleClick();
$this->assertActionSquareHeight(200);
}
/**
* @group mouse-events
* @depends testMouseOverHover
*/
public function testRightClickHover()
{
$this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
$this->findById('reset-square')->mouseOver();
$this->assertActionSquareHeight(100);
$this->findById('action-square')->rightClick();
$this->assertActionSquareHeight(200);
}
private function assertActionSquareHeight($expected)
{
$this->assertEquals(
$expected,
$this->getSession()->evaluateScript("return window.$('#action-square').height();"),
'Mouse is located over the object when mouse-related action is performed'
);
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace Behat\Mink\Tests\Driver\Form;
use Behat\Mink\Tests\Driver\TestCase;
class CheckboxTest extends TestCase
{
public function testManipulate()
{
$this->getSession()->visit($this->pathTo('advanced_form.html'));
$checkbox = $this->getAssertSession()->fieldExists('agreement');
$this->assertNull($checkbox->getValue());
$this->assertFalse($checkbox->isChecked());
$checkbox->check();
$this->assertEquals('yes', $checkbox->getValue());
$this->assertTrue($checkbox->isChecked());
$checkbox->uncheck();
$this->assertNull($checkbox->getValue());
$this->assertFalse($checkbox->isChecked());
}
public function testSetValue()
{
$this->getSession()->visit($this->pathTo('advanced_form.html'));
$checkbox = $this->getAssertSession()->fieldExists('agreement');
$this->assertNull($checkbox->getValue());
$this->assertFalse($checkbox->isChecked());
$checkbox->setValue(true);
$this->assertEquals('yes', $checkbox->getValue());
$this->assertTrue($checkbox->isChecked());
$checkbox->setValue(false);
$this->assertNull($checkbox->getValue());
$this->assertFalse($checkbox->isChecked());
}
public function testCheckboxMultiple()
{
$this->getSession()->visit($this->pathTo('/multicheckbox_form.html'));
$webAssert = $this->getAssertSession();
$this->assertEquals('Multicheckbox Test', $webAssert->elementExists('css', 'h1')->getText());
$updateMail = $webAssert->elementExists('css', '[name="mail_types[]"][value="update"]');
$spamMail = $webAssert->elementExists('css', '[name="mail_types[]"][value="spam"]');
$this->assertEquals('update', $updateMail->getValue());
$this->assertNull($spamMail->getValue());
$this->assertTrue($updateMail->isChecked());
$this->assertFalse($spamMail->isChecked());
$updateMail->uncheck();
$this->assertFalse($updateMail->isChecked());
$this->assertFalse($spamMail->isChecked());
$spamMail->check();
$this->assertFalse($updateMail->isChecked());
$this->assertTrue($spamMail->isChecked());
}
}

View File

@ -0,0 +1,312 @@
<?php
namespace Behat\Mink\Tests\Driver\Form;
use Behat\Mink\Tests\Driver\TestCase;
class GeneralTest extends TestCase
{
// test multiple submit buttons
public function testIssue212()
{
$session = $this->getSession();
$session->visit($this->pathTo('/issue212.html'));
$field = $this->findById('poney-button');
$this->assertEquals('poney', $field->getValue());
}
public function testBasicForm()
{
$this->getSession()->visit($this->pathTo('/basic_form.html'));
$webAssert = $this->getAssertSession();
$page = $this->getSession()->getPage();
$this->assertEquals('Basic Form Page', $webAssert->elementExists('css', 'h1')->getText());
$firstname = $webAssert->fieldExists('first_name');
$lastname = $webAssert->fieldExists('lastn');
$this->assertEquals('Firstname', $firstname->getValue());
$this->assertEquals('Lastname', $lastname->getValue());
$firstname->setValue('Konstantin');
$page->fillField('last_name', 'Kudryashov');
$this->assertEquals('Konstantin', $firstname->getValue());
$this->assertEquals('Kudryashov', $lastname->getValue());
$page->findButton('Reset')->click();
$this->assertEquals('Firstname', $firstname->getValue());
$this->assertEquals('Lastname', $lastname->getValue());
$firstname->setValue('Konstantin');
$page->fillField('last_name', 'Kudryashov');
$page->findButton('Save')->click();
if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
$this->assertEquals('Anket for Konstantin', $webAssert->elementExists('css', 'h1')->getText());
$this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
$this->assertEquals('Lastname: Kudryashov', $webAssert->elementExists('css', '#last')->getText());
}
}
/**
* @dataProvider formSubmitWaysDataProvider
*/
public function testFormSubmitWays($submitVia)
{
$session = $this->getSession();
$session->visit($this->pathTo('/basic_form.html'));
$page = $session->getPage();
$webAssert = $this->getAssertSession();
$firstname = $webAssert->fieldExists('first_name');
$firstname->setValue('Konstantin');
$page->findButton($submitVia)->click();
if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
$this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
} else {
$this->fail('Form was never submitted');
}
}
public function formSubmitWaysDataProvider()
{
return array(
array('Save'),
array('input-type-image'),
array('button-without-type'),
array('button-type-submit'),
);
}
public function testFormSubmit()
{
$session = $this->getSession();
$session->visit($this->pathTo('/basic_form.html'));
$webAssert = $this->getAssertSession();
$webAssert->fieldExists('first_name')->setValue('Konstantin');
$webAssert->elementExists('xpath', 'descendant-or-self::form[1]')->submit();
if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
$this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
};
}
public function testFormSubmitWithoutButton()
{
$session = $this->getSession();
$session->visit($this->pathTo('/form_without_button.html'));
$webAssert = $this->getAssertSession();
$webAssert->fieldExists('first_name')->setValue('Konstantin');
$webAssert->elementExists('xpath', 'descendant-or-self::form[1]')->submit();
if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
$this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
};
}
public function testBasicGetForm()
{
$this->getSession()->visit($this->pathTo('/basic_get_form.php'));
$webAssert = $this->getAssertSession();
$page = $this->getSession()->getPage();
$this->assertEquals('Basic Get Form Page', $webAssert->elementExists('css', 'h1')->getText());
$search = $webAssert->fieldExists('q');
$search->setValue('some#query');
$page->pressButton('Find');
$div = $webAssert->elementExists('css', 'div');
$this->assertEquals('some#query', $div->getText());
}
public function testAdvancedForm()
{
$this->getSession()->visit($this->pathTo('/advanced_form.html'));
$page = $this->getSession()->getPage();
$page->fillField('first_name', 'ever');
$page->fillField('last_name', 'zet');
$page->pressButton('Register');
$this->assertContains('no file', $page->getContent());
$this->getSession()->visit($this->pathTo('/advanced_form.html'));
$webAssert = $this->getAssertSession();
$page = $this->getSession()->getPage();
$this->assertEquals('ADvanced Form Page', $webAssert->elementExists('css', 'h1')->getText());
$firstname = $webAssert->fieldExists('first_name');
$lastname = $webAssert->fieldExists('lastn');
$email = $webAssert->fieldExists('Your email:');
$select = $webAssert->fieldExists('select_number');
$sex = $webAssert->fieldExists('sex');
$maillist = $webAssert->fieldExists('mail_list');
$agreement = $webAssert->fieldExists('agreement');
$notes = $webAssert->fieldExists('notes');
$about = $webAssert->fieldExists('about');
$this->assertEquals('Firstname', $firstname->getValue());
$this->assertEquals('Lastname', $lastname->getValue());
$this->assertEquals('your@email.com', $email->getValue());
$this->assertEquals('20', $select->getValue());
$this->assertEquals('w', $sex->getValue());
$this->assertEquals('original notes', $notes->getValue());
$this->assertEquals('on', $maillist->getValue());
$this->assertNull($agreement->getValue());
$this->assertTrue($maillist->isChecked());
$this->assertFalse($agreement->isChecked());
$agreement->check();
$this->assertTrue($agreement->isChecked());
$maillist->uncheck();
$this->assertFalse($maillist->isChecked());
$select->selectOption('thirty');
$this->assertEquals('30', $select->getValue());
$sex->selectOption('m');
$this->assertEquals('m', $sex->getValue());
$notes->setValue('new notes');
$this->assertEquals('new notes', $notes->getValue());
$about->attachFile($this->mapRemoteFilePath(__DIR__.'/../../web-fixtures/some_file.txt'));
$button = $page->findButton('Register');
$this->assertNotNull($button);
$page->fillField('first_name', 'Foo "item"');
$page->fillField('last_name', 'Bar');
$page->fillField('Your email:', 'ever.zet@gmail.com');
$this->assertEquals('Foo "item"', $firstname->getValue());
$this->assertEquals('Bar', $lastname->getValue());
$button->press();
if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
$out = <<<OUT
array (
'agreement' = 'on',
'email' = 'ever.zet@gmail.com',
'first_name' = 'Foo "item"',
'last_name' = 'Bar',
'notes' = 'new notes',
'select_number' = '30',
'sex' = 'm',
'submit' = 'Register',
)
some_file.txt
1 uploaded file
OUT;
$this->assertContains($out, $page->getContent());
}
}
public function testMultiInput()
{
$this->getSession()->visit($this->pathTo('/multi_input_form.html'));
$page = $this->getSession()->getPage();
$webAssert = $this->getAssertSession();
$this->assertEquals('Multi input Test', $webAssert->elementExists('css', 'h1')->getText());
$first = $webAssert->fieldExists('First');
$second = $webAssert->fieldExists('Second');
$third = $webAssert->fieldExists('Third');
$this->assertEquals('tag1', $first->getValue());
$this->assertSame('tag2', $second->getValue());
$this->assertEquals('tag1', $third->getValue());
$first->setValue('tag2');
$this->assertEquals('tag2', $first->getValue());
$this->assertSame('tag2', $second->getValue());
$this->assertEquals('tag1', $third->getValue());
$second->setValue('one');
$this->assertEquals('tag2', $first->getValue());
$this->assertSame('one', $second->getValue());
$third->setValue('tag3');
$this->assertEquals('tag2', $first->getValue());
$this->assertSame('one', $second->getValue());
$this->assertEquals('tag3', $third->getValue());
$button = $page->findButton('Register');
$this->assertNotNull($button);
$button->press();
$space = ' ';
$out = <<<OUT
'tags' =$space
array (
0 = 'tag2',
1 = 'one',
2 = 'tag3',
),
OUT;
$this->assertContains($out, $page->getContent());
}
public function testAdvancedFormSecondSubmit()
{
$this->getSession()->visit($this->pathTo('/advanced_form.html'));
$page = $this->getSession()->getPage();
$button = $page->findButton('Login');
$this->assertNotNull($button);
$button->press();
$toSearch = array(
"'agreement' = 'off',",
"'submit' = 'Login',",
'no file',
);
$pageContent = $page->getContent();
foreach ($toSearch as $searchString) {
$this->assertContains($searchString, $pageContent);
}
}
public function testSubmitEmptyTextarea()
{
$this->getSession()->visit($this->pathTo('/empty_textarea.html'));
$page = $this->getSession()->getPage();
$page->pressButton('Save');
$toSearch = array(
"'textarea' = '',",
"'submit' = 'Save',",
'no file',
);
$pageContent = $page->getContent();
foreach ($toSearch as $searchString) {
$this->assertContains($searchString, $pageContent);
}
}
}

View File

@ -0,0 +1,128 @@
<?php
namespace Behat\Mink\Tests\Driver\Form;
use Behat\Mink\Tests\Driver\TestCase;
class Html5Test extends TestCase
{
public function testHtml5FormInputAttribute()
{
$this->getSession()->visit($this->pathTo('/html5_form.html'));
$page = $this->getSession()->getPage();
$webAssert = $this->getAssertSession();
$firstName = $webAssert->fieldExists('first_name');
$lastName = $webAssert->fieldExists('last_name');
$this->assertEquals('not set', $lastName->getValue());
$firstName->setValue('John');
$lastName->setValue('Doe');
$this->assertEquals('Doe', $lastName->getValue());
$page->pressButton('Submit in form');
if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
$out = <<<OUT
'first_name' = 'John',
'last_name' = 'Doe',
OUT;
$this->assertContains($out, $page->getContent());
$this->assertNotContains('other_field', $page->getContent());
}
}
public function testHtml5FormRadioAttribute()
{
$this->getSession()->visit($this->pathTo('html5_radio.html'));
$page = $this->getSession()->getPage();
$radio = $this->findById('sex_f');
$otherRadio = $this->findById('sex_invalid');
$this->assertEquals('f', $radio->getValue());
$this->assertEquals('invalid', $otherRadio->getValue());
$radio->selectOption('m');
$this->assertEquals('m', $radio->getValue());
$this->assertEquals('invalid', $otherRadio->getValue());
$page->pressButton('Submit in form');
$out = <<<OUT
'sex' = 'm',
OUT;
$this->assertContains($out, $page->getContent());
}
public function testHtml5FormButtonAttribute()
{
$this->getSession()->visit($this->pathTo('/html5_form.html'));
$page = $this->getSession()->getPage();
$webAssert = $this->getAssertSession();
$firstName = $webAssert->fieldExists('first_name');
$lastName = $webAssert->fieldExists('last_name');
$firstName->setValue('John');
$lastName->setValue('Doe');
$page->pressButton('Submit outside form');
if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
$out = <<<OUT
'first_name' = 'John',
'last_name' = 'Doe',
'submit_button' = 'test',
OUT;
$this->assertContains($out, $page->getContent());
}
}
public function testHtml5FormOutside()
{
$this->getSession()->visit($this->pathTo('/html5_form.html'));
$page = $this->getSession()->getPage();
$page->fillField('other_field', 'hello');
$page->pressButton('Submit separate form');
if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
$out = <<<OUT
'other_field' = 'hello',
OUT;
$this->assertContains($out, $page->getContent());
$this->assertNotContains('first_name', $page->getContent());
}
}
public function testHtml5Types()
{
$this->getSession()->visit($this->pathTo('html5_types.html'));
$page = $this->getSession()->getPage();
$page->fillField('url', 'http://mink.behat.org/');
$page->fillField('email', 'mink@example.org');
$page->fillField('number', '6');
$page->fillField('search', 'mink');
$page->fillField('date', '2014-05-19');
$page->fillField('color', '#ff00aa');
$page->pressButton('Submit');
$out = <<<OUT
'color' = '#ff00aa',
'date' = '2014-05-19',
'email' = 'mink@example.org',
'number' = '6',
'search' = 'mink',
'submit_button' = 'Submit',
'url' = 'http://mink.behat.org/',
OUT;
$this->assertContains($out, $page->getContent());
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace Behat\Mink\Tests\Driver\Form;
use Behat\Mink\Tests\Driver\TestCase;
class RadioTest extends TestCase
{
protected function setUp()
{
$this->getSession()->visit($this->pathTo('radio.html'));
}
public function testIsChecked()
{
$option = $this->findById('first');
$option2 = $this->findById('second');
$this->assertTrue($option->isChecked());
$this->assertFalse($option2->isChecked());
$option2->selectOption('updated');
$this->assertFalse($option->isChecked());
$this->assertTrue($option2->isChecked());
}
public function testSelectOption()
{
$option = $this->findById('first');
$this->assertEquals('set', $option->getValue());
$option->selectOption('updated');
$this->assertEquals('updated', $option->getValue());
$option->selectOption('set');
$this->assertEquals('set', $option->getValue());
}
public function testSetValue()
{
$option = $this->findById('first');
$this->assertEquals('set', $option->getValue());
$option->setValue('updated');
$this->assertEquals('updated', $option->getValue());
$this->assertFalse($option->isChecked());
}
public function testSameNameInMultipleForms()
{
$option1 = $this->findById('reused_form1');
$option2 = $this->findById('reused_form2');
$this->assertEquals('test2', $option1->getValue());
$this->assertEquals('test3', $option2->getValue());
$option1->selectOption('test');
$this->assertEquals('test', $option1->getValue());
$this->assertEquals('test3', $option2->getValue());
}
/**
* @see https://github.com/Behat/MinkSahiDriver/issues/32
*/
public function testSetValueXPathEscaping()
{
$session = $this->getSession();
$session->visit($this->pathTo('/advanced_form.html'));
$page = $session->getPage();
$sex = $page->find('xpath', '//*[@name = "sex"]'."\n|\n".'//*[@id = "sex"]');
$this->assertNotNull($sex, 'xpath with line ending works');
$sex->setValue('m');
$this->assertEquals('m', $sex->getValue(), 'no double xpath escaping during radio button value change');
}
}

View File

@ -0,0 +1,135 @@
<?php
namespace Behat\Mink\Tests\Driver\Form;
use Behat\Mink\Tests\Driver\TestCase;
class SelectTest extends TestCase
{
public function testMultiselect()
{
$this->getSession()->visit($this->pathTo('/multiselect_form.html'));
$webAssert = $this->getAssertSession();
$page = $this->getSession()->getPage();
$this->assertEquals('Multiselect Test', $webAssert->elementExists('css', 'h1')->getText());
$select = $webAssert->fieldExists('select_number');
$multiSelect = $webAssert->fieldExists('select_multiple_numbers[]');
$secondMultiSelect = $webAssert->fieldExists('select_multiple_values[]');
$this->assertEquals('20', $select->getValue());
$this->assertSame(array(), $multiSelect->getValue());
$this->assertSame(array('2', '3'), $secondMultiSelect->getValue());
$select->selectOption('thirty');
$this->assertEquals('30', $select->getValue());
$multiSelect->selectOption('one', true);
$this->assertSame(array('1'), $multiSelect->getValue());
$multiSelect->selectOption('three', true);
$this->assertEquals(array('1', '3'), $multiSelect->getValue());
$secondMultiSelect->selectOption('two');
$this->assertSame(array('2'), $secondMultiSelect->getValue());
$button = $page->findButton('Register');
$this->assertNotNull($button);
$button->press();
$space = ' ';
$out = <<<OUT
'agreement' = 'off',
'select_multiple_numbers' =$space
array (
0 = '1',
1 = '3',
),
'select_multiple_values' =$space
array (
0 = '2',
),
'select_number' = '30',
OUT;
$this->assertContains($out, $page->getContent());
}
/**
* @dataProvider testElementSelectedStateCheckDataProvider
*/
public function testElementSelectedStateCheck($selectName, $optionValue, $optionText)
{
$session = $this->getSession();
$webAssert = $this->getAssertSession();
$session->visit($this->pathTo('/multiselect_form.html'));
$select = $webAssert->fieldExists($selectName);
$optionValueEscaped = $session->getSelectorsHandler()->xpathLiteral($optionValue);
$option = $webAssert->elementExists('named', array('option', $optionValueEscaped));
$this->assertFalse($option->isSelected());
$select->selectOption($optionText);
$this->assertTrue($option->isSelected());
}
public function testElementSelectedStateCheckDataProvider()
{
return array(
array('select_number', '30', 'thirty'),
array('select_multiple_numbers[]', '2', 'two'),
);
}
public function testSetValueSingleSelect()
{
$session = $this->getSession();
$session->visit($this->pathTo('/multiselect_form.html'));
$select = $this->getAssertSession()->fieldExists('select_number');
$select->setValue('10');
$this->assertEquals('10', $select->getValue());
}
public function testSetValueMultiSelect()
{
$session = $this->getSession();
$session->visit($this->pathTo('/multiselect_form.html'));
$select = $this->getAssertSession()->fieldExists('select_multiple_values[]');
$select->setValue(array('1', '2'));
$this->assertEquals(array('1', '2'), $select->getValue());
}
/**
* @see https://github.com/Behat/Mink/issues/193
*/
public function testOptionWithoutValue()
{
$session = $this->getSession();
$session->visit($this->pathTo('/issue193.html'));
$session->getPage()->selectFieldOption('options-without-values', 'Two');
$this->assertEquals('Two', $this->findById('options-without-values')->getValue());
$this->assertTrue($this->findById('two')->isSelected());
$this->assertFalse($this->findById('one')->isSelected());
$session->getPage()->selectFieldOption('options-with-values', 'two');
$this->assertEquals('two', $this->findById('options-with-values')->getValue());
}
/**
* @see https://github.com/Behat/Mink/issues/131
*/
public function testAccentuatedOption()
{
$this->getSession()->visit($this->pathTo('/issue131.html'));
$page = $this->getSession()->getPage();
$page->selectFieldOption('foobar', 'Gimme some accentués characters');
$this->assertEquals('1', $page->findField('foobar')->getValue());
}
}

View File

@ -0,0 +1,152 @@
<?php
namespace Behat\Mink\Tests\Driver\Js;
use Behat\Mink\Tests\Driver\TestCase;
class ChangeEventTest extends TestCase
{
/**
* 'change' event should be fired after selecting an <option> in a <select>
*
* TODO check whether this test is redundant with other change event tests.
*/
public function testIssue255()
{
$session = $this->getSession();
$session->visit($this->pathTo('/issue255.html'));
$session->getPage()->selectFieldOption('foo_select', 'Option 3');
$session->wait(2000, '$("#output_foo_select").text() != ""');
$this->assertEquals('onChangeSelect', $session->getPage()->find('css', '#output_foo_select')->getText());
}
public function testIssue178()
{
$session = $this->getSession();
$session->visit($this->pathTo('/issue178.html'));
$this->findById('source')->setValue('foo');
$this->assertEquals('foo', $this->findById('target')->getText());
}
/**
* @dataProvider setValueChangeEventDataProvider
* @group change-event-detector
*/
public function testSetValueChangeEvent($elementId, $valueForEmpty, $valueForFilled = '')
{
$this->getSession()->visit($this->pathTo('/element_change_detector.html'));
$page = $this->getSession()->getPage();
$input = $this->findById($elementId);
$this->assertNull($page->findById($elementId.'-result'));
// Verify setting value, when control is initially empty.
$input->setValue($valueForEmpty);
$this->assertElementChangeCount($elementId, 'initial value setting triggers change event');
if ($valueForFilled) {
// Verify setting value, when control already has a value.
$this->findById('results')->click();
$input->setValue($valueForFilled);
$this->assertElementChangeCount($elementId, 'value change triggers change event');
}
}
public function setValueChangeEventDataProvider()
{
return array(
'input default' => array('the-input-default', 'from empty', 'from existing'),
'input text' => array('the-input-text', 'from empty', 'from existing'),
'input email' => array('the-email', 'from empty', 'from existing'),
'textarea' => array('the-textarea', 'from empty', 'from existing'),
'file' => array('the-file', 'from empty', 'from existing'),
'select' => array('the-select', '30'),
'radio' => array('the-radio-m', 'm'),
);
}
/**
* @dataProvider selectOptionChangeEventDataProvider
* @group change-event-detector
*/
public function testSelectOptionChangeEvent($elementId, $elementValue)
{
$this->getSession()->visit($this->pathTo('/element_change_detector.html'));
$page = $this->getSession()->getPage();
$input = $this->findById($elementId);
$this->assertNull($page->findById($elementId.'-result'));
$input->selectOption($elementValue);
$this->assertElementChangeCount($elementId);
}
public function selectOptionChangeEventDataProvider()
{
return array(
'select' => array('the-select', '30'),
'radio' => array('the-radio-m', 'm'),
);
}
/**
* @dataProvider checkboxTestWayDataProvider
* @group change-event-detector
*/
public function testCheckChangeEvent($useSetValue)
{
$this->getSession()->visit($this->pathTo('/element_change_detector.html'));
$page = $this->getSession()->getPage();
$checkbox = $this->findById('the-unchecked-checkbox');
$this->assertNull($page->findById('the-unchecked-checkbox-result'));
if ($useSetValue) {
$checkbox->setValue(true);
} else {
$checkbox->check();
}
$this->assertElementChangeCount('the-unchecked-checkbox');
}
/**
* @dataProvider checkboxTestWayDataProvider
* @group change-event-detector
*/
public function testUncheckChangeEvent($useSetValue)
{
$this->getSession()->visit($this->pathTo('/element_change_detector.html'));
$page = $this->getSession()->getPage();
$checkbox = $this->findById('the-checked-checkbox');
$this->assertNull($page->findById('the-checked-checkbox-result'));
if ($useSetValue) {
$checkbox->setValue(false);
} else {
$checkbox->uncheck();
}
$this->assertElementChangeCount('the-checked-checkbox');
}
public function checkboxTestWayDataProvider()
{
return array(
array(true),
array(false),
);
}
private function assertElementChangeCount($elementId, $message = '')
{
$counterElement = $this->getSession()->getPage()->findById($elementId.'-result');
$actualCount = null === $counterElement ? 0 : $counterElement->getText();
$this->assertEquals('1', $actualCount, $message);
}
}

View File

@ -0,0 +1,122 @@
<?php
namespace Behat\Mink\Tests\Driver\Js;
use Behat\Mink\Tests\Driver\TestCase;
class EventsTest extends TestCase
{
/**
* @group mouse-events
*/
public function testClick()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$clicker = $this->getAssertSession()->elementExists('css', '.elements div#clicker');
$this->assertEquals('not clicked', $clicker->getText());
$clicker->click();
$this->assertEquals('single clicked', $clicker->getText());
}
/**
* @group mouse-events
*/
public function testDoubleClick()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$clicker = $this->getAssertSession()->elementExists('css', '.elements div#clicker');
$this->assertEquals('not clicked', $clicker->getText());
$clicker->doubleClick();
$this->assertEquals('double clicked', $clicker->getText());
}
/**
* @group mouse-events
*/
public function testRightClick()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$clicker = $this->getAssertSession()->elementExists('css', '.elements div#clicker');
$this->assertEquals('not clicked', $clicker->getText());
$clicker->rightClick();
$this->assertEquals('right clicked', $clicker->getText());
}
/**
* @group mouse-events
*/
public function testFocus()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$focusBlurDetector = $this->getAssertSession()->elementExists('css', '.elements input#focus-blur-detector');
$this->assertEquals('no action detected', $focusBlurDetector->getValue());
$focusBlurDetector->focus();
$this->assertEquals('focused', $focusBlurDetector->getValue());
}
/**
* @group mouse-events
* @depends testFocus
*/
public function testBlur()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$focusBlurDetector = $this->getAssertSession()->elementExists('css', '.elements input#focus-blur-detector');
$this->assertEquals('no action detected', $focusBlurDetector->getValue());
$focusBlurDetector->blur();
$this->assertEquals('blured', $focusBlurDetector->getValue());
}
/**
* @group mouse-events
*/
public function testMouseOver()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$mouseOverDetector = $this->getAssertSession()->elementExists('css', '.elements div#mouseover-detector');
$this->assertEquals('no mouse action detected', $mouseOverDetector->getText());
$mouseOverDetector->mouseOver();
$this->assertEquals('mouse overed', $mouseOverDetector->getText());
}
/**
* @dataProvider provideKeyboardEventsModifiers
*/
public function testKeyboardEvents($modifier, $eventProperties)
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$webAssert = $this->getAssertSession();
$input1 = $webAssert->elementExists('css', '.elements input.input.first');
$input2 = $webAssert->elementExists('css', '.elements input.input.second');
$input3 = $webAssert->elementExists('css', '.elements input.input.third');
$event = $webAssert->elementExists('css', '.elements .text-event');
$input1->keyDown('u', $modifier);
$this->assertEquals('key downed:'.$eventProperties, $event->getText());
$input2->keyPress('r', $modifier);
$this->assertEquals('key pressed:114 / '.$eventProperties, $event->getText());
$input3->keyUp(78, $modifier);
$this->assertEquals('key upped:78 / '.$eventProperties, $event->getText());
}
public function provideKeyboardEventsModifiers()
{
return array(
'none' => array(null, '0 / 0 / 0 / 0'),
'alt' => array('alt', '1 / 0 / 0 / 0'),
// jQuery considers ctrl as being a metaKey in the normalized event
'ctrl' => array('ctrl', '0 / 1 / 0 / 1'),
'shift' => array('shift', '0 / 0 / 1 / 0'),
'meta' => array('meta', '0 / 0 / 0 / 1'),
);
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace Behat\Mink\Tests\Driver\Js;
use Behat\Mink\Tests\Driver\TestCase;
class JavascriptEvaluationTest extends TestCase
{
/**
* Tests, that `wait` method returns check result after exit.
*/
public function testWaitReturnValue()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$found = $this->getSession()->wait(5000, '$("#draggable").length == 1');
$this->assertTrue($found);
}
public function testWait()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$waitable = $this->findById('waitable');
$waitable->click();
$this->getSession()->wait(3000, '$("#waitable").has("div").length > 0');
$this->assertEquals('arrived', $this->getSession()->getPage()->find('css', '#waitable > div')->getText());
$waitable->click();
$this->getSession()->wait(3000, 'false');
$this->assertEquals('timeout', $this->getSession()->getPage()->find('css', '#waitable > div')->getText());
}
/**
* @dataProvider provideExecutedScript
*/
public function testExecuteScript($script)
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->getSession()->executeScript($script);
sleep(1);
$heading = $this->getAssertSession()->elementExists('css', 'h1');
$this->assertEquals('Hello world', $heading->getText());
}
public function provideExecutedScript()
{
return array(
array('document.querySelector("h1").textContent = "Hello world"'),
array('document.querySelector("h1").textContent = "Hello world";'),
array('function () {document.querySelector("h1").textContent = "Hello world";}()'),
array('function () {document.querySelector("h1").textContent = "Hello world";}();'),
array('(function () {document.querySelector("h1").textContent = "Hello world";})()'),
array('(function () {document.querySelector("h1").textContent = "Hello world";})();'),
);
}
/**
* @dataProvider provideEvaluatedScript
*/
public function testEvaluateJavascript($script)
{
$this->getSession()->visit($this->pathTo('/index.html'));
$this->assertSame(2, $this->getSession()->evaluateScript($script));
}
public function provideEvaluatedScript()
{
return array(
array('1 + 1'),
array('1 + 1;'),
array('return 1 + 1'),
array('return 1 + 1;'),
array('function () {return 1+1;}()'),
array('(function () {return 1+1;})()'),
array('return function () { return 1+1;}()'),
array('return (function () {return 1+1;})()'),
);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Behat\Mink\Tests\Driver\Js;
use Behat\Mink\Tests\Driver\TestCase;
class JavascriptTest extends TestCase
{
public function testAriaRoles()
{
$this->getSession()->visit($this->pathTo('/aria_roles.html'));
$this->getSession()->wait(5000, '$("#hidden-element").is(":visible") === false');
$this->getSession()->getPage()->pressButton('Toggle');
$this->getSession()->wait(5000, '$("#hidden-element").is(":visible") === true');
$this->getSession()->getPage()->clickLink('Go to Index');
$this->assertEquals($this->pathTo('/index.html'), $this->getSession()->getCurrentUrl());
}
public function testDragDrop()
{
$this->getSession()->visit($this->pathTo('/js_test.html'));
$webAssert = $this->getAssertSession();
$draggable = $webAssert->elementExists('css', '#draggable');
$droppable = $webAssert->elementExists('css', '#droppable');
$draggable->dragTo($droppable);
$this->assertEquals('Dropped!', $droppable->find('css', 'p')->getText());
}
// test accentuated char in button
public function testIssue225()
{
$this->getSession()->visit($this->pathTo('/issue225.html'));
$this->getSession()->getPage()->pressButton('Créer un compte');
$this->getSession()->wait(5000, '$("#panel").text() != ""');
$this->assertContains('OH AIH!', $this->getSession()->getPage()->getText());
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace Behat\Mink\Tests\Driver\Js;
use Behat\Mink\Tests\Driver\TestCase;
class WindowTest extends TestCase
{
public function testWindow()
{
$this->getSession()->visit($this->pathTo('/window.html'));
$session = $this->getSession();
$page = $session->getPage();
$webAssert = $this->getAssertSession();
$page->clickLink('Popup #1');
$session->switchToWindow(null);
$page->clickLink('Popup #2');
$session->switchToWindow(null);
$el = $webAssert->elementExists('css', '#text');
$this->assertSame('Main window div text', $el->getText());
$session->switchToWindow('popup_1');
$el = $webAssert->elementExists('css', '#text');
$this->assertSame('Popup#1 div text', $el->getText());
$session->switchToWindow('popup_2');
$el = $webAssert->elementExists('css', '#text');
$this->assertSame('Popup#2 div text', $el->getText());
$session->switchToWindow(null);
$el = $webAssert->elementExists('css', '#text');
$this->assertSame('Main window div text', $el->getText());
}
public function testGetWindowNames()
{
$this->getSession()->visit($this->pathTo('/window.html'));
$session = $this->getSession();
$page = $session->getPage();
$windowName = $this->getSession()->getWindowName();
$this->assertNotNull($windowName);
$page->clickLink('Popup #1');
$page->clickLink('Popup #2');
$windowNames = $this->getSession()->getWindowNames();
$this->assertNotNull($windowNames[0]);
$this->assertNotNull($windowNames[1]);
$this->assertNotNull($windowNames[2]);
}
public function testResizeWindow()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$session = $this->getSession();
$session->resizeWindow(400, 300);
$session->wait(1000, 'false');
$script = "return Math.abs(window.outerHeight - 300) <= 100 && Math.abs(window.outerWidth - 400) <= 100;";
$this->assertTrue($session->evaluateScript($script));
}
public function testWindowMaximize()
{
$this->getSession()->visit($this->pathTo('/index.html'));
$session = $this->getSession();
$session->maximizeWindow();
$session->wait(1000, 'false');
$script = "return Math.abs(screen.availHeight - window.outerHeight) <= 100;";
$this->assertTrue($session->evaluateScript($script));
}
}

View File

@ -0,0 +1,156 @@
<?php
namespace Behat\Mink\Tests\Driver;
use Behat\Mink\Exception\UnsupportedDriverActionException;
use Behat\Mink\Mink;
use Behat\Mink\Session;
use Behat\Mink\WebAssert;
abstract class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* Mink session manager.
*
* @var Mink
*/
private static $mink;
/**
* @var AbstractConfig
*/
private static $config;
/**
* Initializes the test case
*/
public static function setUpBeforeClass()
{
if (null === self::$mink) {
$session = new Session(self::getConfig()->createDriver());
self::$mink = new Mink(array('sess' => $session));
}
}
/**
* @return AbstractConfig
*
* @throws \UnexpectedValueException if the global driver_config_factory returns an invalid object
*/
private static function getConfig()
{
if (null === self::$config) {
self::$config = call_user_func($GLOBALS['driver_config_factory']);
if (!self::$config instanceof AbstractConfig) {
throw new \UnexpectedValueException('The "driver_config_factory" global variable must return a \Behat\Mink\Tests\Driver\AbstractConfig.');
}
}
return self::$config;
}
protected function checkRequirements()
{
if (null !== $message = self::getConfig()->skipMessage(get_class($this), $this->getName(false))) {
$this->markTestSkipped($message);
}
parent::checkRequirements();
}
protected function tearDown()
{
if (null !== self::$mink) {
self::$mink->resetSessions();
}
}
protected function onNotSuccessfulTest(\Exception $e)
{
if ($e instanceof UnsupportedDriverActionException) {
$this->markTestSkipped($e->getMessage());
}
parent::onNotSuccessfulTest($e);
}
/**
* Returns session.
*
* @return Session
*/
protected function getSession()
{
return self::$mink->getSession('sess');
}
/**
* Returns assert session.
*
* @return WebAssert
*/
protected function getAssertSession()
{
return self::$mink->assertSession('sess');
}
/**
* @param string $id
*
* @return \Behat\Mink\Element\NodeElement
*/
protected function findById($id)
{
$id = $this->getSession()->getSelectorsHandler()->xpathLiteral($id);
return $this->getAssertSession()->elementExists('named', array('id', $id));
}
/**
* Map remote file path.
*
* @param string $file File path.
*
* @return string
*/
protected function mapRemoteFilePath($file)
{
$realPath = realpath($file);
if (false !== $realPath) {
$file = $realPath;
}
return self::getConfig()->mapRemoteFilePath($file);
}
/**
* @param string $path
*
* @return string
*/
protected function pathTo($path)
{
return rtrim(self::getConfig()->getWebFixturesUrl(), '/').'/'.ltrim($path, '/');
}
/**
* Waits for a condition to be true, considering than it is successful for drivers not supporting wait()
*
* @param int $time
* @param string $condition A JS condition to evaluate
*
* @return bool
*
* @see \Behat\Mink\Session::wait()
*/
protected function safePageWait($time, $condition)
{
try {
return $this->getSession()->wait($time, $condition);
} catch (UnsupportedDriverActionException $e) {
return true;
}
}
}

View File

@ -0,0 +1,2 @@
<?php header("HTTP/1.0 404 Not Found") ?>
Sorry, page not found

View File

@ -0,0 +1,2 @@
<?php header("HTTP/1.0 500 Server Error") ?>
Sorry, a server error happened

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>ADvanced Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>ADvanced Form Page</h1>
<form method="POST" enctype="multipart/form-data" action="advanced_form_post.php">
<input name="first_name" value="Firstname" type="text" />
<input id="lastn" name="last_name" value="Lastname" type="text" />
<label for="email">
Your email:
<input type="email" id="email" name="email" value="your@email.com" />
</label>
<select name="select_number">
<option value="10">ten</option>
<option selected="selected" value="20">twenty</option>
<option value="30">thirty</option>
</select>
<label>
<span><input type="radio" name="sex" value="m" /> m</span>
<span><input type="radio" name="sex" value="w" checked="checked" /> w</span>
</label>
<input type="checkbox" name="mail_list" checked="checked" value="on"/>
<input type="checkbox" name="agreement" value="yes"/>
<textarea name="notes">original notes</textarea>
<input type="file" name="about" />
<input type="submit" name="submit" value="Register" />
<input type="submit" name="submit" value="Login" />
</form>
</body>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<title>Advanced form save</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
</head>
<body>
<?php
error_reporting(0);
if (isset($_POST['select_multiple_numbers']) && false !== strpos($_POST['select_multiple_numbers'][0], ',')) {
$_POST['select_multiple_numbers'] = explode(',', $_POST['select_multiple_numbers'][0]);
}
$_POST['agreement'] = isset($_POST['agreement']) ? 'on' : 'off';
ksort($_POST);
echo str_replace('>', '', var_export($_POST, true)) . "\n";
if (isset($_FILES['about']) && file_exists($_FILES['about']['tmp_name'])) {
echo $_FILES['about']['name'] . "\n";
echo file_get_contents($_FILES['about']['tmp_name']);
} else {
echo "no file";
}
?>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>ARIA roles test</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
This page tests selected ARIA roles<br />
(see <a href="http://www.w3.org/TR/wai-aria/">http://www.w3.org/TR/wai-aria/</a>)
<div id="hidden-element-toggle-button" role="button">Toggle</div>
<div id="hidden-element" style="display:none;">This content's visibility is changed by clicking the Toggle Button.</div>
<!-- This link is created programmatically -->
<div id="link-element"></div>
<script language="javascript" type="text/javascript" src="js/jquery-1.6.2-min.js"></script>
<script language="javascript" type="text/javascript">
$(document).ready(function() {
$('#hidden-element-toggle-button').click(function() {
$('#hidden-element').toggle();
});
$('#link-element').attr('role', 'link').text('Go to Index').click(function() {
window.location.href = 'index.html';
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,12 @@
<?php
$username = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : false;
$password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : false;
if ($username == 'mink-user' && $password == 'mink-password') {
echo 'is authenticated';
} else {
header('WWW-Authenticate: Basic realm="Mink Testing Area"');
header('HTTP/1.0 401 Unauthorized');
echo 'is not authenticated';
}

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>Basic Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Basic Form Page</h1>
<form method="POST" action="basic_form_post.php">
<input name="first_name" value="Firstname" type="text" />
<input id="lastn" name="last_name" value="Lastname" type="text" />
<input type="reset" id="Reset" />
<input type="submit" id="Save" />
<input type="image" id="input-type-image"/>
<button>button-without-type</button>
<button type="submit">button-type-submit</button>
</form>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>Basic Form Saving</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Anket for <?php echo $_POST['first_name'] ?></h1>
<span id="first">Firstname: <?php echo $_POST['first_name'] ?></span>
<span id="last">Lastname: <?php echo $_POST['last_name'] ?></span>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Basic Get Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Basic Get Form Page</h1>
<div id="serach">
<?php echo isset($_GET['q']) && $_GET['q'] ? $_GET['q'] : 'No search query' ?>
</div>
<form>
<input name="q" value="" type="text" />
<input type="submit" value="Find" />
</form>
</body>
</html>

View File

@ -0,0 +1,21 @@
<?php
if (!isset($cookieAtRootPath)) {
$cookieAtRootPath = true;
}
if (!isset($cookieValue)) {
$cookieValue = 'srv_var_is_set';
}
setcookie('srvr_cookie', $cookieValue, null, $cookieAtRootPath ? '/' : null);
?>
<!DOCTYPE html>
<html>
<head>
<title>Basic Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
Basic Page With Cookie Set from Server Side
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Basic Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
Previous cookie: <?php echo isset($_COOKIE['srvr_cookie']) ? $_COOKIE['srvr_cookie'] : 'NO'; ?>
</body>
</html>

View File

@ -0,0 +1,16 @@
<?php
$hasCookie = isset($_COOKIE['foo']);
setcookie('foo', 'bar', 0, '/', null, false, true);
?>
<!DOCTYPE html>
<html>
<head>
<title>HttpOnly Cookie Test</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div id="cookie-status">Has Cookie: <?php echo json_encode($hasCookie) ?></div>
</body>
</html>

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>CSS Mouse Events Testing</title>
<style type="text/css">
.squares div {
width: 100px;
height: 100px;
border: 1px solid black;
margin-right: 4px;
float: left;
}
.squares div:hover {
height: 200px;
background-color: red;
}
</style>
<script language="javascript" type="text/javascript" src="js/jquery-1.6.2-min.js"></script>
</head>
<body>
<div class="squares">
<div id="reset-square">reset</div>
<div id="action-square">mouse action</div>
</div>
<script>
$('#action-square').bind('contextmenu', function (e) {
// Prevent opening the context menu on right click as the browser might consider the
// mouse is in the context menu rather than hovering the element
e.preventDefault();
});
</script>
</body>
</html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE html>
<html>
<head>
<title>ADvanced Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<script src="js/jquery-1.6.2-min.js"></script>
</head>
<body>
<h1>ADvanced Form Page</h1>
<form method="POST" enctype="multipart/form-data" action="advanced_form_post.php">
<input id="the-input-default" value="" />
<input type="text" id="the-input-text" value="" />
<input type="email" id="the-email" value="" />
<select id="the-select">
<option value="10">ten</option>
<option value="20" selected="selected">twenty</option>
<option value="30">thirty</option>
</select>
<label>
<span><input type="radio" name="sex" id="the-radio-m" value="m" /> m</span>
<span><input type="radio" name="sex" id="the-radio-w" value="w" checked="checked" /> w</span>
</label>
<input type="checkbox" id="the-checked-checkbox" value="cb-val" checked/>
<input type="checkbox" id="the-unchecked-checkbox" value="cb-val"/>
<textarea id="the-textarea"></textarea>
<input type="file" id="the-file" />
</form>
<ul id="results" style="border: 1px solid red;">
<li>for easy element location</li>
</ul>
<script type="text/javascript">
$(document).ready(function () {
var $change_registry = {},
$results = $('#results');
$(':input').change(function ($e) {
var $result_id = this.id + '-result';
if (!$change_registry[this.id]) {
$change_registry[this.id] = 1;
$results.append('<li id="' + $result_id + '"></li>');
}
else {
$change_registry[this.id]++;
}
$('#' + $result_id).text($change_registry[this.id]);
});
$results.click(function () {
$results.empty();
$change_registry = {};
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Empty textarea submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>Empty textarea submission</h1>
<form method="POST" action="advanced_form_post.php">
<textarea name="textarea"></textarea>
<input type="submit" name="submit" value="Save" />
</form>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Form submission without button test</title>
</head>
<body>
<form action="basic_form_post.php" method="POST">
<input name="first_name" type="text" value="not set">
<input name="last_name" type="text" value="not set">
</form>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Headers page</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<?php print_r($_SERVER); ?>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML5 form attribute test</title>
</head>
<body>
<form action="advanced_form_post.php" method="POST" id="test-form">
<input name="first_name" type="text" value="not set">
<input name="other_field" type="text" value="not submitted" form="another">
<input type="submit" value="Submit separate form" form="another">
<input type="submit" value="Submit in form">
</form>
<input name="last_name" type="text" form="test-form" value="not set">
<button type="submit" form="test-form" name="submit_button" value="test">Submit outside form</button>
<form id="another" method="post" action="advanced_form_post.php"></form>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML5 form attribute test</title>
</head>
<body>
<form action="advanced_form_post.php" method="POST" id="test-form">
<input name="sex" type="radio" value="m" id="sex_m">
<input name="sex" type="radio" value="invalid" form="another" id="sex_invalid" checked="checked">
<input type="submit" value="Submit in form">
</form>
<input name="sex" type="radio" form="test-form" value="f" id="sex_f" checked="checked">
<form id="another" method="post" action="advanced_form_post.php"></form>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML5 form attribute test</title>
</head>
<body>
<form action="advanced_form_post.php" method="POST">
<input name="url" type="url">
<input name="email" type="email">
<input name="number" type="number">
<input name="search" type="search">
<input name="color" type="color">
<input name="date" type="date">
<input type="submit" name="submit_button" value="Submit">
</form>
</body>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>HTML Decoding Test</title>
</head>
<body>
<div>
<span custom-attr="&amp;">some text</span>
<form method="post" action="index.html">
<input value="&amp;"/>
<input type="submit" value="Send"/>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<body>
<iframe src="iframe_inner.html" name="subframe"></iframe>
<div id="text">
Main window div text
</div>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<body>
<div id="text">
iFrame div text
</div>
</body>
</html>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>Index page</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Extremely useless page</h1>
<div id="core">
<strong>Lorem</strong> ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim <strong>veniam</strong>, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla <strong class="super-duper">pariatur</strong>. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
<div id="some-element" data-href="http://mink.behat.org">
some <div>very
</div>
<em>interesting</em> text
</div>
<div class="attribute-testing">
<input type="text" id="attr-elem[with-value]" with-value="some-value"/>
<input type="text" id="attr-elem[without-value]" without-value/>
<input type="text" id="attr-elem[with-empty-value]" with-empty-value=""/>
<input type="text" id="attr-elem[with-missing]"/>
</div>
<div class="travers">
<div class="sub">el1</div>
<div class="sub">el2</div>
<div class="sub">
<a href="some_url">some <strong>deep</strong> url</a>
</div>
</div>
<div class="sub">el4</div>
</div>
<footer>
<form id="search-form">
<input type="text" placeholder="Search site..." />
</form>
<form id="profile">
<div data-custom="something">
<label>
<input type="text" id="user-name" name="username" />
</label>
</div>
<input type="submit" />
</form>
</footer>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More