diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6dda443 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.php] +indent_style = tab +indent_size = 4 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..a1ee1c0 --- /dev/null +++ b/.envrc @@ -0,0 +1,3 @@ +export WP_VERSION=latest +export WP_THEME=twentysixteen +export WP_PATH=/tmp/wp-tests diff --git a/.gitignore b/.gitignore index 9ac8ab5..49c4d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ package.json phpspec.yml spec/ vendor/ +wp-cli.yml wp-cli-nightly.phar diff --git a/README.md b/README.md index 3a91135..a947996 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Feature: I login as the specfic role Run to see contexts. ``` -$ vendor/bin/behat --di --lang=en +$ vendor/bin/behat -di --lang=en ``` ### Install headless browser diff --git a/composer.json b/composer.json index 0975c6a..7904c01 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,9 @@ "behat/mink": "~1.7", "behat/mink-extension": "~2.2", "behat/mink-selenium2-driver": "~1.3.1", - "phpunit/phpunit": "^5.6" + "phpunit/phpunit": "^5.6", + "behat/mink-goutte-driver": "^1.2", + "guzzlehttp/guzzle": "^6.2" }, "require-dev": { "phpspec/phpspec": "^3.1" diff --git a/composer.lock b/composer.lock index d92f610..3d28b9a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "f55a34e59c772ce5b911d53d43b11614", - "content-hash": "6ce99aac3774fe2b3c9f6b88a5368def", + "hash": "cc1373da7ac4b695a9161f6b620698f2", + "content-hash": "97eeb6d00cbd5356dc76a08380fe887f", "packages": [ { "name": "behat/behat", @@ -205,6 +205,62 @@ ], "time": "2016-03-05 08:26:18" }, + { + "name": "behat/mink-browserkit-driver", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/minkphp/MinkBrowserKitDriver.git", + "reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/10e67fb4a295efcd62ea0bf16025a85ea19534fb", + "reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb", + "shasum": "" + }, + "require": { + "behat/mink": "^1.7.1@dev", + "php": ">=5.3.6", + "symfony/browser-kit": "~2.3|~3.0", + "symfony/dom-crawler": "~2.3|~3.0" + }, + "require-dev": { + "silex/silex": "~1.2", + "symfony/phpunit-bridge": "~2.7|~3.0" + }, + "type": "mink-driver", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "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": "2016-03-05 08:59:47" + }, { "name": "behat/mink-extension", "version": "v2.2", @@ -264,6 +320,61 @@ ], "time": "2016-02-15 07:55:18" }, + { + "name": "behat/mink-goutte-driver", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/minkphp/MinkGoutteDriver.git", + "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", + "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", + "shasum": "" + }, + "require": { + "behat/mink": "~1.6@dev", + "behat/mink-browserkit-driver": "~1.2@dev", + "fabpot/goutte": "~1.0.4|~2.0|~3.1", + "php": ">=5.3.1" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7|~3.0" + }, + "type": "mink-driver", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "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": "2016-03-05 09:04:22" + }, { "name": "behat/mink-selenium2-driver", "version": "v1.3.1", @@ -419,6 +530,226 @@ ], "time": "2015-06-14 21:17:01" }, + { + "name": "fabpot/goutte", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/Goutte.git", + "reference": "8cc89de5e71daf84051859616891d3320d88a9e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/8cc89de5e71daf84051859616891d3320d88a9e8", + "reference": "8cc89de5e71daf84051859616891d3320d88a9e8", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": ">=5.5.0", + "symfony/browser-kit": "~2.1|~3.0", + "symfony/css-selector": "~2.1|~3.0", + "symfony/dom-crawler": "~2.1|~3.0" + }, + "type": "application", + "extra": { + "branch-alias": { + "dev-master": "3.2-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": "2016-11-15 16:27:29" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.2.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60", + "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.3.1", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2016-10-08 15:01:37" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20 10:07:11" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2016-06-24 23:00:38" + }, { "name": "instaclick/php-webdriver", "version": "1.4.3", @@ -1112,6 +1443,56 @@ ], "time": "2016-10-09 07:01:45" }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06 14:39:51" + }, { "name": "psr/log", "version": "1.0.2", @@ -1672,6 +2053,63 @@ "homepage": "https://github.com/sebastianbergmann/version", "time": "2016-02-04 12:56:52" }, + { + "name": "symfony/browser-kit", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "34348c2691ce6254e8e008026f4c5e72c22bb318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/34348c2691ce6254e8e008026f4c5e72c22bb318", + "reference": "34348c2691ce6254e8e008026f4c5e72c22bb318", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/dom-crawler": "~2.8|~3.0" + }, + "require-dev": { + "symfony/css-selector": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com", + "time": "2016-10-13 13:35:11" + }, { "name": "symfony/class-loader", "version": "v3.1.6", @@ -2012,6 +2450,62 @@ "homepage": "https://symfony.com", "time": "2016-10-24 15:52:44" }, + { + "name": "symfony/dom-crawler", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "1638c7534a8a2fa0bf9e979f9aacb6d7e8e9e24e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1638c7534a8a2fa0bf9e979f9aacb6d7e8e9e24e", + "reference": "1638c7534a8a2fa0bf9e979f9aacb6d7e8e9e24e", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "~2.8|~3.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com", + "time": "2016-12-10 14:24:53" + }, { "name": "symfony/event-dispatcher", "version": "v3.1.6", diff --git a/features/http-response.feature b/features/http-response.feature new file mode 100644 index 0000000..264a063 --- /dev/null +++ b/features/http-response.feature @@ -0,0 +1,18 @@ +Feature: HTTP response + + Scenario: Check http status code + + When I am on "/" + Then the HTTP status should be 200 + + When I am on "/the-page-not-found" + Then the HTTP status should be 404 + + Scenario: Check http response headers + + When I am on "/" + Then the HTTP headers should be: + | header | value | + | Content-Type | text/html; charset=UTF-8 | + | Connection | close | + | Host | 127.0.0.1:8080 | diff --git a/src/Context/RawWordPressContext.php b/src/Context/RawWordPressContext.php index 45b9d9c..165c135 100644 --- a/src/Context/RawWordPressContext.php +++ b/src/Context/RawWordPressContext.php @@ -59,6 +59,28 @@ public function get_variables( $key ) } } + /** + * Get http status code from the current page. + * + * @return int HTTP status code. + */ + protected function get_http_status() + { + $session = $this->get_goutte_session(); + return intval( $session->getStatusCode() ); + } + + /** + * Get http response headers from the current page. + * + * @return array HTTP response headers. + */ + protected function get_http_headers() + { + $session = $this->get_goutte_session(); + return $session->getResponseHeaders(); + } + /** * Log in into the WordPress * @@ -340,4 +362,25 @@ protected function assertFalse( $condition, $message = '' ) { \PHPUnit_Framework_Assert::assertFalse( $condition, $message = '' ); } + + /** + * Create and return session with goutte driver. + * + * @return object The session object of a goutte driver. + */ + protected function get_goutte_session() + { + $current_url = $this->getSession()->getCurrentUrl(); + + $goutteClient = new \Behat\Mink\Driver\Goutte\Client(); + $guzzleClient = new \GuzzleHttp\Client(); + $goutteClient->setClient($guzzleClient); + + $driver = new \Behat\Mink\Driver\GoutteDriver( $goutteClient ); + $session = new \Behat\Mink\Session( $driver ); + $session->start(); + $session->visit( $current_url ); + + return $session; + } } diff --git a/src/Context/WordPressContext.php b/src/Context/WordPressContext.php index e2c9c36..819e435 100644 --- a/src/Context/WordPressContext.php +++ b/src/Context/WordPressContext.php @@ -13,7 +13,7 @@ class WordPressContext extends RawWordPressContext { /** - * Save env to variable + * Save env to variable. * Example: Given save env $WP_VERSION as {WP_VERSION} * * @Given /^save env \$(?P[A-Z_]+) as \{(?P[A-Z_]+)\}$/ @@ -23,22 +23,72 @@ public function save_env_as_var( $env, $var ) $this->set_variables( $var, getenv( $env ) ); } + /** + * Check http status code. + * Example: Given save env $WP_VERSION as {WP_VERSION} + * + * @then /^the HTTP status should be (?P[0-9]+)$/ + */ + public function the_http_status_should_be( $expect ) + { + $status = $this->get_http_status(); + $this->assertSame( $status, intval( $expect ), sprintf( + 'The HTTP status is %1$s, but it should be %2$s', + $status, + $expect + ) ); + } + + /** + * Check HTTP response headers. + * Example: + * Then the HTTP headers should be: + * | header | value | + * | Content-Type | text/html; charset=UTF-8 | + * | Connection | close | + * | Host | 127.0.0.1:8080 | + * + * @then /^the HTTP headers should be:$/ + */ + public function the_http_headers_should_be( TableNode $table ) + { + $headers = $this->get_http_headers(); + + foreach ( $table->getHash() as $row ) { + if ( ! empty( $headers[ $row['header'] ] ) ) { + $value = $headers[ $row['header'] ][0]; + $this->assertSame( $row['value'], $value, sprintf( + 'The value of "%1$s" header is "%1$s", but it should be "%3$s".', + $row['header'], + $value, + $row['value'] + ) ); + } else { + throw new \Exception( sprintf( + 'The value of "%1$s" header is empty, but it should be "%2$s".', + $row['header'], + $row['value'] + ) ); + } + } + } + /** * Check status of plugins * Example: - * Then there are plugins: + * Then the plugins should be: * | slug | status | * | akismet | inactive | * | hello-dolly | inactive | * | wordpress-importer | active | * - * @then /^plugins should be:$/ + * @then /^the plugins should be:$/ */ - public function there_are_plugins( TableNode $table ) + public function the_plugins_should_be( TableNode $table ) { $plugins = $this->get_plugins(); - foreach ($table->getHash() as $row) { + foreach ( $table->getHash() as $row ) { if ( ! empty( $plugins[ $row['slug'] ] ) ) { $status = $plugins[ $row['slug'] ]['status']; $this->assertSame( $row['status'], $status, sprintf( @@ -56,9 +106,9 @@ public function there_are_plugins( TableNode $table ) } /** - * Check status of plugins + * Check status of plugins. * - * @then /^the "(?P[^"]*)" plugins should be (?P(installed|activated))$/ + * @then /^the "(?P[^"]*)" plugin should be (?P(installed|activated))$/ */ public function the_plugin_should_be( $slug, $expect ) { @@ -81,9 +131,9 @@ public function the_plugin_should_be( $slug, $expect ) } /** - * Check status of plugins + * Check status of plugins. * - * @then /^the "(?P[^"]*)" plugins should not be (?P(installed|activated))$/ + * @then /^the "(?P[^"]*)" plugin should not be (?P(installed|activated))$/ */ public function the_plugin_should_not_be( $slug, $expect ) { @@ -106,7 +156,7 @@ public function the_plugin_should_not_be( $slug, $expect ) } /** - * Check the theme is activated + * Check the theme is activated. * Example: Given the "twentysixteen" theme should be activated * * @Then /^the "(?P[^"]*)" theme should be activated$/ @@ -124,7 +174,7 @@ public function theme_should_be_activated( $theme ) } /** - * Check WordPress version + * Check WordPress version. * Example: Given the WordPress version should be "4.6" * * @Given /^the WordPress version should be "(?P[^"]*)"$/ @@ -158,7 +208,7 @@ public function wordpress_version_should_be( $version ) } /** - * Return exception if user is not logged in + * Return exception if user is not logged-in. * Example: Then I should be logged in * * @Then I should be logged in @@ -171,7 +221,7 @@ public function i_should_be_logged_in() } /** - * Return exception if user is logged in + * Return exception if user is logged-in. * Example: I should not be logged in * * @Then I should not be logged in