Skip to content
Snippets Groups Projects
Commit d7c0ed12 authored by Demian Katz's avatar Demian Katz
Browse files

Installed Mink w/ Zombie driver.

parent 08510413
No related merge requests found
Showing
with 2512 additions and 3 deletions
......@@ -4,7 +4,7 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "828ea6c9391fbecaa3c42071bdcfe98a",
"hash": "d5901d4c84a7e286ec6f2076c447928c",
"packages": [
{
"name": "aferrandini/phpqrcode",
......@@ -952,7 +952,219 @@
"time": "2014-03-05 22:25:44"
}
],
"packages-dev": [],
"packages-dev": [
{
"name": "behat/mink",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/Behat/Mink.git",
"reference": "090900a0049c441f1e072bbd837db4079b2250c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Behat/Mink/zipball/090900a0049c441f1e072bbd837db4079b2250c5",
"reference": "090900a0049c441f1e072bbd837db4079b2250c5",
"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-0": {
"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": "Web acceptance testing framework for PHP 5.3",
"homepage": "http://mink.behat.org/",
"keywords": [
"browser",
"testing",
"web"
],
"time": "2014-09-26 09:25:05"
},
{
"name": "behat/mink-zombie-driver",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/Behat/MinkZombieDriver.git",
"reference": "cf15a3a0cc4865bb55253cd033a03a20cee6d2d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Behat/MinkZombieDriver/zipball/cf15a3a0cc4865bb55253cd033a03a20cee6d2d1",
"reference": "cf15a3a0cc4865bb55253cd033a03a20cee6d2d1",
"shasum": ""
},
"require": {
"behat/mink": "~1.6@dev",
"php": ">=5.3.1",
"symfony/process": "~2.1"
},
"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"
},
{
"name": "Pascal Cremer",
"email": "b00gizm@gmail.com",
"homepage": "http://github.com/b00gizm"
}
],
"description": "Zombie.js driver for Mink framework",
"homepage": "http://mink.behat.org/",
"keywords": [
"ajax",
"browser",
"headless",
"javascript",
"testing",
"zombie"
],
"time": "2014-09-26 12:26:25"
},
{
"name": "symfony/css-selector",
"version": "v2.5.6",
"target-dir": "Symfony/Component/CssSelector",
"source": {
"type": "git",
"url": "https://github.com/symfony/CssSelector.git",
"reference": "7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/CssSelector/zipball/7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc",
"reference": "7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\CssSelector\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Jean-François Simon",
"email": "jeanfrancois.simon@sensiolabs.com"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony CssSelector Component",
"homepage": "http://symfony.com",
"time": "2014-10-09 16:00:03"
},
{
"name": "symfony/process",
"version": "v2.5.6",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
"reference": "9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Process/zipball/9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a",
"reference": "9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Process\\": ""
}
},
"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 Process Component",
"homepage": "http://symfony.com",
"time": "2014-10-01 05:50:18"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
......
......@@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInitc013b6451947464e0d11177f185bf9eb::getLoader();
return ComposerAutoloaderInitc4a65bc36a0c8ed2b8f3216ed09d18dc::getLoader();
vendor
composer.phar
composer.lock
phpunit.xml
node_modules
language: php
php: [5.3, 5.4, 5.5, 5.6, hhvm]
before_script:
- export WEB_FIXTURES_HOST=http://localhost
# Install deps
- composer install --dev --prefer-source
- sudo apt-get update > /dev/null
- 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
- npm install zombie
- export NODE_PATH="$(pwd)/node_modules"
- export PATH="/usr/local/share/npm/bin:$PATH"
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
1.2.0 / 2014-09-26
==================
BC break:
* Rewrote the driver based on Zombie 2.0 rather than the old 1.x versions
* Changed the behavior of `getValue` for checkboxes according to the BC break in Mink 1.6
New features:
* Added the support of select elements in `setValue`
* Implemented `getOuterHtml`
* Added support for request headers
* Implemented `submitForm`
* Implemented `isSelected`
Bug fixes:
* Fixed the selection of options for multiple selects to ensure the change event is triggered only once
* Fixed the selection of options for radio groups
* Fixed `getValue` for radio groups
* Fixed the retrieval of response headers
* Fixed a leak of outdated references in the node server when changing page
* Fixed the resetting of the driver to reset everything
* Fixed the code to throw exceptions for invalid usages of the driver
* Fixed handling of errors to throw exceptions in the driver rather than crashing the node server
* Fixed `evaluateScript` and `executeScript` to support all syntaxes required by the Mink API
* Fixed `getContent` to return the source of the page without decoding entities
* Fixed the removal of cookies
* Fixed the basic auth implementation
Testing:
* Updated the testsuite to use the new Mink 1.6 driver testsuite
* Added testing on HHVM
Mink Zombie.js Driver
=====================
[![Latest Stable Version](https://poser.pugx.org/behat/mink-zombie-driver/v/stable.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
[![Latest Unstable Version](https://poser.pugx.org/behat/mink-zombie-driver/v/unstable.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
[![Total Downloads](https://poser.pugx.org/behat/mink-zombie-driver/downloads.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
[![Build Status](https://travis-ci.org/Behat/MinkZombieDriver.svg?branch=master)](https://travis-ci.org/Behat/MinkZombieDriver)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/badges/quality-score.png?s=2e166ed0bc0d8bfde427fb9af2a93aaabbc09723)](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/)
[![Code Coverage](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/badges/coverage.png?s=f271ed5a203ed036c6ce093e5269b60a76951f4f)](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/)
[![License](https://poser.pugx.org/behat/mink-zombie-driver/license.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
Installation & Compatibility
----------------------------
You need a working installation of [NodeJS](http://nodejs.org/) and
[npm](https://npmjs.org/). Install the
[zombie.js](http://zombie.labnotes.org) library through npm:
``` bash
npm install -g zombie
```
The driver requires zombie.js __version 2.0.0 or higher__.
Use [Composer](https://getcomposer.org/) to install all required PHP dependencies:
```json
{
"require": {
"behat/mink": "~1.6",
"behat/mink-zombie-driver": "~1.2"
}
}
```
```bash
$> curl -sS https://getcomposer.org/installer | php
$> php composer.phar install
```
Usage Example
-------------
```php
<?php
use Behat\Mink\Mink,
Behat\Mink\Session,
Behat\Mink\Driver\ZombieDriver,
Behat\Mink\Driver\NodeJS\Server\ZombieServer;
$host = '127.0.0.1';
$port = '8124';
$nodeBinary = '/usr/local/bin/node';
$mink = new Mink(array(
'zombie' => new Session(new ZombieDriver(new ZombieServer(
$host, $port, $nodeBinary
))),
));
$mink->setDefaultSessionName('zombie');
$session = $mink->getSession();
$session->visit('http://example.org');
$page = $session->getPage();
$elem = $page->find('css', 'h1');
echo $elem->getText();
```
Copyright
---------
Copyright (c) 2011-2012 Pascal Cremer <b00gizm@gmail.com>
Maintainers
-----------
* Alexander Obuhovich [aik099](http://github.com/aik099)
{
"name": "behat/mink-zombie-driver",
"description": "Zombie.js driver for Mink framework",
"keywords": ["zombie", "headless", "javascript", "ajax", "testing", "browser"],
"homepage": "http://mink.behat.org/",
"type": "mink-driver",
"license": "MIT",
"authors": [
{
"name": "Pascal Cremer",
"email": "b00gizm@gmail.com",
"homepage": "http://github.com/b00gizm"
},
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
}
],
"require": {
"php": ">=5.3.1",
"behat/mink": "~1.6@dev",
"symfony/process": "~2.1"
},
"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"
}
}
}
<?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</directory>
</testsuite>
</testsuites>
<php>
<var name="driver_config_factory" value="Behat\Mink\Tests\Driver\ZombieConfig::getInstance" />
<!--server name="WEB_FIXTURES_HOST" value="http://test.mink.dev" /-->
<!--server name="NODE_MODULES_PATH" value="path/to/ZombieDriver/node_modules/" /-->
</php>
<filter>
<whitelist>
<directory>./src/Behat/Mink/Driver</directory>
</whitelist>
</filter>
</phpunit>
<?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\NodeJS;
/**
* The connection to the node TCP server.
*
* @author Pascal Cremer <b00gizm@gmail.com>
*/
class Connection
{
/**
* @var string
*/
private $host = null;
/**
* @var integer
*/
private $port = null;
/**
* Initializes connection instance.
*
* @param string $host zombie.js server host
* @param integer $port zombie.js server port
*/
public function __construct($host = '127.0.0.1', $port = 8124)
{
$this->host = $host;
$this->port = intval($port);
}
/**
* Returns connection host.
*
* @return string
*/
public function getHost()
{
return $this->host;
}
/**
* Returns connection port.
*
* @return int
*/
public function getPort()
{
return $this->port;
}
/**
* Sends a payload string of Javascript code to the Zombie Node.js server.
*
* @param string $js String of Javascript code
*
* @return string
*
* @throws \RuntimeException Could not establish connection
*/
public function socketSend($js)
{
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (false === @socket_connect($socket, $this->host, $this->port)) {
$errno = socket_last_error();
throw new \RuntimeException(
sprintf(
"Could not establish connection: %s (%s)",
socket_strerror($errno),
$errno
)
);
}
socket_write($socket, $js, strlen($js));
socket_shutdown($socket, 1);
$out = '';
while ($o = socket_read($socket, 2048)) {
$out .= $o;
}
socket_close($socket);
return $out;
}
}
<?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\NodeJS;
use Symfony\Component\Process\ProcessBuilder;
use Symfony\Component\Process\Process;
/**
* Abstract base class to start and connect to a NodeJS server process.
*
* @author Pascal Cremer <b00gizm@gmail.com>
*/
abstract class Server
{
/**
* @var string
*/
protected $host;
/**
* @var int
*/
protected $port;
/**
* @var string
*/
protected $nodeBin;
/**
* @var string
*/
protected $serverPath;
/**
* @var int
*/
protected $threshold;
/**
* @var string The full path to the NodeJS modules directory.
*/
protected $nodeModulesPath;
/**
* @var Process
*/
protected $process;
/**
* @var Connection
*/
protected $connection;
/**
* Constructor
*
* @param string $host The server host
* @param int $port The server port
* @param string $nodeBin Path to NodeJS binary
* @param string $serverPath Path to server script
* @param int $threshold Threshold value in micro seconds
* @param string $nodeModulesPath Path to node_modules directory
*/
public function __construct(
$host = '127.0.0.1',
$port = 8124,
$nodeBin = null,
$serverPath = null,
$threshold = 2000000,
$nodeModulesPath = ''
) {
if (null === $nodeBin) {
$nodeBin = 'node';
}
$this->host = $host;
$this->port = intval($port);
$this->nodeBin = $nodeBin;
$this->nodeModulesPath = $nodeModulesPath;
if (null === $serverPath) {
$serverPath = $this->createTemporaryServer();
}
$this->serverPath = $serverPath;
$this->threshold = intval($threshold);
}
/**
* Destructor
*
* Make sure that current process is stopped
*/
public function __destruct()
{
$this->stop();
}
/**
* Setter host
*
* @param string $host The server host
*/
public function setHost($host)
{
$this->host = $host;
}
/**
* Getter host
*
* @return string The server host
*/
public function getHost()
{
return $this->host;
}
/**
* Setter port
*
* @param int $port The server port
*/
public function setPort($port)
{
$this->port = intval($port);
}
/**
* Getter port
*
* @return int The server port
*/
public function getPort()
{
return $this->port;
}
/**
* Setter NodeJS binary path
*
* @param string $nodeBin Path to NodeJS binary
*/
public function setNodeBin($nodeBin)
{
$this->nodeBin = $nodeBin;
}
/**
* Getter NodeJS binary path
*
* @return string Path to NodeJS binary
*/
public function getNodeBin()
{
return $this->nodeBin;
}
/**
* Setter NodeJS modules path
*
* @param string $nodeModulesPath Path to NodeJS modules.
* @throws \InvalidArgumentException Invalid path
*/
public function setNodeModulesPath($nodeModulesPath)
{
if (!is_dir($nodeModulesPath) || !preg_match('/\/$/', $nodeModulesPath)) {
throw new \InvalidArgumentException(sprintf(
"Node modules path '%s' is not a directory and/or does not end with a trailing '/'",
$nodeModulesPath
));
}
$this->nodeModulesPath = $nodeModulesPath;
$this->serverPath = $this->createTemporaryServer();
}
/**
* Getter NodeJS modules path.
*
* @return string Path to NodeJS binary.
*/
public function getNodeModulesPath()
{
return $this->nodeModulesPath;
}
/**
* Setter server script path
*
* @param string $serverPath Path to server script
*/
public function setServerPath($serverPath)
{
$this->serverPath = $serverPath;
}
/**
* Getter server script path
*
* @return string Path to server script
*/
public function getServerPath()
{
return $this->serverPath;
}
/**
* Setter threshold value
*
* @param int $threshold Threshold value in micro seconds
*/
public function setThreshold($threshold)
{
$this->threshold = intval($threshold);
}
/**
* Getter threshold value
*
* @return int Threshold value in micro seconds
*/
public function getThreshold()
{
return $this->threshold;
}
/**
* Getter process object
*
* @return Process The process object
*/
public function getProcess()
{
return $this->process;
}
/**
* Getter connection object
*
* @return Connection
*/
public function getConnection()
{
return $this->connection;
}
/**
* Starts the server process
*
* @param Process $process A process object
*
* @throws \RuntimeException
*/
public function start(Process $process = null)
{
// Check if the server script exists at given path
if (false === $this->serverPath || false === is_file($this->serverPath)) {
throw new \RuntimeException(sprintf(
"Could not find server script at path '%s'",
$this->serverPath
));
}
// Create process object if neccessary
if (null === $process) {
$processBuilder = new ProcessBuilder(array(
$this->nodeBin,
$this->serverPath,
));
$process = $processBuilder->getProcess();
}
$this->process = $process;
// Start server process
$this->process->start();
$this->connection = null;
// Wait for the server to start up
$time = 0;
$successString = sprintf("server started on %s:%s", $this->host, $this->port);
while ($this->process->isRunning() && $time < $this->threshold) {
if ($successString == trim($this->process->getOutput())) {
$this->connection = new Connection($this->host, $this->port);
break;
}
usleep(1000);
$time += 1000;
}
// Make sure the server is ready or throw an exception otherwise
$this->checkAvailability();
}
/**
* Stops the server process
* @link https://github.com/symfony/Process
*/
public function stop()
{
if (null === $this->process) {
return;
}
if (!$this->isRunning()) {
return;
}
if (null !== $this->getConnection()) {
// Force a 'clean' exit
// See: http://stackoverflow.com/a/5266208/187954
$this->doEvalJS($this->getConnection(), 'process.exit(0);');
$this->process->stop();
$this->process = null;
}
}
/**
* Restarts the server process
*
* @param Process $process A process object
*/
public function restart(Process $process = null)
{
$this->stop();
$this->start($process);
}
/**
* Checks if the server process is running
*
* @link https://github.com/symfony/Process
*
* @return bool
*/
public function isRunning()
{
if (null === $this->process) {
return false;
}
return $this->process->isRunning();
}
/**
* Checks the availability of the server triggers the evaluation
* of a string of JavaScript code by {{Behat\Mink\Driver\NodeJS\Server::doEvalJS()}}
*
* @param string $str String of JavaScript code
* @param string $returnType Whether it should be eval'ed as JavaScript or wrapped in a JSON response
*
* @return mixed The eval'ed response
*/
public function evalJS($str, $returnType = 'js')
{
$this->checkAvailability();
return $this->doEvalJS($this->connection, $str, $returnType);
}
/**
* Inherited classes will implement this method to prepare a string of
* JavaScript code for evaluation by the server and sending it over
* the server connection socket
*
* @param Connection $conn The server connection
* @param string $str String of JavaScript code
* @param string $returnType The return type
*
* @return mixed The eval'ed response
*
* @throws \InvalidArgumentException When unsupported $returnType given.
*/
abstract protected function doEvalJS(Connection $conn, $str, $returnType = 'js');
/**
* Checks whether server connection and server process are still available
* and running
*
* @throws \RuntimeException
*/
protected function checkAvailability()
{
if (null === $this->connection) {
if (null === $this->process) {
throw new \RuntimeException('No connection available. Did you start the server?');
}
if ($this->process->isRunning()) {
$this->stop();
throw new \RuntimeException(sprintf(
'Server did not respond in time: (%s) [Stopped]',
$this->process->getExitCode()
));
}
}
if (!$this->process->isRunning()) {
throw new \RuntimeException(sprintf(
'Server process has been terminated: (%s) [%s]',
$this->process->getExitCode(),
$this->process->getErrorOutput()
));
}
}
/**
* Creates a temporary server script
*
* @return string Path to the temporary server script
*/
protected function createTemporaryServer()
{
$serverScript = strtr($this->getServerScript(), array(
'%host%' => $this->host,
'%port%' => $this->port,
'%modules_path%' => $this->nodeModulesPath,
));
$serverPath = tempnam(sys_get_temp_dir(), 'mink_nodejs_server');
file_put_contents($serverPath, $serverScript);
return $serverPath;
}
/**
* Inherited classes will implement this method to provide the JavaScript
* code which powers the server script
*
* @return string The server's JavaScript code
*/
abstract protected function getServerScript();
}
<?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\NodeJS\Server;
use Behat\Mink\Driver\NodeJS\Connection;
use Behat\Mink\Driver\NodeJS\Server;
use Behat\Mink\Exception\DriverException;
class ZombieServer extends Server
{
const ERROR_PREFIX = 'CAUGHT_ERROR:';
/**
* {@inheritdoc}
*/
protected function doEvalJS(Connection $conn, $str, $returnType = 'js')
{
switch ($returnType) {
case 'js':
$result = $conn->socketSend($str);
break;
case 'json':
$result = $conn->socketSend("stream.end(JSON.stringify({$str}))");
break;
default:
throw new \InvalidArgumentException(sprintf('Invalid return type "%s"', $returnType));
}
$errorPrefixLength = strlen(self::ERROR_PREFIX);
if (self::ERROR_PREFIX === substr($result, 0, $errorPrefixLength)) {
$errorMessage = json_decode(substr($result, $errorPrefixLength), true);
throw new DriverException(sprintf('Error "%s" while executing code: %s', $errorMessage, $str));
}
if ('json' === $returnType) {
return json_decode($result);
}
return $result;
}
/**
* {@inheritdoc}
*/
protected function getServerScript()
{
$errorPrefix = self::ERROR_PREFIX;
$js = <<<JS
var net = require('net')
, zombie = require('%modules_path%zombie')
, Tough = require('%modules_path%zombie/node_modules/tough-cookie')
, browser = null
, pointers = []
, buffer = ''
, host = '%host%'
, port = %port%;
Tough.Cookie.prototype.cookieString = function cookieString() {
return this.key + '=' + (this.value == null ? '' : this.value);
};
var zombieVersionCompare = function (v2, op) {
var version_compare = function (v1, v2, operator) {
var i = 0,
x = 0,
compare = 0,
vm = {
'dev': -6,
'alpha': -5,
'a': -5,
'beta': -4,
'b': -4,
'RC': -3,
'rc': -3,
'#': -2,
'p': 1,
'pl': 1
},
prepVersion = function (v) {
v = ('' + v).replace(/[_\-+]/g, '.');
v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
return (!v.length ? [-8] : v.split('.'));
},
numVersion = function (v) {
return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
};
v1 = prepVersion(v1);
v2 = prepVersion(v2);
x = Math.max(v1.length, v2.length);
for (i = 0; i < x; i++) {
if (v1[i] == v2[i]) {
continue;
}
v1[i] = numVersion(v1[i]);
v2[i] = numVersion(v2[i]);
if (v1[i] < v2[i]) {
compare = -1;
break;
} else if (v1[i] > v2[i]) {
compare = 1;
break;
}
}
if (!operator) {
return compare;
}
switch (operator) {
case '>':
case 'gt':
return (compare > 0);
case '>=':
case 'ge':
return (compare >= 0);
case '<=':
case 'le':
return (compare <= 0);
case '==':
case '=':
case 'eq':
return (compare === 0);
case '<>':
case '!=':
case 'ne':
return (compare !== 0);
case '':
case '<':
case 'lt':
return (compare < 0);
}
return null;
};
return version_compare(require('%modules_path%zombie/package').version, v2, op);
};
if (false == zombieVersionCompare('2.0.0', '>=')) {
throw new Error("Your zombie.js version is not compatible with this driver. Please use a version >= 2.0.0");
}
net.createServer(function (stream) {
stream.setEncoding('utf8');
stream.allowHalfOpen = true;
stream.on('data', function (data) {
buffer += data;
});
stream.on('end', function () {
if (browser == null) {
browser = new zombie();
// Clean up old pointers
pointers = [];
}
try {
eval(buffer);
buffer = '';
} catch (e) {
buffer = '';
stream.end('{$errorPrefix}' + JSON.stringify(e.message));
}
});
}).listen(port, host, function () {
console.log('server started on ' + host + ':' + port);
});
JS;
return $js;
}
}
This diff is collapsed.
<?php
namespace Behat\Mink\Tests\Driver\Custom;
use Behat\Mink\Tests\Driver\TestCase;
/**
* @group zombiedriver
*/
class ExtraTest extends TestCase
{
// TODO move upstream
public function testSetUserAgent()
{
$session = $this->getSession();
$session->setRequestHeader('user-agent', 'foo bar');
$session->visit($this->pathTo('/headers.php'));
$this->assertContains('foo bar', $session->getPage()->getText());
}
// TODO check whether this is covered by upstream test
public function testSetRequestHeader()
{
$this->getSession()->setRequestHeader('foo', 'bar');
$this->getSession()->visit($this->pathTo('/headers.php'));
$this->assertContains('[HTTP_FOO] => bar', $this->getSession()->getPage()->getText());
}
}
<?php
namespace Behat\Mink\Tests\Driver\Custom\NodeJS;
use Behat\Mink\Driver\NodeJS\Connection;
use Behat\Mink\Driver\NodeJS\Server as BaseServer;
class TestServer extends BaseServer
{
public $serverScript = null;
protected function doEvalJS(Connection $conn, $str, $returnType = 'js')
{
return '';
}
protected function getServerScript()
{
return <<<JS
var zombie = require('%modules_path%zombie')
, host = '%host%'
, port = %port%;
JS;
}
protected function createTemporaryServer()
{
$this->serverScript = strtr($this->getServerScript(), array(
'%host%' => $this->host,
'%port%' => $this->port,
'%modules_path%' => $this->nodeModulesPath,
));
return '/path/to/server';
}
}
class ServerTest extends \PHPUnit_Framework_TestCase
{
public function testCreateServerWithDefaults()
{
$server = new TestServer();
$this->assertEquals('127.0.0.1', $server->getHost());
$this->assertEquals(8124, $server->getPort());
$this->assertEquals('node', $server->getNodeBin());
$this->assertEquals('/path/to/server', $server->getServerPath());
$this->assertEquals(2000000, $server->getThreshold());
$this->assertEquals('', $server->getNodeModulesPath());
$expected = <<<JS
var zombie = require('zombie')
, host = '127.0.0.1'
, port = 8124;
JS;
$this->assertEquals($expected, $server->serverScript);
}
public function testCreateCustomServer()
{
$server = new TestServer(
'123.123.123.123',
1234,
null,
null,
5000000,
'../../'
);
$this->assertEquals('123.123.123.123', $server->getHost());
$this->assertEquals(1234, $server->getPort());
$this->assertEquals('node', $server->getNodeBin());
$this->assertEquals('/path/to/server', $server->getServerPath());
$this->assertEquals(5000000, $server->getThreshold());
$this->assertEquals('../../', $server->getNodeModulesPath());
$expected = <<<JS
var zombie = require('../../zombie')
, host = '123.123.123.123'
, port = 1234;
JS;
$this->assertEquals($expected, $server->serverScript);
}
public function testSetNodeModulesPath()
{
$server = new TestServer();
$server->setNodeModulesPath('../../');
$this->assertEquals('../../', $server->getNodeModulesPath());
$expected = <<<JS
var zombie = require('../../zombie')
, host = '127.0.0.1'
, port = 8124;
JS;
$this->assertEquals($expected, $server->serverScript);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testSetNodeModulesPathWithInvalidPath()
{
$server = new TestServer();
$server->setNodeModulesPath('/does/not/exist/');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testSetNodeModulesPathWithoutTrailingSlash()
{
$server = new TestServer();
$server->setNodeModulesPath('../..');
}
/**
* @expectedException \RuntimeException
*/
public function testStartServerWithNonExistingServerScript()
{
$server = new TestServer('127.0.0.1', 8124, null, '/does/not/exist');
$server->start();
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Server did not respond in time: (1) [Stopped]
*/
public function testStartServerThatDoesNotRespondInTime()
{
$process = $this->getNotRespondingServerProcessMock();
$process->expects($this->once())
->method('start');
$serverPath = __DIR__.'/server-fixtures/test_server.js';
$server = new TestServer('127.0.0.1', 8124, null, $serverPath, 10000);
$server->start($process);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Server process has been terminated: (1) [TROLOLOLO]
*/
public function testStartServerThatWasTerminated()
{
$process = $this->getTerminatedServerProcessMock();
$process->expects($this->once())
->method('start');
$serverPath = __DIR__.'/server-fixtures/test_server.js';
$server = new TestServer('127.0.0.1', 8124, null, $serverPath, 10000);
$server->start($process);
}
public function testStartServerSuccessfully()
{
$host = '127.0.0.1';
$port = 8124;
$process = $this->getWorkingServerProcessMock($host, $port);
$process->expects($this->once())
->method('start');
$serverPath = __DIR__.'/server-fixtures/test_server.js';
$server = new TestServer($host, $port, null, $serverPath, 10000);
try {
$server->start($process);
$this->assertInstanceOf(
'Behat\Mink\Driver\NodeJS\Connection',
$server->getConnection()
);
} catch (\RuntimeException $ex) {
$this->fail('No exception should have been thrown here');
}
}
public function testStopServer()
{
$host = '127.0.0.1';
$port = 8124;
$process = $this->getWorkingServerProcessMock($host, $port);
$process->expects($this->atLeastOnce())
->method('stop');
$serverPath = __DIR__.'/server-fixtures/test_server.js';
$server = new TestServer($host, $port, null, $serverPath, 10000);
$server->start($process);
$server->stop();
}
public function testIsRunning()
{
$host = '127.0.0.1';
$port = 8124;
$serverPath = __DIR__.'/server-fixtures/test_server.js';
$server = new TestServer($host, $port, null, $serverPath, 10000);
$this->assertFalse($server->isRunning());
$process = $this->getWorkingServerProcessMock($host, $port);
$server->start($process);
$this->assertTrue($server->isRunning());
$process = $this->getTerminatedServerProcessMock();
try {
$server->start($process);
} catch (\RuntimeException $ex) {
// ignore error
}
$this->assertFalse($server->isRunning());
}
protected function getNotRespondingServerProcessMock()
{
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$process->expects($this->any())
->method('isRunning')
->will($this->returnValue(true));
$process->expects($this->any())
->method('getOutput')
->will($this->returnValue(''));
$process->expects($this->any())
->method('getExitCode')
->will($this->returnValue(1));
return $process;
}
protected function getTerminatedServerProcessMock()
{
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$process->expects($this->any())
->method('isRunning')
->will($this->returnValue(false));
$process->expects($this->any())
->method('getErrorOutput')
->will($this->returnValue('TROLOLOLO'));
$process->expects($this->any())
->method('getExitCode')
->will($this->returnValue(1));
return $process;
}
protected function getWorkingServerProcessMock($host, $port)
{
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$process->expects($this->any())
->method('isRunning')
->will($this->returnValue(true));
$process->expects($this->once())
->method('getOutput')
->will($this->returnValue(sprintf("server started on %s:%s", $host, $port)));
return $process;
}
}
// Nothing in here.
var net = require('net');
net.createServer(function (stream) {
// This server does nothing.
}).listen(8124, '127.0.0.1');
console.log('Server running at 127.0.0.1:8124');
<?php
namespace Behat\Mink\Tests\Driver;
use Behat\Mink\Driver\NodeJS\Server\ZombieServer;
use Behat\Mink\Driver\ZombieDriver;
class ZombieConfig extends AbstractConfig
{
public static function getInstance()
{
return new self();
}
/**
* {@inheritdoc}
*/
public function createDriver()
{
$server = new ZombieServer('127.0.0.1', 8124, 'node');
if (isset($_SERVER['NODE_MODULES_PATH'])) {
$server->setNodeModulesPath($_SERVER['NODE_MODULES_PATH']);
}
return new ZombieDriver($server);
}
/**
* {@inheritdoc}
*/
public function skipMessage($testCase, $test)
{
if (
'Behat\Mink\Tests\Driver\Form\Html5Test' === $testCase
&& in_array($test, array(
'testHtml5FormInputAttribute',
'testHtml5FormButtonAttribute',
'testHtml5FormOutside',
'testHtml5FormRadioAttribute',
))
) {
return 'Zombie.js doesn\'t HTML5 form attributes. See https://github.com/assaf/zombie/issues/635';
}
if (
'Behat\Mink\Tests\Driver\Js\JavascriptEvaluationTest' === $testCase
&& 'testWait' === $test
) {
return 'Zombie automatically waits for events to fire, so the wait test is irrelevant';
}
if ('Behat\Mink\Tests\Driver\Js\ChangeEventTest' === $testCase && 'testIssue178' === $test) {
return 'Zombie does not trigger the keyup event when writing a value in a text input to simulate keyboard';
}
return parent::skipMessage($testCase, $test);
}
}
*.tgz
*.phar
phpunit.xml
composer.lock
vendor
language: php
php: [5.3, 5.4, 5.5, 5.6, hhvm]
before_script:
- composer install --dev --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
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment