Skip to content

Commit 000bb34

Browse files
authored
Merge pull request #399 from dunglas/feat/native-driver-binaries
feat: remove ChromeDriver and geckodriver from the repo, use native installations instead
2 parents 2bafbd6 + 00c250d commit 000bb34

File tree

5 files changed

+119
-86
lines changed

5 files changed

+119
-86
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
/composer.lock
66
/phpunit.xml
77
/vendor/
8+
/drivers/
9+
/screen.png

README.md

Lines changed: 79 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ all the features you need to test your apps. It will sound familiar if you have
1515
as the API is exactly the same!
1616
Keep in mind that Panther can be used in every PHP project, as it is a standalone library.
1717

18-
Panther automatically finds your local installation of Chrome or Firefox and launches them (thanks to [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/) and [GeckoDriver](https://github.com/mozilla/geckodriver)),
19-
so you don't need to install anything on your computer, neither Selenium server nor any other obscure driver.
18+
Panther automatically finds your local installation of Chrome or Firefox and launches them,
19+
so you don't need to install anything else on your computer, a Selenium server is not needed!
2020

2121
In test mode, Panther automatically starts your application using [the PHP built-in web-server](http://php.net/manual/en/features.commandline.webserver.php).
2222
You can focus on writing your tests or web-scraping scenario and Panther will take care of everything else.
@@ -27,28 +27,57 @@ Unlike testing and web scraping libraries you're used to, Panther:
2727

2828
* executes the JavaScript code contained in webpages
2929
* supports everything that Chrome (or Firefox) implements
30-
* allows screenshots taking
30+
* allows taking screenshots
3131
* can wait for asynchronously loaded elements to show up
3232
* lets you run your own JS code or XPath queries in the context of the loaded page
3333
* supports custom [Selenium server](https://www.seleniumhq.org) installations
3434
* supports remote browser testing services including [SauceLabs](https://saucelabs.com/) and [BrowserStack](https://www.browserstack.com/)
3535

3636
## Documentation
3737

38-
### Install
38+
### Installing Panther
3939

4040
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:
4141

4242
composer req symfony/panther
4343

4444
composer req --dev symfony/panther
4545

46-
**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`).
46+
**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`).
4747
The underlying reason is that PHP's `ZipArchive` doesn't preserve UNIX executable permissions.
4848

49+
### Installing ChromeDriver and geckodriver
50+
51+
Panther uses the WebDriver protocol to control the browser used to crawl websites.
52+
53+
On all systems, you can use `dbrekelmans/browser-driver-installer` to install ChromeDriver and geckodriver locally:
54+
55+
composer require --dev dbrekelmans/bdi
56+
vendor/bin/bdi detect drivers
57+
58+
Panther will detect and use automatically drivers stored in the `drivers/` directory.
59+
60+
Alternatively, you can use the package manager of your operating system to install them.
61+
62+
On Ubuntu, run:
63+
64+
apt-get install chromium-chromedriver firefox-geckodriver
65+
66+
On Mac, using [Homebrew](https://brew.sh):
67+
68+
brew install chromedriver geckodriver
69+
70+
On Windows, using [chocolatey](https://chocolatey.org):
71+
72+
choco install chromedriver selenium-gecko-driver
73+
74+
Finally, you can download manually [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/) (for Chromium or Chrome)
75+
and [GeckoDriver](https://github.com/mozilla/geckodriver) (for Firefox) and put them anywhere in your `PATH`
76+
or in the `drivers/` directory of your project.
77+
4978
#### Registering the PHPUnit Extension
5079

51-
If you intend to use Panther to test your application, we strongly recommended to register the Panther PHPUnit extension.
80+
If you intend to use Panther to test your application, we strongly recommend registering the Panther PHPUnit extension.
5281
While not strictly mandatory, this extension dramatically improves the testing experience by boosting the performance and
5382
allowing to use the [interactive debugging mode](#interactive-mode).
5483

@@ -81,11 +110,13 @@ This listener will start the web server on demand like previously, but it will s
81110
```php
82111
<?php
83112

113+
use Symfony\Component\Panther\Client;
114+
84115
require __DIR__.'/vendor/autoload.php'; // Composer's autoloader
85116

86-
$client = \Symfony\Component\Panther\Client::createChromeClient();
117+
$client = Client::createChromeClient();
87118
// Or, if you care about the open web and prefer to use Firefox
88-
$client = \Symfony\Component\Panther\Client::createFirefoxClient();
119+
$client = Client::createFirefoxClient();
89120

90121
$client->request('GET', 'https://api-platform.com'); // Yes, this website is 100% written in JavaScript
91122
$client->clickLink('Get started');
@@ -103,7 +134,7 @@ $client->takeScreenshot('screen.png'); // Yeah, screenshot!
103134

104135
The `PantherTestCase` class allows you to easily write E2E tests. It automatically starts your app using the built-in PHP
105136
web server and let you crawl it using Panther.
106-
To provide all of the testing tools you're used to, it extends [PHPUnit](https://phpunit.de/)'s `TestCase`.
137+
To provide all the testing tools you're used to, it extends [PHPUnit](https://phpunit.de/)'s `TestCase`.
107138

108139
If you are testing a Symfony application, `PantherTestCase` automatically extends [the `WebTestCase` class](https://symfony.com/doc/current/testing.html#functional-tests).
109140
It means you can easily create functional tests, which can directly execute the kernel of your application and access all
@@ -243,11 +274,11 @@ class ChatTest extends PantherTestCase
243274

244275
### Checking the State of the WebDriver Connection
245276

246-
Use the `Client::ping()` method to check if the WebDriver connection is still active (useful for long running tasks).
277+
Use the `Client::ping()` method to check if the WebDriver connection is still active (useful for long-running tasks).
247278

248279
## Additional Documentation
249280

250-
Since Panther implements the API of popular libraries, it already has extensive documentation:
281+
Since Panther implements the API of popular libraries, it already has an extensive documentation:
251282

252283
* For the `Client` class, read [the BrowserKit documentation](https://symfony.com/doc/current/components/browser_kit.html)
253284
* For the `Crawler` class, read [the DomCrawler documentation](https://symfony.com/doc/current/components/dom_crawler.html)
@@ -257,7 +288,7 @@ Since Panther implements the API of popular libraries, it already has extensive
257288

258289
The following environment variables can be set to change some Panther's behaviour:
259290

260-
* `PANTHER_NO_HEADLESS`: to disable browser's headless mode (will display the testing window, useful to debug)
291+
* `PANTHER_NO_HEADLESS`: to disable the browser's headless mode (will display the testing window, useful to debug)
261292
* `PANTHER_WEB_SERVER_DIR`: to change the project's document root (default to `./public/`, relative paths **must start** by `./`)
262293
* `PANTHER_WEB_SERVER_PORT`: to change the web server's port (default to `9080`)
263294
* `PANTHER_WEB_SERVER_ROUTER`: to use a web server router script which is run at the start of each HTTP request
@@ -279,13 +310,11 @@ $client = self::createPantherClient([
279310
#### Chrome-specific Environment Variables
280311

281312
* `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)
282-
* `PANTHER_CHROME_DRIVER_BINARY`: to use another `chromedriver` binary, instead of relying on the ones already provided by Panther
283313
* `PANTHER_CHROME_ARGUMENTS`: to customize Chrome arguments. You need to set `PANTHER_NO_HEADLESS` to fully customize.
284314
* `PANTHER_CHROME_BINARY`: to use another `google-chrome` binary
285315

286316
#### Firefox-specific Environment Variables
287317

288-
* `PANTHER_GECKO_DRIVER_BINARY`: to use another `geckodriver` binary, instead of relying on the ones already provided by Panther
289318
* `PANTHER_FIREFOX_ARGUMENTS`: to customize Firefox arguments. You need to set `PANTHER_NO_HEADLESS` to fully customize.
290319
* `PANTHER_FIREFOX_BINARY`: to use another `firefox` binary
291320

@@ -344,29 +373,29 @@ To force Chrome to accept invalid and self-signed certificates, set the followin
344373

345374
### Docker Integration
346375

347-
Here is a minimal Docker image that can run Panther:
376+
Here is a minimal Docker image that can run Panther with both Chrome and Firefox:
348377

349-
```
350-
FROM php:latest
378+
```Dockerfile
379+
FROM php:alpine
351380

352-
RUN apt-get update && apt-get install -y libzip-dev zlib1g-dev chromium && docker-php-ext-install zip
381+
# Chromium and ChromeDriver
353382
ENV PANTHER_NO_SANDBOX 1
354383
# Not mandatory, but recommended
355384
ENV PANTHER_CHROME_ARGUMENTS='--disable-dev-shm-usage'
385+
RUN apk add --no-cache chromium chromium-chromedriver
386+
387+
# Firefox and GeckoDriver (optional)
388+
ARG GECKODRIVER_VERSION=0.28.0
389+
RUN apk add --no-cache firefox libzip-dev; \
390+
docker-php-ext-install zip
391+
RUN wget -q https://github.com/mozilla/geckodriver/releases/download/v$GECKODRIVER_VERSION/geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz; \
392+
tar -zxf geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz -C /usr/bin; \
393+
rm geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz
356394
```
357395

358396
Build it with `docker build . -t myproject`
359397
Run it with `docker run -it -v "$PWD":/srv/myproject -w /srv/myproject myproject bin/phpunit`
360398

361-
If you are using **Alpine Linux**, you may need to use another `chromedriver` binary.
362-
363-
```
364-
RUN apk add --no-cache \
365-
chromium \
366-
chromium-chromedriver
367-
ENV PANTHER_CHROME_DRIVER_BINARY /usr/lib/chromium/chromedriver
368-
```
369-
370399
### GitHub Actions Integration
371400

372401
Panther works out of the box with [GitHub Actions](https://help.github.com/en/actions).
@@ -386,7 +415,7 @@ jobs:
386415
- uses: actions/checkout@v2
387416

388417
- name: Install dependencies
389-
run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
418+
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
390419

391420
- name: Run test suite
392421
run: vendor/bin/phpunit
@@ -405,53 +434,34 @@ addons:
405434
firefox: latest
406435
407436
php:
408-
- 7.4
437+
- 8.0
409438
410439
script:
411-
- phpunit
440+
- vendor/bin/phpunit
412441
```
413442

414443
### Gitlab CI Integration
415444

416445
Here is a minimal `.gitlab-ci.yml` file to run Panther tests with [Gitlab CI](https://docs.gitlab.com/ee/ci/):
417446

418447
```yaml
419-
image: ubuntu:bionic
420-
421-
services:
422-
- postgres:11
423-
424-
variables:
425-
POSTGRES_PASSWORD: root
426-
POSTGRES_USER: root
427-
POSTGRES_DB: db
448+
image: ubuntu
428449
429450
before_script:
430-
- apt-get update
431-
- apt-get install software-properties-common -y
432-
- ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
433-
- apt-get install curl wget php php-cli php7.2 php7.2-common php7.2-curl php7.2-pgsql php7.2-mysql php7.2-intl php7.2-gd php7.2-xml php7.2-opcache php7.2-mbstring php7.2-zip libfontconfig1 fontconfig libxrender-dev libfreetype6 libxrender1 zlib1g-dev xvfb chromium-browser chromium-chromedriver -y -qq
434-
- export PANTHER_CHROME_DRIVER_BINARY="/usr/lib/chromium-browser/chromedriver"
435-
- export PANTHER_NO_SANDBOX=1
436-
- export PANTHER_WEB_SERVER_PORT=9080
437-
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
438-
- php composer-setup.php --install-dir=/usr/local/bin --filename=composer
439-
- php -r "unlink('composer-setup.php');"
440-
- composer
441-
- chromedriver --version
442-
- php -v
443-
- php -m
444-
- composer install --ignore-platform-reqs
445-
- bin/console doctrine:schema:update --force
446-
- bin/console doctrine:schema:validate
447-
- bin/console doctrine:fixtures:load
448-
449-
stages:
450-
- test
451+
- apt-get update
452+
- apt-get install software-properties-common -y
453+
- ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
454+
- apt-get install curl wget php php-cli php7.4 php7.4-common php7.4-curl php7.4-intl php7.4-xml php7.4-opcache php7.4-mbstring php7.4-zip libfontconfig1 fontconfig libxrender-dev libfreetype6 libxrender1 zlib1g-dev xvfb chromium-chromedriver firefox-geckodriver -y -qq
455+
- export PANTHER_NO_SANDBOX=1
456+
- export PANTHER_WEB_SERVER_PORT=9080
457+
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
458+
- php composer-setup.php --install-dir=/usr/local/bin --filename=composer
459+
- php -r "unlink('composer-setup.php');"
460+
- composer install
451461
452462
test:
453463
script:
454-
- vendor/bin/simple-phpunit tests/Controller/E2eTest.php
464+
- vendor/bin/phpunit
455465
```
456466

457467
### AppVeyor Integration
@@ -469,9 +479,9 @@ cache:
469479
470480
install:
471481
- ps: Set-Service wuauserv -StartupType Manual
472-
- cinst -y php composer googlechrome
482+
- cinst -y php composer googlechrome chromedriver firfox selenium-gecko-driver
473483
- refreshenv
474-
- cd c:\tools\php74
484+
- cd c:\tools\php80
475485
- copy php.ini-production php.ini /Y
476486
- echo date.timezone="UTC" >> php.ini
477487
- echo extension_dir=ext >> php.ini
@@ -489,7 +499,10 @@ test_script:
489499

490500
### Usage with Other Testing Tools
491501

492-
If you want to use Panther with other testing tools like [LiipFunctionalTestBundle](https://github.com/liip/LiipFunctionalTestBundle) or if you just need to use a different base class, Panther has got you covered. It provides you with the `Symfony\Component\Panther\PantherTestCaseTrait` and you can use it to enhance your existing test-infrastructure with some Panther awesomeness:
502+
If you want to use Panther with other testing tools like [LiipFunctionalTestBundle](https://github.com/liip/LiipFunctionalTestBundle)
503+
or if you just need to use a different base class, Panther has got you covered.
504+
It provides you with the `Symfony\Component\Panther\PantherTestCaseTrait` and you can use it to enhance your existing
505+
test-infrastructure with some Panther awesomeness:
493506

494507
```php
495508
<?php
@@ -534,4 +547,5 @@ If you like this software, help save the (real) panthers by [donating to the Pan
534547

535548
Created by [Kévin Dunglas](https://dunglas.fr). Sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).
536549

537-
Panther is built on top of [PHP WebDriver](https://github.com/php-webdriver/php-webdriver) and [several other FOSS libraries](https://symfony.com/blog/introducing-symfony-panther-a-browser-testing-and-web-scrapping-library-for-php#thank-you-open-source). It has been inspired by [Nightwatch.js](http://nightwatchjs.org/), a WebDriver-based testing tool for JavaScript.
550+
Panther is built on top of [PHP WebDriver](https://github.com/php-webdriver/php-webdriver) and [several other FOSS libraries](https://symfony.com/blog/introducing-symfony-panther-a-browser-testing-and-web-scrapping-library-for-php#thank-you-open-source).
551+
It has been inspired by [Nightwatch.js](http://nightwatchjs.org/), a WebDriver-based testing tool for JavaScript.

examples/basic.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@
1111

1212
declare(strict_types=1);
1313

14+
use Symfony\Component\Panther\Client;
15+
1416
require __DIR__.'/../vendor/autoload.php'; // Composer's autoloader
1517

16-
$client = \Symfony\Component\Panther\Client::createChromeClient();
17-
$crawler = $client->request('GET', 'http://api-platform.com'); // Yes, this website is 100% in JavaScript
18+
$client = Client::createChromeClient();
19+
// Or, if you care about the open web and prefer to use Firefox
20+
//$client = Client::createFirefoxClient();
1821

19-
$link = $crawler->selectLink('Support')->link();
20-
$crawler = $client->click($link);
22+
$client->request('GET', 'https://api-platform.com'); // Yes, this website is 100% written in JavaScript
23+
$client->clickLink('Get started');
2124

22-
// Wait for an element to be rendered
23-
$client->waitFor('.support');
25+
// Wait for an element to be present in the DOM (even if hidden)
26+
$crawler = $client->waitFor('#installing-the-framework');
27+
// Alternatively, wait for an element to be visible
28+
$crawler = $client->waitForVisibility('#installing-the-framework');
2429

25-
echo $crawler->filter('.support')->text();
30+
echo $crawler->filter('#installing-the-framework')->text();
2631
$client->takeScreenshot('screen.png'); // Yeah, screenshot!

src/ProcessManager/ChromeManager.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Facebook\WebDriver\Remote\DesiredCapabilities;
1818
use Facebook\WebDriver\Remote\RemoteWebDriver;
1919
use Facebook\WebDriver\WebDriver;
20+
use Symfony\Component\Process\ExecutableFinder;
2021
use Symfony\Component\Process\Process;
2122

2223
/**
@@ -30,6 +31,9 @@ final class ChromeManager implements BrowserManagerInterface
3031
private $arguments;
3132
private $options;
3233

34+
/**
35+
* @throws \RuntimeException
36+
*/
3337
public function __construct(?string $chromeDriverBinary = null, ?array $arguments = null, array $options = [])
3438
{
3539
$this->options = array_merge($this->getDefaultOptions(), $options);
@@ -72,20 +76,22 @@ public function quit(): void
7276
$this->process->stop();
7377
}
7478

79+
/**
80+
* @throws \RuntimeException
81+
*/
7582
private function findChromeDriverBinary(): string
7683
{
7784
if ($binary = $_SERVER['PANTHER_CHROME_DRIVER_BINARY'] ?? null) {
85+
@trigger_error('The "PANTHER_CHROME_DRIVER_BINARY" environment variable is deprecated since Panther 0.9, add ChromeDriver to your PATH instead.', E_USER_DEPRECATED);
86+
7887
return $binary;
7988
}
8089

81-
switch (PHP_OS_FAMILY) {
82-
case 'Windows':
83-
return __DIR__.'/../../chromedriver-bin/chromedriver.exe';
84-
case 'Darwin':
85-
return __DIR__.'/../../chromedriver-bin/chromedriver_mac64';
86-
default:
87-
return __DIR__.'/../../chromedriver-bin/chromedriver_linux64';
90+
if ($binary = (new ExecutableFinder())->find('chromedriver', null, ['./drivers'])) {
91+
return $binary;
8892
}
93+
94+
throw new \RuntimeException('"chromedriver" binary not found. Install it using the package manager of your operating system or by running "composer require --dev dbrekelmans/bdi && vendor/bin/bdi detect drivers".');
8995
}
9096

9197
private function getDefaultArguments(): array

0 commit comments

Comments
 (0)