New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

playwright-core

Package Overview
Dependencies
Maintainers
1
Versions
4761
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

playwright-core - npm Package Compare versions

Comparing version 0.11.1-next.1584577781703 to 0.11.1-next.1584644386005

39

download-browser.js

@@ -16,11 +16,14 @@ /**

*/
const fs = require('fs');
const browserFetcher = require('./lib/server/browserFetcher.js');
const packageJSON = require('./package.json');
async function downloadBrowser(browserType) {
const browser = browserType.name();
async function downloadBrowserWithProgressBar(downloadPath, browser, version = '') {
let progressBar = null;
let lastDownloadedBytes = 0;
function onProgress(downloadedBytes, totalBytes) {
const revision = packageJSON.playwright[`${browser}_revision`];
function progress(downloadedBytes, totalBytes) {
if (!progressBar) {
const ProgressBar = require('progress');
progressBar = new ProgressBar(`Downloading ${browser} ${browserType._revision} - ${toMegabytes(totalBytes)} [:bar] :percent :etas `, {
progressBar = new ProgressBar(`Downloading ${browser} r${revision} - ${toMegabytes(totalBytes)} [:bar] :percent :etas `, {
complete: '=',

@@ -30,2 +33,3 @@ incomplete: ' ',

total: totalBytes,
host: getFromENV('PLAYWRIGHT_DOWNLOAD_HOST'),
});

@@ -37,14 +41,12 @@ }

}
const fetcher = browserType._createBrowserFetcher();
const revisionInfo = fetcher.revisionInfo();
// Do nothing if the revision is already downloaded.
if (revisionInfo.local)
return revisionInfo;
await browserType.downloadBrowserIfNeeded(onProgress);
logPolitely(`${browser} downloaded to ${revisionInfo.folderPath}`);
return revisionInfo;
const executablePath = await browserFetcher.downloadBrowser({
downloadPath,
browser,
revision,
progress,
});
logPolitely(`${browser} downloaded to ${downloadPath}`);
return executablePath;
}
function toMegabytes(bytes) {

@@ -63,2 +65,9 @@ const mb = bytes / 1024 / 1024;

module.exports = {downloadBrowser};
function getFromENV(name) {
let value = process.env[name];
value = value || process.env[`npm_config_${name.toLowerCase()}`];
value = value || process.env[`npm_package_config_${name.toLowerCase()}`];
return value;
}
module.exports = {downloadBrowserWithProgressBar};

@@ -18,7 +18,15 @@ /**

module.exports = new Playwright({
downloadPath: __dirname,
const playwright = new Playwright({
browsers: ['webkit', 'chromium', 'firefox'],
respectEnvironmentVariables: false,
});
try {
const downloadedBrowsers = require('./.downloaded-browsers.json');
playwright.chromium._executablePath = downloadedBrowsers.crExecutablePath;
playwright.firefox._executablePath = downloadedBrowsers.ffExecutablePath;
playwright.webkit._executablePath = downloadedBrowsers.wkExecutablePath;
} catch (e) {
}
module.exports = playwright;

@@ -83,3 +83,3 @@ /**

private _setContentCounter;
private _detachedPromise;
readonly _detachedPromise: Promise<void>;
private _detachedCallback;

@@ -90,11 +90,2 @@ constructor(page: Page, id: string, parentFrame: Frame | null);

waitForLoadState(options?: types.NavigateOptions): Promise<void>;
_waitForSpecificDocument(expectedDocumentId: string): Disposable<Promise<Error | void>>;
_waitForNewDocument(url?: types.URLMatch): Disposable<Promise<{
error?: Error;
documentId: string;
}>>;
_waitForSameDocumentNavigation(url?: types.URLMatch): Disposable<Promise<void>>;
_waitForLifecycle(waitUntil?: types.LifecycleEvent): Disposable<Promise<void>>;
_trackDocumentRequests(): Disposable<Map<string, network.Request>>;
_createFrameDestroyedPromise(): Promise<Error>;
frameElement(): Promise<dom.ElementHandle>;

@@ -154,6 +145,17 @@ _context(contextType: ContextType): Promise<dom.FrameExecutionContext>;

}
declare type Disposable<T> = {
value: T;
dispose: () => void;
};
export declare class FrameTask {
private _frame;
private _failurePromise;
private _requestMap;
private _disposables;
private _url;
constructor(frame: Frame, options: types.TimeoutOptions, url?: string);
raceAgainstFailures<T>(promise: Promise<T>): Promise<T>;
request(id: string): network.Request | undefined;
waitForSameDocumentNavigation(url?: types.URLMatch): Promise<void>;
waitForSpecificDocument(expectedDocumentId: string): Promise<void>;
waitForNewDocument(url?: types.URLMatch): Promise<string>;
waitForLifecycle(waitUntil?: types.LifecycleEvent): Promise<void>;
done(): void;
}
export {};

@@ -322,164 +322,39 @@ "use strict";

url = helper_1.helper.completeUserURL(url);
const { timeout = this._page._timeoutSettings.navigationTimeout() } = options;
const disposer = new Disposer();
const timeoutPromise = disposer.add(createTimeoutPromise(timeout));
const frameDestroyedPromise = this._createFrameDestroyedPromise();
const sameDocumentPromise = disposer.add(this._waitForSameDocumentNavigation());
const requestWatcher = disposer.add(this._trackDocumentRequests());
let navigateResult;
const navigate = async () => {
try {
navigateResult = await this._page._delegate.navigateFrame(this, url, referer);
}
catch (error) {
return error;
}
};
throwIfError(await Promise.race([
navigate(),
timeoutPromise,
frameDestroyedPromise,
]));
const promises = [timeoutPromise, frameDestroyedPromise];
if (navigateResult.newDocumentId)
promises.push(disposer.add(this._waitForSpecificDocument(navigateResult.newDocumentId)));
else
promises.push(sameDocumentPromise);
throwIfError(await Promise.race(promises));
const request = (navigateResult && navigateResult.newDocumentId) ? requestWatcher.get(navigateResult.newDocumentId) : null;
const waitForLifecyclePromise = disposer.add(this._waitForLifecycle(options.waitUntil));
throwIfError(await Promise.race([timeoutPromise, frameDestroyedPromise, waitForLifecyclePromise]));
disposer.dispose();
const frameTask = new FrameTask(this, options, url);
const sameDocumentPromise = frameTask.waitForSameDocumentNavigation();
const navigateResult = await frameTask.raceAgainstFailures(this._page._delegate.navigateFrame(this, url, referer)).catch(e => {
// Do not leave sameDocumentPromise unhandled.
sameDocumentPromise.catch(e => { });
throw e;
});
if (navigateResult.newDocumentId) {
// Do not leave sameDocumentPromise unhandled.
sameDocumentPromise.catch(e => { });
await frameTask.waitForSpecificDocument(navigateResult.newDocumentId);
}
else {
await sameDocumentPromise;
}
const request = (navigateResult && navigateResult.newDocumentId) ? frameTask.request(navigateResult.newDocumentId) : null;
await frameTask.waitForLifecycle(options.waitUntil);
frameTask.done();
return request ? request._finalRequest().response() : null;
function throwIfError(error) {
if (!error)
return;
disposer.dispose();
const message = `While navigating to ${url}: ${error.message}`;
if (error instanceof errors_1.TimeoutError)
throw new errors_1.TimeoutError(message);
throw new Error(message);
}
}
async waitForNavigation(options = {}) {
const disposer = new Disposer();
const requestWatcher = disposer.add(this._trackDocumentRequests());
const { timeout = this._page._timeoutSettings.navigationTimeout() } = options;
const failurePromise = Promise.race([
this._createFrameDestroyedPromise(),
disposer.add(createTimeoutPromise(timeout)),
const frameTask = new FrameTask(this, options);
let documentId;
await Promise.race([
frameTask.waitForNewDocument(options.url).then(id => documentId = id),
frameTask.waitForSameDocumentNavigation(options.url),
]);
let documentId = null;
let error = await Promise.race([
failurePromise,
disposer.add(this._waitForNewDocument(options.url)).then(result => {
if (result.error)
return result.error;
documentId = result.documentId;
}),
disposer.add(this._waitForSameDocumentNavigation(options.url)),
]);
const request = requestWatcher.get(documentId);
if (!error) {
error = await Promise.race([
failurePromise,
disposer.add(this._waitForLifecycle(options.waitUntil)),
]);
}
disposer.dispose();
if (error)
throw error;
const request = documentId ? frameTask.request(documentId) : null;
await frameTask.waitForLifecycle(options.waitUntil);
frameTask.done();
return request ? request._finalRequest().response() : null;
}
async waitForLoadState(options = {}) {
const { timeout = this._page._timeoutSettings.navigationTimeout() } = options;
const disposer = new Disposer();
const error = await Promise.race([
this._createFrameDestroyedPromise(),
disposer.add(createTimeoutPromise(timeout)),
disposer.add(this._waitForLifecycle(options.waitUntil)),
]);
disposer.dispose();
if (error)
throw error;
const frameTask = new FrameTask(this, options);
await frameTask.waitForLifecycle(options.waitUntil);
frameTask.done();
}
_waitForSpecificDocument(expectedDocumentId) {
let resolve;
const promise = new Promise(x => resolve = x);
const watch = (documentId, error) => {
if (documentId === expectedDocumentId)
resolve(error);
else if (!error)
resolve(new Error('Navigation interrupted by another one'));
};
const dispose = () => this._documentWatchers.delete(watch);
this._documentWatchers.add(watch);
return { value: promise, dispose };
}
_waitForNewDocument(url) {
let resolve;
const promise = new Promise(x => resolve = x);
const watch = (documentId, error) => {
if (!error && !helper_1.helper.urlMatches(this.url(), url))
return;
resolve({ error, documentId });
};
const dispose = () => this._documentWatchers.delete(watch);
this._documentWatchers.add(watch);
return { value: promise, dispose };
}
_waitForSameDocumentNavigation(url) {
let resolve;
const promise = new Promise(x => resolve = x);
const watch = () => {
if (helper_1.helper.urlMatches(this.url(), url))
resolve();
};
const dispose = () => this._sameDocumentNavigationWatchers.delete(watch);
this._sameDocumentNavigationWatchers.add(watch);
return { value: promise, dispose };
}
_waitForLifecycle(waitUntil = 'load') {
let resolve;
if (!types.kLifecycleEvents.has(waitUntil))
throw new Error(`Unsupported waitUntil option ${String(waitUntil)}`);
const checkLifecycleComplete = () => {
if (!checkLifecycleRecursively(this))
return;
resolve();
};
const promise = new Promise(x => resolve = x);
const dispose = () => this._page._frameManager._lifecycleWatchers.delete(checkLifecycleComplete);
this._page._frameManager._lifecycleWatchers.add(checkLifecycleComplete);
checkLifecycleComplete();
return { value: promise, dispose };
function checkLifecycleRecursively(frame) {
if (!frame._firedLifecycleEvents.has(waitUntil))
return false;
for (const child of frame.childFrames()) {
if (!checkLifecycleRecursively(child))
return false;
}
return true;
}
}
_trackDocumentRequests() {
const requestMap = new Map();
const dispose = () => {
this._requestWatchers.delete(onRequest);
};
const onRequest = (request) => {
if (!request._documentId || request.redirectedFrom())
return;
requestMap.set(request._documentId, request);
};
this._requestWatchers.add(onRequest);
return { dispose, value: requestMap };
}
_createFrameDestroyedPromise() {
return Promise.race([
this._page._disconnectedPromise.then(() => new Error('Navigation failed because browser has disconnected!')),
this._detachedPromise.then(() => new Error('Navigating frame was detached!')),
]);
}
async frameElement() {

@@ -881,31 +756,2 @@ return this._page._delegate.getFrameElement(this);

}
class Disposer {
constructor() {
this._disposes = [];
}
add({ value, dispose }) {
this._disposes.push(dispose);
return value;
}
dispose() {
for (const dispose of this._disposes)
dispose();
this._disposes = [];
}
}
function createTimeoutPromise(timeout) {
if (!timeout)
return { value: new Promise(() => { }), dispose: () => void 0 };
let timer;
const errorMessage = 'Navigation timeout of ' + timeout + ' ms exceeded';
const promise = new Promise(fulfill => timer = setTimeout(fulfill, timeout))
.then(() => new errors_1.TimeoutError(errorMessage));
const dispose = () => {
clearTimeout(timer);
};
return {
value: promise,
dispose
};
}
function selectorToString(selector, waitFor) {

@@ -959,2 +805,128 @@ let label;

}
class FrameTask {
constructor(frame, options, url) {
this._requestMap = new Map();
this._disposables = [];
this._frame = frame;
this._url = url;
// Process timeouts
let timeoutPromise = new Promise(() => { });
const { timeout = frame._page._timeoutSettings.navigationTimeout() } = options;
if (timeout) {
const errorMessage = 'Navigation timeout of ' + timeout + ' ms exceeded';
let timer;
timeoutPromise = new Promise(fulfill => timer = setTimeout(fulfill, timeout))
.then(() => { throw new errors_1.TimeoutError(errorMessage); });
this._disposables.push(() => clearTimeout(timer));
}
// Process detached frames
this._failurePromise = Promise.race([
timeoutPromise,
this._frame._page._disconnectedPromise.then(() => { throw new Error('Navigation failed because browser has disconnected!'); }),
this._frame._detachedPromise.then(() => { throw new Error('Navigating frame was detached!'); }),
]);
// Collect requests during the task.
const watcher = (request) => {
if (!request._documentId || request.redirectedFrom())
return;
this._requestMap.set(request._documentId, request);
};
this._disposables.push(() => this._frame._requestWatchers.delete(watcher));
this._frame._requestWatchers.add(watcher);
}
async raceAgainstFailures(promise) {
let result;
let error;
await Promise.race([
this._failurePromise.catch(e => error = e),
promise.then(r => result = r).catch(e => error = e)
]);
if (!error)
return result;
this.done();
if (this._url)
error.message = error.message + ` while navigating to ${this._url}`;
throw error;
}
request(id) {
return this._requestMap.get(id);
}
async waitForSameDocumentNavigation(url) {
let resolve;
const promise = new Promise(x => resolve = x);
const watch = () => {
if (helper_1.helper.urlMatches(this._frame.url(), url))
resolve();
};
this._disposables.push(() => this._frame._sameDocumentNavigationWatchers.delete(watch));
this._frame._sameDocumentNavigationWatchers.add(watch);
return this.raceAgainstFailures(promise);
}
async waitForSpecificDocument(expectedDocumentId) {
let resolve;
let reject;
const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
const watch = (documentId, error) => {
if (documentId === expectedDocumentId) {
if (!error)
resolve();
else
reject(error);
}
else if (!error) {
reject(new Error('Navigation interrupted by another one'));
}
};
this._disposables.push(() => this._frame._documentWatchers.delete(watch));
this._frame._documentWatchers.add(watch);
await this.raceAgainstFailures(promise);
}
waitForNewDocument(url) {
let resolve;
let reject;
const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
const watch = (documentId, error) => {
if (!error && !helper_1.helper.urlMatches(this._frame.url(), url))
return;
if (error)
reject(error);
else
resolve(documentId);
};
this._disposables.push(() => this._frame._documentWatchers.delete(watch));
this._frame._documentWatchers.add(watch);
return this.raceAgainstFailures(promise);
}
waitForLifecycle(waitUntil = 'load') {
let resolve;
if (!types.kLifecycleEvents.has(waitUntil))
throw new Error(`Unsupported waitUntil option ${String(waitUntil)}`);
const checkLifecycleComplete = () => {
if (!checkLifecycleRecursively(this._frame))
return;
resolve();
};
const promise = new Promise(x => resolve = x);
this._disposables.push(() => this._frame._page._frameManager._lifecycleWatchers.delete(checkLifecycleComplete));
this._frame._page._frameManager._lifecycleWatchers.add(checkLifecycleComplete);
checkLifecycleComplete();
return this.raceAgainstFailures(promise);
function checkLifecycleRecursively(frame) {
if (!frame._firedLifecycleEvents.has(waitUntil))
return false;
for (const child of frame.childFrames()) {
if (!checkLifecycleRecursively(child))
return false;
}
return true;
}
}
done() {
this._failurePromise.catch(e => { });
for (const disposable of this._disposables)
disposable();
this._disposables = [];
}
}
exports.FrameTask = FrameTask;
//# sourceMappingURL=frames.js.map

@@ -43,10 +43,10 @@ "use strict";

return page;
const { dispose, value: waitForLifecycle } = page.mainFrame()._waitForLifecycle(lifecycle);
const error = await Promise.race([
page.mainFrame()._createFrameDestroyedPromise(),
waitForLifecycle,
]);
dispose();
if (error)
try {
const frameTask = new frames.FrameTask(page.mainFrame(), { timeout: 0 });
await frameTask.waitForLifecycle(lifecycle);
frameTask.done();
}
catch (error) {
return error;
}
return page;

@@ -53,0 +53,0 @@ }

@@ -17,32 +17,14 @@ /**

*/
declare type ParamsGetter = (platform: string, revision: string) => {
downloadUrl: string;
executablePath: string;
};
export declare type OnProgressCallback = (downloadedBytes: number, totalBytes: number) => void;
export declare class BrowserFetcher {
private _downloadsFolder;
private _platform;
private _preferredRevision;
private _params;
constructor(downloadsFolder: string, platform: string, preferredRevision: string, params: ParamsGetter);
canDownload(revision?: string): Promise<boolean>;
download(revision?: string, progressCallback?: OnProgressCallback): Promise<BrowserFetcherRevisionInfo>;
localRevisions(): Promise<string[]>;
remove(revision?: string): Promise<void>;
revisionInfo(revision?: string): BrowserFetcherRevisionInfo;
_getFolderPath(revision: string): string;
}
export declare type BrowserFetcherOptions = {
platform?: string;
path?: string;
export declare type BrowserName = ('chromium' | 'webkit' | 'firefox');
export declare type BrowserPlatform = ('win32' | 'win64' | 'mac10.14' | 'mac10.15' | 'linux');
export declare type DownloadOptions = {
browser: BrowserName;
revision: string;
downloadPath: string;
platform?: BrowserPlatform;
host?: string;
progress?: OnProgressCallback;
};
export declare type BrowserFetcherRevisionInfo = {
folderPath: string;
executablePath: string;
url: string;
local: boolean;
revision: string;
};
export {};
export declare function downloadBrowser(options: DownloadOptions): Promise<string>;
export declare function canDownload(options: DownloadOptions): Promise<boolean>;

@@ -21,90 +21,120 @@ "use strict";

const fs = require("fs");
const os = require("os");
const util = require("util");
const child_process_1 = require("child_process");
const ProxyAgent = require("https-proxy-agent");
const path = require("path");
const platform = require("../platform");
const proxy_from_env_1 = require("proxy-from-env");
const removeRecursive = require("rimraf");
const URL = require("url");
const helper_1 = require("../helper");
const readdirAsync = platform.promisify(fs.readdir.bind(fs));
const mkdirAsync = platform.promisify(fs.mkdir.bind(fs));
const platform = require("../platform");
const unlinkAsync = platform.promisify(fs.unlink.bind(fs));
const chmodAsync = platform.promisify(fs.chmod.bind(fs));
function existsAsync(filePath) {
let fulfill;
const promise = new Promise(x => fulfill = x);
fs.access(filePath, err => fulfill(!err));
return promise;
const existsAsync = (path) => new Promise(resolve => fs.stat(path, err => resolve(!err)));
const DEFAULT_DOWNLOAD_HOSTS = {
chromium: 'https://storage.googleapis.com',
firefox: 'https://playwright.azureedge.net',
webkit: 'https://playwright.azureedge.net',
};
const DOWNLOAD_URLS = {
chromium: {
'linux': '%s/chromium-browser-snapshots/Linux_x64/%d/chrome-linux.zip',
'mac10.14': '%s/chromium-browser-snapshots/Mac/%d/chrome-mac.zip',
'mac10.15': '%s/chromium-browser-snapshots/Mac/%d/chrome-mac.zip',
'win32': '%s/chromium-browser-snapshots/Win/%d/chrome-win.zip',
'win64': '%s/chromium-browser-snapshots/Win_x64/%d/chrome-win.zip',
},
firefox: {
'linux': '%s/builds/firefox/%s/firefox-linux.zip',
'mac10.14': '%s/builds/firefox/%s/firefox-mac.zip',
'mac10.15': '%s/builds/firefox/%s/firefox-mac.zip',
'win32': '%s/builds/firefox/%s/firefox-win32.zip',
'win64': '%s/builds/firefox/%s/firefox-win64.zip',
},
webkit: {
'linux': '%s/builds/webkit/%s/minibrowser-gtk-wpe.zip',
'mac10.14': '%s/builds/webkit/%s/minibrowser-mac-10.14.zip',
'mac10.15': '%s/builds/webkit/%s/minibrowser-mac-10.15.zip',
'win32': '%s/builds/webkit/%s/minibrowser-win64.zip',
'win64': '%s/builds/webkit/%s/minibrowser-win64.zip',
},
};
const RELATIVE_EXECUTABLE_PATHS = {
chromium: {
'linux': ['chrome-linux', 'chrome'],
'mac10.14': ['chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'],
'mac10.15': ['chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'],
'win32': ['chrome-win', 'chrome.exe'],
'win64': ['chrome-win', 'chrome.exe'],
},
firefox: {
'linux': ['firefox', 'firefox'],
'mac10.14': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'],
'mac10.15': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'],
'win32': ['firefox', 'firefox.exe'],
'win64': ['firefox', 'firefox.exe'],
},
webkit: {
'linux': ['pw_run.sh'],
'mac10.14': ['pw_run.sh'],
'mac10.15': ['pw_run.sh'],
'win32': ['MiniBrowser.exe'],
'win64': ['MiniBrowser.exe'],
},
};
const CURRENT_HOST_PLATFORM = (() => {
const platform = os.platform();
if (platform === 'darwin') {
const macVersion = child_process_1.execSync('sw_vers -productVersion').toString('utf8').trim().split('.').slice(0, 2).join('.');
return `mac${macVersion}`;
}
if (platform === 'linux')
return 'linux';
if (platform === 'win32')
return os.arch() === 'x64' ? 'win64' : 'win32';
return platform;
})();
function revisionURL(options) {
const { browser, revision, platform = CURRENT_HOST_PLATFORM, host = DEFAULT_DOWNLOAD_HOSTS[browser], } = options;
helper_1.assert(revision, `'revision' must be specified`);
helper_1.assert(DOWNLOAD_URLS[browser], 'Unsupported browser: ' + browser);
const urlTemplate = DOWNLOAD_URLS[browser][platform];
helper_1.assert(urlTemplate, `ERROR: Playwright does not support ${browser} on ${platform}`);
return util.format(urlTemplate, host, revision);
}
class BrowserFetcher {
constructor(downloadsFolder, platform, preferredRevision, params) {
this._downloadsFolder = downloadsFolder;
this._platform = platform;
this._preferredRevision = preferredRevision;
this._params = params;
async function downloadBrowser(options) {
const { browser, revision, downloadPath, platform = CURRENT_HOST_PLATFORM, progress, } = options;
helper_1.assert(downloadPath, '`downloadPath` must be provided');
const url = revisionURL(options);
const zipPath = path.join(os.tmpdir(), `playwright-download-${browser}-${platform}-${revision}.zip`);
if (await existsAsync(downloadPath))
throw new Error('ERROR: downloadPath folder already exists!');
try {
await downloadFile(url, zipPath, progress);
// await mkdirAsync(downloadPath, {recursive: true});
await extractZip(zipPath, downloadPath);
}
canDownload(revision = this._preferredRevision) {
const url = this._params(this._platform, revision).downloadUrl;
let resolve = () => { };
const promise = new Promise(x => resolve = x);
const request = httpRequest(url, 'HEAD', response => {
resolve(response.statusCode === 200);
});
request.on('error', (error) => {
console.error(error);
resolve(false);
});
return promise;
finally {
if (await existsAsync(zipPath))
await unlinkAsync(zipPath);
}
async download(revision = this._preferredRevision, progressCallback) {
const url = this._params(this._platform, revision).downloadUrl;
const zipPath = path.join(this._downloadsFolder, `download-${this._platform}-${revision}.zip`);
const folderPath = this._getFolderPath(revision);
if (await existsAsync(folderPath))
return this.revisionInfo(revision);
if (!(await existsAsync(this._downloadsFolder)))
await mkdirAsync(this._downloadsFolder);
try {
await downloadFile(url, zipPath, progressCallback);
await extractZip(zipPath, folderPath);
}
finally {
if (await existsAsync(zipPath))
await unlinkAsync(zipPath);
}
const revisionInfo = this.revisionInfo(revision);
if (revisionInfo)
await chmodAsync(revisionInfo.executablePath, 0o755);
return revisionInfo;
}
async localRevisions() {
if (!await existsAsync(this._downloadsFolder))
return [];
const fileNames = await readdirAsync(this._downloadsFolder);
return fileNames.map(fileName => parseFolderPath(fileName)).filter(entry => entry && entry.platform === this._platform).map(entry => entry.revision);
}
async remove(revision = this._preferredRevision) {
const folderPath = this._getFolderPath(revision);
helper_1.assert(await existsAsync(folderPath), `Failed to remove: revision ${revision} is not downloaded`);
await new Promise(fulfill => removeRecursive(folderPath, fulfill));
}
revisionInfo(revision = this._preferredRevision) {
const folderPath = this._getFolderPath(revision);
const params = this._params(this._platform, revision);
const local = fs.existsSync(folderPath);
return { revision, executablePath: path.join(folderPath, params.executablePath), folderPath, local, url: params.downloadUrl };
}
_getFolderPath(revision) {
return path.join(this._downloadsFolder, this._platform + '-' + revision);
}
const executablePath = path.join(downloadPath, ...RELATIVE_EXECUTABLE_PATHS[browser][platform]);
await chmodAsync(executablePath, 0o755);
return executablePath;
}
exports.BrowserFetcher = BrowserFetcher;
function parseFolderPath(folderPath) {
const name = path.basename(folderPath);
const splits = name.split('-');
if (splits.length !== 2)
return null;
const [platform, revision] = splits;
return { platform, revision };
exports.downloadBrowser = downloadBrowser;
async function canDownload(options) {
const url = revisionURL(options);
let resolve = () => { };
const promise = new Promise(x => resolve = x);
const request = httpRequest(url, 'HEAD', response => {
resolve(response.statusCode === 200);
});
request.on('error', (error) => {
console.error(error);
resolve(false);
});
return promise;
}
exports.canDownload = canDownload;
function downloadFile(url, destinationPath, progressCallback) {

@@ -111,0 +141,0 @@ let fulfill = () => { };

@@ -19,3 +19,2 @@ /**

import { BrowserServer } from './browserServer';
import { OnProgressCallback } from './browserFetcher';
export declare type BrowserArgOptions = {

@@ -53,3 +52,2 @@ headless?: boolean;

connect(options: ConnectOptions): Promise<Browser>;
downloadBrowserIfNeeded(progress?: OnProgressCallback): Promise<void>;
}

@@ -17,3 +17,2 @@ /**

*/
import { BrowserFetcher, OnProgressCallback, BrowserFetcherOptions } from '../server/browserFetcher';
import { CRBrowser } from '../chromium/crBrowser';

@@ -25,6 +24,4 @@ import { LaunchOptions, BrowserType } from './browserType';

export declare class Chromium implements BrowserType {
private _downloadPath;
private _downloadHost;
readonly _revision: string;
constructor(downloadPath: string, downloadHost: (string | undefined), preferredRevision: string);
private _executablePath;
executablePath(): string;
name(): string;

@@ -40,10 +37,3 @@ launch(options?: LaunchOptions & {

connect(options: ConnectOptions): Promise<CRBrowser>;
executablePath(): string;
private _defaultArgs;
downloadBrowserIfNeeded(onProgress?: OnProgressCallback): Promise<void>;
_createBrowserFetcher(options?: BrowserFetcherOptions): BrowserFetcher;
_resolveExecutablePath(): {
executablePath: string;
missingText: string | null;
};
}

@@ -22,4 +22,2 @@ "use strict";

const path = require("path");
const util = require("util");
const browserFetcher_1 = require("../server/browserFetcher");
const helper_1 = require("../helper");

@@ -35,6 +33,6 @@ const crBrowser_1 = require("../chromium/crBrowser");

class Chromium {
constructor(downloadPath, downloadHost, preferredRevision) {
this._downloadPath = downloadPath;
this._downloadHost = downloadHost || 'https://storage.googleapis.com';
this._revision = preferredRevision;
executablePath() {
if (!this._executablePath)
throw new Error('No executable path!');
return this._executablePath;
}

@@ -76,9 +74,5 @@ name() {

chromeArguments.push(...args);
let chromeExecutable = executablePath;
if (!executablePath) {
const { missingText, executablePath } = this._resolveExecutablePath();
if (missingText)
throw new Error(missingText);
chromeExecutable = executablePath;
}
const chromeExecutable = executablePath || this._executablePath;
if (!chromeExecutable)
throw new Error(`No executable path is specified. Pass "executablePath" option directly.`);
let browserServer = undefined;

@@ -113,3 +107,3 @@ const { launchedProcess, gracefullyClose } = await processLauncher_1.launchProcess({

if (launchType === 'server') {
const timeoutError = new errors_1.TimeoutError(`Timed out after ${timeout} ms while trying to connect to Chromium! The only Chromium revision guaranteed to work is r${this._revision}`);
const timeoutError = new errors_1.TimeoutError(`Timed out after ${timeout} ms while trying to connect to Chromium!`);
const match = await processLauncher_1.waitForLine(launchedProcess, launchedProcess.stderr, /^DevTools listening on (ws:\/\/.*)$/, timeout, timeoutError);

@@ -132,5 +126,2 @@ browserWSEndpoint = match[1];

}
executablePath() {
return this._resolveExecutablePath().executablePath;
}
_defaultArgs(options = {}, launchType, userDataDir, port) {

@@ -163,64 +154,2 @@ const { devtools = false, headless = !devtools, args = [], } = options;

}
async downloadBrowserIfNeeded(onProgress) {
const fetcher = this._createBrowserFetcher();
const revisionInfo = fetcher.revisionInfo();
// Do nothing if the revision is already downloaded.
if (revisionInfo.local)
return;
await fetcher.download(revisionInfo.revision, onProgress);
}
_createBrowserFetcher(options = {}) {
const downloadURLs = {
linux: '%s/chromium-browser-snapshots/Linux_x64/%d/%s.zip',
mac: '%s/chromium-browser-snapshots/Mac/%d/%s.zip',
win32: '%s/chromium-browser-snapshots/Win/%d/%s.zip',
win64: '%s/chromium-browser-snapshots/Win_x64/%d/%s.zip',
};
const defaultOptions = {
path: path.join(this._downloadPath, '.local-chromium'),
host: this._downloadHost,
platform: (() => {
const platform = os.platform();
if (platform === 'darwin')
return 'mac';
if (platform === 'linux')
return 'linux';
if (platform === 'win32')
return os.arch() === 'x64' ? 'win64' : 'win32';
return platform;
})()
};
options = {
...defaultOptions,
...options,
};
helper_1.assert(!!downloadURLs[options.platform], 'Unsupported platform: ' + options.platform);
return new browserFetcher_1.BrowserFetcher(options.path, options.platform, this._revision, (platform, revision) => {
let archiveName = '';
let executablePath = '';
if (platform === 'linux') {
archiveName = 'chrome-linux';
executablePath = path.join(archiveName, 'chrome');
}
else if (platform === 'mac') {
archiveName = 'chrome-mac';
executablePath = path.join(archiveName, 'Chromium.app', 'Contents', 'MacOS', 'Chromium');
}
else if (platform === 'win32' || platform === 'win64') {
// Windows archive name changed at r591479.
archiveName = parseInt(revision, 10) > 591479 ? 'chrome-win' : 'chrome-win32';
executablePath = path.join(archiveName, 'chrome.exe');
}
return {
downloadUrl: util.format(downloadURLs[platform], options.host, revision, archiveName),
executablePath
};
});
}
_resolveExecutablePath() {
const browserFetcher = this._createBrowserFetcher();
const revisionInfo = browserFetcher.revisionInfo();
const missingText = !revisionInfo.local ? `Chromium revision is not downloaded. Run "npm install"` : null;
return { executablePath: revisionInfo.executablePath, missingText };
}
}

@@ -227,0 +156,0 @@ exports.Chromium = Chromium;

@@ -20,11 +20,7 @@ /**

import { FFBrowser } from '../firefox/ffBrowser';
import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback } from './browserFetcher';
import { BrowserServer } from './browserServer';
import { BrowserType, LaunchOptions } from './browserType';
export declare class Firefox implements BrowserType {
private _downloadPath;
private _downloadHost;
readonly _revision: string;
constructor(downloadPath: string, downloadHost: (string | undefined), preferredRevision: string);
downloadBrowserIfNeeded(onProgress?: OnProgressCallback): Promise<void>;
private _executablePath;
executablePath(): string;
name(): string;

@@ -40,9 +36,3 @@ launch(options?: LaunchOptions & {

connect(options: ConnectOptions): Promise<FFBrowser>;
executablePath(): string;
private _defaultArgs;
_createBrowserFetcher(options?: BrowserFetcherOptions): BrowserFetcher;
_resolveExecutablePath(): {
executablePath: string;
missingText: string | null;
};
}

@@ -22,3 +22,2 @@ "use strict";

const path = require("path");
const util = require("util");
const errors_1 = require("../errors");

@@ -30,3 +29,2 @@ const events_1 = require("../events");

const platform = require("../platform");
const browserFetcher_1 = require("./browserFetcher");
const browserServer_1 = require("./browserServer");

@@ -36,15 +34,7 @@ const processLauncher_1 = require("./processLauncher");

class Firefox {
constructor(downloadPath, downloadHost, preferredRevision) {
this._downloadPath = downloadPath;
this._downloadHost = downloadHost || 'https://playwright.azureedge.net';
this._revision = preferredRevision;
executablePath() {
if (!this._executablePath)
throw new Error('No executable path!');
return this._executablePath;
}
async downloadBrowserIfNeeded(onProgress) {
const fetcher = this._createBrowserFetcher();
const revisionInfo = fetcher.revisionInfo();
// Do nothing if the revision is already downloaded.
if (revisionInfo.local)
return;
await fetcher.download(revisionInfo.revision, onProgress);
}
name() {

@@ -94,9 +84,5 @@ return 'firefox';

firefoxArguments.push(...args);
let firefoxExecutable = executablePath;
if (!firefoxExecutable) {
const { missingText, executablePath } = this._resolveExecutablePath();
if (missingText)
throw new Error(missingText);
firefoxExecutable = executablePath;
}
const firefoxExecutable = executablePath || this._executablePath;
if (!firefoxExecutable)
throw new Error(`No executable path is specified. Pass "executablePath" option directly.`);
let browserServer = undefined;

@@ -143,5 +129,2 @@ const { launchedProcess, gracefullyClose } = await processLauncher_1.launchProcess({

}
executablePath() {
return this._resolveExecutablePath().executablePath;
}
_defaultArgs(options = {}, launchType, userDataDir, port) {

@@ -173,50 +156,4 @@ const { devtools = false, headless = !devtools, args = [], } = options;

}
_createBrowserFetcher(options = {}) {
const downloadURLs = {
linux: '%s/builds/firefox/%s/firefox-linux.zip',
mac: '%s/builds/firefox/%s/firefox-mac.zip',
win32: '%s/builds/firefox/%s/firefox-win32.zip',
win64: '%s/builds/firefox/%s/firefox-win64.zip',
};
const defaultOptions = {
path: path.join(this._downloadPath, '.local-firefox'),
host: this._downloadHost,
platform: (() => {
const platform = os.platform();
if (platform === 'darwin')
return 'mac';
if (platform === 'linux')
return 'linux';
if (platform === 'win32')
return os.arch() === 'x64' ? 'win64' : 'win32';
return platform;
})()
};
options = {
...defaultOptions,
...options,
};
helper_1.assert(!!downloadURLs[options.platform], 'Unsupported platform: ' + options.platform);
return new browserFetcher_1.BrowserFetcher(options.path, options.platform, this._revision, (platform, revision) => {
let executablePath = '';
if (platform === 'linux')
executablePath = path.join('firefox', 'firefox');
else if (platform === 'mac')
executablePath = path.join('firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox');
else if (platform === 'win32' || platform === 'win64')
executablePath = path.join('firefox', 'firefox.exe');
return {
downloadUrl: util.format(downloadURLs[platform], options.host, revision),
executablePath
};
});
}
_resolveExecutablePath() {
const browserFetcher = this._createBrowserFetcher();
const revisionInfo = browserFetcher.revisionInfo();
const missingText = !revisionInfo.local ? `Firefox revision is not downloaded. Run "npm install"` : null;
return { executablePath: revisionInfo.executablePath, missingText };
}
}
exports.Firefox = Firefox;
//# sourceMappingURL=firefox.js.map

@@ -23,5 +23,3 @@ /**

declare type PlaywrightOptions = {
downloadPath: string;
browsers: Array<('firefox' | 'webkit' | 'chromium')>;
respectEnvironmentVariables: boolean;
};

@@ -28,0 +26,0 @@ export declare class Playwright {

@@ -25,3 +25,2 @@ "use strict";

const firefox_1 = require("./firefox");
const packageJSON = require('../../package.json');
for (const className in api) {

@@ -34,21 +33,14 @@ if (typeof api[className] === 'function')

this.selectors = api.Selectors._instance();
const { downloadPath, browsers, respectEnvironmentVariables, } = options;
const { browsers, } = options;
this.devices = deviceDescriptors_1.DeviceDescriptors;
this.errors = { TimeoutError: errors_1.TimeoutError };
const downloadHost = respectEnvironmentVariables ? getFromENV('PLAYWRIGHT_DOWNLOAD_HOST') : undefined;
if (browsers.includes('chromium'))
this.chromium = new chromium_1.Chromium(downloadPath, downloadHost, packageJSON.playwright.chromium_revision);
this.chromium = new chromium_1.Chromium();
if (browsers.includes('webkit'))
this.webkit = new webkit_1.WebKit(downloadPath, downloadHost, packageJSON.playwright.webkit_revision);
this.webkit = new webkit_1.WebKit();
if (browsers.includes('firefox'))
this.firefox = new firefox_1.Firefox(downloadPath, downloadHost, packageJSON.playwright.firefox_revision);
this.firefox = new firefox_1.Firefox();
}
}
exports.Playwright = Playwright;
function getFromENV(name) {
let value = process.env[name];
value = value || process.env[`npm_config_${name.toLowerCase()}`];
value = value || process.env[`npm_package_config_${name.toLowerCase()}`];
return value;
}
//# sourceMappingURL=playwright.js.map

@@ -17,3 +17,2 @@ /**

*/
import { BrowserFetcher, OnProgressCallback, BrowserFetcherOptions } from './browserFetcher';
import { WKBrowser } from '../webkit/wkBrowser';

@@ -25,8 +24,5 @@ import { LaunchOptions, BrowserArgOptions, BrowserType } from './browserType';

export declare class WebKit implements BrowserType {
private _downloadPath;
private _downloadHost;
readonly _revision: string;
constructor(downloadPath: string, downloadHost: (string | undefined), preferredRevision: string);
private _executablePath;
executablePath(): string;
name(): string;
downloadBrowserIfNeeded(onProgress?: OnProgressCallback): Promise<void>;
launch(options?: LaunchOptions & {

@@ -41,9 +37,3 @@ slowMo?: number;

connect(options: ConnectOptions): Promise<WKBrowser>;
executablePath(): string;
_defaultArgs(options: BrowserArgOptions | undefined, launchType: LaunchType, userDataDir: string, port: number): string[];
_createBrowserFetcher(options?: BrowserFetcherOptions): BrowserFetcher;
_resolveExecutablePath(): {
executablePath: string;
missingText: string | null;
};
}

@@ -19,5 +19,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const browserFetcher_1 = require("./browserFetcher");
const wkBrowser_1 = require("../webkit/wkBrowser");
const child_process_1 = require("child_process");
const pipeTransport_1 = require("./pipeTransport");

@@ -28,3 +26,2 @@ const processLauncher_1 = require("./processLauncher");

const platform = require("../platform");
const util = require("util");
const os = require("os");

@@ -37,6 +34,6 @@ const helper_1 = require("../helper");

class WebKit {
constructor(downloadPath, downloadHost, preferredRevision) {
this._downloadPath = downloadPath;
this._downloadHost = downloadHost || 'https://playwright.azureedge.net';
this._revision = preferredRevision;
executablePath() {
if (!this._executablePath)
throw new Error('No executable path!');
return this._executablePath;
}

@@ -46,10 +43,2 @@ name() {

}
async downloadBrowserIfNeeded(onProgress) {
const fetcher = this._createBrowserFetcher();
const revisionInfo = fetcher.revisionInfo();
// Do nothing if the revision is already downloaded.
if (revisionInfo.local)
return;
await fetcher.download(revisionInfo.revision, onProgress);
}
async launch(options) {

@@ -87,9 +76,5 @@ if (options && options.userDataDir)

webkitArguments.push(...args);
let webkitExecutable = executablePath;
if (!executablePath) {
const { missingText, executablePath } = this._resolveExecutablePath();
if (missingText)
throw new Error(missingText);
webkitExecutable = executablePath;
}
const webkitExecutable = executablePath || this._executablePath;
if (!webkitExecutable)
throw new Error(`No executable path is specified.`);
let transport = undefined;

@@ -133,5 +118,2 @@ let browserServer = undefined;

}
executablePath() {
return this._resolveExecutablePath().executablePath;
}
_defaultArgs(options = {}, launchType, userDataDir, port) {

@@ -156,42 +138,2 @@ const { devtools = false, headless = !devtools, args = [], } = options;

}
_createBrowserFetcher(options) {
const downloadURLs = {
linux: '%s/builds/webkit/%s/minibrowser-gtk-wpe.zip',
mac: '%s/builds/webkit/%s/minibrowser-mac-%s.zip',
win64: '%s/builds/webkit/%s/minibrowser-win64.zip',
};
const defaultOptions = {
path: path.join(this._downloadPath, '.local-webkit'),
host: this._downloadHost,
platform: (() => {
const platform = os.platform();
if (platform === 'darwin')
return 'mac';
if (platform === 'linux')
return 'linux';
if (platform === 'win32')
return 'win64';
return platform;
})()
};
options = {
...defaultOptions,
...options,
};
helper_1.assert(!!downloadURLs[options.platform], 'Unsupported platform: ' + options.platform);
return new browserFetcher_1.BrowserFetcher(options.path, options.platform, this._revision, (platform, revision) => {
return {
downloadUrl: (platform === 'mac') ?
util.format(downloadURLs[platform], options.host, revision, getMacVersion()) :
util.format(downloadURLs[platform], options.host, revision),
executablePath: platform.startsWith('win') ? 'MiniBrowser.exe' : 'pw_run.sh',
};
});
}
_resolveExecutablePath() {
const browserFetcher = this._createBrowserFetcher();
const revisionInfo = browserFetcher.revisionInfo();
const missingText = !revisionInfo.local ? `WebKit revision is not downloaded. Run "npm install"` : null;
return { executablePath: revisionInfo.executablePath, missingText };
}
}

@@ -201,11 +143,2 @@ exports.WebKit = WebKit;

const WEBKIT_PROFILE_PATH = path.join(os.tmpdir(), 'playwright_dev_profile-');
let cachedMacVersion = undefined;
function getMacVersion() {
if (!cachedMacVersion) {
const [major, minor] = child_process_1.execSync('sw_vers -productVersion').toString('utf8').trim().split('.');
helper_1.assert(+major === 10 && +minor >= 14, 'Error: unsupported macOS version, macOS 10.14 and newer are supported');
cachedMacVersion = major + '.' + minor;
}
return cachedMacVersion;
}
class SequenceNumberMixer {

@@ -212,0 +145,0 @@ constructor() {

{
"name": "playwright-core",
"version": "0.11.1-next.1584577781703",
"version": "0.11.1-next.1584644386005",
"description": "A high-level API to automate web browsers",

@@ -5,0 +5,0 @@ "repository": "github:Microsoft/playwright",

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc