diff --git a/.gitignore b/.gitignore
index 6cd316572f..3d0c2d5b9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,5 @@ yarn.lock
/utils/browser/playwright-web.js
lib/
playwright-*.tgz
+/web.js
+/web.js.map
diff --git a/.npmignore b/.npmignore
index 2c270eca1c..037bf682a9 100644
--- a/.npmignore
+++ b/.npmignore
@@ -9,17 +9,21 @@ lib/injected/
#types
!lib/**/*.d.ts
!index.d.ts
+!web.d.ts
# Install
!install.js
# root for "playwright" package
!index.js
+# root for "playwright/web"
+!web.js
+
# specific browsers
!chromium.js
!firefox.js
!webkit.js
-# Dgozman says to remove these
+# dgozman says to remove these
!DeviceDescriptors.js
!Errors.js
diff --git a/README.md b/README.md
index f1fb4a59ad..3452a683a1 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ Playwright can be used to create a browser instance, open pages, and then manipu
### Examples
-#### Page screenshot
+#### Page screenshot
This code snippet navigates to example.com in WebKit, and saves a screenshot.
@@ -94,3 +94,4 @@ Playwright is actively developed as we get to feature parity across Chromium, Fi
## Resources
* [API documentation](https://github.com/microsoft/playwright/blob/master/docs/api.md)
+* [Running in the browser](https://github.com/microsoft/playwright/blob/master/docs/web.md)
diff --git a/docs/web.md b/docs/web.md
new file mode 100644
index 0000000000..6c74279adf
--- /dev/null
+++ b/docs/web.md
@@ -0,0 +1,35 @@
+# Bundling for Web
+
+Playwright contains a version bundled for web browsers under `playwright/web.js`, which
+installs playwright under `window.playwrightweb`.
+You can use it in the web page to drive another browser instance.
+
+API consists of a single `connect` function, similar to
+[chromiumPlaywright.connect(options)](api.md#chromiumplaywrightconnectoptions),
+[firefoxPlaywright.connect(options)](api.md#firefoxplaywrightconnectoptions) and
+[webkitPlaywright.connect(options)](api.md#webkitplaywrightconnectoptions).
+
+```html
+
+
+```
+
+See our [playwright-web tests](https://github.com/Microsoft/playwright/blob/master/test/web.spec.js) for example.
+
+### Running inside Chrome Extension
+
+You might want to enable `unsafe-eval` inside the extension by adding the following
+to your `manifest.json` file:
+
+```
+"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
+```
+
+Please see discussion in https://github.com/GoogleChrome/puppeteer/issues/3455.
diff --git a/index.d.ts b/index.d.ts
index 877cc45e28..79897e0a2a 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -18,6 +18,3 @@ export * from './lib/api';
export function playwright(browser: 'chromium'): import('./lib/api').ChromiumPlaywright;
export function playwright(browser: 'firefox'): import('./lib/api').FirefoxPlaywright;
export function playwright(browser: 'webkit'): import('./lib/api').WebKitPlaywright;
-export function connect(browser: 'chromium'): import('./lib/api').ChromiumBrowser.connect;
-export function connect(browser: 'firefox'): import('./lib/api').FirefoxBrowser.connect;
-export function connect(browser: 'webkit'): import('./lib/api').WebKitBrowser.connect;
diff --git a/index.js b/index.js
index 0b6e5b3ae9..df942e92aa 100644
--- a/index.js
+++ b/index.js
@@ -33,13 +33,3 @@ module.exports.playwright = browser => {
return new api.WebKitPlaywright(__dirname, packageJson.playwright.webkit_revision);
throw new Error(`Unsupported browser "${browser}"`);
};
-
-module.exports.connect = browser => {
- if (browser === 'chromium')
- return api.ChromiumBrowser.connect;
- if (browser === 'firefox')
- return api.FirefoxBrowser.connect;
- if (browser === 'webkit')
- return api.WebKitBrowser.connect;
- throw new Error(`Unsupported browser "${browser}"`);
-};
diff --git a/package.json b/package.json
index 3052a8f488..9f8c51f74c 100644
--- a/package.json
+++ b/package.json
@@ -26,9 +26,7 @@
"tsc": "tsc -p .",
"build": "node utils/runWebpack.js --mode='development' && tsc -p .",
"watch": "node utils/runWebpack.js --mode='development' --watch --silent | tsc -w -p .",
- "apply-next-version": "node utils/apply_next_version.js",
- "bundle": "npx browserify -r ./index.js:playwright -o utils/browser/playwright-web.js",
- "unit-bundle": "node utils/browser/test.js"
+ "apply-next-version": "node utils/apply_next_version.js"
},
"author": {
"name": "Microsoft Corporation"
diff --git a/src/platform.ts b/src/platform.ts
index f8f5a954a8..adaf56f352 100644
--- a/src/platform.ts
+++ b/src/platform.ts
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
+// Note: this is the only file outside of src/server which can import external dependencies.
+// All dependencies must be listed in web.webpack.config.js to avoid bundling them.
import * as nodeEvents from 'events';
import * as nodeFS from 'fs';
import * as nodePath from 'path';
diff --git a/src/web.ts b/src/web.ts
new file mode 100644
index 0000000000..742938824c
--- /dev/null
+++ b/src/web.ts
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { CRBrowser as ChromiumBrowser } from './chromium/crBrowser';
+import { FFBrowser as FirefoxBrowser } from './firefox/ffBrowser';
+import { WKBrowser as WebKitBrowser } from './webkit/wkBrowser';
+
+function connect(browser: 'chromium' | 'firefox' | 'webkit') {
+ if (browser === 'chromium')
+ return ChromiumBrowser.connect;
+ if (browser === 'firefox')
+ return FirefoxBrowser.connect;
+ if (browser === 'webkit')
+ return WebKitBrowser.connect;
+ throw new Error(`Unsupported browser "${browser}"`);
+}
+
+export = connect;
diff --git a/src/web.webpack.config.js b/src/web.webpack.config.js
new file mode 100644
index 0000000000..7144ab8d2c
--- /dev/null
+++ b/src/web.webpack.config.js
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const path = require('path');
+
+module.exports = {
+ entry: path.join(__dirname, 'web.ts'),
+ devtool: 'source-map',
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true
+ },
+ exclude: /node_modules/
+ }
+ ]
+ },
+ resolve: {
+ extensions: [ '.tsx', '.ts', '.js' ]
+ },
+ output: {
+ filename: 'web.js',
+ library: 'playwrightweb',
+ libraryTarget: 'window',
+ path: path.resolve(__dirname, '../')
+ },
+ externals: {
+ 'events': 'dummy',
+ 'fs': 'dummy',
+ 'path': 'dummy',
+ 'debug': 'dummy',
+ 'buffer': 'dummy',
+ 'mime': 'dummy',
+ 'jpeg-js': 'dummy',
+ 'pngjs': 'dummy',
+ 'http': 'dummy',
+ 'https': 'dummy',
+ 'ws': 'dummy',
+ }
+};
diff --git a/test/assets/playwrightweb.html b/test/assets/playwrightweb.html
new file mode 100644
index 0000000000..09b9fdff36
--- /dev/null
+++ b/test/assets/playwrightweb.html
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/test/playwright.spec.js b/test/playwright.spec.js
index f9227c0da4..0b7ac2ff77 100644
--- a/test/playwright.spec.js
+++ b/test/playwright.spec.js
@@ -215,4 +215,6 @@ module.exports.describe = ({testRunner, product, playwrightPath}) => {
if (WEBKIT) {
testRunner.loadTests(require('./webkit/launcher.spec.js'), testOptions);
}
+
+ testRunner.loadTests(require('./web.spec.js'), testOptions);
};
diff --git a/test/test.js b/test/test.js
index a5c592d369..bb0b5eb7da 100644
--- a/test/test.js
+++ b/test/test.js
@@ -44,7 +44,7 @@ beforeAll(async state => {
const assetsPath = path.join(__dirname, 'assets');
const cachedPath = path.join(__dirname, 'assets', 'cached');
- const port = 8907 + state.parallelIndex * 2;
+ const port = 8907 + state.parallelIndex * 3;
state.server = await TestServer.create(assetsPath, port);
state.server.enableHTTPCache(cachedPath);
state.server.PORT = port;
@@ -59,6 +59,11 @@ beforeAll(async state => {
state.httpsServer.PREFIX = `https://localhost:${httpsPort}`;
state.httpsServer.CROSS_PROCESS_PREFIX = `https://127.0.0.1:${httpsPort}`;
state.httpsServer.EMPTY_PAGE = `https://localhost:${httpsPort}/empty.html`;
+
+ const sourcePort = port + 2;
+ state.sourceServer = await TestServer.create(path.join(__dirname, '..'), sourcePort);
+ state.sourceServer.PORT = sourcePort;
+ state.sourceServer.PREFIX = `http://localhost:${sourcePort}`;
});
afterAll(async({server, httpsServer}) => {
diff --git a/test/web.spec.js b/test/web.spec.js
new file mode 100644
index 0000000000..f9cf73e6dc
--- /dev/null
+++ b/test/web.spec.js
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+module.exports.describe = function({testRunner, expect, defaultBrowserOptions, playwright, product, WEBKIT}) {
+ const {describe, xdescribe, fdescribe} = testRunner;
+ const {it, fit, xit, dit} = testRunner;
+ const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
+
+ describe.skip(WEBKIT)('Web', function() {
+ beforeAll(async state => {
+ state.controlledBrowserServer = await playwright.launchServer({ ...defaultBrowserOptions, pipe: false });
+ state.hostBrowserServer = await playwright.launchServer(defaultBrowserOptions);
+ state.hostBrowser = await state.hostBrowserServer.connect();
+ });
+
+ afterAll(async state => {
+ await state.hostBrowserServer.close();
+ state.hostBrowser = null;
+ state.hostBrowserServer = null;
+
+ await state.controlledBrowserServer.close();
+ state.controlledBrowserServer = null;
+ state.webUrl = null;
+ });
+
+ beforeEach(async state => {
+ state.page = await state.hostBrowser.defaultContext().newPage();
+ state.page.on('console', message => console.log('TEST: ' + message.text()));
+ await state.page.goto(state.sourceServer.PREFIX + '/test/assets/playwrightweb.html');
+ await state.page.evaluate((product, connectOptions) => setup(product, connectOptions), product.toLowerCase(), state.controlledBrowserServer.connectOptions());
+ });
+
+ afterEach(async state => {
+ await state.page.evaluate(() => teardown());
+ await state.page.close();
+ state.page = null;
+ });
+
+ it('should navigate', async({page, server}) => {
+ const url = await page.evaluate(async url => {
+ await page.goto(url);
+ return page.evaluate(() => window.location.href);
+ }, server.EMPTY_PAGE);
+ expect(url).toBe(server.EMPTY_PAGE);
+ });
+
+ it('should receive events', async({page, server}) => {
+ const logs = await page.evaluate(async url => {
+ const logs = [];
+ page.on('console', message => logs.push(message.text()));
+ await page.evaluate(() => console.log('hello'));
+ await page.evaluate(() => console.log('world'));
+ return logs;
+ }, server.EMPTY_PAGE);
+ expect(logs).toEqual(['hello', 'world']);
+ });
+
+ it('should take screenshot', async({page, server}) => {
+ const { base64, bufferClassName } = await page.evaluate(async url => {
+ await page.setViewport({width: 500, height: 500});
+ await page.goto(url);
+ const screenshot = await page.screenshot();
+ return { base64: screenshot.toString('base64'), bufferClassName: screenshot.constructor.name };
+ }, server.PREFIX + '/grid.html');
+ const screenshot = Buffer.from(base64, 'base64');
+ expect(screenshot).toBeGolden('screenshot-sanity.png');
+ // Verify that we use web versions of node-specific classes.
+ expect(bufferClassName).toBe('BufferImpl');
+ });
+ });
+};
diff --git a/utils/browser/README.md b/utils/browser/README.md
deleted file mode 100644
index b26f48d8a9..0000000000
--- a/utils/browser/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Bundling For Web Browsers
-
-To bundle Playwright using [Browserify](http://browserify.org/):
-
-1. Clone Playwright repository: `git clone https://github.com/Microsoft/playwright && cd playwright`
-2. `npm install`
-3. Run `npm run bundle`
-
-This will create `./utils/browser/playwright-web.js` file that contains Playwright bundle.
-
-You can use it later on in your web page to drive
-another browser instance through its WS Endpoint:
-
-```html
-
-
-```
-
-See our [playwright-web tests](https://github.com/Microsoft/playwright/blob/master/utils/browser/test.js)
-for details.
-
-### Running inside Chrome Extension
-
-You might want to enable `unsafe-eval` inside the extension by adding the following
-to your `manifest.json` file:
-
-```
-"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
-```
-
-Please see discussion in https://github.com/GoogleChrome/puppeteer/issues/3455.
diff --git a/utils/browser/WebSocket.js b/utils/browser/WebSocket.js
deleted file mode 100644
index a30d920fbf..0000000000
--- a/utils/browser/WebSocket.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = window.WebSocket;
diff --git a/utils/browser/test.js b/utils/browser/test.js
deleted file mode 100644
index 7bea4f116d..0000000000
--- a/utils/browser/test.js
+++ /dev/null
@@ -1,99 +0,0 @@
-const path = require('path');
-const fs = require('fs');
-const playwright = require('../..');
-const {TestServer} = require('../testserver/');
-const {TestRunner, Reporter, Matchers} = require('../testrunner/');
-
-const playwrightWebPath = path.join(__dirname, 'playwright-web.js');
-if (!fs.existsSync(playwrightWebPath))
- throw new Error(`playwright-web is not built; run "npm run bundle"`);
-const playwrightWeb = fs.readFileSync(playwrightWebPath, 'utf8');
-
-const testRunner = new TestRunner();
-const {describe, fdescribe, xdescribe} = testRunner;
-const {it, xit, fit} = testRunner;
-const {afterAll, beforeAll, afterEach, beforeEach} = testRunner;
-const {expect} = new Matchers();
-
-beforeAll(async state => {
- const assetsPath = path.join(__dirname, '..', '..', 'test', 'assets');
- const port = 8998;
- state.server = await TestServer.create(assetsPath, port);
- state.serverConfig = {
- PREFIX: `http://localhost:${port}`,
- EMPTY_PAGE: `http://localhost:${port}/empty.html`,
- };
- state.browser = await playwright.launch();
-});
-
-afterAll(async state => {
- await Promise.all([
- state.server.stop(),
- state.browser.close()
- ]);
- state.browser = null;
- state.server = null;
-});
-
-beforeEach(async state => {
- state.page = await state.browser.defaultContext().newPage();
- await state.page.evaluateOnNewDocument(playwrightWeb);
- await state.page.addScriptTag({
- content: playwrightWeb + '\n//# sourceURL=playwright-web.js'
- });
-});
-
-afterEach(async state => {
- await state.page.close();
- state.page = null;
-});
-
-describe('Playwright-Web', () => {
- it('should work over web socket', async({page, serverConfig}) => {
- const browserServer = await playwright.launchServer();
- // Use in-page playwright to create a new page and navigate it to the EMPTY_PAGE
- await page.evaluate(async(browserWSEndpoint, serverConfig) => {
- const playwright = require('playwright');
- const browser = await playwright.connect({browserWSEndpoint});
- const page = await browser.defaultContext().newPage();
- await page.goto(serverConfig.EMPTY_PAGE);
- }, browserServer.wsEndpoint(), serverConfig);
- const browser = await browserServer.connect();
- const pageURLs = (await browser.defaultContext().pages()).map(page => page.url()).sort();
- expect(pageURLs).toEqual([
- 'about:blank',
- serverConfig.EMPTY_PAGE
- ]);
- await browserServer.close();
- });
- it('should work over exposed DevTools protocol', async({browser, page, serverConfig}) => {
- // Expose devtools protocol binding into page.
- const session = await browser.browserTarget().createCDPSession();
- const pageInfo = (await session.send('Target.getTargets')).targetInfos.find(info => info.attached);
- await session.send('Target.exposeDevToolsProtocol', {targetId: pageInfo.targetId});
- await session.detach();
-
- // Use in-page playwright to create a new page and navigate it to the EMPTY_PAGE
- await page.evaluate(async serverConfig => {
- const playwright = require('playwright');
- window.cdp.close = () => {};
- const browser = await playwright.connect({transport: window.cdp});
- const page = await browser.defaultContext().newPage();
- await page.goto(serverConfig.EMPTY_PAGE);
- }, serverConfig);
- const pageURLs = (await browser.defaultContext().pages()).map(page => page.url()).sort();
- expect(pageURLs).toEqual([
- 'about:blank',
- 'about:blank',
- serverConfig.EMPTY_PAGE
- ]);
- });
-});
-
-if (process.env.CI && testRunner.hasFocusedTestsOrSuites()) {
- console.error('ERROR: "focused" tests/suites are prohibitted on bots. Remove any "fit"/"fdescribe" declarations.');
- process.exit(1);
-}
-
-new Reporter(testRunner);
-testRunner.run();
diff --git a/utils/doclint/check_public_api/JSBuilder.js b/utils/doclint/check_public_api/JSBuilder.js
index f9623cc4f0..d57b056638 100644
--- a/utils/doclint/check_public_api/JSBuilder.js
+++ b/utils/doclint/check_public_api/JSBuilder.js
@@ -23,8 +23,9 @@ module.exports = { checkSources, expandPrefix };
/**
* @param {!Array} sources
+ * @param {!Array} externalDependencies
*/
-function checkSources(sources) {
+function checkSources(sources, externalDependencies) {
// special treatment for Events.js
const classEvents = new Map();
const eventsSources = sources.filter(source => source.name().startsWith('events.ts'));
@@ -106,17 +107,21 @@ function checkSources(sources) {
}
if (fileName.endsWith('/api.ts') && ts.isExportSpecifier(node))
apiClassNames.add(expandPrefix((node.propertyName || node.name).text));
- if (!fileName.endsWith('platform.ts') && !fileName.includes('src/server/')) {
+ const isPlatform = fileName.endsWith('platform.ts');
+ if (!fileName.includes('src/server/')) {
// Only relative imports.
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
const module = node.moduleSpecifier.text;
- if (!module.startsWith('.') || path.resolve(path.dirname(fileName), module).includes('src/server')) {
+ const isRelative = module.startsWith('.');
+ const isPlatformDependency = isPlatform && externalDependencies.includes(module);
+ const isServerDependency = path.resolve(path.dirname(fileName), module).includes('src/server');
+ if (isServerDependency || (!isRelative && !isPlatformDependency)) {
const lac = ts.getLineAndCharacterOfPosition(node.getSourceFile(), node.moduleSpecifier.pos);
errors.push(`Disallowed import "${module}" at ${node.getSourceFile().fileName}:${lac.line + 1}`);
}
}
// No references to external types.
- if (ts.isTypeReferenceNode(node)) {
+ if (!isPlatform && ts.isTypeReferenceNode(node)) {
const isPlatformReference = ts.isQualifiedName(node.typeName) && ts.isIdentifier(node.typeName.left) && node.typeName.left.escapedText === 'platform';
if (!isPlatformReference) {
const type = checker.getTypeAtLocation(node);
diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js
index 90d2197d78..defbcadead 100644
--- a/utils/doclint/check_public_api/index.js
+++ b/utils/doclint/check_public_api/index.js
@@ -33,9 +33,9 @@ const EXCLUDE_PROPERTIES = new Set([
* @param {!Array} mdSources
* @return {!Promise>}
*/
-module.exports = async function lint(page, mdSources, jsSources) {
+module.exports = async function lint(page, mdSources, jsSources, externalDependencies) {
const mdResult = await mdBuilder(page, mdSources);
- const jsResult = jsBuilder.checkSources(jsSources);
+ const jsResult = jsBuilder.checkSources(jsSources, externalDependencies);
const jsDocumentation = filterJSDocumentation(jsSources, jsResult.documentation);
const mdDocumentation = mdResult.documentation;
diff --git a/utils/doclint/cli.js b/utils/doclint/cli.js
index 24741b23a9..ac25a4c80f 100755
--- a/utils/doclint/cli.js
+++ b/utils/doclint/cli.js
@@ -49,7 +49,8 @@ async function run() {
const page = await browser.defaultContext().newPage();
const checkPublicAPI = require('./check_public_api');
const jsSources = await Source.readdir(path.join(PROJECT_DIR, 'src'));
- messages.push(...await checkPublicAPI(page, mdSources, jsSources));
+ const externalDependencies = Object.keys(require('../../src/web.webpack.config').externals);
+ messages.push(...await checkPublicAPI(page, mdSources, jsSources, externalDependencies));
await browser.close();
for (const source of mdSources) {
diff --git a/utils/runWebpack.js b/utils/runWebpack.js
index 9de1a33a9f..8b61e5a87e 100644
--- a/utils/runWebpack.js
+++ b/utils/runWebpack.js
@@ -20,6 +20,7 @@ const path = require('path');
const files = [
path.join('src', 'injected', 'zsSelectorEngine.webpack.config.js'),
path.join('src', 'injected', 'injected.webpack.config.js'),
+ path.join('src', 'web.webpack.config.js'),
];
function runOne(runner, file) {
diff --git a/web.d.ts b/web.d.ts
new file mode 100644
index 0000000000..417be8c272
--- /dev/null
+++ b/web.d.ts
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function connect(browser: 'chromium'): import('./lib/api').ChromiumBrowser.connect;
+function connect(browser: 'firefox'): import('./lib/api').FirefoxBrowser.connect;
+function connect(browser: 'webkit'): import('./lib/api').WebKitBrowser.connect;
+export = connect;