Refactor JavaScript dialog API

This patch introduces a Dialog class and a new 'dialog'
event instead of the 'alert', 'beforeunload', 'confirm' and
'prompt' events and 'Page.handleDialog' method.

Fixes #2.
This commit is contained in:
Andrey Lushnikov 2017-06-15 21:22:41 -07:00
parent 14a75a83ea
commit f62cfc3b34
4 changed files with 110 additions and 27 deletions

69
lib/Dialog.js Normal file
View File

@ -0,0 +1,69 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
class Dialog {
/**
* @param {!Connection} client
* @param {!Dialog.Type} type
* @param {string} message
*/
constructor(client, type, message) {
this._client = client;
this.type = type;
this._message = message;
this._handled = false;
}
/**
* @return {string}
*/
message() {
return this._message;
}
/**
* @param {string=} promptText
* @return {!Promise}
*/
async accept(promptText) {
console.assert(!this._handled, 'Cannot accept dialog which is already handled!');
this._handled = true;
await this._client.send('Page.handleJavaScriptDialog', {
accept: true,
promptText: promptText
});
}
/**
* @return {!Promise}
*/
async dismiss() {
console.assert(!this._handled, 'Cannot dismiss dialog which is already handled!');
this._handled = true;
await this._client.send('Page.handleJavaScriptDialog', {
accept: false
});
}
}
Dialog.Type = {
Alert: 'alert',
BeforeUnload: 'beforeunload',
Confirm: 'confirm',
Prompt: 'prompt'
};
module.exports = Dialog;

View File

@ -19,6 +19,7 @@ var EventEmitter = require('events');
var helpers = require('./helpers'); var helpers = require('./helpers');
var mime = require('mime'); var mime = require('mime');
var Request = require('./Request'); var Request = require('./Request');
var Dialog = require('./Dialog');
class Page extends EventEmitter { class Page extends EventEmitter {
/** /**
@ -228,17 +229,18 @@ class Page extends EventEmitter {
} }
_onDialog(event) { _onDialog(event) {
var eventType = null; var dialogType = null;
if (event.type === 'alert') if (event.type === 'alert')
eventType = Page.Events.Alert; dialogType = Dialog.Type.Alert;
else if (event.type === 'confirm') else if (event.type === 'confirm')
eventType = Page.Events.Confirm; dialogType = Dialog.Type.Confirm;
else if (event.type === 'prompt') else if (event.type === 'prompt')
eventType = Page.Events.Prompt; dialogType = Dialog.Type.Prompt;
else if (event.type === 'beforeunload') else if (event.type === 'beforeunload')
eventType = Page.Events.BeforeUnload; dialogType = Dialog.Type.BeforeUnload;
if (eventType) console.assert(dialogType, 'Unknown javascript dialog type: ' + event.type);
this.emit(eventType, event.message); var dialog = new Dialog(this._client, dialogType, event.message);
this.emit(Page.Events.Dialog, dialog);
} }
/** /**
@ -563,12 +565,9 @@ function convertPrintParameterToInches(parameter) {
} }
Page.Events = { Page.Events = {
Alert: 'alert',
BeforeUnload: 'beforeunload',
Confirm: 'confirm',
ConsoleMessage: 'consolemessage', ConsoleMessage: 'consolemessage',
Dialog: 'dialog',
Exception: 'exception', Exception: 'exception',
Prompt: 'prompt',
ResourceLoadingFailed: 'resourceloadingfailed', ResourceLoadingFailed: 'resourceloadingfailed',
ResponseReceived: 'responsereceived', ResponseReceived: 'responsereceived',
}; };

View File

@ -63,6 +63,7 @@ class WebPage {
this._pageEvents.on(PageEvents.ConsoleMessage, msg => (this.onConsoleMessage || noop).call(null, msg)); this._pageEvents.on(PageEvents.ConsoleMessage, msg => (this.onConsoleMessage || noop).call(null, msg));
this._pageEvents.on(PageEvents.Confirm, message => this._onConfirm(message)); this._pageEvents.on(PageEvents.Confirm, message => this._onConfirm(message));
this._pageEvents.on(PageEvents.Alert, message => this._onAlert(message)); this._pageEvents.on(PageEvents.Alert, message => this._onAlert(message));
this._pageEvents.on(PageEvents.Dialog, dialog => this._onDialog(dialog));
this._pageEvents.on(PageEvents.Exception, (exception, stack) => (this._onError || noop).call(null, exception, stack)); this._pageEvents.on(PageEvents.Exception, (exception, stack) => (this._onError || noop).call(null, exception, stack));
} }
@ -195,16 +196,6 @@ class WebPage {
this._onConfirmCallback = handler; this._onConfirmCallback = handler;
} }
/**
* @param {string} message
*/
_onConfirm(message) {
if (!this._onConfirmCallback)
return;
var accept = this._onConfirmCallback.call(null, message);
await(this._page.handleDialog(accept));
}
/** /**
* @return {(function()|undefined)} * @return {(function()|undefined)}
*/ */
@ -222,13 +213,16 @@ class WebPage {
} }
/** /**
* @param {string} message * @param {!Dialog} dialog
*/ */
_onAlert(message) { _onDialog(dialog) {
if (!this._onAlertCallback) if (dialog.type === 'alert' && this._onAlertCallback) {
return; this._onAlertCallback.call(null, dialog.message());
this._onAlertCallback.call(null, message); await(dialog.accept());
await(this._page.handleDialog(true)); } else if (dialog.type === 'confirm' && this._onConfirmCallback) {
var result = this._onConfirmCallback.call(null, dialog.message());
await(result ? dialog.accept() : dialog.dismiss());
}
} }
/** /**

View File

@ -155,6 +155,27 @@ describe('Puppeteer', function() {
expect(failedResources).toBe(1); expect(failedResources).toBe(1);
})); }));
}); });
describe('Page.Events.Dialog', function() {
it('should fire', function(done) {
page.on('dialog', dialog => {
expect(dialog.type).toBe('alert');
expect(dialog.message()).toBe('yo');
done();
});
page.evaluate(() => alert('yo'));
});
// TODO Enable this when crbug.com/718235 is fixed.
xit('should allow accepting prompts', SX(async function(done) {
page.on('dialog', dialog => {
expect(dialog.type).toBe('prompt');
expect(dialog.message()).toBe('question?');
dialog.accept('answer!');
});
var result = await page.evaluate(() => prompt('question?'));
expect(result).toBe('answer!');
}));
});
}); });
// Since Jasmine doesn't like async functions, they should be wrapped // Since Jasmine doesn't like async functions, they should be wrapped