diff --git a/docs/api.md b/docs/api.md index ad9772f4ca..4d3e5c40d6 100644 --- a/docs/api.md +++ b/docs/api.md @@ -16,6 +16,7 @@ * [playwright.createBrowserFetcher([options])](#playwrightcreatebrowserfetcheroptions) * [playwright.defaultArgs([options])](#playwrightdefaultargsoptions) * [playwright.devices](#playwrightdevices) + * [playwright.downloadBrowser([options])](#playwrightdownloadbrowseroptions) * [playwright.errors](#playwrighterrors) * [playwright.executablePath()](#playwrightexecutablepath) * [playwright.launch([options])](#playwrightlaunchoptions) @@ -431,6 +432,22 @@ const iPhone = playwright.devices['iPhone 6']; > **NOTE** The old way (Playwright versions <= v1.14.0) devices can be obtained with `require('playwright/DeviceDescriptors')`. +#### playwright.downloadBrowser([options]) +- `options` <[Object]> + - `onProgress` <[function]([number], [number])> A function that will be called with two arguments: + - `downloadedBytes` <[number]> how many bytes have been downloaded + - `totalBytes` <[number]> how large is the total download. +- returns: <[Promise]<[Object]>> Resolves with revision information when the revision is downloaded and extracted + - `revision` <[string]> the revision the info was created from + - `folderPath` <[string]> path to the extracted revision folder + - `executablePath` <[string]> path to the revision executable + - `url` <[string]> URL this revision can be downloaded from + - `local` <[boolean]> whether the revision is locally available on disk + +Downloads the default browser that Playwright controls. The browser is usually around 100mb. + +> **NOTE** Depending on your terminal, the progress bar might not appear. + #### playwright.errors - returns: <[Object]> - `TimeoutError` <[function]> A class of [TimeoutError]. diff --git a/install.js b/install.js index 441b3e3443..0a7bc7f34c 100644 --- a/install.js +++ b/install.js @@ -22,48 +22,32 @@ try { stdio: 'ignore' }); } catch (e) { - console.warn('Build failed'); } (async function() { const {generateWebKitProtocol, generateFirefoxProtocol, generateChromeProtocol} = require('./utils/protocol-types-generator/') ; try { - const chromeRevision = await downloadBrowser('chromium', require('./chromium').createBrowserFetcher()); + const chromeRevision = await downloadBrowser('chromium', require('./chromium')); await generateChromeProtocol(chromeRevision); } catch (e) { console.warn(e.message); } try { - const firefoxRevision = await downloadBrowser('firefox', require('./firefox').createBrowserFetcher()); + const firefoxRevision = await downloadBrowser('firefox', require('./firefox')); await generateFirefoxProtocol(firefoxRevision); } catch (e) { console.warn(e.message); } try { - const webkitRevision = await downloadBrowser('webkit', require('./webkit').createBrowserFetcher()); + const webkitRevision = await downloadBrowser('webkit', require('./webkit')); await generateWebKitProtocol(webkitRevision); } catch (e) { console.warn(e.message); } })(); -function getRevision(browser) { - if (browser === 'chromium') - return require('./package.json').playwright.chromium_revision; - if (browser === 'firefox') - return require('./package.json').playwright.firefox_revision; - if (browser === 'webkit') - return require('./package.json').playwright.webkit_revision; -} -async function downloadBrowser(browser, browserFetcher) { - const revision = getRevision(browser); - - const revisionInfo = browserFetcher.revisionInfo(revision); - - // Do nothing if the revision is already downloaded. - if (revisionInfo.local) - return revisionInfo; +async function downloadBrowser(browser, playwright) { let progressBar = null; let lastDownloadedBytes = 0; function onProgress(downloadedBytes, totalBytes) { @@ -81,8 +65,12 @@ async function downloadBrowser(browser, browserFetcher) { progressBar.tick(delta); } - await browserFetcher.download(revisionInfo.revision, onProgress); + const revisionInfo = await playwright.downloadBrowser({onProgress}); + // Do nothing if the revision is already downloaded. + if (revisionInfo.local) + return revisionInfo; logPolitely(`${browser} downloaded to ${revisionInfo.folderPath}`); + const browserFetcher = playwright.createBrowserFetcher(); const localRevisions = await browserFetcher.localRevisions(); // Remove previous chromium revisions. const cleanupOldVersions = localRevisions.filter(revision => revision !== revisionInfo.revision).map(revision => browserFetcher.remove(revision)); @@ -94,7 +82,6 @@ async function downloadBrowser(browser, browserFetcher) { return revisionInfo; } - function toMegabytes(bytes) { const mb = bytes / 1024 / 1024; return `${Math.round(mb * 10) / 10} Mb`; diff --git a/package.json b/package.json index 62f14bf349..e865adceba 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "extract-zip": "^1.6.6", "https-proxy-agent": "^3.0.0", "mime": "^2.0.3", - "progress": "^2.0.1", "proxy-from-env": "^1.0.0", "rimraf": "^2.6.1", "ws": "^6.1.0" @@ -61,6 +60,7 @@ "node-stream-zip": "^1.8.2", "pixelmatch": "^4.0.2", "pngjs": "^3.3.3", + "progress": "^2.0.1", "text-diff": "^1.0.1", "ts-loader": "^6.1.2", "typescript": "3.6.3", diff --git a/src/chromium/LifecycleWatcher.ts b/src/chromium/LifecycleWatcher.ts index 0b5cfec9a3..3f5e70dc22 100644 --- a/src/chromium/LifecycleWatcher.ts +++ b/src/chromium/LifecycleWatcher.ts @@ -39,7 +39,7 @@ export class LifecycleWatcher { private _newDocumentNavigationCompleteCallback: () => void; private _timeoutPromise: Promise; private _terminationPromise: Promise; - private _terminationCallback: () => void; + private _terminationCallback: (err: Error | null) => void; private _maximumTimer: NodeJS.Timer; private _hasSameDocumentNavigation: boolean; diff --git a/src/chromium/Playwright.ts b/src/chromium/Playwright.ts index 195a9de7ab..eab8e44860 100644 --- a/src/chromium/Playwright.ts +++ b/src/chromium/Playwright.ts @@ -20,14 +20,17 @@ import { ConnectionTransport } from '../ConnectionTransport'; import { DeviceDescriptors } from '../DeviceDescriptors'; import * as Errors from '../Errors'; import { Launcher, LauncherBrowserOptions, LauncherChromeArgOptions, LauncherLaunchOptions } from './Launcher'; +import {download, RevisionInfo} from '../download'; export class Playwright { private _projectRoot: string; private _launcher: Launcher; + downloadBrowser: (options?: { onProgress?: (downloadedBytes: number, totalBytes: number) => void; }) => Promise; constructor(projectRoot: string, preferredRevision: string) { this._projectRoot = projectRoot; this._launcher = new Launcher(projectRoot, preferredRevision); + this.downloadBrowser = download.bind(null, this.createBrowserFetcher(), preferredRevision, 'Chromium'); } launch(options: (LauncherLaunchOptions & LauncherChromeArgOptions & LauncherBrowserOptions) | undefined): Promise { @@ -60,7 +63,7 @@ export class Playwright { return this._launcher.defaultArgs(options); } - createBrowserFetcher(options: BrowserFetcherOptions | undefined): BrowserFetcher { + createBrowserFetcher(options?: BrowserFetcherOptions | undefined): BrowserFetcher { return new BrowserFetcher(this._projectRoot, options); } } diff --git a/src/download.ts b/src/download.ts new file mode 100644 index 0000000000..cfb8e10bb7 --- /dev/null +++ b/src/download.ts @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +export async function download( + browserFetcher: + import('./chromium/BrowserFetcher').BrowserFetcher | + import('./firefox/BrowserFetcher').BrowserFetcher | + import('./webkit/BrowserFetcher').BrowserFetcher, + revision: string, + browserName: string, + {onProgress}: {onProgress?: (downloadedBytes: number, totalBytes: number) => void} = {}) : Promise { + return await browserFetcher.download(revision, onProgress); +} + +export type RevisionInfo = { + folderPath: string, + executablePath: string, + url: string, + local: boolean, + revision: string, +}; diff --git a/src/firefox/Playwright.ts b/src/firefox/Playwright.ts index 2756b6798f..6634398c71 100644 --- a/src/firefox/Playwright.ts +++ b/src/firefox/Playwright.ts @@ -20,14 +20,17 @@ import { ConnectionTransport } from '../ConnectionTransport'; import { DeviceDescriptors } from '../DeviceDescriptors'; import * as Errors from '../Errors'; import { Launcher } from './Launcher'; +import {download, RevisionInfo} from '../download'; export class Playwright { private _projectRoot: string; private _launcher: Launcher; + downloadBrowser: (options?: { onProgress?: (downloadedBytes: number, totalBytes: number) => void; }) => Promise; constructor(projectRoot: string, preferredRevision: string) { this._projectRoot = projectRoot; this._launcher = new Launcher(projectRoot, preferredRevision); + this.downloadBrowser = download.bind(null, this.createBrowserFetcher(), preferredRevision, 'Chromium'); } launch(options: any): Promise { @@ -60,7 +63,7 @@ export class Playwright { return this._launcher.defaultArgs(options); } - createBrowserFetcher(options: any | undefined): BrowserFetcher { + createBrowserFetcher(options?: any | undefined): BrowserFetcher { return new BrowserFetcher(this._projectRoot, { browser: 'firefox', ...options }); } } diff --git a/src/webkit/Browser.ts b/src/webkit/Browser.ts index 6cc07a5012..f37b976238 100644 --- a/src/webkit/Browser.ts +++ b/src/webkit/Browser.ts @@ -20,7 +20,6 @@ import { EventEmitter } from 'events'; import { assert, helper, RegisteredListener } from '../helper'; import { filterCookies, NetworkCookie, rewriteCookies, SetNetworkCookieParam } from '../network'; import { Connection } from './Connection'; -import { Events } from './events'; import { Page, Viewport } from './Page'; import { Target } from './Target'; import { TaskQueue } from './TaskQueue'; diff --git a/src/webkit/NetworkManager.ts b/src/webkit/NetworkManager.ts index 6143c31f65..3e84115371 100644 --- a/src/webkit/NetworkManager.ts +++ b/src/webkit/NetworkManager.ts @@ -90,7 +90,7 @@ export class NetworkManager extends EventEmitter { }); } - _onRequestWillBeSent(event: Protocol.Network.requestWillBeSentPayload, interceptionId: string | null) { + _onRequestWillBeSent(event: Protocol.Network.requestWillBeSentPayload) { let redirectChain: network.Request[] = []; if (event.redirectResponse) { const request = this._requestIdToRequest.get(event.requestId); @@ -101,7 +101,7 @@ export class NetworkManager extends EventEmitter { } } const frame = event.frameId && this._frameManager ? this._frameManager.frame(event.frameId) : null; - const request = new InterceptableRequest(frame, interceptionId, event, redirectChain); + const request = new InterceptableRequest(frame, undefined, event, redirectChain); this._requestIdToRequest.set(event.requestId, request); this.emit(NetworkManagerEvents.Request, request.request); } diff --git a/src/webkit/Playwright.ts b/src/webkit/Playwright.ts index 6e8282243d..a3a84bff38 100644 --- a/src/webkit/Playwright.ts +++ b/src/webkit/Playwright.ts @@ -19,14 +19,17 @@ import { BrowserFetcher, BrowserFetcherOptions } from './BrowserFetcher'; import { DeviceDescriptors } from '../DeviceDescriptors'; import * as Errors from '../Errors'; import { Launcher, LauncherLaunchOptions } from './Launcher'; +import { download, RevisionInfo } from '../download'; export class Playwright { private _projectRoot: string; private _launcher: Launcher; + downloadBrowser: (options?: { onProgress?: (downloadedBytes: number, totalBytes: number) => void; }) => Promise; constructor(projectRoot: string, preferredRevision: string) { this._projectRoot = projectRoot; this._launcher = new Launcher(projectRoot, preferredRevision); + this.downloadBrowser = download.bind(null, this.createBrowserFetcher(), preferredRevision, 'WebKit'); } launch(options: (LauncherLaunchOptions) | undefined): Promise { @@ -52,7 +55,7 @@ export class Playwright { return this._launcher.defaultArgs(options); } - createBrowserFetcher(options: BrowserFetcherOptions | undefined): BrowserFetcher { + createBrowserFetcher(options?: BrowserFetcherOptions | undefined): BrowserFetcher { return new BrowserFetcher(this._projectRoot, options); } } diff --git a/src/webkit/Target.ts b/src/webkit/Target.ts index 15047d3d0d..66c379b37b 100644 --- a/src/webkit/Target.ts +++ b/src/webkit/Target.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { helper, RegisteredListener } from '../helper'; +import { RegisteredListener } from '../helper'; import { Browser, BrowserContext } from './Browser'; import { Page } from './Page'; import { Protocol } from './protocol'; diff --git a/tsconfig.json b/tsconfig.json index 83023e9f8c..37ac591efb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "lib": ["esnext", "dom"], "sourceMap": true, "rootDir": "./src", - "outDir": "./lib" + "outDir": "./lib", + "strictBindCallApply": true }, "compileOnSave": true, "include": ["src/**/*.ts"],