mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(chromium): roll chromium to r719491, lint, test (#99)
This commit is contained in:
parent
4d6d81e60e
commit
72b1bb783b
@ -7,7 +7,7 @@
|
|||||||
"node": ">=10.17.0"
|
"node": ">=10.17.0"
|
||||||
},
|
},
|
||||||
"playwright": {
|
"playwright": {
|
||||||
"chromium_revision": "718525",
|
"chromium_revision": "719491",
|
||||||
"firefox_revision": "1004",
|
"firefox_revision": "1004",
|
||||||
"webkit_revision": "1001"
|
"webkit_revision": "1001"
|
||||||
},
|
},
|
||||||
|
@ -151,7 +151,7 @@ export class ExecutionContext implements types.EvaluationContext<JSHandle> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId) {
|
async _adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId): Promise<ElementHandle> {
|
||||||
const {object} = await this._client.send('DOM.resolveNode', {
|
const {object} = await this._client.send('DOM.resolveNode', {
|
||||||
backendNodeId,
|
backendNodeId,
|
||||||
executionContextId: this._contextId,
|
executionContextId: this._contextId,
|
||||||
|
@ -25,7 +25,7 @@ import { LifecycleWatcher } from './LifecycleWatcher';
|
|||||||
import { NetworkManager, Response } from './NetworkManager';
|
import { NetworkManager, Response } from './NetworkManager';
|
||||||
import { Page } from './Page';
|
import { Page } from './Page';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { ElementHandle, createJSHandle } from './JSHandle';
|
import { ElementHandle } from './JSHandle';
|
||||||
|
|
||||||
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ type Point = {
|
|||||||
y: number;
|
y: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createJSHandle(context: ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject) {
|
export function createJSHandle(context: ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): JSHandle {
|
||||||
const frame = context.frame();
|
const frame = context.frame();
|
||||||
if (remoteObject.subtype === 'node' && frame) {
|
if (remoteObject.subtype === 'node' && frame) {
|
||||||
const frameManager = frame._delegate as FrameManager;
|
const frameManager = frame._delegate as FrameManager;
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as mime from 'mime';
|
import * as mime from 'mime';
|
||||||
import * as path from 'path';
|
|
||||||
import { assert, debugError, helper } from '../helper';
|
import { assert, debugError, helper } from '../helper';
|
||||||
import { ClickOptions, MultiClickOptions, PointerActionOptions, SelectOption, mediaTypes, mediaColorSchemes } from '../input';
|
import { ClickOptions, MultiClickOptions, PointerActionOptions, SelectOption, mediaTypes, mediaColorSchemes } from '../input';
|
||||||
import { TimeoutSettings } from '../TimeoutSettings';
|
import { TimeoutSettings } from '../TimeoutSettings';
|
||||||
@ -76,7 +75,6 @@ export class Page extends EventEmitter {
|
|||||||
_javascriptEnabled = true;
|
_javascriptEnabled = true;
|
||||||
private _viewport: Viewport | null = null;
|
private _viewport: Viewport | null = null;
|
||||||
private _screenshotTaskQueue: TaskQueue;
|
private _screenshotTaskQueue: TaskQueue;
|
||||||
private _fileChooserInterceptionIsDisabled = false;
|
|
||||||
private _fileChooserInterceptors = new Set<(chooser: FileChooser) => void>();
|
private _fileChooserInterceptors = new Set<(chooser: FileChooser) => void>();
|
||||||
private _disconnectPromise: Promise<Error> | undefined;
|
private _disconnectPromise: Promise<Error> | undefined;
|
||||||
private _emulatedMediaType: string | undefined;
|
private _emulatedMediaType: string | undefined;
|
||||||
@ -135,7 +133,7 @@ export class Page extends EventEmitter {
|
|||||||
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
|
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
|
||||||
client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
|
client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
|
||||||
client.on('Log.entryAdded', event => this._onLogEntryAdded(event));
|
client.on('Log.entryAdded', event => this._onLogEntryAdded(event));
|
||||||
client.on('Page.fileChooserOpened', event => this._onFileChooser(event));
|
client.on('Page.fileChooserOpened', event => this._onFileChooserOpened(event));
|
||||||
this._target._isClosedPromise.then(() => {
|
this._target._isClosedPromise.then(() => {
|
||||||
this.emit(Events.Page.Close);
|
this.emit(Events.Page.Close);
|
||||||
this._closed = true;
|
this._closed = true;
|
||||||
@ -148,27 +146,25 @@ export class Page extends EventEmitter {
|
|||||||
this._client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
|
this._client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
|
||||||
this._client.send('Performance.enable', {}),
|
this._client.send('Performance.enable', {}),
|
||||||
this._client.send('Log.enable', {}),
|
this._client.send('Log.enable', {}),
|
||||||
this._client.send('Page.setInterceptFileChooserDialog', {enabled: true}).catch(e => {
|
this._client.send('Page.setInterceptFileChooserDialog', {enabled: true})
|
||||||
this._fileChooserInterceptionIsDisabled = true;
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onFileChooser(event: Protocol.Page.fileChooserOpenedPayload) {
|
async _onFileChooserOpened(event: Protocol.Page.fileChooserOpenedPayload) {
|
||||||
if (!this._fileChooserInterceptors.size) {
|
if (!this._fileChooserInterceptors.size)
|
||||||
this._client.send('Page.handleFileChooser', { action: 'fallback' }).catch(debugError);
|
|
||||||
return;
|
return;
|
||||||
}
|
const frame = this._frameManager.frame(event.frameId);
|
||||||
|
const context = await frame._utilityContext();
|
||||||
|
const handle = await context._adoptBackendNodeId(event.backendNodeId);
|
||||||
const interceptors = Array.from(this._fileChooserInterceptors);
|
const interceptors = Array.from(this._fileChooserInterceptors);
|
||||||
this._fileChooserInterceptors.clear();
|
this._fileChooserInterceptors.clear();
|
||||||
const fileChooser = new FileChooser(this._client, event);
|
const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple);
|
||||||
|
const fileChooser = new FileChooser(handle, multiple);
|
||||||
for (const interceptor of interceptors)
|
for (const interceptor of interceptors)
|
||||||
interceptor.call(null, fileChooser);
|
interceptor.call(null, fileChooser);
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForFileChooser(options: { timeout?: number; } = {}): Promise<FileChooser> {
|
async waitForFileChooser(options: { timeout?: number; } = {}): Promise<FileChooser> {
|
||||||
if (this._fileChooserInterceptionIsDisabled)
|
|
||||||
throw new Error('File chooser handling does not work with multiple connections to the same page');
|
|
||||||
const {
|
const {
|
||||||
timeout = this._timeoutSettings.timeout(),
|
timeout = this._timeoutSettings.timeout(),
|
||||||
} = options;
|
} = options;
|
||||||
@ -732,13 +728,13 @@ export class ConsoleMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class FileChooser {
|
export class FileChooser {
|
||||||
private _client: CDPSession;
|
private _element: ElementHandle;
|
||||||
private _multiple: boolean;
|
private _multiple: boolean;
|
||||||
private _handled = false;
|
private _handled = false;
|
||||||
|
|
||||||
constructor(client: CDPSession, event: Protocol.Page.fileChooserOpenedPayload) {
|
constructor(element: ElementHandle, multiple: boolean) {
|
||||||
this._client = client;
|
this._element = element;
|
||||||
this._multiple = event.mode !== 'selectSingle';
|
this._multiple = multiple;
|
||||||
}
|
}
|
||||||
|
|
||||||
isMultiple(): boolean {
|
isMultiple(): boolean {
|
||||||
@ -748,18 +744,11 @@ export class FileChooser {
|
|||||||
async accept(filePaths: string[]): Promise<any> {
|
async accept(filePaths: string[]): Promise<any> {
|
||||||
assert(!this._handled, 'Cannot accept FileChooser which is already handled!');
|
assert(!this._handled, 'Cannot accept FileChooser which is already handled!');
|
||||||
this._handled = true;
|
this._handled = true;
|
||||||
const files = filePaths.map(filePath => path.resolve(filePath));
|
await this._element.setInputFiles(...filePaths);
|
||||||
await this._client.send('Page.handleFileChooser', {
|
|
||||||
action: 'accept',
|
|
||||||
files,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async cancel(): Promise<any> {
|
async cancel(): Promise<any> {
|
||||||
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!');
|
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!');
|
||||||
this._handled = true;
|
this._handled = true;
|
||||||
await this._client.send('Page.handleFileChooser', {
|
|
||||||
action: 'cancel',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,11 +304,10 @@ export class BrowserContext extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setCookies(cookies: SetNetworkCookieParam[]) {
|
async setCookies(cookies: SetNetworkCookieParam[]) {
|
||||||
const items = cookies.map(cookie => {
|
cookies.forEach(cookie => {
|
||||||
const item = Object.assign({}, cookie);
|
const item = Object.assign({}, cookie);
|
||||||
assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
|
assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
|
||||||
assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
|
assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
|
||||||
return item;
|
|
||||||
});
|
});
|
||||||
await this._connection.send('Browser.setCookies', {
|
await this._connection.send('Browser.setCookies', {
|
||||||
browserContextId: this._browserContextId || undefined,
|
browserContextId: this._browserContextId || undefined,
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { assert, debugError, helper } from '../helper';
|
import { assert, debugError, helper } from '../helper';
|
||||||
import Injected from '../injected/injected';
|
import Injected from '../injected/injected';
|
||||||
import * as input from '../input';
|
import * as input from '../input';
|
||||||
@ -25,7 +24,6 @@ import { ExecutionContext } from './ExecutionContext';
|
|||||||
import { Frame } from './FrameManager';
|
import { Frame } from './FrameManager';
|
||||||
|
|
||||||
type SelectorRoot = Element | ShadowRoot | Document;
|
type SelectorRoot = Element | ShadowRoot | Document;
|
||||||
const readFileAsync = helper.promisify(fs.readFile);
|
|
||||||
|
|
||||||
export class JSHandle {
|
export class JSHandle {
|
||||||
_context: ExecutionContext;
|
_context: ExecutionContext;
|
||||||
|
@ -5,7 +5,7 @@ import { TimeoutError } from '../Errors';
|
|||||||
import { assert, debugError, helper, RegisteredListener } from '../helper';
|
import { assert, debugError, helper, RegisteredListener } from '../helper';
|
||||||
import { TimeoutSettings } from '../TimeoutSettings';
|
import { TimeoutSettings } from '../TimeoutSettings';
|
||||||
import { BrowserContext, Target } from './Browser';
|
import { BrowserContext, Target } from './Browser';
|
||||||
import { Connection, JugglerSession, JugglerSessionEvents } from './Connection';
|
import { JugglerSession, JugglerSessionEvents } from './Connection';
|
||||||
import { Dialog } from './Dialog';
|
import { Dialog } from './Dialog';
|
||||||
import { Events } from './events';
|
import { Events } from './events';
|
||||||
import { Accessibility } from './features/accessibility';
|
import { Accessibility } from './features/accessibility';
|
||||||
@ -35,7 +35,6 @@ export class Page extends EventEmitter {
|
|||||||
private _eventListeners: RegisteredListener[];
|
private _eventListeners: RegisteredListener[];
|
||||||
private _viewport: Viewport;
|
private _viewport: Viewport;
|
||||||
private _disconnectPromise: Promise<Error>;
|
private _disconnectPromise: Promise<Error>;
|
||||||
private _fileChooserInterceptionIsDisabled = false;
|
|
||||||
private _fileChooserInterceptors = new Set<(chooser: FileChooser) => void>();
|
private _fileChooserInterceptors = new Set<(chooser: FileChooser) => void>();
|
||||||
|
|
||||||
static async create(session: JugglerSession, target: Target, defaultViewport: Viewport | null) {
|
static async create(session: JugglerSession, target: Target, defaultViewport: Viewport | null) {
|
||||||
@ -44,9 +43,7 @@ export class Page extends EventEmitter {
|
|||||||
session.send('Runtime.enable'),
|
session.send('Runtime.enable'),
|
||||||
session.send('Network.enable'),
|
session.send('Network.enable'),
|
||||||
session.send('Page.enable'),
|
session.send('Page.enable'),
|
||||||
session.send('Page.setInterceptFileChooserDialog', { enabled: true }).catch(e => {
|
session.send('Page.setInterceptFileChooserDialog', { enabled: true })
|
||||||
page._fileChooserInterceptionIsDisabled = true;
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (defaultViewport)
|
if (defaultViewport)
|
||||||
@ -534,8 +531,6 @@ export class Page extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async waitForFileChooser(options: { timeout?: number; } = {}): Promise<FileChooser> {
|
async waitForFileChooser(options: { timeout?: number; } = {}): Promise<FileChooser> {
|
||||||
if (this._fileChooserInterceptionIsDisabled)
|
|
||||||
throw new Error('File chooser handling does not work with multiple connections to the same page');
|
|
||||||
const {
|
const {
|
||||||
timeout = this._timeoutSettings.timeout(),
|
timeout = this._timeoutSettings.timeout(),
|
||||||
} = options;
|
} = options;
|
||||||
@ -549,11 +544,9 @@ export class Page extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _onFileChooserOpened({executionContextId, element}) {
|
async _onFileChooserOpened({executionContextId, element}) {
|
||||||
const context = this._frameManager.executionContextById(executionContextId);
|
if (!this._fileChooserInterceptors.size)
|
||||||
if (!this._fileChooserInterceptors.size) {
|
|
||||||
this._session.send('Page.handleFileChooser', { action: 'fallback' }).catch(debugError);
|
|
||||||
return;
|
return;
|
||||||
}
|
const context = this._frameManager.executionContextById(executionContextId);
|
||||||
const handle = createHandle(context, element) as ElementHandle;
|
const handle = createHandle(context, element) as ElementHandle;
|
||||||
const interceptors = Array.from(this._fileChooserInterceptors);
|
const interceptors = Array.from(this._fileChooserInterceptors);
|
||||||
this._fileChooserInterceptors.clear();
|
this._fileChooserInterceptors.clear();
|
||||||
|
@ -360,7 +360,7 @@ export const loadFiles = async (items: (string|FilePayload)[]): Promise<FilePayl
|
|||||||
return item as FilePayload;
|
return item as FilePayload;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
};
|
||||||
|
|
||||||
export const setFileInputFunction = async (element: HTMLInputElement, payloads: FilePayload[]) => {
|
export const setFileInputFunction = async (element: HTMLInputElement, payloads: FilePayload[]) => {
|
||||||
const files = await Promise.all(payloads.map(async (file: FilePayload) => {
|
const files = await Promise.all(payloads.map(async (file: FilePayload) => {
|
||||||
|
@ -93,23 +93,6 @@ module.exports.addLauncherTests = function({testRunner, expect, defaultBrowserOp
|
|||||||
await disconnectedEventPromise;
|
await disconnectedEventPromise;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page.waitForFileChooser', () => {
|
|
||||||
it('should fail gracefully when trying to work with filechoosers within multiple connections', async() => {
|
|
||||||
// 1. Launch a browser and connect to all pages.
|
|
||||||
const originalBrowser = await playwright.launch(defaultBrowserOptions);
|
|
||||||
await originalBrowser.pages();
|
|
||||||
// 2. Connect a remote browser and connect to first page.
|
|
||||||
const remoteBrowser = await playwright.connect({browserWSEndpoint: originalBrowser.chromium.wsEndpoint()});
|
|
||||||
const [page] = await remoteBrowser.pages();
|
|
||||||
// 3. Make sure |page.waitForFileChooser()| does not work with multiclient.
|
|
||||||
let error = null;
|
|
||||||
await page.waitForFileChooser().catch(e => error = e);
|
|
||||||
expect(error.message).toBe('File chooser handling does not work with multiple connections to the same page');
|
|
||||||
originalBrowser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user