diff --git a/src/chromium/Page.ts b/src/chromium/Page.ts index 06e70570f6..1396999fad 100644 --- a/src/chromium/Page.ts +++ b/src/chromium/Page.ts @@ -373,7 +373,7 @@ export class Page extends EventEmitter { this.emit(Events.Page.Console, message); } - _onDialog(event) { + _onDialog(event : Protocol.Page.javascriptDialogOpeningPayload) { let dialogType = null; if (event.type === 'alert') dialogType = DialogType.Alert; diff --git a/src/webkit/Dialog.ts b/src/webkit/Dialog.ts new file mode 100644 index 0000000000..fdf41678bb --- /dev/null +++ b/src/webkit/Dialog.ts @@ -0,0 +1,70 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TargetSession } from './Connection'; +import { assert } from '../helper'; + +export class Dialog { + private _client: TargetSession; + private _type: string; + private _message: string; + private _handled = false; + private _defaultValue: string; + + constructor(client: TargetSession, type: string, message: string, defaultValue: (string | undefined) = '') { + this._client = client; + this._type = type; + this._message = message; + this._defaultValue = defaultValue; + } + + type(): string { + return this._type; + } + + message(): string { + return this._message; + } + + defaultValue(): string { + return this._defaultValue; + } + + async accept(promptText: string | undefined) { + assert(!this._handled, 'Cannot accept dialog which is already handled!'); + this._handled = true; + await this._client.send('Dialog.handleJavaScriptDialog', { + accept: true, + promptText: promptText + }); + } + + async dismiss() { + assert(!this._handled, 'Cannot dismiss dialog which is already handled!'); + this._handled = true; + await this._client.send('Dialog.handleJavaScriptDialog', { + accept: false + }); + } +} + +export const DialogType = { + Alert: 'alert', + BeforeUnload: 'beforeunload', + Confirm: 'confirm', + Prompt: 'prompt' +}; diff --git a/src/webkit/Page.ts b/src/webkit/Page.ts index 711acc1ec0..9dcfc2affb 100644 --- a/src/webkit/Page.ts +++ b/src/webkit/Page.ts @@ -34,6 +34,7 @@ import { Target } from './Target'; import { TaskQueue } from './TaskQueue'; import * as input from '../input'; import * as types from '../types'; +import { Dialog, DialogType } from './Dialog'; const writeFileAsync = helper.promisify(fs.writeFile); @@ -94,6 +95,7 @@ export class Page extends EventEmitter { return Promise.all([ this._frameManager.initialize(), this._session.send('Console.enable'), + this._session.send('Dialog.enable'), ]); } @@ -105,9 +107,25 @@ export class Page extends EventEmitter { helper.addEventListener(this._session, 'Page.loadEventFired', event => this.emit(Events.Page.Load)), helper.addEventListener(this._session, 'Console.messageAdded', event => this._onConsoleMessage(event)), helper.addEventListener(this._session, 'Page.domContentEventFired', event => this.emit(Events.Page.DOMContentLoaded)), + helper.addEventListener(this._session, 'Dialog.javascriptDialogOpening', event => this._onDialog(event)) ]; } + _onDialog(event: Protocol.Dialog.javascriptDialogOpeningPayload) { + let dialogType = null; + if (event.type === 'alert') + dialogType = DialogType.Alert; + else if (event.type === 'confirm') + dialogType = DialogType.Confirm; + else if (event.type === 'prompt') + dialogType = DialogType.Prompt; + else if (event.type === 'beforeunload') + dialogType = DialogType.BeforeUnload; + assert(dialogType, 'Unknown javascript dialog type: ' + event.type); + const dialog = new Dialog(this._session, dialogType, event.message, event.defaultPrompt); + this.emit(Events.Page.Dialog, dialog); + } + _setTarget(newTarget: Target) { this._target = newTarget; this._target._isClosedPromise.then(() => { diff --git a/src/webkit/events.ts b/src/webkit/events.ts index b29cc6da20..54d33500e5 100644 --- a/src/webkit/events.ts +++ b/src/webkit/events.ts @@ -19,6 +19,7 @@ export const Events = { Page: { Close: 'close', Console: 'console', + Dialog: 'dialog', DOMContentLoaded: 'domcontentloaded', Request: 'request', Response: 'response', diff --git a/test/dialog.spec.js b/test/dialog.spec.js index 0d9e58b752..501b828108 100644 --- a/test/dialog.spec.js +++ b/test/dialog.spec.js @@ -19,7 +19,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { const {it, fit, xit} = testRunner; const {beforeAll, beforeEach, afterAll, afterEach} = testRunner; - describe.skip(WEBKIT)('Page.Events.Dialog', function() { + describe('Page.Events.Dialog', function() { it('should fire', async({page, server}) => { page.on('dialog', dialog => { expect(dialog.type()).toBe('alert'); @@ -46,5 +46,19 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { const result = await page.evaluate(() => prompt('question?')); expect(result).toBe(null); }); + it('should accept the confirm prompt', async({page, server}) => { + page.on('dialog', dialog => { + dialog.accept(); + }); + const result = await page.evaluate(() => confirm('boolean?')); + expect(result).toBe(true); + }); + it('should dismiss the confirm prompt', async({page, server}) => { + page.on('dialog', dialog => { + dialog.dismiss(); + }); + const result = await page.evaluate(() => confirm('boolean?')); + expect(result).toBe(false); + }); }); };