Skip to content

Commit 0a03bfe

Browse files
authored
Merge pull request #220 from dunglas/changelog-0.5.0
Update CHANGELOG, README and small code quality improvements
2 parents 9ff6003 + cb20ba2 commit 0a03bfe

File tree

3 files changed

+132
-72
lines changed

3 files changed

+132
-72
lines changed

CHANGELOG.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
CHANGELOG
22
=========
33

4+
0.5.0
5+
-----
6+
7+
* Add support for [Crawler test assertions](https://symfony.com/doc/current/testing/functional_tests_assertions.html#crawler)
8+
* Add the `PantherTestCase::createAdditionalPantherClient()` to retrieve additional isolated browsers, useful to test applications using [Mercure](https://mercure.rocks) or [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
9+
* Improved support for non-standard web server directories
10+
* Allow the integrated web server to start even if the homepage doesn't return a 200 HTTP status code
11+
* Increase default timeouts from 5 seconds to 30 seconds
12+
* Improve error messages
13+
* Add compatibility with Symfony 4.3
14+
* Upgrade ChromeDriver to version 76.0.3809.68
15+
* Various quality improvements
16+
417
0.4.1
518
-----
619

@@ -22,7 +35,7 @@ CHANGELOG
2235
* Keep the browser window open on fail, when running in non-headless mode
2336
* Automatically open Chrome DevTools when running in non-headless mode
2437
* PHPUnit 8 compatibility
25-
* Add a PHPUnit extension to keep alive the webserver and the client between tests
38+
* Add a PHPUnit extension to keep alive the web server and the client between tests
2639
* Change the default port of the web server to `9080` to prevent a conflict with Xdebug
2740
* Allow to use an external web server instead of the built-in one for testing
2841
* Allow to use a custom router script
@@ -32,7 +45,7 @@ CHANGELOG
3245
-----
3346

3447
* Add JS execution capabilities to `Client`
35-
* Allow keeping the webserver and client active even after test teardown
48+
* Allow keeping the web server and client active even after test teardown
3649
* Add a method to refresh the crawler (`Client::refreshCrawler()`)
3750
* Add options to configure the web server and ChromeDriver
3851
* PHP 7.1 compatibility

README.md

Lines changed: 111 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,23 @@ so you don't need to install anything on your computer, neither Selenium server
2222
In test mode, Panther automatically starts your application using [the PHP built-in web-server](http://php.net/manual/en/features.commandline.webserver.php).
2323
You can focus on writing your tests or web-scraping scenario and Panther will take care of everything else.
2424

25-
## Install
25+
## Features
26+
27+
Unlike testing and web scraping libraries you're used to, Panther:
28+
29+
* executes the JavaScript code contained in webpages
30+
* supports everything that Chrome (or Firefox) implements
31+
* allows screenshots taking
32+
* can wait for asynchronously loaded elements to show up
33+
* lets you run your own JS code or XPath queries in the context of the loaded page
34+
* supports custom [Selenium server](https://www.seleniumhq.org) installations
35+
* supports remote browser testing services including [SauceLabs](https://saucelabs.com/) and [BrowserStack](https://www.browserstack.com/)
36+
37+
## Documentation
2638

27-
Use [Composer](https://getcomposer.org/) to install Panther in your project. You may want to use the --dev flag if you want to use Panther for testing only and not for web scraping in a production environment:
39+
### Install
40+
41+
Use [Composer](https://getcomposer.org/) to install Panther in your project. You may want to use the `--dev` flag if you want to use Panther for testing only and not for web scraping in a production environment:
2842

2943
composer req symfony/panther
3044

@@ -33,18 +47,17 @@ Use [Composer](https://getcomposer.org/) to install Panther in your project. You
3347
**Warning:** On \*nix systems, the `unzip` command must be installed or you will encounter an error similar to `RuntimeException: sh: 1: exec: /app/vendor/symfony/panther/src/ProcessManager/../../chromedriver-bin/chromedriver_linux64: Permission denied` (or `chromedriver_linux64: not found`).
3448
The underlying reason is that PHP's `ZipArchive` doesn't preserve UNIX executable permissions.
3549

36-
## Basic Usage
50+
### Basic Usage
3751

3852
```php
3953
<?php
4054

4155
require __DIR__.'/vendor/autoload.php'; // Composer's autoloader
4256

4357
$client = \Symfony\Component\Panther\Client::createChromeClient();
44-
$crawler = $client->request('GET', 'https://api-platform.com'); // Yes, this website is 100% in JavaScript
58+
$crawler = $client->request('GET', 'https://api-platform.com'); // Yes, this website is 100% written in JavaScript
4559

46-
$link = $crawler->selectLink('Support')->link();
47-
$crawler = $client->click($link);
60+
$crawler->clickLink('Support');
4861

4962
// Wait for an element to be rendered
5063
$client->waitFor('.support');
@@ -53,11 +66,16 @@ echo $crawler->filter('.support')->text();
5366
$client->takeScreenshot('screen.png'); // Yeah, screenshot!
5467
```
5568

56-
## Testing Usage
69+
### Testing Usage
5770

5871
The `PantherTestCase` class allows you to easily write E2E tests. It automatically starts your app using the built-in PHP
5972
web server and let you crawl it using Panther.
60-
It extends [PHPUnit](https://phpunit.de/)'s `TestCase` and provides all of the testing tools you're used to.
73+
To provides all of the testing tools you're used to, it extends [PHPUnit](https://phpunit.de/)'s `TestCase`.
74+
75+
If you are testing a Symfony application, `PantherTestCase` automatically extends [the `WebTestCase` class](https://symfony.com/doc/current/testing.html#functional-tests).
76+
It means you can easily create functional tests, which can directly execute the kernel of your application and access all
77+
your existing services. In this case, you can use [all crawler test assertions](https://symfony.com/doc/current/testing/functional_tests_assertions.html#crawler)
78+
provided by Symfony with Panther.
6179

6280
```php
6381
<?php
@@ -68,12 +86,14 @@ use Symfony\Component\Panther\PantherTestCase;
6886

6987
class E2eTest extends PantherTestCase
7088
{
71-
public function testMyApp()
89+
public function testMyApp(): void
7290
{
7391
$client = static::createPantherClient(); // Your app is automatically started using the built-in web server
74-
$crawler = $client->request('GET', '/mypage');
92+
$client->request('GET', '/mypage');
7593

76-
$this->assertContains('My Title', $crawler->filter('title')->html()); // You can use any PHPUnit assertion
94+
// Use any PHPUnit assertion, including the ones provided by Symfony
95+
$this->assertPageTitleContains('My Title');
96+
$this->assertSelectorTextContains('#main', 'My body');
7797
}
7898
}
7999
```
@@ -84,20 +104,26 @@ To run this test:
84104

85105
### A Polymorphic Feline
86106

87-
If you are testing a Symfony application, `PantherTestCase` automatically extends the `WebTestCase` class. It means
88-
you can easily create functional tests, which can directly execute the kernel of your application and access all your existing
89-
services. Unlike the Panther's client, the Symfony's testing client doesn't support JavaScript and screenshots capturing, but
90-
it is super-fast!
107+
Panther also gives you instant access to other BrowserKit-based implementations of `Client` and `Crawler`.
108+
Unlike Panther's native client, these alternative clients don't support JavaScript, CSS and screenshots capturing,
109+
but they are **super-fast**!
91110

92-
Alternatively (and even for non-Symfony apps), Panther can also leverage the [Goutte](https://github.com/FriendsOfPHP/Goutte)
93-
web scraping library, which is an intermediate between the Symfony's and the Panther's test clients. Goutte sends real HTTP
94-
requests, it is fast and is able to browse any webpage, not only the ones of the application under test.
95-
However, Goutte doesn't support JavaScript and other advanced features because it is entirely written in PHP.
111+
Two alternative clients are available:
96112

97-
The fun part is that the 3 libraries implement the exact same API, so you can switch from one to another just by calling
113+
* The first directly manipulates the Symfony kernel provided by `WebTestCase`, it's the fastest client available,
114+
but it is only available for Symfony apps.
115+
* The second leverages the [Goutte](https://github.com/FriendsOfPHP/Goutte) web scraping library.
116+
It is an intermediate between the Symfony's and the Panther's test clients. Goutte sends real HTTP requests, it is fast
117+
and is able to browse any webpage, not only the ones of the application under test.
118+
However, Goutte doesn't support JavaScript and other advanced features because it is entirely written in PHP.
119+
This one is available even for non-Symfony apps!
120+
121+
The fun part is that the 3 clients implement the exact same API, so you can switch from one to another just by calling
98122
the appropriate factory method, resulting in a good trade-off for every single test case (Do I need JavaScript? Do I need
99123
to authenticate with an external SSO server? Do I want to access the kernel of the current request? ... etc).
100124

125+
Here is how to retrieve instances of these clients:
126+
101127
```php
102128
<?php
103129

@@ -110,7 +136,7 @@ class E2eTest extends PantherTestCase
110136
{
111137
public function testMyApp()
112138
{
113-
$symfonyClient = static::createClient(); // A cute kitty: the Symfony's functional test too
139+
$symfonyClient = static::createClient(); // A cute kitty: the Symfony's functional test tool
114140
$goutteClient = static::createGoutteClient(); // An agile lynx: Goutte
115141
$pantherClient = static::createPantherClient(); // A majestic Panther
116142
// Both Goutte and Panther benefits from the built-in HTTP server
@@ -123,13 +149,74 @@ class E2eTest extends PantherTestCase
123149
// enjoy the same API for the 3 felines
124150
// $*client->request('GET', '...')
125151

126-
$kernel = static::createKernel(); // You have also access to the app's kernel
152+
$kernel = static::createKernel(); // If you are testing a Symfony app, you also have access to the kernel
127153

128154
// ...
129155
}
130156
}
131157
```
132158

159+
### Creating Isolated Browsers to Test Apps Using [Mercure](https://mercure.rocks) or WebSockets
160+
161+
Panther provides a convenient way to test applications with real-time capabilities which use [Mercure](https://symfony.com/doc/current/mercure.html), [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
162+
and similar technologies.
163+
164+
The `PantherTestCase::createAdditionalPantherClient()` creates additional, isolated, browsers; that can interact with each others.
165+
For instance, this can be useful to test a chat application having several users connected simultaneously:
166+
167+
```php
168+
<?php
169+
170+
use Symfony\Component\Panther\PantherTestCase;
171+
172+
class ChatTest extends PantherTestCase
173+
{
174+
public function testChat(): void
175+
{
176+
$client1 = self::createPantherClient();
177+
$client1->request('GET', '/chat');
178+
179+
// Connect a 2nd user using an isolated browser and say hi!
180+
$crawler2 = self::createAdditionalPantherClient()->request('GET', '/chat');
181+
$crawler2->submitForm('Post message', ['message' => 'Hi folks 👋😻']);
182+
183+
// Wait for the message to be received by the first client
184+
$client1->waitFor('.message');
185+
186+
// Symfony Assertions are always executed in the **primary** browser
187+
$this->assertSelectorTextContains('.message', 'Hi folks 👋😻');
188+
}
189+
}
190+
```
191+
192+
## Extra Documentations
193+
194+
Since Panther implements the API of popular libraries, it already has an extensive documentation:
195+
196+
* For the `Client` class, read [the BrowserKit's documentation](https://symfony.com/doc/current/components/browser_kit.html)
197+
* For the `Crawler` class, read [the DomCrawler's documentation](https://symfony.com/doc/current/components/dom_crawler.html)
198+
* For Webdriver, read [the Facebook's PHP WebDriver documentation](https://github.com/facebook/php-webdriver)
199+
200+
### Environment Variables
201+
202+
The following environment variables can be set to change some Panther's behaviour:
203+
204+
* `PANTHER_NO_HEADLESS`: to disable browser's headless mode (will display the testing window, useful to debug)
205+
* `PANTHER_NO_SANDBOX`: to disable [Chrome's sandboxing](https://chromium.googlesource.com/chromium/src/+/b4730a0c2773d8f6728946013eb812c6d3975bec/docs/design/sandbox.md) (unsafe, but allows to use Panther in containers)
206+
* `PANTHER_WEB_SERVER_DIR`: to change the project's document root (default to `public/`)
207+
* `PANTHER_CHROME_DRIVER_BINARY`: to use another `chromedriver` binary, instead of relying on the ones already provided by Panther
208+
* `PANTHER_CHROME_ARGUMENTS`: to customize `chromedriver` arguments. You need to set `PANTHER_NO_HEADLESS` to fully customize.
209+
* `PANTHER_WEB_SERVER_PORT`: to change the web server's port (default to `9080`)
210+
* `PANTHER_WEB_SERVER_ROUTER`: to use a web server router script which is run at the start of each HTTP request
211+
* `PANTHER_EXTERNAL_BASE_URI`: to use an external web server (the PHP built-in web server will not be started)
212+
* `PANTHER_CHROME_BINARY`: to use another `google-chrome` binary
213+
214+
### Accessing To Hidden Text
215+
216+
According to the spec, WebDriver implementations returns only the **displayed** text by default.
217+
When you filter on a head tag (like `title`), the method `text()` returns an empty string. Use the method `html()` to get
218+
the complete contents of the tag, including the tag itself.
219+
133220
### Interactive Mode
134221

135222
Panther can make a pause in your tests suites after a failure.
@@ -144,27 +231,8 @@ For enabling this mode, you need the `--debug` PHPUnit option without the headle
144231

145232
Press enter to continue...
146233

147-
## Features
148-
149-
Unlike testing and web scraping libraries you're used to, Panther:
150-
151-
* executes the JavaScript code contained in webpages
152-
* supports everything that Chrome (or Firefox) implements
153-
* allows screenshots taking
154-
* can wait for the appearance of asynchronously loaded elements
155-
* lets you run your own JS code or XPath queries in the context of the loaded page
156-
* supports custom [Selenium server](https://www.seleniumhq.org) installations
157-
* supports remote browser testing services including [SauceLabs](https://saucelabs.com/) and [BrowserStack](https://www.browserstack.com/)
158-
159-
## Documentation
160-
161-
Since Panther implements the API of popular libraries, it already has an extensive documentation:
162-
163-
* For the `Client` class, read [the BrowserKit's documentation](https://symfony.com/doc/current/components/browser_kit.html)
164-
* For the `Crawler` class, read [the DomCrawler's documentation](https://symfony.com/doc/current/components/dom_crawler.html)
165-
* For Webdriver, read [the Facebook's PHP WebDriver documentation](https://github.com/facebook/php-webdriver)
166234

167-
### Improve Performances by Having a Persistent Web Server Running
235+
### Using a Persistent Web Server to Improve Performance
168236

169237
When you use the Panther client, the web server running in the background will be started on demand at the first call to
170238
`createPantherClient()`, `createGoutteClient()` or `startWebServer()` and it will be stopped at `tearDownAfterClass()`.
@@ -217,28 +285,7 @@ class E2eTest extends PantherTestCase
217285

218286
### Using a Proxy
219287

220-
To use a proxy server, override the `--proxy-server` option passed to the Chrome binary by using the `PANTHER_CHROME_ARGUMENTS` environment variable.
221-
222-
Example: `PANTHER_CHROME_ARGUMENTS="--proxy-server=socks://127.0.0.1:9050"`
223-
224-
### Hidden Text
225-
226-
Webdriver returns only the displayed text. When you filter on a head tag (like `title`), the method `text()` returns an
227-
empty string. Use the method `html()` to get the complete contents of the tag, including the tag itself.
228-
229-
### Environment Variables
230-
231-
The following environment variables can be set to change some Panther's behaviour:
232-
233-
* `PANTHER_NO_HEADLESS`: to disable browser's headless mode (will display the testing window, useful to debug)
234-
* `PANTHER_NO_SANDBOX`: to disable [Chrome's sandboxing](https://chromium.googlesource.com/chromium/src/+/b4730a0c2773d8f6728946013eb812c6d3975bec/docs/design/sandbox.md) (unsafe, but allows to use Panther in containers)
235-
* `PANTHER_WEB_SERVER_DIR`: to change the project's document root (default to `public/`)
236-
* `PANTHER_CHROME_DRIVER_BINARY`: to use another `chromedriver` binary, instead of relying on the ones already provided by Panther
237-
* `PANTHER_CHROME_ARGUMENTS`: to customize `chromedriver` arguments. You need to set `PANTHER_NO_HEADLESS` to fully customize.
238-
* `PANTHER_WEB_SERVER_PORT`: to change the web server's port (default to `9080`)
239-
* `PANTHER_WEB_SERVER_ROUTER`: to use a web server router script which is run at the start of each HTTP request
240-
* `PANTHER_EXTERNAL_BASE_URI`: to use an external web server (the PHP built-in web server will not be started)
241-
* `PANTHER_CHROME_BINARY`: to use another `google-chrome` binary
288+
To use a proxy server, set the following environment variable: `PANTHER_CHROME_ARGUMENTS='--proxy-server=socks://127.0.0.1:9050'`
242289

243290
### Accepting Self-signed SSL Certificates
244291

src/PantherTestCaseTrait.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,14 @@ private static function getWebServerDir(array $options)
213213
return static::$webServerDir;
214214
}
215215

216-
if (isset($_SERVER['PANTHER_WEB_SERVER_DIR'])) {
217-
if ('./' === substr($_SERVER['PANTHER_WEB_SERVER_DIR'], 0, 2)) {
218-
return getcwd().substr($_SERVER['PANTHER_WEB_SERVER_DIR'], 1);
219-
}
216+
if (!isset($_SERVER['PANTHER_WEB_SERVER_DIR'])) {
217+
return self::$defaultOptions['webServerDir'];
218+
}
220219

221-
return $_SERVER['PANTHER_WEB_SERVER_DIR'];
220+
if (0 === strpos($_SERVER['PANTHER_WEB_SERVER_DIR'], './')) {
221+
return getcwd().substr($_SERVER['PANTHER_WEB_SERVER_DIR'], 1);
222222
}
223223

224-
return self::$defaultOptions['webServerDir'];
224+
return $_SERVER['PANTHER_WEB_SERVER_DIR'];
225225
}
226226
}

0 commit comments

Comments
 (0)