Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

0.7.1
-----

* Fix some inconsistencies between Chrome and Firefox

0.7.0
-----

Expand Down
51 changes: 48 additions & 3 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ final class Client extends AbstractBrowser implements WebDriver, JavaScriptExecu
private $webDriver;
private $browserManager;
private $baseUri;
private $isFirefox = false;

/**
* @param string[]|null $arguments
Expand Down Expand Up @@ -89,9 +90,30 @@ public function __destruct()

public function start()
{
if (null === $this->webDriver) {
$this->webDriver = $this->browserManager->start();
if (null !== $this->webDriver) {
return;
}

$this->webDriver = $this->browserManager->start();
if ($this->browserManager instanceof FirefoxManager) {
$this->isFirefox = true;

return;
}

if ($this->browserManager instanceof ChromeManager) {
$this->isFirefox = false;

return;
}

if (method_exists($this->webDriver, 'getCapabilities')) {
$this->isFirefox = 'firefox' === $this->webDriver->getCapabilities()->getBrowserName();

return;
}

$this->isFirefox = false;
}

public function getRequest()
Expand Down Expand Up @@ -169,7 +191,30 @@ public function submit(Form $form, array $values = [], array $serverParameters =
}

$button = $form->getButton();
null === $button ? $form->getElement()->submit() : $button->click();

if ($this->isFirefox) {
// For Firefox, we have to wait for the page to reload
// https://github.com/SeleniumHQ/selenium/issues/4570#issuecomment-327473270
$selector = WebDriverBy::cssSelector('html');
$previousId = $this->webDriver->findElement($selector)->getID();

null === $button ? $form->getElement()->submit() : $button->click();

try {
$this->webDriver->wait(5)->until(static function (WebDriver $driver) use ($previousId, $selector) {
try {
return $previousId !== $driver->findElement($selector)->getID();
} catch (NoSuchElementException $e) {
// The html element isn't already available
return false;
}
});
} catch (TimeoutException $e) {
// Probably a form using AJAX, do nothing
}
} else {
null === $button ? $form->getElement()->submit() : $button->click();
}

return $this->crawler = $this->createCrawler();
}
Expand Down
13 changes: 10 additions & 3 deletions src/DomCrawler/Crawler.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ public function text(string $default = null, bool $normalizeWhitespace = true):
public function html($default = null): string
{
try {
$this->getElementOrThrow();
$element = $this->getElementOrThrow();

if ('html' === $element->getTagName()) {
return $this->webDriver->getPageSource();
}

return $this->attr('outerHTML');
} catch (\InvalidArgumentException $e) {
Expand All @@ -227,7 +231,7 @@ public function extract($attributes)
foreach ($this->elements as $element) {
$elements = [];
foreach ($attributes as $attribute) {
$elements[] = '_text' === $attribute ? $element->getText() : $element->getAttribute($attribute);
$elements[] = '_text' === $attribute ? $element->getText() : (string) $element->getAttribute($attribute);
}

$data[] = 1 === $count ? $elements[0] : $elements;
Expand Down Expand Up @@ -385,7 +389,10 @@ private function filterWebDriverBy(WebDriverBy $selector): self
{
$subElements = [];
foreach ($this->elements as $element) {
$subElements = \array_merge($subElements, $element->findElements($selector));
$subElements = \array_merge(
$subElements,
$element->findElements($selector)
);
}

return $this->createSubCrawler($subElements);
Expand Down
13 changes: 11 additions & 2 deletions src/PantherTestCaseTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use Symfony\Component\BrowserKit\HttpBrowser as HttpBrowserClient;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\Panther\Client as PantherClient;
use Symfony\Component\Panther\ProcessManager\ChromeManager;
use Symfony\Component\Panther\ProcessManager\FirefoxManager;
use Symfony\Component\Panther\ProcessManager\WebServerManager;

/**
Expand Down Expand Up @@ -160,14 +162,21 @@ public static function isWebServerStarted()
*/
protected static function createPantherClient(array $options = [], array $kernelOptions = []): PantherClient
{
$browser = ($options['browser'] ?? self::$defaultOptions['browser'] ?? self::CHROME);
$callGetClient = \is_callable([self::class, 'getClient']) && (new \ReflectionMethod(self::class, 'getClient'))->isStatic();
if (null !== self::$pantherClient) {
return $callGetClient ? self::getClient(self::$pantherClient) : self::$pantherClient;
$browserManager = self::$pantherClient->getBrowserManager();
if (
(self::CHROME === $browser && $browserManager instanceof ChromeManager) ||
(self::FIREFOX === $browser && $browserManager instanceof FirefoxManager)
) {
return $callGetClient ? self::getClient(self::$pantherClient) : self::$pantherClient;
}
}

self::startWebServer($options);

if (PantherTestCase::CHROME === ($options['browser'] ?? self::$defaultOptions['browser'] ?? PantherTestCase::CHROME)) {
if (self::CHROME === $browser) {
self::$pantherClients[0] = self::$pantherClient = Client::createChromeClient(null, null, [], self::$baseUri);
} else {
self::$pantherClients[0] = self::$pantherClient = Client::createFirefoxClient(null, null, [], self::$baseUri);
Expand Down
4 changes: 2 additions & 2 deletions src/WebDriver/WebDriverCheckbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,12 @@ private function byVisibleText($text, $partial = false, $select = true)
}
}

private function getRelatedElements($value = null)
private function getRelatedElements($value = null): array
{
$valueSelector = $value ? \sprintf(' and @value = %s', XPathEscaper::escapeQuotes($value)) : '';
if (null === $formId = $this->element->getAttribute('form')) {
$form = $this->element->findElement(WebDriverBy::xpath('ancestor::form'));
if ('' === $formId = $form->getAttribute('id')) {
if ('' === $formId = (string) $form->getAttribute('id')) {
return $form->findElements(WebDriverBy::xpath(\sprintf('.//input[@name = %s%s]', XPathEscaper::escapeQuotes($this->name), $valueSelector)));
}
}
Expand Down
31 changes: 20 additions & 11 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Symfony\Component\Panther\Client;
use Symfony\Component\Panther\Cookie\CookieJar;
use Symfony\Component\Panther\DomCrawler\Crawler;
use Symfony\Component\Panther\ProcessManager\ChromeManager;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
Expand Down Expand Up @@ -61,16 +62,10 @@ public function testWaitFor(string $locator)
$this->assertSame('Hello', $crawler->filter('#hello')->text());
}

public function waitForDataProvider(): array
public function waitForDataProvider(): iterable
{
return [
'css selector' => [
'locator' => '#hello',
],
'xpath expression' => [
'locator' => '//*[@id="hello"]',
],
];
yield 'css selector' => ['locator' => '#hello'];
yield 'xpath expression' => ['locator' => '//*[@id="hello"]'];
}

public function testWaitForInvisibleElement(): void
Expand Down Expand Up @@ -158,7 +153,7 @@ public function testFollowLink(callable $clientFactory, string $type): void
/**
* @dataProvider clientFactoryProvider
*/
public function testSubmitForm(callable $clientFactory, string $type): void
public function testSubmitForm(callable $clientFactory): void
{
/** @var AbstractBrowser $client */
$client = $clientFactory();
Expand All @@ -169,7 +164,7 @@ public function testSubmitForm(callable $clientFactory, string $type): void

$crawler = $client->submit($form);
$this->assertInstanceOf(DomCrawlerCrawler::class, $crawler);
if (Client::class === $type) {
if ($client instanceof Client) {
$this->assertInstanceOf(Crawler::class, $crawler);
}
$this->assertSame(self::$baseUri.'/form-handle.php', $crawler->getUri());
Expand Down Expand Up @@ -294,4 +289,18 @@ public function testServerPort(callable $clientFactory): void
$clientFactory();
$this->assertEquals($expectedPort, \mb_substr(self::$baseUri, -4));
}

/**
* @dataProvider clientFactoryProvider
*/
public function testBrowserProvider(callable $clientFactory): void
{
$client = $clientFactory();
if (!$client instanceof Client) {
$this->markTestSkipped();
}

$client->request('GET', self::$baseUri.'/ua.php');
$this->assertStringContainsString($client->getBrowserManager() instanceof ChromeManager ? 'Chrome' : 'Firefox', $client->getPageSource());
}
}
2 changes: 1 addition & 1 deletion tests/DomCrawler/CrawlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public function testExtract(callable $clientFactory): void
$this->assertSame([['', 'Sibling'], ['foo', 'Sibling 2'], ['', 'Sibling 3']], $crawler->filter('main > p')->extract(['class', '_text']));

// Uncomment when https://github.com/symfony/symfony/pull/26433 will be merged
//$this->assertSame([[], [], []], $crawler->filter('main > p')->extract([]));
$this->assertSame([[], [], []], $crawler->filter('main > p')->extract([]));
}

/**
Expand Down
16 changes: 16 additions & 0 deletions tests/fixtures/ua.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

/*
* This file is part of the Panther project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

require __DIR__.'/security-check.php';

echo $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';