symfony / panther Goto Github PK
View Code? Open in Web Editor NEWA browser testing and web crawling library for PHP and Symfony
License: MIT License
A browser testing and web crawling library for PHP and Symfony
License: MIT License
Hello,
I should open a webpage, wait for all the js to load (eg. in puppeteer 'waitUntil' => 'networkidle0'
) and then store the entire page source into a variable....
<?php
require __DIR__.'/vendor/autoload.php'; // Composer's autoloader
$client = \Symfony\Component\Panther\Client::createChromeClient();
$crawler = $client->request('GET', 'https://myurl.com/page.html');
// Wait for an element to be rendered
$client->waitFor('.support'); //indeed, I should wait for all the js executed on this page...to store the page source somewhere else....
....
how to do it here, please? Thank you
I came across this Docker config to run Chromium headless on Alpine, and I see lots of disabled options, like apps, google translate, google sync, etc.
Do you think Panthère should automatically define these options too?
I'm using waitFor('.wai_hidden'), the page fail to load after a while
If I use wait(5) then $crawler->html(), there's an element with class=wai_hidden
helloo
can u write small example of using cookie jar?
Is it possible to get the webserver with a test_case started? The page I want to test uses vue.js and the controller normaly requests an external API, which I would like to mock.
Hi,
when I use the crawler to filter the DOM and test the content of the title tag, I receive an empty string.
Tested with:
<?php
// tests/PanthereTest.php
declare(strict_types=1);
namespace App\Tests;
use Panthere\PanthereTestCase;
/**
* Class PanthereTest
* @package App\Tests
*/
class PanthereTest extends PanthereTestCase
{
public function testSomething(): void
{
$client = static::createClient();
$crawler = $client->request('GET', static::$baseUri.'/');
$this->assertEquals('Welcome!', $crawler->filterXPath('//title')->html());
$this->assertEquals('Welcome!', $crawler->filterXPath('//title')->text());
$client = static::createPanthereClient();
$crawler = $client->request('GET', static::$baseUri.'/');
$this->assertEquals('<title>Welcome!</title>', $crawler->filterXPath('//title')->html());
$this->assertEquals('Welcome!', $crawler->filterXPath('//title')->text());
}
}
// composer.json
{
"type": "project",
"license": "proprietary",
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"symfony/console": "^4.0",
"symfony/flex": "^1.0",
"symfony/framework-bundle": "^4.0",
"symfony/lts": "^4@dev",
"symfony/yaml": "^4.0"
},
"require-dev": {
"dunglas/panthere": "^1.0@dev",
"symfony/dotenv": "^4.0",
"symfony/phpunit-bridge": "^4.0"
},
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php56": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"id": "01C9W9DMK0BWP564TKPSF2P5F0",
"allow-contrib": false
}
}
}
Result:
PHPUnit 6.5.7 by Seb
astian Bergmann and contributors.
Testing Project Test Suite
F 1 / 1 (100%)
Time: 4.76 seconds, Memory: 8.00MB
There was 1 failure:
1) App\Tests\PanthereTest::testSomething
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Welcome!'
+''
tests/PanthereTest.php:24
FAILURES!
Tests: 1, Assertions: 4, Failures: 1.
Following on from this pr I'd like to suggest some naming alternatives which are perhaps a bit funky:
takeScreenshot
-> screenshot
(also, can a basedir be set for all screenshots, e.g. var/screenshots
?
sendKeys
-> type
(as @javiereguiluz suggests)
getLocation
-> ?
getLocationOnScreenOnceScrolledIntoView()
-> ??
Your project is very interesting. π
What about code coverage? Does it work like for a regular Symfony WebTestCase
? If not, is that a panned thing or is it not feasible?
Thanks!
PANTHER_NO_HEADLESS env var gave me many headaches...
headless means "hidden", so "no headless" means "no hidden" , so "show". If in the code we use "! no headless", that means "no no hidden", so "yes hidden", so "show". Why not get rid of this double negation by simply renaming it PANTHER_HEADLESS ?
When working with panther tests, the website seems to be running with dev
mode config, even though if I dd(getenv('APP_ENV'))
it reports it's in 'test' environment. This causes lots of problems when testing because of the web profiler toolbar overlay preventing buttons from being clicked.
The toolbar is disabled for the test env per the config, and the only way to prevent the toolbar from showing is by editing the config/dev/web_profiler
and set toolbar:false
. Something I shouldn't have to do as I'm in the test environment
Why is this crazy behaviour happening?
When a failed assertion occurs, how about saving the screen with the current timestamp?
Hi,
is there a specific reason why Panther requires symfony/browser-kit
and symfony/console
in ^4.0
version?
Since Symfony 4.0 does not yet have an LTS version, and since it is fully compatible with 3.4, it would be nice to allow installing Panther with Symfony 3.4 present.
Thanks!
is it possible to run tests with ENV PANTHER_NO_HEADLESS 1
in docker ?
now i get error
Fatal error: Uncaught Facebook\WebDriver\Exception\WebDriverCurlException: Curl error thrown for http POST to /session with params: {"desiredCapabilities":{"browserName":"chrome","platform":"ANY","chromeOptions":{"binary":"","args":["--no-sandbox"]}}}
Operation timed out after 30001 milliseconds with 0 bytes received in /app/vendor/facebook/webdriver/lib/Remote/HttpCommandExecutor.php:292
Stack trace:
#0 /app/vendor/facebook/webdriver/lib/Remote/RemoteWebDriver.php(126): Facebook\WebDriver\Remote\HttpCommandExecutor->execute(Object(Facebook\WebDriver\Remote\WebDriverCommand))
#1 /app/vendor/symfony/panther/src/ProcessManager/ChromeManager.php(59): Facebook\WebDriver\Remote\RemoteWebDriver::create('http://127.0.0....', Object(Facebook\WebDriver\Remote\DesiredCapabilities))
#2 /app/vendor/symfony/panther/src/Client.php(74): Symfony\Component\Panther\ProcessManager\ChromeManager->start()
#3 /app/vendor/symfony/panther/src/Client.php(245): Symfony\Component\Panther\Client->start()
#4 /app/vendor/symfony/panther/src/Client.ph in /app/vendor/facebook/webdriver/lib/Remote/HttpCommandExecutor.php on line 292
i tried to start chromedriver on host machine, and share 9515 port - but same error
Getting the value of inputs is fairly common: $crawler->filter('#course_title')->attr('value')
is perhaps a little long-winded. Could a helper function like $crawler->filter('#foo')->value()
be more appropriate? Or even something shorter like $crawler->input('#foo')->val()
?
A browser testing and web scrapping library for PHP and Symfony.
scrapping should be "scraping"
Your requirements could not be resolved to an installable set of packages.
Problem 1
- dunglas/panthere dev-master requires symfony/browser-kit ^4.0 -> satisfiable by symfony/browser-kit[v4.1.0].
- dunglas/panthere dev-master conflicts with symfony/browser-kit[v4.1.0].
- dunglas/panthere dev-master conflicts with symfony/browser-kit[v4.1.0].
- dunglas/panthere dev-master conflicts with symfony/browser-kit[v4.1.0].
- Installation request for dunglas/panthere dev-master -> satisfiable by dunglas/panthere[dev-master].
Why exactly was the conflict with browser-kit 4.1 added?
My test isn't running at all, it appears to be pausing until stopped. I've tracked it down to: PantherTestCaseTrait
, specifically StartWebServer
, and after the lines:
self::$webServerManager = new WebServerManager($webServerDir, $hostname, $port);
self::$webServerManager->start();
It would appear the server starts, but then blocks.
My test is directly from the examples
$client = static::createPantherClient(); // Your app is automatically started using the built-in web server
$crawler = $client->request('GET', '/');
$this->assertContains('My Title', $crawler->filter('title')->text()); // You can use any PHPUnit assertion
After a bit more digging, it would seem although port 9000
is free, it really will not run on 9000
and hangs. Changing to port 9001
doesn't present any such problem. I'd like to suggest a quick note in the readme as being able to pass in the port isn't immediately obvious.
As seeing nothing during a hung test run, is there some way the server can be tested on the port before starting it without having to do an nmap
?
I've been using $client->wait(10)
as a sleep, thinking, it'll wait for x seconds, right? Except it doesn't. Digging through the code, it's a max time out for an operation rather than a wait:
* $driver->wait(20, 1000)->until(
* WebDriverExpectedCondition::titleIs('WebDriver Page')
* );
Can this be renamed, or perhaps made a little clearer somehow? Maybe passing the until condition as a closure to the wait method?
Hello, this code is working fine with Symfony crawler, but it's not working anymore with panthere
$crawler->filter('div:contains("This value should not be blank")')
Here is the error:
WebDriver\Exception\InvalidSelectorException: invalid selector: An invalid or illegal selector was specified
As a complete newbie, I think a quick addition to the example code will be useful to help populate inputs, so something like:
// populate the search box with some text - this will trigger a search box to appear with results
$client->findElement(WebDriverBy::cssSelector('.search__input.ds-input'))
->sendKeys('how');
// Wait for the dynamic searchbox to appear
$client->waitFor('#algolia-autocomplete-listbox-0');
The Chrome DevTools Protocol allows for tools to instrument, inspect, debug and profile Chromium, Chrome and other Blink-based browsers.
https://chromedevtools.github.io/devtools-protocol/
Basically, Chrome allows to be started with a --remote-debugging-port
agument which gives access to the DevTools. That could significantly expand what we can do by manipulating for instance the Network panel in the DevTools. But maybe, integrating it in this project is off topic ?
I think it'd be useful to have an alert box triggered in an example with the brief code of how to accept / dismiss it:
$client->switchTo()->alert()->accept();
Q | A |
---|---|
Bug report? | yes |
Feature request? | no |
BC Break report? | yes |
When using PanthereTestCase
, and when making a request, we can't get access to the Symfony\Component\HttpFoundation\Response
object that should normally be sent to the Kernel. Instead, we only get access to the BrowserKit
one.
Steps to reproduce:
<?php
use Panthere\PanthereTestCase;
class MyPanthereTest extends PanthereTestCase
{
public function testMyApp()
{
$client = static::createPanthereClient();
$crawler = $client->request('GET', static::$baseUri.'/any-page');
static::assertSame(200, $client->getResponse()->getStatusCode());
}
}
PHPUnit's output:
Error : Call to undefined method Symfony\Component\BrowserKit\Response::getStatusCode()
I consider this as a BC break, because the $client->request()
method SHOULD return an instance of the Symfony\Component\BrowserKit\Client
class, for which getResponse()
returns an instance of Symfony\Component\HttpFoundation\Response
.
This is the same for the Request
via $client->getRequest()
by the way.
The issue comes from these lines:
https://github.com/dunglas/panthere/blob/b3f0601e105010d365360f238ca1b572a4e5ec82/src/Client.php#L238-L241
IMO, the Request and Response object should be either blocked from the PanthereClient via an exception (easy pick), or created & adapted based on the WebDriver results (harder).
WDYT?
Hi everyone,
Small question about the usage of Panther into a PHP Alpine image, I've tried to install Chromedriver and chromium but here's the error that I get:
#!/usr/bin/env php
PHPUnit 6.5.13 by Sebastian Bergmann and contributors.
Error: No code coverage driver is available
Testing E2E
E 1 / 1 (100%)
Time: 8.08 seconds, Memory: 40.25MB
There was 1 error:
1) E2E\Core\HomeE2ETest::testStatusCode
RuntimeException: sh: exec: line 1: /var/www/marketReminder/vendor/symfony/panther/src/ProcessManager/../../chromedriver-bin/chromedriver_linux64: not found
/var/www/marketReminder/vendor/symfony/panther/src/ProcessManager/WebServerReadinessProbeTrait.php:50
/var/www/marketReminder/vendor/symfony/panther/src/ProcessManager/ChromeManager.php:49
/var/www/marketReminder/vendor/symfony/panther/src/Client.php:80
/var/www/marketReminder/vendor/symfony/panther/src/Client.php:272
/var/www/marketReminder/vendor/symfony/panther/src/Client.php:186
/var/www/marketReminder/E2E/Core/HomeE2ETest.php:26
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
Remaining deprecation notices (1)
1x: Doctrine\Common\ClassLoader is deprecated.
1x in HomeE2ETest::testStatusCode from E2E\Core
make: *** [panther] Error 2
For information, here's the Dockerfile:
# Development build
FROM php:fpm-alpine as base
ARG WORKFOLDER
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV PANTHER_NO_SANDBOX 1
ENV PANTHER_WEB_SERVER_PORT 9800
ENV WORKPATH ${WORKFOLDER}
RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS icu-dev postgresql-dev gnupg graphviz make autoconf git zlib-dev curl chromium chromium-chromedriver go rabbitmq-c rabbitmq-c-dev \
&& docker-php-ext-configure pgsql --with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install zip intl pdo_pgsql pdo_mysql opcache json pdo_pgsql pgsql mysqli \
&& pecl install apcu redis grpc protobuf amqp \
&& docker-php-ext-enable apcu mysqli redis grpc protobuf amqp
COPY docker/php/conf/php.ini /usr/local/etc/php/php.ini
# Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Blackfire (Docker approach) & Blackfire Player
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/alpine/amd64/$version \
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp \
&& mv /tmp/blackfire-*.so $(php -r "echo ini_get('extension_dir');")/blackfire.so \
&& printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
&& mkdir -p /tmp/blackfire \
&& curl -A "Docker" -L https://blackfire.io/api/v1/releases/client/linux_static/amd64 | tar zxp -C /tmp/blackfire \
&& mv /tmp/blackfire/blackfire /usr/bin/blackfire \
&& rm -Rf /tmp/blackfire \
&& curl -OLsS http://get.blackfire.io/blackfire-player.phar \
&& chmod +x blackfire-player.phar \
&& mv blackfire-player.phar /usr/local/bin/blackfire-player
# PHP-CS-FIXER & Deptrac
RUN wget http://cs.sensiolabs.org/download/php-cs-fixer-v2.phar -O php-cs-fixer \
&& chmod a+x php-cs-fixer \
&& mv php-cs-fixer /usr/local/bin/php-cs-fixer \
&& curl -LS http://get.sensiolabs.de/deptrac.phar -o deptrac.phar \
&& chmod +x deptrac.phar \
&& mv deptrac.phar /usr/local/bin/deptrac
RUN mkdir -p ${WORKPATH} \
&& chown -R www-data /tmp/ \
&& mkdir -p \
${WORKPATH}/var/cache \
${WORKPATH}/var/logs \
${WORKPATH}/var/sessions \
&& chown -R www-data ${WORKPATH}/var
WORKDIR ${WORKPATH}
COPY --chown=www-data:www-data . ./
# Production build
FROM base as production
COPY --from=gcr.io/marketreminder-206206/node:latest ${WORKPATH}/public/build ./public/build
COPY docker/php/conf/production/php.ini /usr/local/etc/php/php.ini
RUN rm -rf /usr/local/bin/deptrac \
&& rm -rf /usr/local/bin/php-cs-fixer
I don't really see where the problem is coming from and i've search to see if someone has the same problem but nothing about this type of error, does anyone has an idea ?
PS: I've tried the installation recommanded by the documentation but the driver doesn't seem to be found
Thanks for the help :)
Hi,
I'm trying to use Panthère in Symfony on Debian, but I have this error when launching my tests :
RuntimeException: sh: 1: exec: /srv/app/vendor/symfony/panthere/src/ProcessManager/../../chromedriver-bin/chromedriver_linux64: Permission denied
Indeed, here's the permission status :
Is there a way to install chromedriver without setting permissions by hand ?
I could like to use panther in my symfony project, I am not using PhPUnit but kahlan which is using natural langage & describe syntax, It do not use any classes, how should I use panther in this kind of framework ?
For sure I can use namespace but what about the class to extend ? π§
Is it possible to use a secure web server for the panther client?
I can see that the scheme is hardcoded here: https://github.com/symfony/panther/blob/master/src/PantherTestCaseTrait.php#L114
The reason for the request is that I'm using dunglas/DunglasAngularCsrfBundle with the secure cookie option. I noticed while trying to run tests the cookie was not set when using the http:// scheme.
This works for me:
$client = \Symfony\Bundle\FrameworkBundle\Test\WebTestCase::createClient();
$crawler = $client->request('GET', '/login');
For this:
$client = \Symfony\Component\Panther\Client::createChromeClient();
$crawler = $client->request('GET', '/login');
I get the error:
Facebook\WebDriver\Exception\UnknownServerException : unknown error: unhandled inspector error: {"code":-32000,"message":"Cannot navigate to invalid URL"}
(Session info: headless chrome=68.0.3440.106)
(Driver info: chromedriver=2.37.544337 (8c0344a12e552148c185f7d5117db1f28d6c9e85),platform=Mac OS X 10.13.6 x86_64)
/private/var/www/app/vendor/facebook/webdriver/lib/Exception/WebDriverException.php:114
/private/var/www/app/vendor/facebook/webdriver/lib/Remote/HttpCommandExecutor.php:326
/private/var/www/app/vendor/facebook/webdriver/lib/Remote/RemoteWebDriver.php:547
/private/var/www/app/vendor/facebook/webdriver/lib/Remote/RemoteWebDriver.php:226
/private/var/www/app/vendor/symfony/panther/src/Client.php:253
/private/var/www/app/vendor/symfony/panther/src/Client.php:165
/private/var/www/app/tests/Controller/ControllerTest.php:193
What is there wrong?
$client->getResponse()->getStatusCode
is invalid as getResponse
returns an object. I'm confused, does the getResponse
function have to be wrapped inside PantherClient?
When using the example code, i.e
$client = \Panthere\Client::createChromeClient();
$crawler = $client->request('GET', 'http://api-platform.com'); // Yes, this website is 100% in JavaScript
$link = $crawler->selectLink('Support')->link();
$crawler = $client->click($link);
// Wait for an element to be rendered
$client->waitFor('.support');
echo $crawler->filter('.support')->text();
An Exception is thrown:
Return value of Panthere\Client::waitFor() must be an instance of Panthere\object, instance of Facebook\WebDriver\Remote\RemoteWebElement returned
TypeError
in vendor/symfony/panthere/src/Client.php (line 230)
Client->waitFor('.support')
in src/Controller/StocksController.php (line 97)
$link = $crawler->selectLink('Support')->link(); $crawler = $client->click($link);// Wait for an element to be rendered $client->waitFor('.support'); echo $crawler->filter('.support')->text(); // $client->takeScreenshot('screen.png'); // Yeah, screenshot! }
StocksController->seekingalphaDividendScraper('R')
in src/Controller/StocksController.php (line 75)
in vendor/symfony/http-kernel/HttpKernel.php->build (line 149)
in vendor/symfony/http-kernel/HttpKernel.php->handleRaw (line 66)
in vendor/symfony/http-kernel/Kernel.php->handle (line 188)
Kernel->handle(object(Request))
in public/index.php (line 37)
$ php -v
PHP 7.2.7 (cli) (built: Jun 22 2018 06:27:50) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.7, Copyright (c) 1999-2018, by Zend Technologies
{
"type": "project",
"license": "proprietary",
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"eleirbag89/telegrambotphp": "dev-master",
"mgp25/instagram-php": "^4.1",
"paquettg/php-html-parser": "^1.7",
"sensio/framework-extra-bundle": "^5.1",
"shaked/time": "dev-master",
"symfony/asset": "^4.1",
"symfony/console": "^4.1",
"symfony/expression-language": "^4.1",
"symfony/flex": "^1.0",
"symfony/form": "^4.1",
"symfony/framework-bundle": "^4.1",
"symfony/lts": "^4@dev",
"symfony/monolog-bundle": "^3.1",
"symfony/orm-pack": "*",
"symfony/panthere": "dev-master",
"symfony/process": "^4.1",
"symfony/security-bundle": "^4.1",
"symfony/serializer-pack": "*",
"symfony/swiftmailer-bundle": "^3.1",
"symfony/twig-bundle": "^4.1",
"symfony/validator": "^4.1",
"symfony/web-link": "^4.1",
"symfony/webpack-encore-pack": "*",
"symfony/yaml": "^4.1"
},
"require-dev": {
"symfony/debug-pack": "*",
"symfony/dotenv": "^4.1",
"symfony/maker-bundle": "^1.0",
"symfony/profiler-pack": "*",
"symfony/test-pack": "^1.0",
"symfony/web-server-bundle": "^4.1"
},
"repositories": [
{
"type": "git",
"url": "https://github.com/Shaked/TelegramBotPHP"
}
],
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php56": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false
}
}
}
It's a bit strange when making a $client->request('GET', '/foos/')
for $client->getCurrentURL()
to return the full url including the host. Shouldn't it just return the relative url?
e.g. getCurrentURL returns: http://127.0.0.1:9000/foos/
, and I think it should return /foos/
.
How to set custom chrome binary path?
e.g. composer require --dev symfony/panthere:dev-master
src
βββ ...
βββ PHPUnit
Β Β βββ PantherTestCase.php
Β Β βββ PantherTestCaseTrait.php
Β Β βββ ServerExtension.php
Β Β βββ ServerListener.php
Β Β βββ ServerTrait.php
It would be better like that, no ?
According to this code:
I would suggest a few things (before making a PR for it):
public
dir from the composer.json
file if possible (maybe create a getWebServerDir()
protected method)startWebServer()
arguments (especially IP, because it's mandatory to test multi-domains applications)WDYT?
if ($_SERVER['PANTHER_NO_SANDBOX'] ?? $_SERVER['HAS_JOSH_K_SEAL_OF_APPROVAL'] ?? false)
I don't know a JoshK to ask for his seal of approval :( Should this be removed?
(Sorry for all these issues - I'm working on writing lots of e2e tests at the moment!)
Hy,
on a new installation, I'll testing the example request code on a laravel installation and will become, with the default configuration the following error:
unknown error: cannot find Chrome binary (Driver info: chromedriver=2.37.544315 (730aa6a5fdba159ac9f4c1e8cbc59bf1b5ce12b7),platform=Linux 4.4.0-131-generic x86_64)
The binaries are avalaible and executable. I've tested the chromium X64 binary for linux on the command line interface and can resolve the status from the server.
For the completenes here the code to test symfony/panther
:
Route::get('test', function(){
$client = \Symfony\Component\Panther\Client::createChromeClient();
$crawler = $client->request('GET', 'http://api-platform.com'); // Yes, this website is 100% in JavaScript
$link = $crawler->selectLink('Support')->link();
$crawler = $client->click($link);
// Wait for an element to be rendered
$client->waitFor('.support');
echo $crawler->filter('.support')->text();
$client->takeScreenshot('screen.png');
});
The class Symfony\Component\Panther\ServerExtension
described in the section "Improve Performances by Having a Persistent Web Server Running" of the readme is missing in the last release.
By using symfony/web-server-bundle
:
Ok, it is a bundle at the moment but not a component, but it is from the same Symfony family. Very probably, there will be new others needs which will be requested and already covered by this package. Why not use it now ?
So, wanted to give a go to this project. When running example in readme, this happens:
Fatal error: Uncaught RuntimeException: /root/.composer/vendor-bin/dunglas/vendor/dunglas/panthere/src/ProcessManager/../../chromedriver-bin/chromedriver_linux64: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory
in /root/.composer/vendor-bin/dunglas/vendor/dunglas/panthere/src/ProcessManager/WebServerReadinessProbeTrait.php:62
Stack trace:
#0 /root/.composer/vendor-bin/dunglas/vendor/dunglas/panthere/src/ProcessManager/ChromeManager.php(48): Panthere\ProcessManager\ChromeManager->waitUntilReady(Object(Symfony\Component\Process\Process), 'http://127.0.0....')
#1 /root/.composer/vendor-bin/dunglas/vendor/dunglas/panthere/src/Client.php(65): Panthere\ProcessManager\ChromeManager->start()
#2 /root/.composer/vendor-bin/dunglas/vendor/dunglas/panthere/src/Client.php(236): Panthere\Client->start()
#3 /root/.composer/vendor-bin/dunglas/vendor/dunglas/panthere/src/Client.php(156): Panthere\Client->get('http://api-plat...')
#4 /root/.composer/vendor-bin/dunglas/test.php(6) in /root/.composer/vendor-bin/dunglas/vendor/dunglas/panthere/src/ProcessManager/WebServerReadinessProbeTrait.php on line 62
I got a real case, on this website there's no form but an ajax call launched when I put value in this input.
But I can't use ->form() as there's no form.
Is setValue on element possible ?
The current mouse API of the Panther client is still little bit messy and confusing, despite #128. Have a look:
click(Symfony\Component\DomCrawler\Link $link)
getMouse()->click(Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates $where)
getMouse()->clickTo($cssSelector)
getMouse()->contextClick(Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates $where)
getMouse()->contextClickTo($cssSelector)
getMouse()->doubleClick(Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates $where)
getMouse()->doubleClickTo($cssSelector)
getMouse()->mouseDown(Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates $where)
getMouse()->mouseDownTo($cssSelector)
getMouse()->mouseMove(Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates $where, $xOffset = null, $yOffset = null)
getMouse()->mouseMoveTo($cssSelector, $xOffset = null, $yOffset = null)
getMouse()->mouseUp(Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates $where)
getMouse()->mouseUpTo($cssSelector)
I suggest:
getMouse() // is marked as internal
click($cssSelector) // is able to deal with Crawler Link, Panther Link and getMouse()->clickTo($cssSelector)
contextClick($cssSelector) // calls getMouse()->contextClickTo($cssSelector)
doubleClick($cssSelector) // calls getMouse()->doubleClickTo($cssSelector)
mouseDown($cssSelector) // calls getMouse()->mouseDownTo($cssSelector)
mouseMove($cssSelector, $xOffset = null, $yOffset = null) // calls getMouse()->mouseMoveTo($cssSelector, $xOffset = null, $yOffset = null)
mouseUp($cssSelector) // calls getMouse()->mouseUpTo($cssSelector)
My project have routing based on hosts. But web driver make request to http://127.0.0.1:9080.
How can i change host?
I'm using Panther to crawl and analyse other's websites. Is there an easy way to mock the Client and Crawler class for unit testing?
Thanks!
If the script that's fetched doesnt execute without an error, the readiness probe loops endlessly.
I'm currently not sure what happens, but i think it might be a issue with my php version.
In my case, the kernel fails completely and a 5xx is returned.
Here's my test case:
namespace Tests\EsterenMaps\Controller\PanthereTests;
use Panthere\PanthereTestCase;
use Tests\WebTestCase as PiersTestCase;
class JSMapsControllerTest extends PanthereTestCase
{
use PiersTestCase;
public function testMapIndex()
{
static::startWebServer(null);
$client = static::createPanthereClient();
$crawler = $client->request('GET', 'http://maps.esteren.piers:9000/fr/map/map-tri-kazel');
static::assertSame(200, $client->getInternalResponse()->getStatus());
static::assertCount(1, $crawler->filter('#map_wrapper'), 'Map view seems broken');
}
}
The maps.esteren.piers
is resolved to 127.0.0.1
in my hosts file so it's not an issue with hosts.
I'm using the #31 fix
For debug purposes, I updated WebServerReadinessProbeTrait::waitUntilReady()
a little to check why it is throwing an exception:
+dump($process->getStatus());
while (Process::STATUS_STARTED !== ($status = $process->getStatus()) || false === @\file_get_contents($url, false, $context)) {
+ dump($process->getStatus());
if (Process::STATUS_TERMINATED === $status) {
+ dump($process);
throw new \RuntimeException($process->getErrorOutput(), $process->getExitCode());
}
// block until the web server is ready
\usleep(1000);
}
Here's my output:
Testing Tests\EsterenMaps\Controller\PanthereTests\JSMapsControllerTest
"started"
"started"
"terminated"
"terminated"
Symfony\Component\Process\Process {#38242
-callback: null
-hasCallback: false
-commandline: array:6 [
0 => "E:\dev\php72-nts\php.exe"
1 => "-dvariables_order=EGPCS"
2 => "-S"
3 => "127.0.0.1:9000"
4 => "-t"
5 => "E:\dev\www\corahn_rin\vendor\dunglas\panthere\src/../../../../public"
]
-cwd: "E:\dev\www\corahn_rin\vendor\dunglas\panthere\src/../../../../public"
-env: null
-input: null
-starttime: 1528881806.93
-lastOutputTime: 1528881806.93
-timeout: null
-idleTimeout: null
-exitcode: -1073740791
-fallbackStatus: []
-processInformation: array:8 [
"command" => "cmd /V:ON /E:ON /D /C (E:\dev\php72-nts\php.exe -dvariables_order=EGPCS -S 127.0.0.1:9000 -t "E:\dev\www\corahn_rin\vendor\dunglas\panthere\src/../../../../public") 1>"E:\dev\www\tmp\php72\sf_proc_00.out" 2>"E:\dev\www\tmp\php72\sf_proc_00.err""
"pid" => 9492
"running" => false
"signaled" => false
"stopped" => false
"exitcode" => -1073740791
"termsig" => 0
"stopsig" => 0
]
-outputDisabled: false
-stdout: stream resource {@5903
wrapper_type: "PHP"
stream_type: "TEMP"
mode: "w+b"
unread_bytes: 0
seekable: true
uri: "php://temp/maxmemory:1048576"
options: []
}
-stderr: stream resource {@5905
wrapper_type: "PHP"
stream_type: "TEMP"
mode: "w+b"
unread_bytes: 0
seekable: true
uri: "php://temp/maxmemory:1048576"
options: []
}
-process: Closed resource @5917
-status: "terminated"
-incrementalOutputOffset: 0
-incrementalErrorOutputOffset: 0
-tty: null
-pty: false
-useFileHandles: true
-processPipes: Symfony\Component\Process\Pipes\WindowsPipes {#36889
-files: array:2 [
1 => "E:\dev\www\tmp\php72\sf_proc_00.out"
2 => "E:\dev\www\tmp\php72\sf_proc_00.err"
]
-fileHandles: []
-readBytes: array:2 [
1 => 0
2 => 0
]
-haveReadSupport: true
+pipes: []
-inputBuffer: ""
-input: null
-blocked: false
-lastError: null
}
-latestSignal: null
}
E:\dev\www\corahn_rin\vendor\dunglas\panthere\src\ProcessManager\WebServerReadinessProbeTrait.php:54
E:\dev\www\corahn_rin\vendor\dunglas\panthere\src\ProcessManager\WebServerManager.php:69
E:\dev\www\corahn_rin\vendor\dunglas\panthere\src\PanthereTestCase.php:99
E:\dev\www\corahn_rin\tests\EsterenMaps\Controller\PanthereTests\JSMapsControllerTest.php:23
Something very strange is that if I run the provided command-line instruction:
cmd /V:ON /E:ON /D /C (E:\dev\php72-nts\php.exe -dvariables_order=EGPCS -S 127.0.0.1:9000 -t "E:\dev\www\corahn_rin\vendor\dunglas\panthere\src/../../../../public") 1>"E:\dev\www\tmp\php72\sf_proc_00.out" 2>"E:\dev\www\tmp\php72\sf_proc_00.err"
The server runs properly and I can make HTTP calls to it (even if I retrieve HTTP errors because of env vars), but at least it keeps being started and doesn't quit anytime.
Could it be that file_get_contents()
that makes the server fail? Or anything else? Am I missing something?
I'm using Windows 10 and PHP 7.2.2 NTS.
I use the filter
method to target elements, and I want to clear out the product title, and type "test title2":
$crawler->filter('#product_title')->clear()->sendKeys('test title2');
But this gives the error: InvalidArgumentException: The "Symfony\Component\Panther\DomCrawler\Crawler::clear" method is not supported when using WebDriver.
I instead have to use:
$crawler->findElement(WebDriverBy::id('product_title'))->clear()->sendKeys('test title2');
I think this is an inconsistency which need addressing?
I've just spent the last few hours trying to figure out why a url that should be 404'ing is returning 200. I assumed it was a problem with the cache, but after dd'ing the response, clearly it isn't. The response contains the normal 404 response text from symfony, but with a 200 status.
reproduce: use a panther client to make a request to a non-existing url, and see the status is 200, instead of 404.
If a PHP file is given on the command line when the web server is started it is treated as a "router" script. The script is run at the start of each HTTP request.
http://php.net/manual/en/features.commandline.webserver.php
Basically, we could add a router param to createPantherClient()
method.
protected static function createPantherClient(
string $hostname = '127.0.0.1',
int $port = 9000,
string $router = null
): PantherClient
If you are interested, I can suggest a PR.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.