diff --git a/docs/src/browsers.md b/docs/src/browsers.md index f96881ad33..86f54c1f4e 100644 --- a/docs/src/browsers.md +++ b/docs/src/browsers.md @@ -991,3 +991,41 @@ mvn test Playwright keeps track of the clients that use its browsers. When there are no more clients that require a particular version of the browser, that version is deleted from the system. That way you can safely use Playwright instances of different versions and at the same time, you don't waste disk space for the browsers that are no longer in use. To opt-out from the unused browser removal, you can set the `PLAYWRIGHT_SKIP_BROWSER_GC=1` environment variable. + +### Remove browsers + +This will remove the browsers (chromium, firefox, webkit) of the current Playwright installation: + +```bash js +npx playwright uninstall +``` + +```bash java +mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="uninstall" +``` + +```bash python +playwright uninstall +``` + +```bash csharp +pwsh bin/Debug/netX/playwright.ps1 uninstall +``` + +To remove browsers of other Playwright installations as well, pass `--all` flag: + +```bash js +npx playwright uninstall --all +``` + +```bash java +mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="uninstall --all" +``` + +```bash python +playwright uninstall --all +``` + +```bash csharp +pwsh bin/Debug/netX/playwright.ps1 uninstall --all +``` diff --git a/packages/playwright-core/src/cli/program.ts b/packages/playwright-core/src/cli/program.ts index fb55f8d4d9..2f97e4b6da 100644 --- a/packages/playwright-core/src/cli/program.ts +++ b/packages/playwright-core/src/cli/program.ts @@ -173,6 +173,18 @@ Examples: - $ install chrome firefox Install custom browsers, supports ${suggestedBrowsersToInstall()}.`); +program + .command('uninstall') + .description('Removes browsers used by this version of Playwright from the system (chromium, firefox, webkit, ffmpeg). This does not include branded channels.') + .option('--all', 'Removes all browsers used by any Playwright version from the system.') + .action(async (options: { all?: boolean }) => { + await registry.uninstall(!!options.all).then(({ numberOfBrowsersLeft }) => { + if (!options.all && numberOfBrowsersLeft > 0) { + console.log('Successfully uninstalled Playwright browsers for the current Playwright installation.'); + console.log(`There are still ${numberOfBrowsersLeft} browsers left, used by other Playwright installations.\nTo uninstall Playwright browsers for all versions, re-run with --all flag.`); + } + }).catch(logErrorAndExit); + }); program .command('install-deps [browser...]') diff --git a/packages/playwright-core/src/server/registry/index.ts b/packages/playwright-core/src/server/registry/index.ts index f9bbb9813e..d6f822c119 100644 --- a/packages/playwright-core/src/server/registry/index.ts +++ b/packages/playwright-core/src/server/registry/index.ts @@ -767,6 +767,23 @@ export class Registry { } } + async uninstall(all: boolean): Promise<{ numberOfBrowsersLeft: number }> { + const linksDir = path.join(registryDirectory, '.links'); + if (all) { + const links = await fs.promises.readdir(linksDir).catch(() => []); + for (const link of links) + await fs.promises.unlink(path.join(linksDir, link)); + } else { + await fs.promises.unlink(path.join(linksDir, calculateSha1(PACKAGE_PATH))).catch(() => {}); + } + + // Remove stale browsers. + await this._validateInstallationCache(linksDir); + return { + numberOfBrowsersLeft: (await fs.promises.readdir(registryDirectory).catch(() => [])).filter(browserDirectory => isBrowserDirectory(browserDirectory)).length + }; + } + private _downloadURLs(descriptor: BrowsersJSONDescriptor): string[] { const paths = (DOWNLOAD_PATHS as any)[descriptor.name]; const downloadPathTemplate: string|undefined = paths[hostPlatform] || paths['']; diff --git a/tests/installation/playwright-cli-install-should-work.spec.ts b/tests/installation/playwright-cli-install-should-work.spec.ts index 1a348e193f..d5f3013913 100755 --- a/tests/installation/playwright-cli-install-should-work.spec.ts +++ b/tests/installation/playwright-cli-install-should-work.spec.ts @@ -33,3 +33,11 @@ test('codegen should work', async ({ exec, installedSoftwareOnDisk }) => { await exec('node sanity.js playwright none', { env: { PLAYWRIGHT_BROWSERS_PATH: undefined } }); await exec('node sanity.js playwright'); }); + +test('should be able to remove browsers', async ({ exec, installedSoftwareOnDisk }) => { + await exec('npm i --foreground-scripts playwright', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } }); + await exec('npx playwright install chromium'); + expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg']); + await exec('npx playwright uninstall'); + expect(await installedSoftwareOnDisk()).toEqual([]); +});