Skip to content
Closed
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
28 changes: 20 additions & 8 deletions src/Browser/PlaywrightBrowser.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

namespace Zenstruck\Browser;

use Playwright\Assertions\Failure\AssertionException;
use Playwright\Console\ConsoleMessage;
use Playwright\Page\PageInterface;
use Playwright\Symfony\Client\PlaywrightKernelClient;
use Playwright\Testing\Expect;
use Symfony\Component\BrowserKit\CookieJar;
use Symfony\Component\Filesystem\Filesystem;
use Zenstruck\Assert;
Expand Down Expand Up @@ -60,6 +62,10 @@ final public function __construct(PlaywrightKernelClient $client, array $options
$this->screenshotDir = $options['screenshot_dir'] ?? null;
$this->consoleLogDir = $options['console_log_dir'] ?? null;

if (null !== ($timeout = $options['default_timeout'] ?? null)) {
$this->page()->setDefaultTimeout((int) $timeout);
}

// subscribe before anything is navigated to, or the messages are already gone
// @todo also collect uncaught errors once playwright-php exposes the "pageerror" event
$this->page()->events()->onConsole(function(ConsoleMessage $message): void {
Expand All @@ -76,9 +82,15 @@ final public function __construct(PlaywrightKernelClient $client, array $options
*/
final public function assertVisible(string $selector): self
{
$element = $this->session()->assert()->elementExists('css', $selector);
$this->session()->assert();

Assert::true($element->isVisible(), 'Expected element "%s" to be visible but it isn\'t.', [$selector]);
try {
(new Expect($this->page()->locator($selector)))->toBeVisible();

Assert::pass();
} catch (AssertionException) {
Assert::fail('Expected element "%s" to be visible but it isn\'t.', [$selector]);
}

return $this;
}
Expand All @@ -88,16 +100,16 @@ final public function assertVisible(string $selector): self
*/
final public function assertNotVisible(string $selector): self
{
$element = $this->session()->page()->find('css', $selector);
$this->session()->assert();

if (!$element) {
Assert::pass();
try {
(new Expect($this->page()->locator($selector)))->toBeHidden();

return $this;
Assert::pass();
} catch (AssertionException) {
Assert::fail('Expected element "%s" to not be visible but it is.', [$selector]);
}

Assert::false($element->isVisible(), 'Expected element "%s" to not be visible but it is.', [$selector]);

return $this;
}

Expand Down
1 change: 1 addition & 0 deletions src/Browser/Test/HasBrowser.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ protected function playwrightBrowser(): PlaywrightBrowser
'console_log_dir' => $_SERVER['BROWSER_CONSOLE_LOG_DIR'] ?? './var/browser/console-logs',
'follow_redirects' => (bool) ($_SERVER['BROWSER_FOLLOW_REDIRECTS'] ?? true),
'catch_exceptions' => (bool) ($_SERVER['BROWSER_CATCH_EXCEPTIONS'] ?? true),
'default_timeout' => $_SERVER['BROWSER_DEFAULT_TIMEOUT'] ?? null,
]);

BrowserExtension::registerBrowser($browser);
Expand Down
46 changes: 46 additions & 0 deletions tests/PlaywrightBrowserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Test;
use Playwright\Exception\PlaywrightException;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Zenstruck\Browser\PlaywrightBrowser;
use Zenstruck\Browser\Test\HasBrowser;
Expand Down Expand Up @@ -163,6 +164,51 @@ public function can_check_if_element_is_visible_and_not_visible(): void
;
}

/**
* @test
*/
#[Test]
public function visibility_assertions_retry_until_the_element_settles(): void
{
// #timeout-box only becomes visible 500ms after the page loads, #hide-box
// is hidden on click without a delay
$this->browser()
->visit('/javascript')
->assertVisible('#timeout-box')
->click('hide')
->assertNotVisible('#hide-box')
;
}

/**
* @test
*/
#[Test]
public function can_configure_the_default_timeout(): void
{
$_SERVER['BROWSER_DEFAULT_TIMEOUT'] = '250';

try {
$start = \hrtime(true);

try {
$this->browser()
->visit('/javascript')
->waitUntilVisible('#invalid-element')
;

$this->fail('The wait should have timed out.');
} catch (PlaywrightException) {
}

// Playwright's own default is 30 seconds: timing out well before that
// proves the configured value was applied
$this->assertLessThan(10.0, (\hrtime(true) - $start) / 1e9);
} finally {
unset($_SERVER['BROWSER_DEFAULT_TIMEOUT']);
}
}

/**
* @test
*/
Expand Down