chore: remove apiName plumbing and some unused methods from server side (#3481)
We append apiName where needed on the client instead.
This commit is contained in:
parent
244c2f37b6
commit
bc23324878
|
|
@ -86,7 +86,7 @@ export abstract class BrowserContextBase extends EventEmitter implements Browser
|
||||||
|
|
||||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||||
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
||||||
const progressController = new ProgressController(this._apiLogger, this._timeoutSettings.timeout(options), 'browserContext.waitForEvent');
|
const progressController = new ProgressController(this._apiLogger, this._timeoutSettings.timeout(options));
|
||||||
if (event !== Events.BrowserContext.Close)
|
if (event !== Events.BrowserContext.Close)
|
||||||
this._closePromise.then(error => progressController.abort(error));
|
this._closePromise.then(error => progressController.abort(error));
|
||||||
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate).promise);
|
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate).promise);
|
||||||
|
|
@ -191,9 +191,9 @@ export abstract class BrowserContextBase extends EventEmitter implements Browser
|
||||||
if (!this.pages().length)
|
if (!this.pages().length)
|
||||||
await this.waitForEvent('page');
|
await this.waitForEvent('page');
|
||||||
const pages = this.pages();
|
const pages = this.pages();
|
||||||
await pages[0].waitForLoadState();
|
await pages[0].mainFrame().waitForLoadState();
|
||||||
if (pages.length !== 1 || pages[0].url() !== 'about:blank')
|
if (pages.length !== 1 || pages[0].mainFrame().url() !== 'about:blank')
|
||||||
throw new Error(`Arguments can not specify page to be opened (first url is ${pages[0].url()})`);
|
throw new Error(`Arguments can not specify page to be opened (first url is ${pages[0].mainFrame().url()})`);
|
||||||
if (this._options.isMobile || this._options.locale) {
|
if (this._options.isMobile || this._options.locale) {
|
||||||
// Workaround for:
|
// Workaround for:
|
||||||
// - chromium fails to change isMobile for existing page;
|
// - chromium fails to change isMobile for existing page;
|
||||||
|
|
|
||||||
30
src/dom.ts
30
src/dom.ts
|
|
@ -223,7 +223,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
async scrollIntoViewIfNeeded(options: types.TimeoutOptions = {}) {
|
async scrollIntoViewIfNeeded(options: types.TimeoutOptions = {}) {
|
||||||
return this._page._runAbortableTask(
|
return this._page._runAbortableTask(
|
||||||
progress => this._waitAndScrollIntoViewIfNeeded(progress),
|
progress => this._waitAndScrollIntoViewIfNeeded(progress),
|
||||||
this._page._timeoutSettings.timeout(options), 'elementHandle.scrollIntoViewIfNeeded');
|
this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _waitForVisible(progress: Progress): Promise<'error:notconnected' | 'done'> {
|
private async _waitForVisible(progress: Progress): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -376,7 +376,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._hover(progress, options);
|
const result = await this._hover(progress, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.hover');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_hover(progress: Progress, options: types.PointerActionOptions & types.PointerActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
_hover(progress: Progress, options: types.PointerActionOptions & types.PointerActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -387,7 +387,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._click(progress, options);
|
const result = await this._click(progress, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.click');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_click(progress: Progress, options: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
_click(progress: Progress, options: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -398,7 +398,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._dblclick(progress, options);
|
const result = await this._dblclick(progress, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.dblclick');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dblclick(progress: Progress, options: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
_dblclick(progress: Progress, options: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -409,7 +409,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._selectOption(progress, values, options);
|
const result = await this._selectOption(progress, values, options);
|
||||||
return throwRetargetableDOMError(result);
|
return throwRetargetableDOMError(result);
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.selectOption');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _selectOption(progress: Progress, values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions): Promise<string[] | 'error:notconnected'> {
|
async _selectOption(progress: Progress, values: string | ElementHandle | types.SelectOption | string[] | ElementHandle[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions): Promise<string[] | 'error:notconnected'> {
|
||||||
|
|
@ -444,7 +444,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._fill(progress, value, options);
|
const result = await this._fill(progress, value, options);
|
||||||
assertDone(throwRetargetableDOMError(result));
|
assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.fill');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fill(progress: Progress, value: string, options: types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
async _fill(progress: Progress, value: string, options: types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -483,14 +483,14 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
const pollHandler = new InjectedScriptPollHandler(progress, poll);
|
||||||
const result = throwFatalDOMError(await pollHandler.finish());
|
const result = throwFatalDOMError(await pollHandler.finish());
|
||||||
assertDone(throwRetargetableDOMError(result));
|
assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.selectText');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setInputFiles(files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}) {
|
async setInputFiles(files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}) {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._setInputFiles(progress, files, options);
|
const result = await this._setInputFiles(progress, files, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.setInputFiles');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _setInputFiles(progress: Progress, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
async _setInputFiles(progress: Progress, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -517,7 +517,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._focus(progress);
|
const result = await this._focus(progress);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, 0, 'elementHandle.focus');
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _focus(progress: Progress, resetSelectionIfNotFocused?: boolean): Promise<'error:notconnected' | 'done'> {
|
async _focus(progress: Progress, resetSelectionIfNotFocused?: boolean): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -530,7 +530,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._type(progress, text, options);
|
const result = await this._type(progress, text, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.type');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _type(progress: Progress, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
async _type(progress: Progress, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -549,7 +549,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._press(progress, key, options);
|
const result = await this._press(progress, key, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.press');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _press(progress: Progress, key: string, options: { delay?: number } & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
async _press(progress: Progress, key: string, options: { delay?: number } & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -568,14 +568,14 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._setChecked(progress, true, options);
|
const result = await this._setChecked(progress, true, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.check');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async uncheck(options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
async uncheck(options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
const result = await this._setChecked(progress, false, options);
|
const result = await this._setChecked(progress, false, options);
|
||||||
return assertDone(throwRetargetableDOMError(result));
|
return assertDone(throwRetargetableDOMError(result));
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.uncheck');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _setChecked(progress: Progress, state: boolean, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
async _setChecked(progress: Progress, state: boolean, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
|
|
@ -596,7 +596,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
async screenshot(options: types.ElementScreenshotOptions = {}): Promise<Buffer> {
|
async screenshot(options: types.ElementScreenshotOptions = {}): Promise<Buffer> {
|
||||||
return this._page._runAbortableTask(
|
return this._page._runAbortableTask(
|
||||||
progress => this._page._screenshotter.screenshotElement(progress, this, options),
|
progress => this._page._screenshotter.screenshotElement(progress, this, options),
|
||||||
this._page._timeoutSettings.timeout(options), 'elementHandle.screenshot');
|
this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $(selector: string): Promise<ElementHandle | null> {
|
async $(selector: string): Promise<ElementHandle | null> {
|
||||||
|
|
@ -655,7 +655,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
}
|
}
|
||||||
const handle = result.asElement() as ElementHandle<Element>;
|
const handle = result.asElement() as ElementHandle<Element>;
|
||||||
return handle._adoptTo(await this._context.frame._mainContext());
|
return handle._adoptTo(await this._context.frame._mainContext());
|
||||||
}, this._page._timeoutSettings.timeout(options), 'elementHandle.waitForSelector');
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _adoptTo(context: FrameExecutionContext): Promise<ElementHandle<T>> {
|
async _adoptTo(context: FrameExecutionContext): Promise<ElementHandle<T>> {
|
||||||
|
|
|
||||||
|
|
@ -378,11 +378,6 @@ export class Frame {
|
||||||
return this._page;
|
return this._page;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _apiName(method: string) {
|
|
||||||
const subject = this._page._callingPageAPI ? 'page' : 'frame';
|
|
||||||
return `${subject}.${method}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
_onLifecycleEvent(event: types.LifecycleEvent) {
|
_onLifecycleEvent(event: types.LifecycleEvent) {
|
||||||
if (this._firedLifecycleEvents.has(event))
|
if (this._firedLifecycleEvents.has(event))
|
||||||
return;
|
return;
|
||||||
|
|
@ -434,7 +429,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async goto(url: string, options: types.GotoOptions = {}): Promise<network.Response | null> {
|
async goto(url: string, options: types.GotoOptions = {}): Promise<network.Response | null> {
|
||||||
return runNavigationTask(this, options, this._apiName('goto'), async progress => {
|
return runNavigationTask(this, options, async progress => {
|
||||||
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||||
progress.logger.info(`navigating to "${url}", waiting until "${waitUntil}"`);
|
progress.logger.info(`navigating to "${url}", waiting until "${waitUntil}"`);
|
||||||
const headers = (this._page._state.extraHTTPHeaders || {});
|
const headers = (this._page._state.extraHTTPHeaders || {});
|
||||||
|
|
@ -478,7 +473,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForNavigation(options: types.WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
async waitForNavigation(options: types.WaitForNavigationOptions = {}): Promise<network.Response | null> {
|
||||||
return runNavigationTask(this, options, this._apiName('waitForNavigation'), async progress => {
|
return runNavigationTask(this, options, async progress => {
|
||||||
const toUrl = typeof options.url === 'string' ? ` to "${options.url}"` : '';
|
const toUrl = typeof options.url === 'string' ? ` to "${options.url}"` : '';
|
||||||
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||||
progress.logger.info(`waiting for navigation${toUrl} until "${waitUntil}"`);
|
progress.logger.info(`waiting for navigation${toUrl} until "${waitUntil}"`);
|
||||||
|
|
@ -502,7 +497,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForLoadState(state: types.LifecycleEvent = 'load', options: types.TimeoutOptions = {}): Promise<void> {
|
async waitForLoadState(state: types.LifecycleEvent = 'load', options: types.TimeoutOptions = {}): Promise<void> {
|
||||||
return runNavigationTask(this, options, this._apiName('waitForLoadState'), progress => this._waitForLoadState(progress, state));
|
return runNavigationTask(this, options, progress => this._waitForLoadState(progress, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _waitForLoadState(progress: Progress, state: types.LifecycleEvent): Promise<void> {
|
async _waitForLoadState(progress: Progress, state: types.LifecycleEvent): Promise<void> {
|
||||||
|
|
@ -578,7 +573,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
const handle = result.asElement() as dom.ElementHandle<Element>;
|
const handle = result.asElement() as dom.ElementHandle<Element>;
|
||||||
return handle._adoptTo(await this._mainContext());
|
return handle._adoptTo(await this._mainContext());
|
||||||
}, this._page._timeoutSettings.timeout(options), this._apiName('waitForSelector'));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async dispatchEvent(selector: string, type: string, eventInit?: Object, options: types.TimeoutOptions = {}): Promise<void> {
|
async dispatchEvent(selector: string, type: string, eventInit?: Object, options: types.TimeoutOptions = {}): Promise<void> {
|
||||||
|
|
@ -588,7 +583,7 @@ export class Frame {
|
||||||
progress.logger.info(`Dispatching "${type}" event on selector "${selector}"...`);
|
progress.logger.info(`Dispatching "${type}" event on selector "${selector}"...`);
|
||||||
// Note: we always dispatch events in the main world.
|
// Note: we always dispatch events in the main world.
|
||||||
await this._scheduleRerunnableTask(progress, 'main', task);
|
await this._scheduleRerunnableTask(progress, 'main', task);
|
||||||
}, this._page._timeoutSettings.timeout(options), this._apiName('dispatchEvent'));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async $eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
|
async $eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
|
||||||
|
|
@ -638,7 +633,7 @@ export class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
async setContent(html: string, options: types.NavigateOptions = {}): Promise<void> {
|
async setContent(html: string, options: types.NavigateOptions = {}): Promise<void> {
|
||||||
return runNavigationTask(this, options, this._apiName('setContent'), async progress => {
|
return runNavigationTask(this, options, async progress => {
|
||||||
const waitUntil = options.waitUntil === undefined ? 'load' : options.waitUntil;
|
const waitUntil = options.waitUntil === undefined ? 'load' : options.waitUntil;
|
||||||
progress.logger.info(`setting frame content, waiting until "${waitUntil}"`);
|
progress.logger.info(`setting frame content, waiting until "${waitUntil}"`);
|
||||||
const tag = `--playwright--set--content--${this._id}--${++this._setContentCounter}--`;
|
const tag = `--playwright--set--content--${this._id}--${++this._setContentCounter}--`;
|
||||||
|
|
@ -823,8 +818,7 @@ export class Frame {
|
||||||
|
|
||||||
private async _retryWithSelectorIfNotConnected<R>(
|
private async _retryWithSelectorIfNotConnected<R>(
|
||||||
selector: string, options: types.TimeoutOptions,
|
selector: string, options: types.TimeoutOptions,
|
||||||
action: (progress: Progress, handle: dom.ElementHandle<Element>) => Promise<R | 'error:notconnected'>,
|
action: (progress: Progress, handle: dom.ElementHandle<Element>) => Promise<R | 'error:notconnected'>): Promise<R> {
|
||||||
apiName: string): Promise<R> {
|
|
||||||
const info = selectors._parseSelector(selector);
|
const info = selectors._parseSelector(selector);
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
while (progress.isRunning()) {
|
while (progress.isRunning()) {
|
||||||
|
|
@ -846,23 +840,23 @@ export class Frame {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return undefined as any;
|
return undefined as any;
|
||||||
}, this._page._timeoutSettings.timeout(options), apiName);
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async click(selector: string, options: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
async click(selector: string, options: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._click(progress, options), this._apiName('click'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._click(progress, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async dblclick(selector: string, options: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
async dblclick(selector: string, options: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._dblclick(progress, options), this._apiName('dblclick'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._dblclick(progress, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async fill(selector: string, value: string, options: types.NavigatingActionWaitOptions = {}) {
|
async fill(selector: string, value: string, options: types.NavigatingActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._fill(progress, value, options), this._apiName('fill'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._fill(progress, value, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async focus(selector: string, options: types.TimeoutOptions = {}) {
|
async focus(selector: string, options: types.TimeoutOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._focus(progress), this._apiName('focus'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._focus(progress));
|
||||||
}
|
}
|
||||||
|
|
||||||
async textContent(selector: string, options: types.TimeoutOptions = {}): Promise<string | null> {
|
async textContent(selector: string, options: types.TimeoutOptions = {}): Promise<string | null> {
|
||||||
|
|
@ -871,7 +865,7 @@ export class Frame {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
progress.logger.info(` retrieving textContent from "${selector}"`);
|
progress.logger.info(` retrieving textContent from "${selector}"`);
|
||||||
return this._scheduleRerunnableTask(progress, info.world, task);
|
return this._scheduleRerunnableTask(progress, info.world, task);
|
||||||
}, this._page._timeoutSettings.timeout(options), this._apiName('textContent'));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async innerText(selector: string, options: types.TimeoutOptions = {}): Promise<string> {
|
async innerText(selector: string, options: types.TimeoutOptions = {}): Promise<string> {
|
||||||
|
|
@ -881,7 +875,7 @@ export class Frame {
|
||||||
progress.logger.info(` retrieving innerText from "${selector}"`);
|
progress.logger.info(` retrieving innerText from "${selector}"`);
|
||||||
const result = dom.throwFatalDOMError(await this._scheduleRerunnableTask(progress, info.world, task));
|
const result = dom.throwFatalDOMError(await this._scheduleRerunnableTask(progress, info.world, task));
|
||||||
return result.innerText;
|
return result.innerText;
|
||||||
}, this._page._timeoutSettings.timeout(options), this._apiName('innerText'));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async innerHTML(selector: string, options: types.TimeoutOptions = {}): Promise<string> {
|
async innerHTML(selector: string, options: types.TimeoutOptions = {}): Promise<string> {
|
||||||
|
|
@ -890,7 +884,7 @@ export class Frame {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
progress.logger.info(` retrieving innerHTML from "${selector}"`);
|
progress.logger.info(` retrieving innerHTML from "${selector}"`);
|
||||||
return this._scheduleRerunnableTask(progress, info.world, task);
|
return this._scheduleRerunnableTask(progress, info.world, task);
|
||||||
}, this._page._timeoutSettings.timeout(options), this._apiName('innerHTML'));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAttribute(selector: string, name: string, options: types.TimeoutOptions = {}): Promise<string | null> {
|
async getAttribute(selector: string, name: string, options: types.TimeoutOptions = {}): Promise<string | null> {
|
||||||
|
|
@ -899,35 +893,35 @@ export class Frame {
|
||||||
return this._page._runAbortableTask(async progress => {
|
return this._page._runAbortableTask(async progress => {
|
||||||
progress.logger.info(` retrieving attribute "${name}" from "${selector}"`);
|
progress.logger.info(` retrieving attribute "${name}" from "${selector}"`);
|
||||||
return this._scheduleRerunnableTask(progress, info.world, task);
|
return this._scheduleRerunnableTask(progress, info.world, task);
|
||||||
}, this._page._timeoutSettings.timeout(options), this._apiName('getAttribute'));
|
}, this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async hover(selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
|
async hover(selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._hover(progress, options), this._apiName('hover'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._hover(progress, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectOption(selector: string, values: string | dom.ElementHandle | types.SelectOption | string[] | dom.ElementHandle[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions = {}): Promise<string[]> {
|
async selectOption(selector: string, values: string | dom.ElementHandle | types.SelectOption | string[] | dom.ElementHandle[] | types.SelectOption[] | null, options: types.NavigatingActionWaitOptions = {}): Promise<string[]> {
|
||||||
return this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._selectOption(progress, values, options), this._apiName('selectOption'));
|
return this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._selectOption(progress, values, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setInputFiles(selector: string, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
async setInputFiles(selector: string, files: string | types.FilePayload | string[] | types.FilePayload[], options: types.NavigatingActionWaitOptions = {}): Promise<void> {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._setInputFiles(progress, files, options), this._apiName('setInputFiles'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._setInputFiles(progress, files, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async type(selector: string, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
async type(selector: string, text: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._type(progress, text, options), this._apiName('type'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._type(progress, text, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async press(selector: string, key: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
async press(selector: string, key: string, options: { delay?: number } & types.NavigatingActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._press(progress, key, options), this._apiName('press'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._press(progress, key, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async check(selector: string, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
async check(selector: string, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._setChecked(progress, true, options), this._apiName('check'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._setChecked(progress, true, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async uncheck(selector: string, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
async uncheck(selector: string, options: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions = {}) {
|
||||||
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._setChecked(progress, false, options), this._apiName('uncheck'));
|
await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._setChecked(progress, false, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForTimeout(timeout: number) {
|
async waitForTimeout(timeout: number) {
|
||||||
|
|
@ -957,7 +951,7 @@ export class Frame {
|
||||||
}, { predicateBody, polling, arg });
|
}, { predicateBody, polling, arg });
|
||||||
return this._page._runAbortableTask(
|
return this._page._runAbortableTask(
|
||||||
progress => this._scheduleRerunnableHandleTask(progress, 'main', task),
|
progress => this._scheduleRerunnableHandleTask(progress, 'main', task),
|
||||||
this._page._timeoutSettings.timeout(options), this._apiName('waitForFunction'));
|
this._page._timeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
async title(): Promise<string> {
|
async title(): Promise<string> {
|
||||||
|
|
@ -1134,9 +1128,9 @@ class SignalBarrier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runNavigationTask<T>(frame: Frame, options: types.TimeoutOptions, apiName: string, task: (progress: Progress) => Promise<T>): Promise<T> {
|
async function runNavigationTask<T>(frame: Frame, options: types.TimeoutOptions, task: (progress: Progress) => Promise<T>): Promise<T> {
|
||||||
const page = frame._page;
|
const page = frame._page;
|
||||||
const controller = new ProgressController(page._logger, page._timeoutSettings.navigationTimeout(options), apiName);
|
const controller = new ProgressController(page._logger, page._timeoutSettings.navigationTimeout(options));
|
||||||
page._disconnectedPromise.then(() => controller.abort(new Error('Navigation failed because page was closed!')));
|
page._disconnectedPromise.then(() => controller.abort(new Error('Navigation failed because page was closed!')));
|
||||||
page._crashedPromise.then(() => controller.abort(new Error('Navigation failed because page crashed!')));
|
page._crashedPromise.then(() => controller.abort(new Error('Navigation failed because page crashed!')));
|
||||||
frame._detachedPromise.then(() => controller.abort(new Error('Navigating frame was detached!')));
|
frame._detachedPromise.then(() => controller.abort(new Error('Navigating frame was detached!')));
|
||||||
|
|
|
||||||
190
src/page.ts
190
src/page.ts
|
|
@ -117,7 +117,6 @@ export class Page extends EventEmitter {
|
||||||
readonly coverage: any;
|
readonly coverage: any;
|
||||||
_routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
|
_routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
|
||||||
_ownedContext: BrowserContext | undefined;
|
_ownedContext: BrowserContext | undefined;
|
||||||
_callingPageAPI = false;
|
|
||||||
|
|
||||||
constructor(delegate: PageDelegate, browserContext: BrowserContextBase) {
|
constructor(delegate: PageDelegate, browserContext: BrowserContextBase) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -168,10 +167,10 @@ export class Page extends EventEmitter {
|
||||||
this._disconnectedCallback(new Error('Page closed'));
|
this._disconnectedCallback(new Error('Page closed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _runAbortableTask<T>(task: (progress: Progress) => Promise<T>, timeout: number, apiName: string): Promise<T> {
|
async _runAbortableTask<T>(task: (progress: Progress) => Promise<T>, timeout: number): Promise<T> {
|
||||||
return runAbortableTask(async progress => {
|
return runAbortableTask(async progress => {
|
||||||
return task(progress);
|
return task(progress);
|
||||||
}, this._logger, timeout, apiName);
|
}, this._logger, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
||||||
|
|
@ -219,63 +218,6 @@ export class Page extends EventEmitter {
|
||||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $(selector: string): Promise<dom.ElementHandle<Element> | null> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().$(selector));
|
|
||||||
}
|
|
||||||
|
|
||||||
async waitForSelector(selector: string, options?: types.WaitForElementOptions): Promise<dom.ElementHandle<Element> | null> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().waitForSelector(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async dispatchEvent(selector: string, type: string, eventInit?: Object, options?: types.TimeoutOptions): Promise<void> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().dispatchEvent(selector, type, eventInit, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async evaluateHandle<R, Arg>(pageFunction: js.Func1<Arg, R>, arg: Arg): Promise<js.SmartHandle<R>>;
|
|
||||||
async evaluateHandle<R>(pageFunction: js.Func1<void, R>, arg?: any): Promise<js.SmartHandle<R>>;
|
|
||||||
async evaluateHandle<R, Arg>(pageFunction: js.Func1<Arg, R>, arg: Arg): Promise<js.SmartHandle<R>> {
|
|
||||||
assertMaxArguments(arguments.length, 2);
|
|
||||||
return this._attributeToPage(() => this.mainFrame().evaluateHandle(pageFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _evaluateExpressionHandle(expression: string, isFunction: boolean, arg: any): Promise<any> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame()._evaluateExpressionHandle(expression, isFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async $eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
|
|
||||||
async $eval<R>(selector: string, pageFunction: js.FuncOn<Element, void, R>, arg?: any): Promise<R>;
|
|
||||||
async $eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
|
|
||||||
assertMaxArguments(arguments.length, 3);
|
|
||||||
return this._attributeToPage(() => this.mainFrame().$eval(selector, pageFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _$evalExpression(selector: string, expression: string, isFunction: boolean, arg: any): Promise<any> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame()._$evalExpression(selector, expression, isFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async $$eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
|
|
||||||
async $$eval<R>(selector: string, pageFunction: js.FuncOn<Element[], void, R>, arg?: any): Promise<R>;
|
|
||||||
async $$eval<R, Arg>(selector: string, pageFunction: js.FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
|
|
||||||
assertMaxArguments(arguments.length, 3);
|
|
||||||
return this._attributeToPage(() => this.mainFrame().$$eval(selector, pageFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _$$evalExpression(selector: string, expression: string, isFunction: boolean, arg: any): Promise<any> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame()._$$evalExpression(selector, expression, isFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async $$(selector: string): Promise<dom.ElementHandle<Element>[]> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().$$(selector));
|
|
||||||
}
|
|
||||||
|
|
||||||
async addScriptTag(options: { url?: string; path?: string; content?: string; type?: string; }): Promise<dom.ElementHandle> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().addScriptTag(options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async addStyleTag(options: { url?: string; path?: string; content?: string; }): Promise<dom.ElementHandle> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().addStyleTag(options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async exposeFunction(name: string, playwrightFunction: Function) {
|
async exposeFunction(name: string, playwrightFunction: Function) {
|
||||||
await this.exposeBinding(name, (options, ...args: any) => playwrightFunction(...args));
|
await this.exposeBinding(name, (options, ...args: any) => playwrightFunction(...args));
|
||||||
}
|
}
|
||||||
|
|
@ -310,36 +252,12 @@ export class Page extends EventEmitter {
|
||||||
this.emit(Events.Page.Console, message);
|
this.emit(Events.Page.Console, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
url(): string {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().url());
|
|
||||||
}
|
|
||||||
|
|
||||||
async content(): Promise<string> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().content());
|
|
||||||
}
|
|
||||||
|
|
||||||
async setContent(html: string, options?: types.NavigateOptions): Promise<void> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().setContent(html, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async goto(url: string, options?: types.GotoOptions): Promise<network.Response | null> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().goto(url, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async reload(options?: types.NavigateOptions): Promise<network.Response | null> {
|
async reload(options?: types.NavigateOptions): Promise<network.Response | null> {
|
||||||
const waitPromise = this.waitForNavigation(options);
|
const waitPromise = this.mainFrame().waitForNavigation(options);
|
||||||
await this._delegate.reload();
|
await this._delegate.reload();
|
||||||
return waitPromise;
|
return waitPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForLoadState(state?: types.LifecycleEvent, options?: types.TimeoutOptions): Promise<void> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().waitForLoadState(state, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async waitForNavigation(options?: types.WaitForNavigationOptions): Promise<network.Response | null> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().waitForNavigation(options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async waitForRequest(urlOrPredicate: string | RegExp | ((r: network.Request) => boolean), options: types.TimeoutOptions = {}): Promise<network.Request> {
|
async waitForRequest(urlOrPredicate: string | RegExp | ((r: network.Request) => boolean), options: types.TimeoutOptions = {}): Promise<network.Request> {
|
||||||
const predicate = (request: network.Request) => {
|
const predicate = (request: network.Request) => {
|
||||||
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
|
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
|
||||||
|
|
@ -360,7 +278,7 @@ export class Page extends EventEmitter {
|
||||||
|
|
||||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||||
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
||||||
const progressController = new ProgressController(this._logger, this._timeoutSettings.timeout(options), 'page.waitForEvent');
|
const progressController = new ProgressController(this._logger, this._timeoutSettings.timeout(options));
|
||||||
this._disconnectedPromise.then(error => progressController.abort(error));
|
this._disconnectedPromise.then(error => progressController.abort(error));
|
||||||
if (event !== Events.Page.Crash)
|
if (event !== Events.Page.Crash)
|
||||||
this._crashedPromise.then(error => progressController.abort(error));
|
this._crashedPromise.then(error => progressController.abort(error));
|
||||||
|
|
@ -368,7 +286,7 @@ export class Page extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
async goBack(options?: types.NavigateOptions): Promise<network.Response | null> {
|
async goBack(options?: types.NavigateOptions): Promise<network.Response | null> {
|
||||||
const waitPromise = this.waitForNavigation(options);
|
const waitPromise = this.mainFrame().waitForNavigation(options);
|
||||||
const result = await this._delegate.goBack();
|
const result = await this._delegate.goBack();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
waitPromise.catch(() => {});
|
waitPromise.catch(() => {});
|
||||||
|
|
@ -378,7 +296,7 @@ export class Page extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
async goForward(options?: types.NavigateOptions): Promise<network.Response | null> {
|
async goForward(options?: types.NavigateOptions): Promise<network.Response | null> {
|
||||||
const waitPromise = this.waitForNavigation(options);
|
const waitPromise = this.mainFrame().waitForNavigation(options);
|
||||||
const result = await this._delegate.goForward();
|
const result = await this._delegate.goForward();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
waitPromise.catch(() => {});
|
waitPromise.catch(() => {});
|
||||||
|
|
@ -412,17 +330,6 @@ export class Page extends EventEmitter {
|
||||||
await this._delegate.bringToFront();
|
await this._delegate.bringToFront();
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluate<R, Arg>(pageFunction: js.Func1<Arg, R>, arg: Arg): Promise<R>;
|
|
||||||
async evaluate<R>(pageFunction: js.Func1<void, R>, arg?: any): Promise<R>;
|
|
||||||
async evaluate<R, Arg>(pageFunction: js.Func1<Arg, R>, arg: Arg): Promise<R> {
|
|
||||||
assertMaxArguments(arguments.length, 2);
|
|
||||||
return this._attributeToPage(() => this.mainFrame().evaluate(pageFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _evaluateExpression(expression: string, isFunction: boolean, arg: any): Promise<any> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame()._evaluateExpression(expression, isFunction, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
|
async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
|
||||||
const source = await helper.evaluationScript(script, arg);
|
const source = await helper.evaluationScript(script, arg);
|
||||||
await this._addInitScriptExpression(source);
|
await this._addInitScriptExpression(source);
|
||||||
|
|
@ -482,11 +389,7 @@ export class Page extends EventEmitter {
|
||||||
async screenshot(options: types.ScreenshotOptions = {}): Promise<Buffer> {
|
async screenshot(options: types.ScreenshotOptions = {}): Promise<Buffer> {
|
||||||
return this._runAbortableTask(
|
return this._runAbortableTask(
|
||||||
progress => this._screenshotter.screenshotPage(progress, options),
|
progress => this._screenshotter.screenshotPage(progress, options),
|
||||||
this._timeoutSettings.timeout(options), 'page.screenshot');
|
this._timeoutSettings.timeout(options));
|
||||||
}
|
|
||||||
|
|
||||||
async title(): Promise<string> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().title());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(options?: { runBeforeUnload?: boolean }) {
|
async close(options?: { runBeforeUnload?: boolean }) {
|
||||||
|
|
@ -513,89 +416,10 @@ export class Page extends EventEmitter {
|
||||||
return this._closedState === 'closed';
|
return this._closedState === 'closed';
|
||||||
}
|
}
|
||||||
|
|
||||||
private _attributeToPage<T>(func: () => T): T {
|
|
||||||
try {
|
|
||||||
this._callingPageAPI = true;
|
|
||||||
return func();
|
|
||||||
} finally {
|
|
||||||
this._callingPageAPI = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async click(selector: string, options?: types.MouseClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().click(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async dblclick(selector: string, options?: types.MouseMultiClickOptions & types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().dblclick(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fill(selector: string, value: string, options?: types.NavigatingActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().fill(selector, value, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async focus(selector: string, options?: types.TimeoutOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().focus(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async textContent(selector: string, options?: types.TimeoutOptions): Promise<null|string> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().textContent(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async innerText(selector: string, options?: types.TimeoutOptions): Promise<string> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().innerText(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async innerHTML(selector: string, options?: types.TimeoutOptions): Promise<string> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().innerHTML(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAttribute(selector: string, name: string, options?: types.TimeoutOptions): Promise<string | null> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().getAttribute(selector, name, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async hover(selector: string, options?: types.PointerActionOptions & types.PointerActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().hover(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async selectOption(selector: string, values: string | dom.ElementHandle | types.SelectOption | string[] | dom.ElementHandle[] | types.SelectOption[] | null, options?: types.NavigatingActionWaitOptions): Promise<string[]> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().selectOption(selector, values, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async setInputFiles(selector: string, files: string | types.FilePayload | string[] | types.FilePayload[], options?: types.NavigatingActionWaitOptions): Promise<void> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().setInputFiles(selector, files, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async type(selector: string, text: string, options?: { delay?: number } & types.NavigatingActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().type(selector, text, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async press(selector: string, key: string, options?: { delay?: number } & types.NavigatingActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().press(selector, key, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async check(selector: string, options?: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().check(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async uncheck(selector: string, options?: types.PointerActionWaitOptions & types.NavigatingActionWaitOptions) {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().uncheck(selector, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async waitForTimeout(timeout: number) {
|
async waitForTimeout(timeout: number) {
|
||||||
await this.mainFrame().waitForTimeout(timeout);
|
await this.mainFrame().waitForTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForFunction<R, Arg>(pageFunction: js.Func1<Arg, R>, arg: Arg, options?: types.WaitForFunctionOptions): Promise<js.SmartHandle<R>>;
|
|
||||||
async waitForFunction<R>(pageFunction: js.Func1<void, R>, arg?: any, options?: types.WaitForFunctionOptions): Promise<js.SmartHandle<R>>;
|
|
||||||
async waitForFunction<R, Arg>(pageFunction: js.Func1<Arg, R>, arg: Arg, options?: types.WaitForFunctionOptions): Promise<js.SmartHandle<R>> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame().waitForFunction(pageFunction, arg, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _waitForFunctionExpression<R>(expression: string, isFunction: boolean, arg: any, options: types.WaitForFunctionOptions = {}): Promise<js.SmartHandle<R>> {
|
|
||||||
return this._attributeToPage(() => this.mainFrame()._waitForFunctionExpression(expression, isFunction, arg, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
workers(): Worker[] {
|
workers(): Worker[] {
|
||||||
return [...this._workers.values()];
|
return [...this._workers.values()];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,11 @@ export interface Progress {
|
||||||
throwIfAborted(): void;
|
throwIfAborted(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runAbortableTask<T>(task: (progress: Progress) => Promise<T>, logger: Logger, timeout: number, apiName: string): Promise<T> {
|
export async function runAbortableTask<T>(task: (progress: Progress) => Promise<T>, logger: Logger, timeout: number): Promise<T> {
|
||||||
const controller = new ProgressController(logger, timeout, apiName);
|
const controller = new ProgressController(logger, timeout);
|
||||||
return controller.run(task);
|
return controller.run(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
let useApiName = true;
|
|
||||||
export function setUseApiName(value: boolean) {
|
|
||||||
useApiName = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ProgressController {
|
export class ProgressController {
|
||||||
// Promise and callback that forcefully abort the progress.
|
// Promise and callback that forcefully abort the progress.
|
||||||
// This promise always rejects.
|
// This promise always rejects.
|
||||||
|
|
@ -54,12 +49,10 @@ export class ProgressController {
|
||||||
|
|
||||||
private _logger: Logger;
|
private _logger: Logger;
|
||||||
private _state: 'before' | 'running' | 'aborted' | 'finished' = 'before';
|
private _state: 'before' | 'running' | 'aborted' | 'finished' = 'before';
|
||||||
private _apiName: string;
|
|
||||||
private _deadline: number;
|
private _deadline: number;
|
||||||
private _timeout: number;
|
private _timeout: number;
|
||||||
|
|
||||||
constructor(logger: Logger, timeout: number, apiName: string) {
|
constructor(logger: Logger, timeout: number) {
|
||||||
this._apiName = apiName;
|
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
|
|
||||||
this._timeout = timeout;
|
this._timeout = timeout;
|
||||||
|
|
@ -74,7 +67,7 @@ export class ProgressController {
|
||||||
assert(this._state === 'before');
|
assert(this._state === 'before');
|
||||||
this._state = 'running';
|
this._state = 'running';
|
||||||
|
|
||||||
const loggerScope = this._logger.createScope(useApiName ? this._apiName : undefined, true);
|
const loggerScope = this._logger.createScope(undefined, true);
|
||||||
|
|
||||||
const progress: Progress = {
|
const progress: Progress = {
|
||||||
aborted: this._abortedPromise,
|
aborted: this._abortedPromise,
|
||||||
|
|
@ -105,7 +98,6 @@ export class ProgressController {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._aborted();
|
this._aborted();
|
||||||
rewriteErrorMessage(e,
|
rewriteErrorMessage(e,
|
||||||
(useApiName ? `${this._apiName}: ` : '') +
|
|
||||||
e.message +
|
e.message +
|
||||||
formatLogRecording(loggerScope.recording()) +
|
formatLogRecording(loggerScope.recording()) +
|
||||||
kLoggingNote);
|
kLoggingNote);
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,11 @@ import { DispatcherConnection } from './server/dispatcher';
|
||||||
import type { Playwright as PlaywrightImpl } from '../server/playwright';
|
import type { Playwright as PlaywrightImpl } from '../server/playwright';
|
||||||
import type { Playwright as PlaywrightAPI } from './client/playwright';
|
import type { Playwright as PlaywrightAPI } from './client/playwright';
|
||||||
import { PlaywrightDispatcher } from './server/playwrightDispatcher';
|
import { PlaywrightDispatcher } from './server/playwrightDispatcher';
|
||||||
import { setUseApiName } from '../progress';
|
|
||||||
import { Connection } from './client/connection';
|
import { Connection } from './client/connection';
|
||||||
import { isUnderTest } from '../helper';
|
import { isUnderTest } from '../helper';
|
||||||
import { BrowserServerLauncherImpl } from './browserServerImpl';
|
import { BrowserServerLauncherImpl } from './browserServerImpl';
|
||||||
|
|
||||||
export function setupInProcess(playwright: PlaywrightImpl): PlaywrightAPI {
|
export function setupInProcess(playwright: PlaywrightImpl): PlaywrightAPI {
|
||||||
setUseApiName(false);
|
|
||||||
|
|
||||||
const clientConnection = new Connection();
|
const clientConnection = new Connection();
|
||||||
const dispatcherConnection = new DispatcherConnection();
|
const dispatcherConnection = new DispatcherConnection();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,8 @@ import { DispatcherConnection } from './server/dispatcher';
|
||||||
import { Playwright } from '../server/playwright';
|
import { Playwright } from '../server/playwright';
|
||||||
import { PlaywrightDispatcher } from './server/playwrightDispatcher';
|
import { PlaywrightDispatcher } from './server/playwrightDispatcher';
|
||||||
import { Electron } from '../server/electron';
|
import { Electron } from '../server/electron';
|
||||||
import { setUseApiName } from '../progress';
|
|
||||||
import { gracefullyCloseAll } from '../server/processLauncher';
|
import { gracefullyCloseAll } from '../server/processLauncher';
|
||||||
|
|
||||||
setUseApiName(false);
|
|
||||||
|
|
||||||
const dispatcherConnection = new DispatcherConnection();
|
const dispatcherConnection = new DispatcherConnection();
|
||||||
const transport = new Transport(process.stdout, process.stdin);
|
const transport = new Transport(process.stdout, process.stdin);
|
||||||
transport.onclose = async () => {
|
transport.onclose = async () => {
|
||||||
|
|
|
||||||
|
|
@ -149,10 +149,6 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
||||||
this._page.removeListener(Events.Page.FileChooser, this._onFileChooser);
|
this._page.removeListener(Events.Page.FileChooser, this._onFileChooser);
|
||||||
}
|
}
|
||||||
|
|
||||||
async title() {
|
|
||||||
return await this._page.title();
|
|
||||||
}
|
|
||||||
|
|
||||||
async keyboardDown(params: { key: string }): Promise<void> {
|
async keyboardDown(params: { key: string }): Promise<void> {
|
||||||
await this._page.keyboard.down(params.key);
|
await this._page.keyboard.down(params.key);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||||
options = validateLaunchOptions(options);
|
options = validateLaunchOptions(options);
|
||||||
const loggers = new Loggers(options.logger);
|
const loggers = new Loggers(options.logger);
|
||||||
const label = 'browserType.launch';
|
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, loggers, undefined), loggers.browser, TimeoutSettings.timeout(options)).catch(e => { throw this._rewriteStartupError(e); });
|
||||||
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, loggers, undefined), loggers.browser, TimeoutSettings.timeout(options), label).catch(e => { throw this._rewriteStartupError(e, label); });
|
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,8 +94,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
options = validateLaunchOptions(options);
|
options = validateLaunchOptions(options);
|
||||||
const persistent = validateBrowserContextOptions(options);
|
const persistent = validateBrowserContextOptions(options);
|
||||||
const loggers = new Loggers(options.logger);
|
const loggers = new Loggers(options.logger);
|
||||||
const label = 'browserType.launchPersistentContext';
|
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, loggers, persistent, userDataDir), loggers.browser, TimeoutSettings.timeout(options)).catch(e => { throw this._rewriteStartupError(e); });
|
||||||
const browser = await runAbortableTask(progress => this._innerLaunch(progress, options, loggers, persistent, userDataDir), loggers.browser, TimeoutSettings.timeout(options), label).catch(e => { throw this._rewriteStartupError(e, label); });
|
|
||||||
return browser._defaultContext!;
|
return browser._defaultContext!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,7 +222,7 @@ export abstract class BrowserTypeBase implements BrowserType {
|
||||||
abstract _connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<BrowserBase>;
|
abstract _connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<BrowserBase>;
|
||||||
abstract _amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env;
|
abstract _amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env;
|
||||||
abstract _amendArguments(browserArguments: string[]): string[];
|
abstract _amendArguments(browserArguments: string[]): string[];
|
||||||
abstract _rewriteStartupError(error: Error, prefix: string): Error;
|
abstract _rewriteStartupError(error: Error): Error;
|
||||||
abstract _attemptToGracefullyCloseBrowser(transport: ConnectionTransport): void;
|
abstract _attemptToGracefullyCloseBrowser(transport: ConnectionTransport): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,13 @@ export class Chromium extends BrowserTypeBase {
|
||||||
return CRBrowser.connect(transport, options, devtools);
|
return CRBrowser.connect(transport, options, devtools);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rewriteStartupError(error: Error, prefix: string): Error {
|
_rewriteStartupError(error: Error): Error {
|
||||||
// These error messages are taken from Chromium source code as of July, 2020:
|
// These error messages are taken from Chromium source code as of July, 2020:
|
||||||
// https://github.com/chromium/chromium/blob/70565f67e79f79e17663ad1337dc6e63ee207ce9/content/browser/zygote_host/zygote_host_impl_linux.cc
|
// https://github.com/chromium/chromium/blob/70565f67e79f79e17663ad1337dc6e63ee207ce9/content/browser/zygote_host/zygote_host_impl_linux.cc
|
||||||
if (!error.message.includes('crbug.com/357670') && !error.message.includes('No usable sandbox!') && !error.message.includes('crbug.com/638180'))
|
if (!error.message.includes('crbug.com/357670') && !error.message.includes('No usable sandbox!') && !error.message.includes('crbug.com/638180'))
|
||||||
return error;
|
return error;
|
||||||
return rewriteErrorMessage(error, [
|
return rewriteErrorMessage(error, [
|
||||||
`${prefix}: Chromium sandboxing failed!`,
|
`Chromium sandboxing failed!`,
|
||||||
`================================`,
|
`================================`,
|
||||||
`To workaround sandboxing issues, do either of the following:`,
|
`To workaround sandboxing issues, do either of the following:`,
|
||||||
` - (preferred): Configure environment to support sandboxing: https://github.com/microsoft/playwright/blob/master/docs/troubleshooting.md`,
|
` - (preferred): Configure environment to support sandboxing: https://github.com/microsoft/playwright/blob/master/docs/troubleshooting.md`,
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ export class ElectronApplication extends EventEmitter {
|
||||||
this._windows.delete(page);
|
this._windows.delete(page);
|
||||||
});
|
});
|
||||||
this._windows.add(page);
|
this._windows.add(page);
|
||||||
await page.waitForLoadState('domcontentloaded').catch(e => {}); // can happen after detach
|
await page.mainFrame().waitForLoadState('domcontentloaded').catch(e => {}); // can happen after detach
|
||||||
this.emit(ElectronEvents.ElectronApplication.Window, page);
|
this.emit(ElectronEvents.ElectronApplication.Window, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,7 +136,7 @@ export class ElectronApplication extends EventEmitter {
|
||||||
|
|
||||||
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
|
||||||
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
|
||||||
const progressController = new ProgressController(this._apiLogger, this._timeoutSettings.timeout(options), 'electron.waitForEvent');
|
const progressController = new ProgressController(this._apiLogger, this._timeoutSettings.timeout(options));
|
||||||
if (event !== ElectronEvents.ElectronApplication.Close)
|
if (event !== ElectronEvents.ElectronApplication.Close)
|
||||||
this._browserContext._closePromise.then(error => progressController.abort(error));
|
this._browserContext._closePromise.then(error => progressController.abort(error));
|
||||||
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate).promise);
|
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate).promise);
|
||||||
|
|
@ -212,6 +212,6 @@ export class Electron {
|
||||||
app = new ElectronApplication(loggers, browser, nodeConnection);
|
app = new ElectronApplication(loggers, browser, nodeConnection);
|
||||||
await app._init();
|
await app._init();
|
||||||
return app;
|
return app;
|
||||||
}, loggers.browser, TimeoutSettings.timeout(options), 'electron.launch');
|
}, loggers.browser, TimeoutSettings.timeout(options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export class Firefox extends BrowserTypeBase {
|
||||||
return FFBrowser.connect(transport, options);
|
return FFBrowser.connect(transport, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rewriteStartupError(error: Error, prefix: string): Error {
|
_rewriteStartupError(error: Error): Error {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ export class WebKit extends BrowserTypeBase {
|
||||||
return browserArguments;
|
return browserArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
_rewriteStartupError(error: Error, prefix: string): Error {
|
_rewriteStartupError(error: Error): Error {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ const CRASH_FAIL = (FFOX && WIN) || WIRE;
|
||||||
// Firefox Win: it just doesn't crash sometimes.
|
// Firefox Win: it just doesn't crash sometimes.
|
||||||
function crash(pageImpl) {
|
function crash(pageImpl) {
|
||||||
if (CHROMIUM)
|
if (CHROMIUM)
|
||||||
pageImpl.goto('chrome://crash').catch(e => {});
|
pageImpl.mainFrame().goto('chrome://crash').catch(e => {});
|
||||||
else if (WEBKIT)
|
else if (WEBKIT)
|
||||||
pageImpl._delegate._session.send('Page.crash', {}).catch(e => {});
|
pageImpl._delegate._session.send('Page.crash', {}).catch(e => {});
|
||||||
else if (FFOX)
|
else if (FFOX)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue