Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pw-web): generate playwright/web.js which can be used in the browser #455

Merged
merged 1 commit into from
Jan 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ yarn.lock
/utils/browser/playwright-web.js
lib/
playwright-*.tgz
/web.js
/web.js.map
6 changes: 5 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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)
35 changes: 35 additions & 0 deletions docs/web.md
Original file line number Diff line number Diff line change
@@ -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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will probably want to do something with modules for this at some point, but for now its fine.

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
<script src='../playwright/web.js'></script>
<script>
async function usePlaywright() {
const connect = window.playwrightweb('chromium'); // or 'firefox', 'webkit'
const browser = await connect(options);
// ... drive automation ...
await browser.disconnect();
}
</script>
```

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.
3 changes: 0 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
10 changes: 0 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}"`);
};
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions src/platform.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
31 changes: 31 additions & 0 deletions src/web.ts
Original file line number Diff line number Diff line change
@@ -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;
56 changes: 56 additions & 0 deletions src/web.webpack.config.js
Original file line number Diff line number Diff line change
@@ -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',
}
};
13 changes: 13 additions & 0 deletions test/assets/playwrightweb.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script src='../../web.js'></script>
<script>
async function setup(product, connectOptions) {
window.connect = window.playwrightweb(product);
window.browser = await window.connect(connectOptions);
window.context = await window.browser.newContext();
window.page = await window.context.newPage();
}
async function teardown() {
await window.context.close();
await window.browser.disconnect();
}
</script>
2 changes: 2 additions & 0 deletions test/playwright.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
7 changes: 6 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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}) => {
Expand Down
84 changes: 84 additions & 0 deletions test/web.spec.js
Original file line number Diff line number Diff line change
@@ -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');
});
});
};
37 changes: 0 additions & 37 deletions utils/browser/README.md

This file was deleted.

1 change: 0 additions & 1 deletion utils/browser/WebSocket.js

This file was deleted.

Loading