Skip to content
Draft
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
3 changes: 2 additions & 1 deletion src/Api/AwaitableWebpage.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Pest\Browser\Exceptions\BrowserExpectationFailedException;
use Pest\Browser\Execution;
use Pest\Browser\Page as BrowserPage;
use Pest\Browser\Playwright\Page;
use Pest\Browser\Playwright\Playwright;
use Pest\Browser\ServerManager;
Expand All @@ -24,7 +25,7 @@
*/
public function __construct(
private Page $page,
private string $initialUrl,
private string|BrowserPage $initialUrl,
private array $nonAwaitableMethods = [
'assertScreenshotMatches',
'assertNoAccessibilityIssues',
Expand Down
5 changes: 4 additions & 1 deletion src/Api/Concerns/InteractsWithToolbar.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Pest\Browser\Api\Concerns;

use Pest\Browser\Api\Webpage;
use Pest\Browser\Page as BrowserPage;
use Pest\Browser\Support\ComputeUrl;

/**
Expand All @@ -27,8 +28,10 @@ public function refresh(): self
*
* @param array<string, mixed> $options
*/
public function navigate(string $url, array $options = []): self
public function navigate(string|BrowserPage $url, array $options = []): self
{
$this->page->setShorthandElements($url);

$url = ComputeUrl::from($url);

$this->page->goto($url, $options);
Expand Down
6 changes: 3 additions & 3 deletions src/Api/Concerns/MakesConsoleAssertions.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function assertNoBrokenImages(): Webpage

expect($brokenImages)->toBeEmpty(sprintf(
'Expected no broken images on the page initially with the url [%s], but found %s: %s',
$this->initialUrl,
$this->initialUrl(),
count($brokenImages),
implode(', ', $brokenImages),
));
Expand All @@ -64,7 +64,7 @@ public function assertNoConsoleLogs(): Webpage

expect($consoleLogs)->toBeEmpty(sprintf(
'Expected no console logs on the page initially with the url [%s], but found %s: %s',
$this->initialUrl,
$this->initialUrl(),
count($consoleLogs),
implode(', ', array_map(fn (array $log) => $log['message'], $consoleLogs)),
));
Expand All @@ -81,7 +81,7 @@ public function assertNoJavaScriptErrors(): Webpage

expect($javaScriptErrors)->toBeEmpty(sprintf(
'Expected no JavaScript errors on the page initially with the url [%s], but found %s: %s',
$this->initialUrl,
$this->initialUrl(),
count($javaScriptErrors),
implode(', ', array_map(fn (array $log) => $log['message'], $javaScriptErrors)),
));
Expand Down
74 changes: 37 additions & 37 deletions src/Api/Concerns/MakesElementAssertions.php

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/Api/From.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Pest\Browser\Enums\BrowserType;
use Pest\Browser\Enums\Cities;
use Pest\Browser\Enums\Device;
use Pest\Browser\Page as BrowserPage;

/**
* @mixin PendingAwaitablePage
Expand All @@ -22,7 +23,7 @@
public function __construct(
private BrowserType $browserType,
private Device $device,
private string $url,
private string|BrowserPage $url,
private array $options,
) {
//
Expand Down
3 changes: 2 additions & 1 deletion src/Api/On.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Pest\Browser\Enums\BrowserType;
use Pest\Browser\Enums\Device;
use Pest\Browser\Page as BrowserPage;

/**
* @mixin PendingAwaitablePage
Expand All @@ -20,7 +21,7 @@
public function __construct(
private BrowserType $browserType,
private Device $device,
private string $url,
private string|BrowserPage $url,
private array $options,
) {
//
Expand Down
7 changes: 4 additions & 3 deletions src/Api/PendingAwaitablePage.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Pest\Browser\Enums\Cities;
use Pest\Browser\Enums\ColorScheme;
use Pest\Browser\Enums\Device;
use Pest\Browser\Page as BrowserPage;
use Pest\Browser\Playwright\InitScript;
use Pest\Browser\Playwright\Playwright;
use Pest\Browser\Support\ComputeUrl;
Expand All @@ -31,7 +32,7 @@ final class PendingAwaitablePage
public function __construct(
private readonly BrowserType $browserType,
private readonly Device $device,
private readonly string $url,
private readonly string|BrowserPage $url,
private readonly array $options,
) {
//
Expand Down Expand Up @@ -177,8 +178,8 @@ private function createAwaitablePage(): AwaitableWebpage
$url = ComputeUrl::from($this->url);

return new AwaitableWebpage(
$context->newPage()->goto($url, $this->options),
$url,
$context->newPage()->setShorthandElements($this->url)->goto($url, $this->options),
$this->url,
);
}
}
53 changes: 52 additions & 1 deletion src/Api/Webpage.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Pest\Browser\Api;

use BadMethodCallException;
use Pest\Browser\Execution;
use Pest\Browser\Page as BrowserPage;
use Pest\Browser\Playwright\Locator;
use Pest\Browser\Playwright\Page;
use Pest\Browser\Support\GuessLocator;
Expand All @@ -31,11 +33,32 @@ final class Webpage
*/
public function __construct(
private readonly Page $page,
private readonly string $initialUrl,
private readonly string|BrowserPage $initialUrl,
) {
//
}

/**
* Dynamically call a method on the browser.
*
* @param array<int, mixed> $arguments
*
* @throws BadMethodCallException
*/
public function __call(string $method, array $arguments): self
{
if ($this->initialUrl instanceof BrowserPage && method_exists($this->initialUrl, $method)) {
array_unshift($arguments, $this);

// @phpstan-ignore-next-line method.dynamicName
$this->initialUrl->{$method}(...$arguments);

return $this;
}

throw new BadMethodCallException("Call to undefined method [{$method}].");
}

/**
* Dumps the current page's content and stops the execution.
*/
Expand Down Expand Up @@ -72,6 +95,18 @@ public function url(): string
return $this->page->url();
}

/**
* Gets the page's initial URL.
*/
public function initialUrl(): string
{
if ($this->initialUrl instanceof BrowserPage) {
return $this->initialUrl->url();
}

return $this->initialUrl;
}

/**
* Submits the first form found on the page.
*/
Expand Down Expand Up @@ -100,6 +135,8 @@ public function value(string $selector): string

public function within(string $selector, callable $callback): self
{
$selector = $this->resolveShorthandSelector($selector);

$previousScope = $this->currentScope;

$this->currentScope = $previousScope !== null ? $previousScope.' >> '.$selector : $selector;
Expand All @@ -118,6 +155,20 @@ public function within(string $selector, callable $callback): self
*/
private function guessLocator(string $selector, ?string $value = null): Locator
{
$selector = $this->resolveShorthandSelector($selector);

return (new GuessLocator($this->page, $this->currentScope))->for($selector, $value);
}

/**
* Resolve the shorthand selector for the given page.
*/
private function resolveShorthandSelector(string $selector): string
{
$shorthandElements = $this->page->shorthandElements();

return str_replace(
array_keys($shorthandElements), array_values($shorthandElements), $selector
);
}
}
60 changes: 51 additions & 9 deletions src/Browsable.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,29 @@ public function __markAsBrowserTest(): void
/**
* Browse to the given URL.
*
* @template TUrl of array<int, string>|string
* @template TUrl of array<int, string|Page>|string|Page
*
* @param TUrl $url
* @param array<string, mixed> $options
* @return (TUrl is array<int, string> ? ArrayablePendingAwaitablePage : PendingAwaitablePage)
* @return (TUrl is array<int, string|Page> ? ArrayablePendingAwaitablePage : PendingAwaitablePage)
*/
public function visit(array|string $url, array $options = []): ArrayablePendingAwaitablePage|PendingAwaitablePage
public function visit(array|string|Page $url, array $options = []): ArrayablePendingAwaitablePage|PendingAwaitablePage
{
if ($url instanceof Page) {
$options = [
...$this->pageTimezone($url),
...$this->pageLocale($url),
...$options,
];

return new PendingAwaitablePage(
$url->browserType(),
$url->device(),
$url,
$options,
);
}

if (is_string($url)) {
return new PendingAwaitablePage(
Playwright::defaultBrowserType(),
Expand All @@ -52,12 +67,39 @@ public function visit(array|string $url, array $options = []): ArrayablePendingA
}

return new ArrayablePendingAwaitablePage(
array_map(fn (string $singleUrl): PendingAwaitablePage => new PendingAwaitablePage(
Playwright::defaultBrowserType(),
Device::DESKTOP,
$singleUrl,
$options,
), $url),
array_map(fn (string|Page $singleUrl): PendingAwaitablePage => $this->visit($singleUrl, $options), $url),
);
}

/**
* Get the locale from page.
*
* @return array{locale?: string}
*/
private function pageLocale(Page $page): array
{
$locale = $page->locale();

if ($locale === '') {
return [];
}

return ['locale' => $locale];
}

/**
* Get the timezone from page.
*
* @return array{timezoneId?: string}
*/
private function pageTimezone(Page $page): array
{
$timezone = $page->timezone();

if ($timezone === '') {
return [];
}

return ['timezoneId' => $timezone];
}
}
15 changes: 15 additions & 0 deletions src/Page.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Pest\Browser;

abstract class Page
{
use PageConfiguration;

/**
* Get the URL for the page.
*/
abstract public function url(): string;
}
64 changes: 64 additions & 0 deletions src/PageConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace Pest\Browser;

use Pest\Browser\Enums\BrowserType;
use Pest\Browser\Enums\Device;
use Pest\Browser\Playwright\Playwright;

trait PageConfiguration
{
/**
* Get the global element shortcuts for the site.
*
* @return array<string, string>
*/
public static function siteElements(): array
{
return [];
}

/**
* Get the timezone for the page.
*/
public function timezone(): string
{
return '';
}

/**
* Get the locale for the page.
*/
public function locale(): string
{
return '';
}

/**
* Get the element shortcuts for the page.
*
* @return array<string, string>
*/
public function elements(): array
{
return [];
}

/**
* Get the device for the page.
*/
public function device(): Device
{
return Device::DESKTOP;
}

/**
* Get the browser type for the page.
*/
public function browserType(): BrowserType
{
return Playwright::defaultBrowserType();
}
}
Loading