docs: add python snippets for class Page (#5010)

This commit is contained in:
Pavel Feldman 2021-01-13 21:03:35 -08:00 committed by GitHub
parent 0a999bf0a6
commit 5408e26e02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 964 additions and 275 deletions

File diff suppressed because it is too large Load Diff

View File

@ -106,7 +106,7 @@ failed, as reported by `requestfailed` event.
Example of logging of all the failed requests:
```python
```py
page.on('requestfailed', lambda request: print(request.url + ' ' + request.failure);
```

View File

@ -33,7 +33,7 @@ with sync_playwright() as p:
Playwright supports two variations of the API: synchronous and asynchronous. If your modern project uses [asyncio](https://docs.python.org/3/library/asyncio.html), you should use async API:
```python
```py
import asyncio
from playwright.async_api import async_playwright
@ -52,7 +52,7 @@ asyncio.run(main())
In our first script, we will navigate to `whatsmyuseragent.org` and take a screenshot in WebKit.
```python
```py
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
@ -65,7 +65,7 @@ with sync_playwright() as p:
By default, Playwright runs the browsers in headless mode. To see the browser UI, pass the `headless=False` flag while launching the browser. You can also use `slowMo` to slow down execution. Learn more in the debugging tools [section](./debug.md).
```python
```py
firefox.launch(headless=False, slowMo=50)
```

148
types/types.d.ts vendored
View File

@ -202,7 +202,7 @@ export interface Page {
* Examples:
*
* ```js
* const divsCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10);
* const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10);
* ```
*
* @param selector A selector to query for. See [working with selectors](https://github.com/microsoft/playwright/blob/master/docs/selectors.md#working-with-selectors) for more details.
@ -225,14 +225,15 @@ export interface Page {
* (async () => {
* const browser = await webkit.launch();
* const page = await browser.newPage();
* const watchDog = page.waitForFunction('window.innerWidth < 100');
* const watchDog = page.waitForFunction(() => window.innerWidth < 100);
* await page.setViewportSize({width: 50, height: 50});
* await watchDog;
* await browser.close();
* })();
* ```
*
* To pass an argument to the predicate of `page.waitForFunction` function:
* To pass an argument to the predicate of
* [page.waitForFunction()](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagewaitforfunction) function:
*
* ```js
* const selector = '.foo';
@ -264,12 +265,10 @@ export interface Page {
* (async () => {
* const browser = await chromium.launch();
* const page = await browser.newPage();
* let currentURL;
* page
* .waitForSelector('img')
* .then(() => console.log('First URL with image: ' + currentURL));
* for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com']) {
* for (let currentURL of ['https://google.com', 'https://bbc.com']) {
* await page.goto(currentURL);
* const element = await page.waitForSelector('img');
* console.log('Loaded image: ' + await element.getAttribute('src'));
* }
* await browser.close();
* })();
@ -359,7 +358,7 @@ export interface Page {
* ```js
* page.on('console', msg => {
* for (let i = 0; i < msg.args().length; ++i)
* console.log(`${i}: ${msg.args()[i]}`);
* console.log(`${i}: ${await msg.args()[i].jsonValue()}`);
* });
* page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
* ```
@ -384,19 +383,6 @@ export interface Page {
* }
* ```
*
* However, when manually listening to events, it might be useful to avoid stalling when the page crashes. In this case,
* handling `crash` event helps:
*
* ```js
* await new Promise((resolve, reject) => {
* page.on('requestfinished', async request => {
* if (await someProcessing(request))
* resolve(request);
* });
* page.on('crash', error => reject(error));
* });
* ```
*
*/
on(event: 'crash', listener: () => void): this;
@ -543,7 +529,7 @@ export interface Page {
* ```js
* page.on('console', msg => {
* for (let i = 0; i < msg.args().length; ++i)
* console.log(`${i}: ${msg.args()[i]}`);
* console.log(`${i}: ${await msg.args()[i].jsonValue()}`);
* });
* page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
* ```
@ -568,19 +554,6 @@ export interface Page {
* }
* ```
*
* However, when manually listening to events, it might be useful to avoid stalling when the page crashes. In this case,
* handling `crash` event helps:
*
* ```js
* await new Promise((resolve, reject) => {
* page.on('requestfinished', async request => {
* if (await someProcessing(request))
* resolve(request);
* });
* page.on('crash', error => reject(error));
* });
* ```
*
*/
once(event: 'crash', listener: () => void): this;
@ -727,7 +700,7 @@ export interface Page {
* ```js
* page.on('console', msg => {
* for (let i = 0; i < msg.args().length; ++i)
* console.log(`${i}: ${msg.args()[i]}`);
* console.log(`${i}: ${await msg.args()[i].jsonValue()}`);
* });
* page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
* ```
@ -752,19 +725,6 @@ export interface Page {
* }
* ```
*
* However, when manually listening to events, it might be useful to avoid stalling when the page crashes. In this case,
* handling `crash` event helps:
*
* ```js
* await new Promise((resolve, reject) => {
* page.on('requestfinished', async request => {
* if (await someProcessing(request))
* resolve(request);
* });
* page.on('crash', error => reject(error));
* });
* ```
*
*/
addListener(event: 'crash', listener: () => void): this;
@ -911,7 +871,7 @@ export interface Page {
* ```js
* page.on('console', msg => {
* for (let i = 0; i < msg.args().length; ++i)
* console.log(`${i}: ${msg.args()[i]}`);
* console.log(`${i}: ${await msg.args()[i].jsonValue()}`);
* });
* page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
* ```
@ -936,19 +896,6 @@ export interface Page {
* }
* ```
*
* However, when manually listening to events, it might be useful to avoid stalling when the page crashes. In this case,
* handling `crash` event helps:
*
* ```js
* await new Promise((resolve, reject) => {
* page.on('requestfinished', async request => {
* if (await someProcessing(request))
* resolve(request);
* });
* page.on('crash', error => reject(error));
* });
* ```
*
*/
removeListener(event: 'crash', listener: () => void): this;
@ -1095,7 +1042,7 @@ export interface Page {
* ```js
* page.on('console', msg => {
* for (let i = 0; i < msg.args().length; ++i)
* console.log(`${i}: ${msg.args()[i]}`);
* console.log(`${i}: ${await msg.args()[i].jsonValue()}`);
* });
* page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
* ```
@ -1120,19 +1067,6 @@ export interface Page {
* }
* ```
*
* However, when manually listening to events, it might be useful to avoid stalling when the page crashes. In this case,
* handling `crash` event helps:
*
* ```js
* await new Promise((resolve, reject) => {
* page.on('requestfinished', async request => {
* if (await someProcessing(request))
* resolve(request);
* });
* page.on('crash', error => reject(error));
* });
* ```
*
*/
off(event: 'crash', listener: () => void): this;
@ -1279,10 +1213,11 @@ export interface Page {
* ```js
* // preload.js
* Math.random = () => 42;
* ```
*
* ```js
* // In your playwright script, assuming the preload.js file is in same directory
* const preloadFile = fs.readFileSync('./preload.js', 'utf8');
* await page.addInitScript(preloadFile);
* await page.addInitScript({ path: './preload.js' });
* ```
*
* > NOTE: The order of evaluation of multiple scripts installed via
@ -1632,7 +1567,6 @@ export interface Page {
}): Promise<void>;
/**
*
* ```js
* await page.evaluate(() => matchMedia('screen').matches);
* // → true
@ -1693,7 +1627,7 @@ export interface Page {
* [page.exposeFunction()](https://github.com/microsoft/playwright/blob/master/docs/api.md#pageexposefunction) survive
* navigations.
*
* An example of adding an `md5` function to the page:
* An example of adding an `sha1` function to the page:
*
* ```js
* const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.
@ -1702,11 +1636,11 @@ export interface Page {
* (async () => {
* const browser = await webkit.launch({ headless: false });
* const page = await browser.newPage();
* await page.exposeFunction('md5', text => crypto.createHash('md5').update(text).digest('hex'));
* await page.exposeFunction('sha1', text => crypto.createHash('sha1').update(text).digest('hex'));
* await page.setContent(`
* <script>
* async function onClick() {
* document.querySelector('div').textContent = await window.md5('PLAYWRIGHT');
* document.querySelector('div').textContent = await window.sha1('PLAYWRIGHT');
* }
* </script>
* <button onclick="onClick()">Click me</button>
@ -1716,35 +1650,6 @@ export interface Page {
* })();
* ```
*
* An example of adding a `window.readfile` function to the page:
*
* ```js
* const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
* const fs = require('fs');
*
* (async () => {
* const browser = await chromium.launch();
* const page = await browser.newPage();
* page.on('console', msg => console.log(msg.text()));
* await page.exposeFunction('readfile', async filePath => {
* return new Promise((resolve, reject) => {
* fs.readFile(filePath, 'utf8', (err, text) => {
* if (err)
* reject(err);
* else
* resolve(text);
* });
* });
* });
* await page.evaluate(async () => {
* // use window.readfile to read contents of a file
* const content = await window.readfile('/etc/hosts');
* console.log(content);
* });
* await browser.close();
* })();
* ```
*
* @param name Name of the function on the window object
* @param callback Callback function which will be called in Playwright's context.
*/
@ -2499,7 +2404,7 @@ export interface Page {
* // single selection matching the value
* page.selectOption('select#colors', 'blue');
*
* // single selection matching both the value and the label
* // single selection matching the label
* page.selectOption('select#colors', { label: 'Blue' });
*
* // multiple selection
@ -2931,7 +2836,7 @@ export interface Page {
* ```js
* page.on('console', msg => {
* for (let i = 0; i < msg.args().length; ++i)
* console.log(`${i}: ${msg.args()[i]}`);
* console.log(`${i}: ${await msg.args()[i].jsonValue()}`);
* });
* page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
* ```
@ -2956,19 +2861,6 @@ export interface Page {
* }
* ```
*
* However, when manually listening to events, it might be useful to avoid stalling when the page crashes. In this case,
* handling `crash` event helps:
*
* ```js
* await new Promise((resolve, reject) => {
* page.on('requestfinished', async request => {
* if (await someProcessing(request))
* resolve(request);
* });
* page.on('crash', error => reject(error));
* });
* ```
*
*/
waitForEvent(event: 'crash', optionsOrPredicate?: { predicate?: () => boolean, timeout?: number } | (() => boolean)): Promise<void>;

View File

@ -0,0 +1,116 @@
// @ts-check
const { outputHelp } = require("commander");
const fs = require("fs");
const { createImportSpecifier } = require("typescript");
const md = require("../markdown");
const inputFile = "docs/src/api/class-page.md";
const fileContent = fs.readFileSync(inputFile).toString();
const nodes = md.parse(fileContent);
/**
* @param {string[]} input
* @param {boolean} isSync
*/
function transformValue(input, isSync) {
const out = [];
const suffix = [];
for (let line of input) {
let match = line.match(/const { (\w+) } = require\('playwright'\);/);
if (match) {
if (isSync) {
out.push('from playwright.sync_api import sync_playwright');
out.push('');
out.push('def run(playwright):');
out.push(` ${match[1]} = playwright.${match[1]}`);
suffix.push(``);
suffix.push(`with sync_playwright() as playwright:`);
suffix.push(` run(playwright)`);
} else {
out.push('import asyncio');
out.push('from playwright.async_api import async_playwright');
out.push('');
out.push('async def run(playwright):');
out.push(` ${match[1]} = playwright.${match[1]}`);
suffix.push(``);
suffix.push(`async def main():`);
suffix.push(` async with async_playwright() as playwright:`);
suffix.push(` await run(playwright)`);
suffix.push(`asyncio.run(main())`);
}
continue;
}
if (line.trim() === '(async () => {' || line.trim() === '})();')
continue;
if (!line)
continue;
if (line.trim() === '}')
continue;
line = line.replace(/\$\$eval/g, 'eval_on_selector_all');
line = line.replace(/\$eval/g, 'eval_on_selector');
line = line.replace(/\$\$/g, 'query_selector_all');
line = line.replace(/\$/g, 'query_selector');
line = line.replace(/([a-zA-Z$]+)/g, (match, p1) => toSnakeCase(p1));
line = line.replace(/try {/, 'try:');
line = line.replace(/async \(([^)]+)\) => {/, 'lambda $1:');
line = line.replace(/} catch \(e\) {/, 'except Error as e:');
line = line.replace(/;$/, '');
line = line.replace(/ /g, ' ');
line = line.replace(/'/g, '"');
line = line.replace(/const /g, '');
line = line.replace(/{\s*(\w+):\s*([^} ]+)\s*}/, "$1=$2");
line = line.replace(/\/\/ /, "# ");
line = line.replace(/\(\) => /, 'lambda: ');
line = line.replace(/console.log/, 'print');
line = line.replace(/function /, 'def ');
line = line.replace(/{$/, '');
if (isSync)
line = line.replace(/await /g, "")
out.push(line)
}
return [...out, ...suffix].join("\n");
}
/**
*
* @param {md.MarkdownNode} node
* @param {boolean} isSync
*/
function generateComment(node, isSync) {
const commentNode = md.clone(node)
commentNode.codeLang = isSync ? "python sync" : "python async";
commentNode.lines = ['# FIXME', ...transformValue(node.lines, isSync).split("\n")];
return commentNode;
}
/**
*
* @param {md.MarkdownNode[]} spec
*/
function multiplyComment(spec) {
const children = []
for (const node of (spec || [])) {
if (node.codeLang === "js")
children.push(node, generateComment(node, false), generateComment(node, true));
else
children.push(node);
}
return children;
}
md.visitAll(nodes, node => {
if (node.children)
node.children = multiplyComment(node.children);
});
/**
* @param {string} name
*/
function toSnakeCase(name) {
const toSnakeCaseRegex = /((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))/g;
return name.replace(toSnakeCaseRegex, `_$1`).toLowerCase();
}
const out = md.render(nodes, 120);
fs.writeFileSync(inputFile, out);

View File

@ -264,7 +264,25 @@ function parentClass(classDesc) {
function writeComment(comment, indent = '') {
const parts = [];
const out = [];
const pushLine = (line) => {
if (line || out[out.length - 1])
out.push(line)
};
let skipExample = false;
for (let line of comment.split('\n')) {
const match = line.match(/```(\w+)/);
if (match) {
const lang = match[1];
skipExample = !["html", "yml", "sh", "js"].includes(lang);
} else if (skipExample && line.trim().startsWith('```')) {
skipExample = false;
continue;
}
if (!skipExample)
pushLine(line);
}
comment = out.join('\n');
comment = comment.replace(/\[`([^`]+)`\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
comment = comment.replace(/\[([^\]]+)\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
comment = comment.replace(/\[`([^`]+)`\]\(\.\/([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/$2)');