mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
api: evaluateOnNewDocument -> addInitScript (#1152)
Also adds more options to specify the script.
This commit is contained in:
parent
9478bf3ee5
commit
823bf389a7
106
docs/api.md
106
docs/api.md
@ -264,11 +264,11 @@ await context.close();
|
||||
|
||||
<!-- GEN:toc -->
|
||||
- [event: 'close'](#event-close)
|
||||
- [browserContext.addInitScript(script[, ...args])](#browsercontextaddinitscriptscript-args)
|
||||
- [browserContext.clearCookies()](#browsercontextclearcookies)
|
||||
- [browserContext.clearPermissions()](#browsercontextclearpermissions)
|
||||
- [browserContext.close()](#browsercontextclose)
|
||||
- [browserContext.cookies([...urls])](#browsercontextcookiesurls)
|
||||
- [browserContext.evaluateOnNewDocument(pageFunction[, ...args])](#browsercontextevaluateonnewdocumentpagefunction-args)
|
||||
- [browserContext.newPage()](#browsercontextnewpage)
|
||||
- [browserContext.pages()](#browsercontextpages)
|
||||
- [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
|
||||
@ -286,6 +286,32 @@ Emitted when Browser context gets closed. This might happen because of one of th
|
||||
- Browser application is closed or crashed.
|
||||
- The [`browser.close`](#browserclose) method was called.
|
||||
|
||||
#### browserContext.addInitScript(script[, ...args])
|
||||
- `script` <[function]|[string]|[Object]> Script to be evaluated in all pages in the browser context.
|
||||
- `path` <[string]> Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
|
||||
- `content` <[string]> Raw script content.
|
||||
- `...args` <...[Serializable]> Arguments to pass to `script` (only supported when passing a function).
|
||||
- returns: <[Promise]>
|
||||
|
||||
Adds a script which would be evaluated in one of the following scenarios:
|
||||
- Whenever a page is created in the browser context or is navigated.
|
||||
- Whenever a child frame is attached or navigated in any page in the browser context. In this case, the script is evaluated in the context of the newly attached frame.
|
||||
|
||||
The script is evaluated after the document was created but before any of its scripts were run. This is useful to amend the JavaScript environment, e.g. to seed `Math.random`.
|
||||
|
||||
An example of overriding `Math.random` before the page loads:
|
||||
|
||||
```js
|
||||
// preload.js
|
||||
Math.random = () => 42;
|
||||
|
||||
// In your playwright script, assuming the preload.js file is in same folder
|
||||
const preloadFile = fs.readFileSync('./preload.js', 'utf8');
|
||||
await browserContext.addInitScript(preloadFile);
|
||||
```
|
||||
|
||||
> **NOTE** The order of evaluation of multiple scripts installed via [browserContext.addInitScript(script[, ...args])](#browsercontextaddinitscriptscript-args) and [page.addInitScript(script[, ...args])](#pageaddinitscriptscript-args) is not defined.
|
||||
|
||||
#### browserContext.clearCookies()
|
||||
- returns: <[Promise]>
|
||||
|
||||
@ -328,30 +354,6 @@ will be closed.
|
||||
If no URLs are specified, this method returns all cookies.
|
||||
If URLs are specified, only cookies that affect those URLs are returned.
|
||||
|
||||
#### browserContext.evaluateOnNewDocument(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated in all pages in the browser context
|
||||
- `...args` <...[Serializable]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]>
|
||||
|
||||
Adds a function which would be invoked in one of the following scenarios:
|
||||
- Whenever a page is created in the browser context or is navigated.
|
||||
- Whenever a child frame is attached or navigated in any page in the browser context. In this case, the function is invoked in the context of the newly attached frame.
|
||||
|
||||
The function is invoked after the document was created but before any of its scripts were run. This is useful to amend the JavaScript environment, e.g. to seed `Math.random`.
|
||||
|
||||
An example of overriding `Math.random` before the page loads:
|
||||
|
||||
```js
|
||||
// preload.js
|
||||
Math.random = () => 42;
|
||||
|
||||
// In your playwright script, assuming the preload.js file is in same folder
|
||||
const preloadFile = fs.readFileSync('./preload.js', 'utf8');
|
||||
await browserContext.evaluateOnNewDocument(preloadFile);
|
||||
```
|
||||
|
||||
> **NOTE** The order of evaluation of multiple scripts installed via [browserContext.evaluateOnNewDocument(pageFunction[, ...args])](#browsercontextevaluateonnewdocumentpagefunction-args) and [page.evaluateOnNewDocument(pageFunction[, ...args])](#pageevaluateonnewdocumentpagefunction-args) is not defined.
|
||||
|
||||
#### browserContext.newPage()
|
||||
- returns: <[Promise]<[Page]>>
|
||||
|
||||
@ -511,6 +513,7 @@ page.removeListener('request', logRequest);
|
||||
- [page.$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args-1)
|
||||
- [page.$wait(selector[, options])](#pagewaitselector-options)
|
||||
- [page.accessibility](#pageaccessibility)
|
||||
- [page.addInitScript(script[, ...args])](#pageaddinitscriptscript-args)
|
||||
- [page.addScriptTag(options)](#pageaddscripttagoptions)
|
||||
- [page.addStyleTag(options)](#pageaddstyletagoptions)
|
||||
- [page.authenticate(credentials)](#pageauthenticatecredentials)
|
||||
@ -524,7 +527,6 @@ page.removeListener('request', logRequest);
|
||||
- [page.emulateMedia(options)](#pageemulatemediaoptions)
|
||||
- [page.evaluate(pageFunction[, ...args])](#pageevaluatepagefunction-args)
|
||||
- [page.evaluateHandle(pageFunction[, ...args])](#pageevaluatehandlepagefunction-args)
|
||||
- [page.evaluateOnNewDocument(pageFunction[, ...args])](#pageevaluateonnewdocumentpagefunction-args)
|
||||
- [page.exposeFunction(name, playwrightFunction)](#pageexposefunctionname-playwrightfunction)
|
||||
- [page.fill(selector, value, options)](#pagefillselector-value-options)
|
||||
- [page.focus(selector, options)](#pagefocusselector-options)
|
||||
@ -752,6 +754,32 @@ This is a shortcut to [page.waitForSelector(selector[, options])](#pagewaitforse
|
||||
#### page.accessibility
|
||||
- returns: <[Accessibility]>
|
||||
|
||||
#### page.addInitScript(script[, ...args])
|
||||
- `script` <[function]|[string]|[Object]> Script to be evaluated in the page.
|
||||
- `path` <[string]> Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
|
||||
- `content` <[string]> Raw script content.
|
||||
- `...args` <...[Serializable]> Arguments to pass to `script` (only supported when passing a function).
|
||||
- returns: <[Promise]>
|
||||
|
||||
Adds a script which would be evaluated in one of the following scenarios:
|
||||
- Whenever the page is navigated.
|
||||
- Whenever the child frame is attached or navigated. In this case, the scritp is evaluated in the context of the newly attached frame.
|
||||
|
||||
The script is evaluated after the document was created but before any of its scripts were run. This is useful to amend the JavaScript environment, e.g. to seed `Math.random`.
|
||||
|
||||
An example of overriding `Math.random` before the page loads:
|
||||
|
||||
```js
|
||||
// preload.js
|
||||
Math.random = () => 42;
|
||||
|
||||
// In your playwright script, assuming the preload.js file is in same folder
|
||||
const preloadFile = fs.readFileSync('./preload.js', 'utf8');
|
||||
await page.addInitScript(preloadFile);
|
||||
```
|
||||
|
||||
> **NOTE** The order of evaluation of multiple scripts installed via [browserContext.addInitScript(script[, ...args])](#browsercontextaddinitscriptscript-args) and [page.addInitScript(script[, ...args])](#pageaddinitscriptscript-args) is not defined.
|
||||
|
||||
#### page.addScriptTag(options)
|
||||
- `options` <[Object]>
|
||||
- `url` <[string]> URL of a script to be added.
|
||||
@ -966,30 +994,6 @@ console.log(await resultHandle.jsonValue());
|
||||
await resultHandle.dispose();
|
||||
```
|
||||
|
||||
#### page.evaluateOnNewDocument(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated in the page
|
||||
- `...args` <...[Serializable]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]>
|
||||
|
||||
Adds a function which would be invoked in one of the following scenarios:
|
||||
- whenever the page is navigated
|
||||
- whenever the child frame is attached or navigated. In this case, the function is invoked in the context of the newly attached frame
|
||||
|
||||
The function is invoked after the document was created but before any of its scripts were run. This is useful to amend the JavaScript environment, e.g. to seed `Math.random`.
|
||||
|
||||
An example of overriding `Math.random` before the page loads:
|
||||
|
||||
```js
|
||||
// preload.js
|
||||
Math.random = () => 42;
|
||||
|
||||
// In your playwright script, assuming the preload.js file is in same folder
|
||||
const preloadFile = fs.readFileSync('./preload.js', 'utf8');
|
||||
await page.evaluateOnNewDocument(preloadFile);
|
||||
```
|
||||
|
||||
> **NOTE** The order of evaluation of multiple scripts installed via [browserContext.evaluateOnNewDocument(pageFunction[, ...args])](#browsercontextevaluateonnewdocumentpagefunction-args) and [page.evaluateOnNewDocument(pageFunction[, ...args])](#pageevaluateonnewdocumentpagefunction-args) is not defined.
|
||||
|
||||
#### page.exposeFunction(name, playwrightFunction)
|
||||
- `name` <[string]> Name of the function on the window object
|
||||
- `playwrightFunction` <[function]> Callback function which will be called in Playwright's context.
|
||||
@ -3604,11 +3608,11 @@ const backgroundPage = await backroundPageTarget.page();
|
||||
<!-- GEN:stop -->
|
||||
<!-- GEN:toc-extends-BrowserContext -->
|
||||
- [event: 'close'](#event-close)
|
||||
- [browserContext.addInitScript(script[, ...args])](#browsercontextaddinitscriptscript-args)
|
||||
- [browserContext.clearCookies()](#browsercontextclearcookies)
|
||||
- [browserContext.clearPermissions()](#browsercontextclearpermissions)
|
||||
- [browserContext.close()](#browsercontextclose)
|
||||
- [browserContext.cookies([...urls])](#browsercontextcookiesurls)
|
||||
- [browserContext.evaluateOnNewDocument(pageFunction[, ...args])](#browsercontextevaluateonnewdocumentpagefunction-args)
|
||||
- [browserContext.newPage()](#browsercontextnewpage)
|
||||
- [browserContext.pages()](#browsercontextpages)
|
||||
- [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
|
||||
|
||||
@ -46,7 +46,7 @@ export interface BrowserContext {
|
||||
clearPermissions(): Promise<void>;
|
||||
setGeolocation(geolocation: types.Geolocation | null): Promise<void>;
|
||||
setExtraHTTPHeaders(headers: network.Headers): Promise<void>;
|
||||
evaluateOnNewDocument(pageFunction: Function | string, ...args: any[]): Promise<void>;
|
||||
addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
|
||||
_existingPages(): Page[];
|
||||
|
||||
@ -302,8 +302,8 @@ export class CRBrowserContext extends platform.EventEmitter implements BrowserCo
|
||||
await (page._delegate as CRPage).updateExtraHTTPHeaders();
|
||||
}
|
||||
|
||||
async evaluateOnNewDocument(pageFunction: Function | string, ...args: any[]) {
|
||||
const source = helper.evaluationString(pageFunction, ...args);
|
||||
async addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]) {
|
||||
const source = await helper.evaluationScript(script, ...args);
|
||||
this._evaluateOnNewDocumentSources.push(source);
|
||||
for (const page of this._existingPages())
|
||||
await (page._delegate as CRPage).evaluateOnNewDocument(source);
|
||||
|
||||
@ -359,8 +359,8 @@ export class FFBrowserContext extends platform.EventEmitter implements BrowserCo
|
||||
await this._browser._connection.send('Browser.setExtraHTTPHeaders', { browserContextId: this._browserContextId || undefined, headers: headersArray(this._options.extraHTTPHeaders) });
|
||||
}
|
||||
|
||||
async evaluateOnNewDocument(pageFunction: Function | string, ...args: any[]) {
|
||||
const source = helper.evaluationString(pageFunction, ...args);
|
||||
async addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]) {
|
||||
const source = await helper.evaluationScript(script, ...args);
|
||||
this._evaluateOnNewDocumentSources.push(source);
|
||||
await this._browser._connection.send('Browser.addScriptToEvaluateOnNewDocument', { browserContextId: this._browserContextId || undefined, script: source });
|
||||
}
|
||||
|
||||
@ -41,6 +41,21 @@ class Helper {
|
||||
}
|
||||
}
|
||||
|
||||
static async evaluationScript(fun: Function | string | { path?: string, content?: string }, ...args: any[]): Promise<string> {
|
||||
if (!helper.isString(fun) && typeof fun !== 'function') {
|
||||
if (fun.content !== undefined) {
|
||||
fun = fun.content;
|
||||
} else if (fun.path !== undefined) {
|
||||
let contents = await platform.readFileAsync(fun.path, 'utf8');
|
||||
contents += '//# sourceURL=' + fun.path.replace(/\n/g, '');
|
||||
fun = contents;
|
||||
} else {
|
||||
throw new Error('Either path or content property must be present');
|
||||
}
|
||||
}
|
||||
return helper.evaluationString(fun, ...args);
|
||||
}
|
||||
|
||||
static installApiHooks(className: string, classType: any) {
|
||||
const log = platform.debug('pw:api');
|
||||
for (const methodName of Reflect.ownKeys(classType.prototype)) {
|
||||
|
||||
@ -411,9 +411,8 @@ export class Page extends platform.EventEmitter {
|
||||
return this.mainFrame().evaluate(pageFunction, ...args as any);
|
||||
}
|
||||
|
||||
async evaluateOnNewDocument(pageFunction: Function | string, ...args: any[]) {
|
||||
const source = helper.evaluationString(pageFunction, ...args);
|
||||
await this._delegate.evaluateOnNewDocument(source);
|
||||
async addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]) {
|
||||
await this._delegate.evaluateOnNewDocument(await helper.evaluationScript(script, ...args));
|
||||
}
|
||||
|
||||
async setCacheEnabled(enabled: boolean = true) {
|
||||
|
||||
@ -278,8 +278,8 @@ export class WKBrowserContext extends platform.EventEmitter implements BrowserCo
|
||||
await (page._delegate as WKPage).updateExtraHTTPHeaders();
|
||||
}
|
||||
|
||||
async evaluateOnNewDocument(pageFunction: Function | string, ...args: any[]) {
|
||||
const source = helper.evaluationString(pageFunction, ...args);
|
||||
async addInitScript(script: Function | string | { path?: string, content?: string }, ...args: any[]) {
|
||||
const source = await helper.evaluationScript(script, ...args);
|
||||
this._evaluateOnNewDocumentSources.push(source);
|
||||
for (const page of this._existingPages())
|
||||
await (page._delegate as WKPage)._updateBootstrapScript();
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
window.__injected = 42;
|
||||
window.injected = 123;
|
||||
window.__injectedError = new Error('hi');
|
||||
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
const utils = require('./utils');
|
||||
|
||||
const path = require('path');
|
||||
const bigint = typeof BigInt !== 'undefined';
|
||||
|
||||
/**
|
||||
@ -277,19 +277,41 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
|
||||
})
|
||||
});
|
||||
|
||||
describe('Page.evaluateOnNewDocument', function() {
|
||||
describe('Page.addInitScript', function() {
|
||||
it('should evaluate before anything else on the page', async({page, server}) => {
|
||||
await page.evaluateOnNewDocument(function(){
|
||||
await page.addInitScript(function(){
|
||||
window.injected = 123;
|
||||
});
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
expect(await page.evaluate(() => window.result)).toBe(123);
|
||||
});
|
||||
it('should work with a path', async({page, server}) => {
|
||||
await page.addInitScript({ path: path.join(__dirname, 'assets/injectedfile.js') });
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
expect(await page.evaluate(() => window.result)).toBe(123);
|
||||
});
|
||||
it('should work with content', async({page, server}) => {
|
||||
await page.addInitScript({ content: 'window.injected = 123' });
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
expect(await page.evaluate(() => window.result)).toBe(123);
|
||||
});
|
||||
it('should throw without path and content', async({page, server}) => {
|
||||
const error = await page.addInitScript({ foo: 'bar' }).catch(e => e);
|
||||
expect(error.message).toBe('Either path or content property must be present');
|
||||
});
|
||||
it('should work with browser context scripts', async({browser, server}) => {
|
||||
const context = await browser.newContext();
|
||||
await context.evaluateOnNewDocument(() => window.temp = 123);
|
||||
await context.addInitScript(() => window.temp = 123);
|
||||
const page = await context.newPage();
|
||||
await page.addInitScript(() => window.injected = window.temp);
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
expect(await page.evaluate(() => window.result)).toBe(123);
|
||||
await context.close();
|
||||
});
|
||||
it('should work with browser context scripts with a path', async({browser, server}) => {
|
||||
const context = await browser.newContext();
|
||||
await context.addInitScript({ path: path.join(__dirname, 'assets/injectedfile.js') });
|
||||
const page = await context.newPage();
|
||||
await page.evaluateOnNewDocument(() => window.injected = window.temp);
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
expect(await page.evaluate(() => window.result)).toBe(123);
|
||||
await context.close();
|
||||
@ -297,17 +319,17 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
|
||||
it('should work with browser context scripts for already created pages', async({browser, server}) => {
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
await context.evaluateOnNewDocument(() => window.temp = 123);
|
||||
await page.evaluateOnNewDocument(() => window.injected = window.temp);
|
||||
await context.addInitScript(() => window.temp = 123);
|
||||
await page.addInitScript(() => window.injected = window.temp);
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
expect(await page.evaluate(() => window.result)).toBe(123);
|
||||
await context.close();
|
||||
});
|
||||
it('should support multiple scripts', async({page, server}) => {
|
||||
await page.evaluateOnNewDocument(function(){
|
||||
await page.addInitScript(function(){
|
||||
window.script1 = 1;
|
||||
});
|
||||
await page.evaluateOnNewDocument(function(){
|
||||
await page.addInitScript(function(){
|
||||
window.script2 = 2;
|
||||
});
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
@ -316,7 +338,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
|
||||
});
|
||||
it('should work with CSP', async({page, server}) => {
|
||||
server.setCSP('/empty.html', 'script-src ' + server.PREFIX);
|
||||
await page.evaluateOnNewDocument(function(){
|
||||
await page.addInitScript(function(){
|
||||
window.injected = 123;
|
||||
});
|
||||
await page.goto(server.PREFIX + '/empty.html');
|
||||
@ -328,7 +350,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
|
||||
});
|
||||
it('should work after a cross origin navigation', async({page, server}) => {
|
||||
await page.goto(server.CROSS_PROCESS_PREFIX);
|
||||
await page.evaluateOnNewDocument(function(){
|
||||
await page.addInitScript(function(){
|
||||
window.injected = 123;
|
||||
});
|
||||
await page.goto(server.PREFIX + '/tamperable.html');
|
||||
|
||||
@ -412,12 +412,12 @@ module.exports.describe = function({testRunner, expect, headless, playwright, FF
|
||||
});
|
||||
expect(thrown).toBe(null);
|
||||
});
|
||||
it('should be callable from-inside evaluateOnNewDocument', async({page, server}) => {
|
||||
it('should be callable from-inside addInitScript', async({page, server}) => {
|
||||
let called = false;
|
||||
await page.exposeFunction('woof', function() {
|
||||
called = true;
|
||||
});
|
||||
await page.evaluateOnNewDocument(() => woof());
|
||||
await page.addInitScript(() => woof());
|
||||
await page.reload();
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
|
||||
@ -74,9 +74,9 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
|
||||
await context.close();
|
||||
expect(size).toEqual({width: 400, height: 500});
|
||||
});
|
||||
it.skip(CHROMIUM || WEBKIT)('should apply evaluateOnNewDocument from browser context', async function({browser, server}) {
|
||||
it.skip(CHROMIUM)('should apply addInitScript from browser context', async function({browser, server}) {
|
||||
const context = await browser.newContext();
|
||||
await context.evaluateOnNewDocument(() => window.injected = 123);
|
||||
await context.addInitScript(() => window.injected = 123);
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const injected = await page.evaluate(() => {
|
||||
|
||||
@ -85,7 +85,7 @@ module.exports.describe = function({testRunner, expect, product, playwright, FFO
|
||||
await watchdog;
|
||||
});
|
||||
it('should work when resolved right before execution context disposal', async({page, server}) => {
|
||||
await page.evaluateOnNewDocument(() => window.__RELOADED = true);
|
||||
await page.addInitScript(() => window.__RELOADED = true);
|
||||
await page.waitForFunction(() => {
|
||||
if (!window.__RELOADED)
|
||||
window.location.reload();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user