From ec373c743011cde77d1be24329483c70b66056b5 Mon Sep 17 00:00:00 2001 From: Peter Elmered Date: Fri, 26 Jun 2026 13:46:04 +0200 Subject: [PATCH] feat: add slow-motion support to ease debugging Adds an optional delay before each browser action, mapped to Playwright's slowMo launch option: - CLI: `--slow-mo` (defaults to 500ms) or `--slow-mo ` for an explicit delay - Config: `pest()->browser()->slowMo()` / `->slowMo($ms)` slowMo defaults to 0 (no delay), so the launch options are unchanged when unused. --- src/Configuration.php | 10 ++++ src/Playwright/Client.php | 1 + src/Playwright/Playwright.php | 27 ++++++++++ src/Plugin.php | 18 +++++++ .../Configuration/SlowMoConfigurationTest.php | 51 +++++++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 tests/Unit/Configuration/SlowMoConfigurationTest.php diff --git a/src/Configuration.php b/src/Configuration.php index bf3c458f..d04fb215 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -85,6 +85,16 @@ public function headed(): self return $this; } + /** + * Slows down each browser action by the given number of milliseconds. + */ + public function slowMo(int $milliseconds = Playwright::DEFAULT_SLOW_MO): self + { + Playwright::setSlowMo($milliseconds); + + return $this; + } + /** * Sets the browsers userAgent. */ diff --git a/src/Playwright/Client.php b/src/Playwright/Client.php index 876e7af3..2997fcd7 100644 --- a/src/Playwright/Client.php +++ b/src/Playwright/Client.php @@ -53,6 +53,7 @@ public function connectTo(string $url): void $launchOptions = json_encode([ 'headless' => Playwright::isHeadless(), + 'slowMo' => Playwright::slowMo(), 'ignoreHTTPSErrors' => true, 'bypassCSP' => true, ]); diff --git a/src/Playwright/Playwright.php b/src/Playwright/Playwright.php index c0cffae1..6f8d9355 100644 --- a/src/Playwright/Playwright.php +++ b/src/Playwright/Playwright.php @@ -12,6 +12,12 @@ */ final class Playwright { + /** + * The default slow-motion delay, in milliseconds, used when `--slow-mo` is + * passed without a value. + */ + public const int DEFAULT_SLOW_MO = 500; + /** * Browser types * @@ -49,6 +55,11 @@ final class Playwright */ private static int $timeout = 5_000; + /** + * The delay, in milliseconds, applied before each browser action. + */ + private static int $slowMo = 0; + /** * The default userAgent. */ @@ -131,6 +142,22 @@ public static function timeout(): int return self::$timeout; } + /** + * Set the delay, in milliseconds, applied before each browser action. + */ + public static function setSlowMo(int $milliseconds): void + { + self::$slowMo = $milliseconds; + } + + /** + * Get the delay, in milliseconds, applied before each browser action. + */ + public static function slowMo(): int + { + return self::$slowMo; + } + /** * Set the default userAgent. */ diff --git a/src/Plugin.php b/src/Plugin.php index 90ff64ca..173c0fd4 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -118,6 +118,24 @@ public function handleArguments(array $arguments): array $arguments = array_values($arguments); } + if ($this->hasArgument('--slow-mo', $arguments)) { + $index = array_search('--slow-mo', $arguments, true); + + // `--slow-mo` may be passed bare (uses a sensible default) or with an + // explicit millisecond value: `--slow-mo 250`. + if ($index !== false && isset($arguments[$index + 1]) && is_numeric($arguments[$index + 1])) { + Playwright::setSlowMo((int) $arguments[$index + 1]); + + unset($arguments[$index], $arguments[$index + 1]); + } else { + Playwright::setSlowMo(Playwright::DEFAULT_SLOW_MO); + + unset($arguments[$index]); + } + + $arguments = array_values($arguments); + } + $this->validateNonSupportedParallelFeatures(); return $arguments; diff --git a/tests/Unit/Configuration/SlowMoConfigurationTest.php b/tests/Unit/Configuration/SlowMoConfigurationTest.php new file mode 100644 index 00000000..5d4355f0 --- /dev/null +++ b/tests/Unit/Configuration/SlowMoConfigurationTest.php @@ -0,0 +1,51 @@ +toBe(0); +}); + +it('can set slow motion via configuration', function (): void { + $config = new Configuration(); + + $result = $config->slowMo(250); + + expect($result)->toBeInstanceOf(Configuration::class); + expect(Playwright::slowMo())->toBe(250); +}); + +it('uses a sensible default when no value is given', function (): void { + $config = new Configuration(); + + $config->slowMo(); + + expect(Playwright::slowMo())->toBe(Playwright::DEFAULT_SLOW_MO); +}); + +it('follows fluent interface pattern', function (): void { + $config = new Configuration(); + + $result = $config + ->slowMo(500) + ->timeout(10000); + + expect($result)->toBeInstanceOf(Configuration::class); + expect(Playwright::slowMo())->toBe(500); +}); + +it('stores slow motion in Playwright global state', function (): void { + expect(Playwright::slowMo())->toBe(0); + + Playwright::setSlowMo(1000); + + expect(Playwright::slowMo())->toBe(1000); +});