From ce2f3b55dc5f9826c92c76ae60fe8cadea5f8df1 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 18:49:07 +0500 Subject: [PATCH 01/18] Exten client to handle dialogs --- src/Playwright/Client.php | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Playwright/Client.php b/src/Playwright/Client.php index 876e7af3..da192c7c 100644 --- a/src/Playwright/Client.php +++ b/src/Playwright/Client.php @@ -26,6 +26,11 @@ final class Client */ private ?WebsocketConnection $websocketConnection = null; + /** + * Current page instance for handling events. + */ + private ?Page $currentPage = null; + /** * Default timeout for requests in milliseconds. */ @@ -88,7 +93,8 @@ public function execute(string $guid, string $method, array $params = [], array while (true) { $responseJson = $this->fetch($this->websocketConnection); - /** @var array{id: string|null, params: array{add: string|null}, error: array{error: array{message: string|null}}} $response */ + + /** @var array{id: string|null, method?: string, params: array{add: string|null, type: string|null, guid: string|null, initializer: array{type: string, message: string, defaultValue: string}|null }, error: array{error: array{message: string|null}}} $response */ $response = json_decode($responseJson, true); if (isset($response['error']['error']['message'])) { @@ -101,6 +107,13 @@ public function execute(string $guid, string $method, array $params = [], array throw new ExpectationFailedException($message); } + // Handle dialog creation + if (isset($response['method']) && $response['method'] === '__create__' + && isset($response['params']['type']) && $response['params']['type'] === 'Dialog' + && isset($response['params']['guid'], $response['params']['initializer'])) { + $this->handleDialogCreation($response['params']['guid'], $response['params']['initializer']); + } + yield $response; if ( @@ -128,6 +141,24 @@ public function timeout(): int return $this->timeout; } + /** + * Sets the current page for event handling. + */ + public function setCurrentPage(Page $page): void + { + $this->currentPage = $page; + } + + /** + * Handles dialog creation events. + * + * @param array{type: string, message: string, defaultValue: string} $initializer + */ + private function handleDialogCreation(string $dialogGuid, array $initializer): void + { + // TODO: Implement dialog handling + } + /** * Fetches the response from the Playwright server. */ From c956b45aeea5440d4a9452b42c5294c662b2e2ae Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 18:56:58 +0500 Subject: [PATCH 02/18] Add Dialog class --- src/Playwright/Dialog.php | 93 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/Playwright/Dialog.php diff --git a/src/Playwright/Dialog.php b/src/Playwright/Dialog.php new file mode 100644 index 00000000..ed46157d --- /dev/null +++ b/src/Playwright/Dialog.php @@ -0,0 +1,93 @@ +guid; + } + + /** + * Returns the dialog's message. + */ + public function message(): string + { + return $this->message; + } + + /** + * Returns the dialog's type (alert, confirm, prompt, beforeunload). + */ + public function type(): string + { + return $this->type; + } + + /** + * Returns the dialog's default value (for prompt dialogs). + */ + public function defaultValue(): string + { + return $this->defaultValue; + } + + /** + * Accepts the dialog. + * For prompt dialogs, you can provide text input. + */ + public function accept(?string $promptText = null): void + { + $params = []; + if ($promptText !== null) { + $params['promptText'] = $promptText; + } + + $response = $this->sendMessage('accept', $params); + $this->processVoidResponse($response); + } + + /** + * Dismisses the dialog. + */ + public function dismiss(): void + { + $response = $this->sendMessage('dismiss'); + $this->processVoidResponse($response); + } + + /** + * Send a message to the dialog via the channel. + * + * @param array $params + */ + private function sendMessage(string $method, array $params = []): \Generator + { + return Client::instance()->execute($this->guid, $method, $params); + } +} \ No newline at end of file From 80d8d847a5a2e5ff3e145ccd3a8181ceb0f37d22 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 19:11:55 +0500 Subject: [PATCH 03/18] handle Dialog creation in client class --- src/Playwright/Client.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Playwright/Client.php b/src/Playwright/Client.php index da192c7c..751133f6 100644 --- a/src/Playwright/Client.php +++ b/src/Playwright/Client.php @@ -156,7 +156,16 @@ public function setCurrentPage(Page $page): void */ private function handleDialogCreation(string $dialogGuid, array $initializer): void { - // TODO: Implement dialog handling + if ($this->currentPage !== null && $this->currentPage->hasDialogHandler()) { + $dialog = new Dialog( + $dialogGuid, + $initializer['type'], + $initializer['message'], + $initializer['defaultValue'] + ); + + $this->currentPage->handleDialogEvent($dialog); + } } /** From a7ba9a2132ffcbcd08ab7c2c31721ae8ecd3def4 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 19:12:41 +0500 Subject: [PATCH 04/18] add dialog handling to page --- src/Playwright/Page.php | 62 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Playwright/Page.php b/src/Playwright/Page.php index d97f3db3..e68abf02 100644 --- a/src/Playwright/Page.php +++ b/src/Playwright/Page.php @@ -4,6 +4,7 @@ namespace Pest\Browser\Playwright; +use Closure; use Generator; use Pest\Browser\Execution; use Pest\Browser\Support\ImageDiffView; @@ -32,6 +33,11 @@ final class Page */ private bool $strictLocators = true; + /** + * Dialog event handler. + */ + private ?Closure $dialogHandler = null; + /** * Creates a new page instance. */ @@ -40,7 +46,7 @@ public function __construct( private readonly string $guid, private readonly string $frameGuid, ) { - // + Client::instance()->setCurrentPage($this); } /** @@ -566,6 +572,60 @@ public function expectScreenshot(bool $fullPage, bool $openDiff): void } } + /** + * Sets up a dialog handler for this page. + */ + public function onDialog(Closure $handler): void + { + $this->dialogHandler = $handler; + + $response = Client::instance()->execute($this->guid, 'updateSubscription', [ + 'event' => 'dialog', + 'enabled' => true, + ]); + $this->processVoidResponse($response); + } + + /** + * Removes any previously set dialog handler. + */ + public function removeDialogHandler(): void + { + $this->dialogHandler = null; + + $response = Client::instance()->execute($this->guid, 'updateSubscription', [ + 'event' => 'dialog', + 'enabled' => false, + ]); + $this->processVoidResponse($response); + } + + /** + * Checks if a dialog handler is currently set. + */ + public function hasDialogHandler(): bool + { + return $this->dialogHandler !== null; + } + + /** + * Gets the current dialog handler. + */ + public function getDialogHandler(): ?Closure + { + return $this->dialogHandler; + } + + /** + * Handles a dialog event from the Playwright server. + */ + public function handleDialogEvent(Dialog $dialog): void + { + if ($this->dialogHandler !== null) { + ($this->dialogHandler)($dialog); + } + } + /** * Closes the page. */ From 9c6f74c3b819d0cb73fd2578a3a53a7c59306f33 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 19:13:19 +0500 Subject: [PATCH 05/18] Add InteractsWithDialogs to expose methods to WebPage --- src/Api/Concerns/InteractsWithDialogs.php | 95 +++++++++++++++++++++++ src/Api/Webpage.php | 1 + 2 files changed, 96 insertions(+) create mode 100644 src/Api/Concerns/InteractsWithDialogs.php diff --git a/src/Api/Concerns/InteractsWithDialogs.php b/src/Api/Concerns/InteractsWithDialogs.php new file mode 100644 index 00000000..459a4522 --- /dev/null +++ b/src/Api/Concerns/InteractsWithDialogs.php @@ -0,0 +1,95 @@ +page->onDialog($handler); + + return $this; + } + + /** + * Remove any previously set dialog handler. + */ + public function removeDialogHandler(): self + { + $this->page->removeDialogHandler(); + + return $this; + } + + /** + * Check if a dialog handler is currently set. + */ + public function hasDialogHandler(): bool + { + return $this->page->hasDialogHandler(); + } + + /** + * Set up automatic dialog acceptance for all future dialogs. + */ + public function acceptingDialogs(?string $promptText = null): self + { + $this->page->onDialog(function (Dialog $dialog) use ($promptText) { + $dialog->accept($promptText); + }); + + return $this; + } + + /** + * Set up automatic dialog dismissal for all future dialogs. + */ + public function dismissingDialogs(): self + { + $this->page->onDialog(function (Dialog $dialog) { + $dialog->dismiss(); + }); + + return $this; + } + + /** + * Set up a dialog handler that accepts confirm dialogs and dismisses all others. + */ + public function acceptingConfirms(): self + { + $this->page->onDialog(function (Dialog $dialog) { + if ($dialog->type() === 'confirm') { + $dialog->accept(); + } else { + $dialog->dismiss(); + } + }); + + return $this; + } + + /** + * Set up a dialog handler that dismisses confirm dialogs and accepts all others. + */ + public function dismissingConfirms(): self + { + $this->page->onDialog(function (Dialog $dialog) { + if ($dialog->type() === 'confirm') { + $dialog->dismiss(); + } else { + $dialog->accept(); + } + }); + + return $this; + } +} diff --git a/src/Api/Webpage.php b/src/Api/Webpage.php index d42876a7..c27b672e 100644 --- a/src/Api/Webpage.php +++ b/src/Api/Webpage.php @@ -12,6 +12,7 @@ final readonly class Webpage { use Concerns\HasWaitCapabilities, + Concerns\InteractsWithDialogs, Concerns\InteractsWithElements, Concerns\InteractsWithFrames, Concerns\InteractsWithScreen, From 3a8e012eb273dc6dca80779b120731ec42677d8c Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 19:15:54 +0500 Subject: [PATCH 06/18] add a basic test --- tests/Browser/Webpage/DialogTest.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Browser/Webpage/DialogTest.php diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php new file mode 100644 index 00000000..e2f5218a --- /dev/null +++ b/tests/Browser/Webpage/DialogTest.php @@ -0,0 +1,28 @@ + ' + +
+ '); + + $dialogHandled = false; + $dialogMessage = ''; + + $page = visit('/')->onDialog(function ($dialog) use (&$dialogHandled, &$dialogMessage) { + $dialogHandled = true; + $dialogMessage = $dialog->message(); + expect($dialog->type())->toBe('alert'); + $dialog->accept(); + }); + + $page->click('#alert-btn'); + + expect($dialogHandled)->toBeTrue(); + expect($dialogMessage)->toBe('Hello World!'); + expect($page->text('#result'))->toBe('Alert handled'); +}); From 04fb7a6c8ea96abfac928da0b549a6a0c43334cc Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 19:18:32 +0500 Subject: [PATCH 07/18] add test to see playwright auto dismisses the dialog --- tests/Browser/Webpage/DialogTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index e2f5218a..50a21739 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -26,3 +26,15 @@ expect($dialogMessage)->toBe('Hello World!'); expect($page->text('#result'))->toBe('Alert handled'); }); + +it('can auto dismiss dialog', function (): void { + Route::get('/', fn (): string => ' + +

Normal text on page.

+ '); + + $page = visit('/'); + + $page->assertSee('Normal text on page.'); +}); + From 53bd9969514f6b2be092acacd4fdae224c167017 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 19:19:31 +0500 Subject: [PATCH 08/18] add test to check playwright cant auto dismiss on interuptins --- tests/Browser/Webpage/DialogTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index 50a21739..ff7637bb 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Illuminate\Support\Facades\Route; +use PHPUnit\Framework\ExpectationFailedException; it('can handle alert dialog with custom handler', function (): void { Route::get('/', fn (): string => ' @@ -38,3 +39,17 @@ $page->assertSee('Normal text on page.'); }); +it('can not auto dismiss dialog when interupted', function (): void { + Route::get('/', fn (): string => ' + +

Normal text on page.

+ '); + + $page = visit('/') + ->onDialog(function ($dialog) { + // + }); + + $page->click('#alert-btn'); +})->throws(ExpectationFailedException::class); + From 45ad75a9879a7787156ff4ea55bb6f162d80fd80 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 19:24:09 +0500 Subject: [PATCH 09/18] refactor the tests --- tests/Browser/Webpage/DialogTest.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index ff7637bb..15371e8a 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Illuminate\Support\Facades\Route; +use Pest\Browser\Playwright\Dialog; use PHPUnit\Framework\ExpectationFailedException; it('can handle alert dialog with custom handler', function (): void { @@ -11,20 +12,15 @@
'); - $dialogHandled = false; - $dialogMessage = ''; - - $page = visit('/')->onDialog(function ($dialog) use (&$dialogHandled, &$dialogMessage) { - $dialogHandled = true; - $dialogMessage = $dialog->message(); + $page = visit('/')->onDialog(function (Dialog $dialog) { expect($dialog->type())->toBe('alert'); + expect($dialog->message())->toBe('Hello World!'); + $dialog->accept(); }); $page->click('#alert-btn'); - expect($dialogHandled)->toBeTrue(); - expect($dialogMessage)->toBe('Hello World!'); expect($page->text('#result'))->toBe('Alert handled'); }); @@ -46,7 +42,7 @@ '); $page = visit('/') - ->onDialog(function ($dialog) { + ->onDialog(function (Dialog $dialog) { // }); From ec40b7eb547a9288e08835768b220174f112effc Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 21:47:09 +0500 Subject: [PATCH 10/18] wip: add more tests --- tests/Browser/Webpage/DialogTest.php | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index 15371e8a..25341130 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -49,3 +49,83 @@ $page->click('#alert-btn'); })->throws(ExpectationFailedException::class); +it('can handle confirm dialog with acceptance', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->onDialog(function ($dialog) { + expect($dialog->type())->toBe('confirm'); + expect($dialog->message())->toBe('Are you sure?'); + $dialog->accept(); + }); + + $page->click('#confirm-btn'); + + expect($page->text('#result'))->toBe('Confirmed'); +}); + +it('can handle confirm dialog with dismissal', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->onDialog(function ($dialog) { + expect($dialog->type())->toBe('confirm'); + expect($dialog->message())->toBe('Are you sure?'); + $dialog->dismiss(); + }); + + $page->click('#confirm-btn'); + + expect($page->text('#result'))->toBe('Cancelled'); +}); + +it('can handle prompt dialog with custom input', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->onDialog(function ($dialog) { + expect($dialog->type())->toBe('prompt'); + expect($dialog->message())->toBe('What is your name?'); + expect($dialog->defaultValue())->toBe('Default Name'); + $dialog->accept('John Doe'); + }); + + $page->click('#prompt-btn'); + + expect($page->text('#result'))->toBe('John Doe'); +}); + +it('can handle prompt dialog with dismissal', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->onDialog(function ($dialog) { + expect($dialog->type())->toBe('prompt'); + $dialog->dismiss(); + }); + + $page->click('#prompt-btn'); + + expect($page->text('#result'))->toBe('No input'); +}); + From 866c4d4beec852b1d120e73e1414408fcf5c6e4f Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 21:48:10 +0500 Subject: [PATCH 11/18] wip: accept or dismiss all dialogs --- src/Api/Concerns/InteractsWithDialogs.php | 4 +-- tests/Browser/Webpage/DialogTest.php | 36 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/Api/Concerns/InteractsWithDialogs.php b/src/Api/Concerns/InteractsWithDialogs.php index 459a4522..7cb4e2b2 100644 --- a/src/Api/Concerns/InteractsWithDialogs.php +++ b/src/Api/Concerns/InteractsWithDialogs.php @@ -40,7 +40,7 @@ public function hasDialogHandler(): bool /** * Set up automatic dialog acceptance for all future dialogs. */ - public function acceptingDialogs(?string $promptText = null): self + public function acceptAllDialogs(?string $promptText = null): self { $this->page->onDialog(function (Dialog $dialog) use ($promptText) { $dialog->accept($promptText); @@ -52,7 +52,7 @@ public function acceptingDialogs(?string $promptText = null): self /** * Set up automatic dialog dismissal for all future dialogs. */ - public function dismissingDialogs(): self + public function dismissAllDialogs(): self { $this->page->onDialog(function (Dialog $dialog) { $dialog->dismiss(); diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index 25341130..f40e32ae 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -129,3 +129,39 @@ expect($page->text('#result'))->toBe('No input'); }); +it('can auto-accept all dialogs', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->acceptAllDialogs('Test User'); + + $page->click('#multi-btn'); + + expect($page->text('#result'))->toBe('true-Test User'); +}); + +it('can auto-dismiss all dialogs', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->dismissAllDialogs(); + + $page->click('#multi-btn'); + + expect($page->text('#result'))->toBe('false-null'); +}); + From 6762f53de1978a3c49f612d7916d763b3a75a831 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 21:52:26 +0500 Subject: [PATCH 12/18] fix: tests --- tests/Browser/Webpage/DialogTest.php | 92 ++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index f40e32ae..76f46711 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -59,8 +59,8 @@ '); $page = visit('/')->onDialog(function ($dialog) { - expect($dialog->type())->toBe('confirm'); expect($dialog->message())->toBe('Are you sure?'); + $dialog->accept(); }); @@ -79,8 +79,8 @@ '); $page = visit('/')->onDialog(function ($dialog) { - expect($dialog->type())->toBe('confirm'); expect($dialog->message())->toBe('Are you sure?'); + $dialog->dismiss(); }); @@ -99,9 +99,9 @@ '); $page = visit('/')->onDialog(function ($dialog) { - expect($dialog->type())->toBe('prompt'); expect($dialog->message())->toBe('What is your name?'); expect($dialog->defaultValue())->toBe('Default Name'); + $dialog->accept('John Doe'); }); @@ -120,7 +120,6 @@ '); $page = visit('/')->onDialog(function ($dialog) { - expect($dialog->type())->toBe('prompt'); $dialog->dismiss(); }); @@ -165,3 +164,88 @@ expect($page->text('#result'))->toBe('false-null'); }); +it('can selectively accept only confirm dialogs', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->acceptingConfirms(); + + $page->click('#mixed-btn'); + + expect($page->text('#result'))->toBe('confirm:true'); +}); + +it('can selectively dismiss only confirm dialogs', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/')->dismissingConfirms(); + + $page->click('#mixed-btn'); + + expect($page->text('#result'))->toBe('confirm:false'); +}); + +it('can remove dialog handlers', function (): void { + $page = visit('/'); + + expect($page->hasDialogHandler())->toBeFalse(); + + $page->acceptAllDialogs(); + expect($page->hasDialogHandler())->toBeTrue(); + + $page->removeDialogHandler(); + expect($page->hasDialogHandler())->toBeFalse(); +}); + +it('can handle multiple sequential dialogs with different types', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $stepCount = 0; + $page = visit('/')->onDialog(function ($dialog) use (&$stepCount) { + $stepCount++; + + if ($stepCount === 1) { + expect($dialog->message())->toBe('Step 1: Alert'); + + $dialog->accept(); + } elseif ($stepCount === 2) { + expect($dialog->message())->toBe('Step 2: Confirm?'); + + $dialog->accept(); + } elseif ($stepCount === 3) { + expect($dialog->message())->toBe('Step 3: Your name?'); + + $dialog->accept('Integration Test'); + } + }); + + $page->click('#sequence-btn'); + + expect($stepCount)->toBe(3); + expect($page->text('#result'))->toBe('Hello Integration Test'); +}); From a8053470e59b2550ba56507615df72c3e19376cb Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 21:58:07 +0500 Subject: [PATCH 13/18] fix: rector --- src/Api/Concerns/InteractsWithDialogs.php | 8 ++++---- src/Playwright/Client.php | 2 +- src/Playwright/Dialog.php | 15 ++++++++------- src/Playwright/Page.php | 4 ++-- tests/Browser/Webpage/DialogTest.php | 14 +++++++------- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/Api/Concerns/InteractsWithDialogs.php b/src/Api/Concerns/InteractsWithDialogs.php index 7cb4e2b2..e2bac915 100644 --- a/src/Api/Concerns/InteractsWithDialogs.php +++ b/src/Api/Concerns/InteractsWithDialogs.php @@ -42,7 +42,7 @@ public function hasDialogHandler(): bool */ public function acceptAllDialogs(?string $promptText = null): self { - $this->page->onDialog(function (Dialog $dialog) use ($promptText) { + $this->page->onDialog(function (Dialog $dialog) use ($promptText): void { $dialog->accept($promptText); }); @@ -54,7 +54,7 @@ public function acceptAllDialogs(?string $promptText = null): self */ public function dismissAllDialogs(): self { - $this->page->onDialog(function (Dialog $dialog) { + $this->page->onDialog(function (Dialog $dialog): void { $dialog->dismiss(); }); @@ -66,7 +66,7 @@ public function dismissAllDialogs(): self */ public function acceptingConfirms(): self { - $this->page->onDialog(function (Dialog $dialog) { + $this->page->onDialog(function (Dialog $dialog): void { if ($dialog->type() === 'confirm') { $dialog->accept(); } else { @@ -82,7 +82,7 @@ public function acceptingConfirms(): self */ public function dismissingConfirms(): self { - $this->page->onDialog(function (Dialog $dialog) { + $this->page->onDialog(function (Dialog $dialog): void { if ($dialog->type() === 'confirm') { $dialog->dismiss(); } else { diff --git a/src/Playwright/Client.php b/src/Playwright/Client.php index 751133f6..0d26a140 100644 --- a/src/Playwright/Client.php +++ b/src/Playwright/Client.php @@ -156,7 +156,7 @@ public function setCurrentPage(Page $page): void */ private function handleDialogCreation(string $dialogGuid, array $initializer): void { - if ($this->currentPage !== null && $this->currentPage->hasDialogHandler()) { + if ($this->currentPage instanceof Page && $this->currentPage->hasDialogHandler()) { $dialog = new Dialog( $dialogGuid, $initializer['type'], diff --git a/src/Playwright/Dialog.php b/src/Playwright/Dialog.php index ed46157d..9fa3b512 100644 --- a/src/Playwright/Dialog.php +++ b/src/Playwright/Dialog.php @@ -4,12 +4,13 @@ namespace Pest\Browser\Playwright; +use Generator; use Pest\Browser\Playwright\Concerns\InteractsWithPlaywright; /** * @internal */ -final class Dialog +final readonly class Dialog { use InteractsWithPlaywright; @@ -17,10 +18,10 @@ final class Dialog * Creates a new dialog instance. */ public function __construct( - private readonly string $guid, - private readonly string $type, - private readonly string $message, - private readonly string $defaultValue, + private string $guid, + private string $type, + private string $message, + private string $defaultValue, ) { // } @@ -86,8 +87,8 @@ public function dismiss(): void * * @param array $params */ - private function sendMessage(string $method, array $params = []): \Generator + private function sendMessage(string $method, array $params = []): Generator { return Client::instance()->execute($this->guid, $method, $params); } -} \ No newline at end of file +} diff --git a/src/Playwright/Page.php b/src/Playwright/Page.php index e68abf02..ec41bfb5 100644 --- a/src/Playwright/Page.php +++ b/src/Playwright/Page.php @@ -605,7 +605,7 @@ public function removeDialogHandler(): void */ public function hasDialogHandler(): bool { - return $this->dialogHandler !== null; + return $this->dialogHandler instanceof Closure; } /** @@ -621,7 +621,7 @@ public function getDialogHandler(): ?Closure */ public function handleDialogEvent(Dialog $dialog): void { - if ($this->dialogHandler !== null) { + if ($this->dialogHandler instanceof Closure) { ($this->dialogHandler)($dialog); } } diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index 76f46711..d15650cb 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -12,7 +12,7 @@
'); - $page = visit('/')->onDialog(function (Dialog $dialog) { + $page = visit('/')->onDialog(function (Dialog $dialog): void { expect($dialog->type())->toBe('alert'); expect($dialog->message())->toBe('Hello World!'); @@ -42,7 +42,7 @@ '); $page = visit('/') - ->onDialog(function (Dialog $dialog) { + ->onDialog(function (Dialog $dialog): void { // }); @@ -58,7 +58,7 @@
'); - $page = visit('/')->onDialog(function ($dialog) { + $page = visit('/')->onDialog(function (Dialog $dialog): void { expect($dialog->message())->toBe('Are you sure?'); $dialog->accept(); @@ -78,7 +78,7 @@
'); - $page = visit('/')->onDialog(function ($dialog) { + $page = visit('/')->onDialog(function (Dialog $dialog): void { expect($dialog->message())->toBe('Are you sure?'); $dialog->dismiss(); @@ -98,7 +98,7 @@
'); - $page = visit('/')->onDialog(function ($dialog) { + $page = visit('/')->onDialog(function (Dialog $dialog): void { expect($dialog->message())->toBe('What is your name?'); expect($dialog->defaultValue())->toBe('Default Name'); @@ -119,7 +119,7 @@
'); - $page = visit('/')->onDialog(function ($dialog) { + $page = visit('/')->onDialog(function (Dialog $dialog): void { $dialog->dismiss(); }); @@ -226,7 +226,7 @@ '); $stepCount = 0; - $page = visit('/')->onDialog(function ($dialog) use (&$stepCount) { + $page = visit('/')->onDialog(function (Dialog $dialog) use (&$stepCount): void { $stepCount++; if ($stepCount === 1) { From e5509e1e6bb8f4e77aeb2043f20b44d762156d40 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 22:04:16 +0500 Subject: [PATCH 14/18] fix: phpstan error --- src/Playwright/Client.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Playwright/Client.php b/src/Playwright/Client.php index 0d26a140..d49e7463 100644 --- a/src/Playwright/Client.php +++ b/src/Playwright/Client.php @@ -92,6 +92,7 @@ public function execute(string $guid, string $method, array $params = [], array $this->websocketConnection->sendText($requestJson); while (true) { + // @phpstan-ignore-next-line $responseJson = $this->fetch($this->websocketConnection); /** @var array{id: string|null, method?: string, params: array{add: string|null, type: string|null, guid: string|null, initializer: array{type: string, message: string, defaultValue: string}|null }, error: array{error: array{message: string|null}}} $response */ From 3fac03f67f6170aacecf45f336f3b008ff14c083 Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 22:17:44 +0500 Subject: [PATCH 15/18] fix: tests --- tests/Browser/Webpage/DialogTest.php | 49 ++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index d15650cb..3829bd07 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -12,7 +12,9 @@
'); - $page = visit('/')->onDialog(function (Dialog $dialog): void { + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { expect($dialog->type())->toBe('alert'); expect($dialog->message())->toBe('Hello World!'); @@ -41,10 +43,11 @@

Normal text on page.

'); - $page = visit('/') - ->onDialog(function (Dialog $dialog): void { - // - }); + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { + // + }); $page->click('#alert-btn'); })->throws(ExpectationFailedException::class); @@ -58,7 +61,9 @@
'); - $page = visit('/')->onDialog(function (Dialog $dialog): void { + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { expect($dialog->message())->toBe('Are you sure?'); $dialog->accept(); @@ -78,7 +83,9 @@
'); - $page = visit('/')->onDialog(function (Dialog $dialog): void { + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { expect($dialog->message())->toBe('Are you sure?'); $dialog->dismiss(); @@ -98,7 +105,9 @@
'); - $page = visit('/')->onDialog(function (Dialog $dialog): void { + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { expect($dialog->message())->toBe('What is your name?'); expect($dialog->defaultValue())->toBe('Default Name'); @@ -119,7 +128,9 @@
'); - $page = visit('/')->onDialog(function (Dialog $dialog): void { + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { $dialog->dismiss(); }); @@ -139,7 +150,9 @@
'); - $page = visit('/')->acceptAllDialogs('Test User'); + $page = visit('/'); + + $page->acceptAllDialogs('Test User'); $page->click('#multi-btn'); @@ -157,7 +170,9 @@
'); - $page = visit('/')->dismissAllDialogs(); + $page = visit('/'); + + $page->dismissAllDialogs(); $page->click('#multi-btn'); @@ -174,7 +189,9 @@
'); - $page = visit('/')->acceptingConfirms(); + $page = visit('/'); + + $page->acceptingConfirms(); $page->click('#mixed-btn'); @@ -191,7 +208,9 @@
'); - $page = visit('/')->dismissingConfirms(); + $page = visit('/'); + + $page->dismissingConfirms(); $page->click('#mixed-btn'); @@ -226,7 +245,9 @@ '); $stepCount = 0; - $page = visit('/')->onDialog(function (Dialog $dialog) use (&$stepCount): void { + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog) use (&$stepCount): void { $stepCount++; if ($stepCount === 1) { From fe262b8d80672e9a6e937adecff7b17426432c9f Mon Sep 17 00:00:00 2001 From: Mansoor Khan <8mansoorkhan@gmail.com> Date: Wed, 10 Sep 2025 22:18:00 +0500 Subject: [PATCH 16/18] add one more test --- tests/Browser/Webpage/DialogTest.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/Browser/Webpage/DialogTest.php b/tests/Browser/Webpage/DialogTest.php index 3829bd07..a39ba571 100644 --- a/tests/Browser/Webpage/DialogTest.php +++ b/tests/Browser/Webpage/DialogTest.php @@ -179,6 +179,32 @@ expect($page->text('#result'))->toBe('false-null'); }); +it('can accept one and dismiss all dialogs', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { + if ($dialog->type() === 'alert') { + $dialog->accept(); + } + }); + + $page->dismissAllDialogs(); + + $page->click('#multi-btn'); + + expect($page->text('#result'))->toBe('false-null'); +}); + it('can selectively accept only confirm dialogs', function (): void { Route::get('/', fn (): string => ' + '); + + $page = visit('/'); + + $page->onDialog(function (Dialog $dialog): void { + expect($dialog->message())->toBe('Wrong text'); + + $dialog->accept(); + }); + + $page->click('Show Confirm'); +})->throws(ExpectationFailedException::class);