mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 13:45:36 +03:00
api: remove ExecutionContext from api (#290)
In the current state, it is superseeded by Frame and JSHandle.
This commit is contained in:
parent
58cd8210b0
commit
7750db97fe
@ -125,7 +125,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate {
|
||||
if (error.message.includes('Object couldn\'t be returned by value'))
|
||||
return {result: {type: 'undefined'}};
|
||||
|
||||
if (error.message.endsWith('Cannot find context with specified id') || error.message.endsWith('Inspected target navigated or closed'))
|
||||
if (error.message.endsWith('Cannot find context with specified id') || error.message.endsWith('Inspected target navigated or closed') || error.message.endsWith('Execution context was destroyed.'))
|
||||
throw new Error('Execution context was destroyed, most likely because of a navigation.');
|
||||
throw error;
|
||||
}
|
||||
@ -140,7 +140,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate {
|
||||
for (const property of response.result) {
|
||||
if (!property.enumerable)
|
||||
continue;
|
||||
result.set(property.name, handle.executionContext()._createHandle(property.value));
|
||||
result.set(property.name, handle._context._createHandle(property.value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ export { ElementHandle } from '../dom';
|
||||
export { TimeoutError } from '../errors';
|
||||
export { Frame } from '../frames';
|
||||
export { Keyboard, Mouse } from '../input';
|
||||
export { ExecutionContext, JSHandle } from '../javascript';
|
||||
export { JSHandle } from '../javascript';
|
||||
export { Request, Response } from '../network';
|
||||
export { Browser } from './Browser';
|
||||
export { BrowserContext } from '../browserContext';
|
||||
|
@ -85,10 +85,6 @@ export class Worker extends EventEmitter {
|
||||
return this._url;
|
||||
}
|
||||
|
||||
async executionContext(): Promise<js.ExecutionContext> {
|
||||
return this._executionContextPromise;
|
||||
}
|
||||
|
||||
evaluate: types.Evaluate = async (pageFunction, ...args) => {
|
||||
return (await this._executionContextPromise).evaluate(pageFunction, ...args as any);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export class ConsoleMessage {
|
||||
|
||||
text(): string {
|
||||
if (this._text === undefined)
|
||||
this._text = this._args.map(arg => arg.executionContext()._delegate.handleToString(arg, false /* includeType */)).join(' ');
|
||||
this._text = this._args.map(arg => arg._context._delegate.handleToString(arg, false /* includeType */)).join(' ');
|
||||
return this._text;
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,10 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
this._page = context.frame()._page;
|
||||
}
|
||||
|
||||
frame(): frames.Frame {
|
||||
return this._context.frame();
|
||||
}
|
||||
|
||||
asElement(): ElementHandle<T> | null {
|
||||
return this;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate {
|
||||
return context._createHandle(payload.result);
|
||||
|
||||
function rewriteError(error) : never {
|
||||
if (error.message.includes('Failed to find execution context with id'))
|
||||
if (error.message.includes('Failed to find execution context with id') || error.message.includes('Execution context was destroyed!'))
|
||||
throw new Error('Execution context was destroyed, most likely because of a navigation.');
|
||||
throw error;
|
||||
}
|
||||
@ -119,7 +119,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate {
|
||||
});
|
||||
const result = new Map();
|
||||
for (const property of response.properties)
|
||||
result.set(property.name, handle.executionContext()._createHandle(property.value));
|
||||
result.set(property.name, handle._context._createHandle(property.value));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ export { Browser } from './Browser';
|
||||
export { BrowserContext } from '../browserContext';
|
||||
export { BrowserFetcher } from '../browserFetcher';
|
||||
export { Dialog } from '../dialog';
|
||||
export { ExecutionContext, JSHandle } from '../javascript';
|
||||
export { JSHandle } from '../javascript';
|
||||
export { ElementHandle } from '../dom';
|
||||
export { Accessibility } from './features/accessibility';
|
||||
export { Interception } from './features/interception';
|
||||
|
@ -354,10 +354,6 @@ export class Frame {
|
||||
return this._context('utility');
|
||||
}
|
||||
|
||||
executionContext(): Promise<dom.FrameExecutionContext> {
|
||||
return this._mainContext();
|
||||
}
|
||||
|
||||
evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => {
|
||||
const context = await this._mainContext();
|
||||
return context.evaluateHandle(pageFunction, ...args as any);
|
||||
@ -632,7 +628,7 @@ export class Frame {
|
||||
const values = value === undefined ? [] : Array.isArray(value) ? value : [value];
|
||||
const context = await this._utilityContext();
|
||||
const adoptedValues = await Promise.all(values.map(async value => {
|
||||
if (value instanceof dom.ElementHandle && value.executionContext() !== context) {
|
||||
if (value instanceof dom.ElementHandle && value._context !== context) {
|
||||
const adopted = this._page._delegate.adoptElementHandle(value, context);
|
||||
toDispose.push(adopted);
|
||||
return adopted;
|
||||
|
@ -47,10 +47,6 @@ export class JSHandle<T = any> {
|
||||
this._remoteObject = remoteObject;
|
||||
}
|
||||
|
||||
executionContext(): ExecutionContext {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
evaluate: types.EvaluateOn<T> = (pageFunction, ...args) => {
|
||||
return this._context.evaluate(pageFunction, this, ...args);
|
||||
}
|
||||
|
@ -174,8 +174,7 @@ export class Page extends EventEmitter {
|
||||
}
|
||||
|
||||
evaluateHandle: types.EvaluateHandle = async (pageFunction, ...args) => {
|
||||
const context = await this.mainFrame().executionContext();
|
||||
return context.evaluateHandle(pageFunction, ...args as any);
|
||||
return this.mainFrame().evaluateHandle(pageFunction, ...args as any);
|
||||
}
|
||||
|
||||
$eval: types.$Eval = (selector, pageFunction, ...args) => {
|
||||
|
@ -261,7 +261,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate {
|
||||
for (const property of response.properties) {
|
||||
if (!property.enumerable)
|
||||
continue;
|
||||
result.set(property.name, handle.executionContext()._createHandle(property.value));
|
||||
result.set(property.name, handle._context._createHandle(property.value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ export class FrameManager implements PageDelegate {
|
||||
else if (type === 'timing')
|
||||
derivedType = 'timeEnd';
|
||||
|
||||
const mainFrameContext = await this._page.mainFrame().executionContext();
|
||||
const mainFrameContext = await this._page.mainFrame()._mainContext();
|
||||
const handles = (parameters || []).map(p => {
|
||||
let context: dom.FrameExecutionContext | null = null;
|
||||
if (p.objectId) {
|
||||
|
@ -5,7 +5,7 @@ export { TimeoutError } from '../errors';
|
||||
export { Browser } from './Browser';
|
||||
export { BrowserContext } from '../browserContext';
|
||||
export { BrowserFetcher } from '../browserFetcher';
|
||||
export { ExecutionContext, JSHandle } from '../javascript';
|
||||
export { JSHandle } from '../javascript';
|
||||
export { ElementHandle } from '../dom';
|
||||
export { Frame } from '../frames';
|
||||
export { Mouse, Keyboard } from '../input';
|
||||
|
@ -67,11 +67,11 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(log.args().length).toBe(4);
|
||||
expect(await (await log.args()[3].getProperty('origin')).jsonValue()).toBe('null');
|
||||
});
|
||||
it('should have an execution context', async function({page}) {
|
||||
it('should evaluate', async function({page}) {
|
||||
const workerCreatedPromise = new Promise(x => page.workers.once('workercreated', x));
|
||||
await page.evaluate(() => new Worker(`data:text/javascript,console.log(1)`));
|
||||
const worker = await workerCreatedPromise;
|
||||
expect(await (await worker.executionContext()).evaluate('1+1')).toBe(2);
|
||||
expect(await worker.evaluate('1+1')).toBe(2);
|
||||
});
|
||||
it('should report errors', async function({page}) {
|
||||
const errorPromise = new Promise(x => page.on('pageerror', x));
|
||||
|
@ -83,7 +83,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
location.reload();
|
||||
return new Promise(() => {});
|
||||
}).catch(e => error = e);
|
||||
expect(error.message).toContain('Protocol error');
|
||||
expect(error.message).toContain('navigation');
|
||||
});
|
||||
it('should await promise', async({page, server}) => {
|
||||
const result = await page.evaluate(() => Promise.resolve(8 * 7));
|
||||
@ -227,13 +227,15 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
it('should throw a nice error after a navigation', async({page, server}) => {
|
||||
const executionContext = await page.mainFrame().executionContext();
|
||||
|
||||
const errorPromise = page.evaluate(() => new Promise(f => window.__resolve = f)).catch(e => e);
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
executionContext.evaluate(() => window.location.reload())
|
||||
page.evaluate(() => {
|
||||
window.location.reload();
|
||||
setTimeout(() => window.__resolve(42), 1000);
|
||||
})
|
||||
]);
|
||||
const error = await executionContext.evaluate(() => null).catch(e => e);
|
||||
const error = await errorPromise;
|
||||
expect(error.message).toContain('navigation');
|
||||
});
|
||||
it.skip(FFOX)('should not throw an error when evaluation does a navigation', async({page, server}) => {
|
||||
|
@ -22,33 +22,6 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
|
||||
describe('Frame.executionContext', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
expect(page.frames().length).toBe(2);
|
||||
const [frame1, frame2] = page.frames();
|
||||
const context1 = await frame1.executionContext();
|
||||
const context2 = await frame2.executionContext();
|
||||
expect(context1).toBeTruthy();
|
||||
expect(context2).toBeTruthy();
|
||||
expect(context1 !== context2).toBeTruthy();
|
||||
expect(context1.frame()).toBe(frame1);
|
||||
expect(context2.frame()).toBe(frame2);
|
||||
|
||||
await Promise.all([
|
||||
context1.evaluate(() => window.a = 1),
|
||||
context2.evaluate(() => window.a = 2)
|
||||
]);
|
||||
const [a1, a2] = await Promise.all([
|
||||
context1.evaluate(() => window.a),
|
||||
context2.evaluate(() => window.a)
|
||||
]);
|
||||
expect(a1).toBe(1);
|
||||
expect(a2).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.evaluateHandle', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -66,6 +39,24 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
|
||||
await frame1.evaluate(() => 7 * 8).catch(e => error = e);
|
||||
expect(error.message).toContain('Execution Context is not available in detached frame');
|
||||
});
|
||||
it('should be isolated between frames', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
expect(page.frames().length).toBe(2);
|
||||
const [frame1, frame2] = page.frames();
|
||||
expect(frame1 !== frame2).toBeTruthy();
|
||||
|
||||
await Promise.all([
|
||||
frame1.evaluate(() => window.a = 1),
|
||||
frame2.evaluate(() => window.a = 2)
|
||||
]);
|
||||
const [a1, a2] = await Promise.all([
|
||||
frame1.evaluate(() => window.a),
|
||||
frame2.evaluate(() => window.a)
|
||||
]);
|
||||
expect(a1).toBe(1);
|
||||
expect(a2).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame Management', function() {
|
||||
|
@ -146,14 +146,17 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(true);
|
||||
});
|
||||
it('should work with fake-clicking target=_blank and rel=noopener', async({page, server}) => {
|
||||
it.skip(FFOX)('should work with fake-clicking target=_blank and rel=noopener', async({page, server}) => {
|
||||
// TODO: FFOX sends events for "one-style.html" request to both pages.
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
new Promise(x => page.once('popup', x)),
|
||||
page.waitForEvent('popup'),
|
||||
page.$eval('a', a => a.click()),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
// TODO: At this point popup might still have about:blank as the current document.
|
||||
// FFOX is slow enough to trigger this. We should do something about popups api.
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(false);
|
||||
});
|
||||
it('should work with clicking target=_blank and rel=noopener', async({page, server}) => {
|
||||
@ -381,7 +384,7 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
|
||||
it('should work with relaxed search params match', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [request] = await Promise.all([
|
||||
page.waitForRequest({ searchParams: { 'foo': ['bar', /^baz$/], 'bar': 'foo' } }),
|
||||
page.waitForRequest({ searchParams: { 'foo': ['bar', /^baz$/], 'bar': 'foo' }, url: /\.png/ }),
|
||||
page.evaluate(() => {
|
||||
fetch('/digits/1.png?key=value&foo=something');
|
||||
fetch('/digits/2.png?foo=baz');
|
||||
@ -402,7 +405,7 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
|
||||
it('should throw for incorrect searchParams match', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [error] = await Promise.all([
|
||||
page.waitForRequest({ searchParams: { 'foo': 123 } }).catch(e => e),
|
||||
page.waitForRequest({ searchParams: { 'foo': 123 }, url: /\.png/ }).catch(e => e),
|
||||
page.evaluate(() => {
|
||||
fetch('/digits/1.png?foo=bar');
|
||||
})
|
||||
|
@ -252,7 +252,7 @@ module.exports.addTests = function({testRunner, expect, product, playwright, FFO
|
||||
await otherFrame.evaluate(addElement, 'div');
|
||||
await page.evaluate(addElement, 'div');
|
||||
const eHandle = await watchdog;
|
||||
expect(eHandle.executionContext().frame()).toBe(page.mainFrame());
|
||||
expect(eHandle.frame()).toBe(page.mainFrame());
|
||||
});
|
||||
|
||||
it('should run in specified frame', async({page, server}) => {
|
||||
@ -264,7 +264,7 @@ module.exports.addTests = function({testRunner, expect, product, playwright, FFO
|
||||
await frame1.evaluate(addElement, 'div');
|
||||
await frame2.evaluate(addElement, 'div');
|
||||
const eHandle = await waitForSelectorPromise;
|
||||
expect(eHandle.executionContext().frame()).toBe(frame2);
|
||||
expect(eHandle.frame()).toBe(frame2);
|
||||
});
|
||||
|
||||
it('should throw when frame is detached', async({page, server}) => {
|
||||
@ -415,7 +415,7 @@ module.exports.addTests = function({testRunner, expect, product, playwright, FFO
|
||||
await frame1.evaluate(addElement, 'div');
|
||||
await frame2.evaluate(addElement, 'div');
|
||||
const eHandle = await waitForXPathPromise;
|
||||
expect(eHandle.executionContext().frame()).toBe(frame2);
|
||||
expect(eHandle.frame()).toBe(frame2);
|
||||
});
|
||||
it('should throw when frame is detached', async({page, server}) => {
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
|
Loading…
Reference in New Issue
Block a user