diff --git a/CHANGELOG.md b/CHANGELOG.md index 57a57b6..f403d3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## [Unreleased] + +### Added +- Targeted browser installation through `playwright-install [browser...]` + ## [1.4.0] - 2026-08-10 ### Added diff --git a/README.md b/README.md index 5eaf3e0..049906d 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ Install the Playwright browsers (Chromium, Firefox, WebKit): # Run after composer install in your application or in this repository vendor/bin/playwright-install --browsers +# Or install only the browser targets your project uses +vendor/bin/playwright-install chromium + # On fresh machines/CI where you need Playwright's OS dependencies too vendor/bin/playwright-install --with-deps @@ -44,8 +47,8 @@ vendor/bin/playwright-install --with-deps vendor/bin/playwright-install --dry-run --with-deps ``` -For advanced install options (including browser cache location), see the -[Getting Started guide](docs/guide/getting-started.md). +For targeted installation, browser cache location, and Chrome or Edge channels, +see [Browsers, Browser Types, and Channels](docs/guide/browsers.md). ## Quick Start diff --git a/bin/playwright-install b/bin/playwright-install index b203613..3419d63 100755 --- a/bin/playwright-install +++ b/bin/playwright-install @@ -50,6 +50,11 @@ final class PlaywrightServerInstaller private bool $withDeps; + /** + * @var list + */ + private array $browserTargets; + /** * Cache of command availability checks. * @@ -57,7 +62,10 @@ final class PlaywrightServerInstaller */ private array $commandAvailability = []; - public function __construct(bool $verbose, bool $dryRun, bool $installBrowsers, bool $withDeps) + /** + * @param list $browserTargets + */ + public function __construct(bool $verbose, bool $dryRun, bool $installBrowsers, bool $withDeps, array $browserTargets) { $this->serverDir = __DIR__; $this->output = new ConsoleOutput(); @@ -65,6 +73,7 @@ final class PlaywrightServerInstaller $this->dryRun = $dryRun; $this->shouldInstallBrowsers = $installBrowsers; $this->withDeps = $withDeps; + $this->browserTargets = $browserTargets; if ($this->verbose) { $this->output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); @@ -288,6 +297,16 @@ final class PlaywrightServerInstaller { $this->output->writeln('Installing Playwright browsers...'); + $brandedTargets = array_intersect($this->browserTargets, [ + 'chrome', + 'chrome-beta', + 'msedge', + 'msedge-beta', + ]); + if ([] !== $brandedTargets) { + $this->output->writeln('Warning: branded browsers are installed in the operating system\'s global location.'); + } + $packageManager = $this->detectPackageManager(); $command = $this->getBrowserInstallCommand($packageManager); @@ -304,6 +323,8 @@ final class PlaywrightServerInstaller $args[] = '--with-deps'; } + array_push($args, ...$this->browserTargets); + return match ($packageManager) { 'pnpm' => array_merge(['pnpm', 'exec', 'playwright'], $args), 'yarn' => array_merge(['yarn', 'playwright'], $args), @@ -363,6 +384,17 @@ $dryRun = false; $installBrowsers = false; $withDeps = false; $help = false; +$browserTargets = []; +$defaultBrowsersRequested = false; +$supportedBrowserTargets = [ + 'chromium', + 'firefox', + 'webkit', + 'chrome', + 'chrome-beta', + 'msedge', + 'msedge-beta', +]; foreach ($args as $arg) { switch ($arg) { @@ -379,27 +411,65 @@ foreach ($args as $arg) { break; case '--browsers': $installBrowsers = true; + $defaultBrowsersRequested = true; break; case '--with-deps': $installBrowsers = true; $withDeps = true; break; default: - throw new \InvalidArgumentException(sprintf('Unknown option: %s', $arg)); + if (str_starts_with($arg, '-')) { + throw new \InvalidArgumentException(sprintf('Unknown option: %s', $arg)); + } + + if (!in_array($arg, $supportedBrowserTargets, true)) { + fwrite(STDERR, sprintf( + "Unknown browser target: %s. Supported browsers: %s.\n", + $arg, + implode(', ', $supportedBrowserTargets), + )); + + exit(2); + } + + $installBrowsers = true; + if (!in_array($arg, $browserTargets, true)) { + $browserTargets[] = $arg; + } } } +if ($defaultBrowsersRequested && [] !== $browserTargets) { + fwrite(STDERR, "The --browsers option cannot be combined with explicit browser targets.\n"); + + exit(2); +} + if ($help) { echo "Playwright Server Installer\n"; echo "\n"; - echo "Usage: playwright-install [options]\n"; + echo "Usage: playwright-install [options] [browser...]\n"; echo "\n"; echo "Options:\n"; echo " -v, --verbose Show detailed output\n"; echo " -h, --help Show this help message\n"; echo " --dry-run Print commands without executing install steps\n"; - echo " --browsers Install Playwright browser binaries\n"; - echo " --with-deps Install browsers and system dependencies (implies --browsers)\n"; + echo " --browsers Install Playwright's default browsers\n"; + echo " --with-deps Install selected browsers and system dependencies\n"; + echo "\n"; + echo "Managed browser targets:\n"; + echo " chromium Playwright's bundled Chromium browser\n"; + echo " firefox Playwright's Firefox browser\n"; + echo " webkit Playwright's WebKit browser\n"; + echo "\n"; + echo "Branded browser targets:\n"; + echo " chrome Google Chrome stable\n"; + echo " chrome-beta Google Chrome Beta\n"; + echo " msedge Microsoft Edge stable\n"; + echo " msedge-beta Microsoft Edge Beta\n"; + echo "\n"; + echo "Branded browsers are installed in the operating system's global location.\n"; + echo "They are distinct from Playwright's managed Chromium browser.\n"; echo "\n"; echo "Requirements:\n"; echo " - Node.js 20+ (for optimal performance and security)\n"; @@ -410,8 +480,14 @@ if ($help) { echo "\n"; echo "Environment:\n"; echo " PLAYWRIGHT_BROWSERS_PATH Custom directory for Playwright browser binaries\n"; + echo "\n"; + echo "Examples:\n"; + echo " playwright-install --browsers\n"; + echo " playwright-install firefox\n"; + echo " playwright-install chromium webkit\n"; + echo " playwright-install chrome\n"; exit(0); } -$installer = new PlaywrightServerInstaller($verbose, $dryRun, $installBrowsers, $withDeps); +$installer = new PlaywrightServerInstaller($verbose, $dryRun, $installBrowsers, $withDeps, $browserTargets); exit($installer->install()); diff --git a/docs/guide.md b/docs/guide.md index 871cd50..43c6668 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1,6 +1,7 @@ # Playwright PHP - Quick Start Guide - [Getting Started](./guide/getting-started.md) +- [Browsers, Browser Types, and Channels](./guide/browsers.md) - [Core Concepts](./guide/core-concepts.md) - [Handling Authentication](./guide/handling-authentication.md) - [Testing with PHPUnit](./guide/testing-with-phpunit.md) diff --git a/docs/guide/browsers.md b/docs/guide/browsers.md new file mode 100644 index 0000000..7afa7df --- /dev/null +++ b/docs/guide/browsers.md @@ -0,0 +1,117 @@ +# Browsers, Browser Types, and Channels + +Playwright PHP can launch Playwright-managed Chromium, Firefox, and WebKit. It +can also launch supported Google Chrome and Microsoft Edge distributions through +Chromium channels. Installation and launch configuration are separate choices. + +## Choose what to install + +Install Playwright's default managed browser set: + +```bash +vendor/bin/playwright-install --browsers +``` + +This installs Chromium, Firefox, and WebKit, together with the support binaries +required by the bundled Playwright version. + +Install only the browser targets your project needs by passing their names: + +```bash +vendor/bin/playwright-install chromium +vendor/bin/playwright-install chromium webkit +``` + +The installer accepts these targets: + +| Target | Installation | +| --- | --- | +| `chromium` | Playwright-managed Chromium | +| `firefox` | Playwright-managed Firefox | +| `webkit` | Playwright-managed WebKit | +| `chrome` | Google Chrome stable | +| `chrome-beta` | Google Chrome Beta | +| `msedge` | Microsoft Edge stable | +| `msedge-beta` | Microsoft Edge Beta | + +`--browsers` cannot be combined with explicit targets. Use one form or the +other. + +The installer does not treat browser names as aliases. In particular, `chrome` +installs Google Chrome and does not install Playwright-managed Chromium. There +is no `safari` target because Playwright uses a patched WebKit build, not the +installed Safari application. + +## Understand branded browser installation + +Google Chrome and Microsoft Edge are installed in the operating system's global +location. Playwright warns that this can replace an existing installation. +`PLAYWRIGHT_BROWSERS_PATH` does not redirect branded browser installations. + +Use a branded browser when the test specifically needs its stable or beta +distribution. For general automation, Playwright recommends its managed +Chromium build. + +## Choose a browser type at runtime + +Browser types are the three Playwright API families used to launch browsers: + +| PHP method | Browser type | Default installation | +| --- | --- | --- | +| `$playwright->chromium()` | Chromium | `chromium` | +| `$playwright->firefox()` | Firefox | `firefox` | +| `$playwright->webkit()` | WebKit | `webkit` | + +`Playwright::safari()` is an existing alias for WebKit. It does not automate +Apple Safari. + +Installing several browsers does not make a script run in all of them. Each +launch still selects one browser type. + +## Launch a Chromium channel + +A channel selects a Chromium distribution at launch. It is not another browser +type. + +```php +withChannel('chrome') + ->build(); + +$playwright = PlaywrightFactory::create($config); +$browser = $playwright->chromium()->launch(); +``` + +Install the matching branded target before using a channel on a machine where +that browser is absent: + +```bash +vendor/bin/playwright-install chrome +``` + +`PW_CHANNEL=chrome` provides the same launch choice when configuration is built +with `PlaywrightConfigBuilder::fromEnv()`. + +## Keep the browser cache consistent + +Set `PLAYWRIGHT_BROWSERS_PATH` during installation and at runtime when managed +browsers use a custom cache: + +```bash +PLAYWRIGHT_BROWSERS_PATH=var/playwright-browsers vendor/bin/playwright-install chromium +``` + +Browser revisions are tied to the Playwright version. Run the installer again +after updating Playwright when its required browser revisions change. + +See the official [Playwright browser guide](https://playwright.dev/docs/browsers) +for current browser behavior and platform support. diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 94d2566..2583217 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -34,6 +34,12 @@ root: vendor/bin/playwright-install --browsers ``` +Install a specific browser when the project does not need the full set: + +```bash +vendor/bin/playwright-install chromium +``` + Need Playwright to pull in recommended system dependencies as well (handy on fresh CI runners)? ```bash @@ -49,6 +55,9 @@ If you need a custom browsers cache location (for example in CI), set `PLAYWRIGH PLAYWRIGHT_BROWSERS_PATH=/path/to/.playwright-browsers vendor/bin/playwright-install --browsers ``` +For browser targets, branded Chrome and Edge channels, and runtime browser +types, see [Browsers, Browser Types, and Channels](./browsers.md). + ## Your First Script You're now ready to write your first script. Create a new file named `example.php` and add the following code: diff --git a/tests/Integration/Installer/PlaywrightInstallCliTest.php b/tests/Integration/Installer/PlaywrightInstallCliTest.php new file mode 100644 index 0000000..9b617d3 --- /dev/null +++ b/tests/Integration/Installer/PlaywrightInstallCliTest.php @@ -0,0 +1,118 @@ +runInstaller('--dry-run', '--verbose', 'firefox'); + + $this->assertSame(0, $process->getExitCode(), $process->getErrorOutput()); + $this->assertStringContainsString("'playwright' 'install' 'firefox'", $process->getOutput()); + } + + #[Test] + public function itForwardsBrowserTargetsAfterTheSystemDependenciesOption(): void + { + $process = $this->runInstaller('--dry-run', '--verbose', '--with-deps', 'chromium', 'firefox'); + + $this->assertSame(0, $process->getExitCode(), $process->getErrorOutput()); + $this->assertStringContainsString("'playwright' 'install' '--with-deps' 'chromium' 'firefox'", $process->getOutput()); + } + + #[Test] + public function itKeepsTheDefaultBrowserInstallShortcut(): void + { + $process = $this->runInstaller('--dry-run', '--verbose', '--browsers'); + + $this->assertSame(0, $process->getExitCode(), $process->getErrorOutput()); + $this->assertStringContainsString("'playwright' 'install'", $process->getOutput()); + $this->assertStringNotContainsString("'playwright' 'install' 'firefox'", $process->getOutput()); + } + + #[Test] + public function itForwardsBrandedBrowserTargetsWithoutTreatingThemAsAliases(): void + { + $process = $this->runInstaller('--dry-run', '--verbose', 'chrome', 'msedge-beta'); + + $this->assertSame(0, $process->getExitCode(), $process->getErrorOutput()); + $this->assertStringContainsString("'playwright' 'install' 'chrome' 'msedge-beta'", $process->getOutput()); + $this->assertStringContainsString( + "Warning: branded browsers are installed in the operating system's global location.", + $process->getOutput(), + ); + } + + #[Test] + public function itRejectsUnknownBrowserTargetsWithoutNormalizingAliases(): void + { + $process = $this->runInstaller('safari'); + + $this->assertSame(2, $process->getExitCode()); + $this->assertSame('', $process->getOutput()); + $this->assertSame( + "Unknown browser target: safari. Supported browsers: chromium, firefox, webkit, chrome, chrome-beta, msedge, msedge-beta.\n", + $process->getErrorOutput(), + ); + } + + #[Test] + public function itRejectsTheDefaultShortcutCombinedWithExplicitTargets(): void + { + $process = $this->runInstaller('--browsers', 'chromium'); + + $this->assertSame(2, $process->getExitCode()); + $this->assertSame('', $process->getOutput()); + $this->assertSame( + "The --browsers option cannot be combined with explicit browser targets.\n", + $process->getErrorOutput(), + ); + } + + #[Test] + public function itListsTheSupportedBrowserTargetsInHelp(): void + { + $process = $this->runInstaller('--help'); + + $this->assertSame(0, $process->getExitCode(), $process->getErrorOutput()); + $this->assertStringContainsString('Managed browser targets:', $process->getOutput()); + $this->assertStringContainsString("chromium Playwright's bundled Chromium browser", $process->getOutput()); + $this->assertStringContainsString("firefox Playwright's Firefox browser", $process->getOutput()); + $this->assertStringContainsString("webkit Playwright's WebKit browser", $process->getOutput()); + $this->assertStringContainsString('Branded browser targets:', $process->getOutput()); + $this->assertStringContainsString('chrome Google Chrome stable', $process->getOutput()); + $this->assertStringContainsString('msedge-beta Microsoft Edge Beta', $process->getOutput()); + } + + private function runInstaller(string ...$arguments): Process + { + $process = new Process([ + \PHP_BINARY, + dirname(__DIR__, 3).'/bin/playwright-install', + ...$arguments, + ]); + $process->run(); + + return $process; + } +}