Merge pull request #4382 from atom/throw-explicit-error-when-webview-api-is-unavailable

Throw explicit error when WebView API isn't ready
This commit is contained in:
Kevin Sawicki 2016-02-11 13:34:01 -08:00
commit 9d6344704e
2 changed files with 201 additions and 151 deletions

View file

@ -404,10 +404,13 @@ var registerWebViewElement = function() {
// Forward proto.foo* method calls to WebViewImpl.foo*. // Forward proto.foo* method calls to WebViewImpl.foo*.
createBlockHandler = function(m) { createBlockHandler = function(m) {
return function() { return function() {
var args, internal, ref1; var args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
args = 1 <= arguments.length ? slice.call(arguments, 0) : []; var internal = v8Util.getHiddenValue(this, 'internal');
internal = v8Util.getHiddenValue(this, 'internal'); if (internal.webContents) {
return (ref1 = internal.webContents)[m].apply(ref1, args); return internal.webContents[m].apply(internal.webContents, args);
} else {
throw new Error(`Cannot call ${m} because the webContents is unavailable. The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.`);
}
}; };
}; };
for (i = 0, len = methods.length; i < len; i++) { for (i = 0, len = methods.length; i < len; i++) {

View file

@ -1,166 +1,175 @@
var assert, http, path, url; const assert = require('assert');
const path = require('path');
assert = require('assert'); const http = require('http');
const url = require('url');
path = require('path');
http = require('http');
url = require('url');
describe('<webview> tag', function() { describe('<webview> tag', function() {
var fixtures, webview;
this.timeout(10000); this.timeout(10000);
fixtures = path.join(__dirname, 'fixtures');
webview = null; var fixtures = path.join(__dirname, 'fixtures');
var webview = null;
beforeEach(function() { beforeEach(function() {
return webview = new WebView; webview = new WebView;
}); });
afterEach(function() { afterEach(function() {
if (document.body.contains(webview)) { if (document.body.contains(webview)) {
return document.body.removeChild(webview); document.body.removeChild(webview);
} }
}); });
describe('src attribute', function() { describe('src attribute', function() {
it('specifies the page to load', function(done) { it('specifies the page to load', function(done) {
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'a'); assert.equal(e.message, 'a');
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/a.html"; webview.src = "file://" + fixtures + "/pages/a.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('navigates to new page when changed', function(done) {
it('navigates to new page when changed', function(done) {
var listener = function() { var listener = function() {
webview.src = "file://" + fixtures + "/pages/b.html"; webview.src = "file://" + fixtures + "/pages/b.html";
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'b'); assert.equal(e.message, 'b');
return done(); done();
}); });
return webview.removeEventListener('did-finish-load', listener); webview.removeEventListener('did-finish-load', listener);
}; };
webview.addEventListener('did-finish-load', listener); webview.addEventListener('did-finish-load', listener);
webview.src = "file://" + fixtures + "/pages/a.html"; webview.src = "file://" + fixtures + "/pages/a.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('nodeintegration attribute', function() { describe('nodeintegration attribute', function() {
it('inserts no node symbols when not set', function(done) { it('inserts no node symbols when not set', function(done) {
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'undefined undefined undefined undefined'); assert.equal(e.message, 'undefined undefined undefined undefined');
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/c.html"; webview.src = "file://" + fixtures + "/pages/c.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it('inserts node symbols when set', function(done) { it('inserts node symbols when set', function(done) {
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'function object object'); assert.equal(e.message, 'function object object');
return done(); done();
}); });
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
webview.src = "file://" + fixtures + "/pages/d.html"; webview.src = "file://" + fixtures + "/pages/d.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it('loads node symbols after POST navigation when set', function(done) { it('loads node symbols after POST navigation when set', function(done) {
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'function object object'); assert.equal(e.message, 'function object object');
return done(); done();
}); });
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
webview.src = "file://" + fixtures + "/pages/post.html"; webview.src = "file://" + fixtures + "/pages/post.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
if (process.platform !== 'win32' || process.execPath.toLowerCase().indexOf('\\out\\d\\') === -1) { if (process.platform !== 'win32' || process.execPath.toLowerCase().indexOf('\\out\\d\\') === -1) {
return it('loads native modules when navigation happens', function(done) { it('loads native modules when navigation happens', function(done) {
var listener = function() { var listener = function() {
webview.removeEventListener('did-finish-load', listener); webview.removeEventListener('did-finish-load', listener);
var listener2 = function(e) { var listener2 = function(e) {
assert.equal(e.message, 'function'); assert.equal(e.message, 'function');
return done(); done();
}; };
webview.addEventListener('console-message', listener2); webview.addEventListener('console-message', listener2);
return webview.reload(); webview.reload();
}; };
webview.addEventListener('did-finish-load', listener); webview.addEventListener('did-finish-load', listener);
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
webview.src = "file://" + fixtures + "/pages/native-module.html"; webview.src = "file://" + fixtures + "/pages/native-module.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
} }
}); });
describe('preload attribute', function() { describe('preload attribute', function() {
it('loads the script before other scripts in window', function(done) { it('loads the script before other scripts in window', function(done) {
var listener; var listener;
listener = function(e) { listener = function(e) {
assert.equal(e.message, 'function object object'); assert.equal(e.message, 'function object object');
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.setAttribute('preload', fixtures + "/module/preload.js"); webview.setAttribute('preload', fixtures + "/module/preload.js");
webview.src = "file://" + fixtures + "/pages/e.html"; webview.src = "file://" + fixtures + "/pages/e.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it('preload script can still use "process" in required modules when nodeintegration is off', function(done) { it('preload script can still use "process" in required modules when nodeintegration is off', function(done) {
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'object undefined object'); assert.equal(e.message, 'object undefined object');
return done(); done();
}); });
webview.setAttribute('preload', fixtures + "/module/preload-node-off.js"); webview.setAttribute('preload', fixtures + "/module/preload-node-off.js");
webview.src = "file://" + fixtures + "/api/blank.html"; webview.src = "file://" + fixtures + "/api/blank.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('receives ipc message in preload script', function(done) {
it('receives ipc message in preload script', function(done) {
var listener, listener2, message; var listener, listener2, message;
message = 'boom!'; message = 'boom!';
listener = function(e) { listener = function(e) {
assert.equal(e.channel, 'pong'); assert.equal(e.channel, 'pong');
assert.deepEqual(e.args, [message]); assert.deepEqual(e.args, [message]);
webview.removeEventListener('ipc-message', listener); webview.removeEventListener('ipc-message', listener);
return done(); done();
}; };
listener2 = function() { listener2 = function() {
webview.send('ping', message); webview.send('ping', message);
return webview.removeEventListener('did-finish-load', listener2); webview.removeEventListener('did-finish-load', listener2);
}; };
webview.addEventListener('ipc-message', listener); webview.addEventListener('ipc-message', listener);
webview.addEventListener('did-finish-load', listener2); webview.addEventListener('did-finish-load', listener2);
webview.setAttribute('preload', fixtures + "/module/preload-ipc.js"); webview.setAttribute('preload', fixtures + "/module/preload-ipc.js");
webview.src = "file://" + fixtures + "/pages/e.html"; webview.src = "file://" + fixtures + "/pages/e.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('httpreferrer attribute', function() { describe('httpreferrer attribute', function() {
return it('sets the referrer url', function(done) { it('sets the referrer url', function(done) {
var listener, referrer; var listener, referrer;
referrer = 'http://github.com/'; referrer = 'http://github.com/';
listener = function(e) { listener = function(e) {
assert.equal(e.message, referrer); assert.equal(e.message, referrer);
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.setAttribute('httpreferrer', referrer); webview.setAttribute('httpreferrer', referrer);
webview.src = "file://" + fixtures + "/pages/referrer.html"; webview.src = "file://" + fixtures + "/pages/referrer.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('useragent attribute', function() { describe('useragent attribute', function() {
return it('sets the user agent', function(done) { it('sets the user agent', function(done) {
var listener, referrer; var listener, referrer;
referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko'; referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko';
listener = function(e) { listener = function(e) {
assert.equal(e.message, referrer); assert.equal(e.message, referrer);
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.setAttribute('useragent', referrer); webview.setAttribute('useragent', referrer);
webview.src = "file://" + fixtures + "/pages/useragent.html"; webview.src = "file://" + fixtures + "/pages/useragent.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('disablewebsecurity attribute', function() { describe('disablewebsecurity attribute', function() {
it('does not disable web security when not set', function(done) { it('does not disable web security when not set', function(done) {
var encoded, listener, src; var encoded, listener, src;
@ -169,164 +178,177 @@ describe('<webview> tag', function() {
listener = function(e) { listener = function(e) {
assert(/Not allowed to load local resource/.test(e.message)); assert(/Not allowed to load local resource/.test(e.message));
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.src = "data:text/html;base64," + encoded; webview.src = "data:text/html;base64," + encoded;
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('disables web security when set', function(done) {
it('disables web security when set', function(done) {
var encoded, listener, src; var encoded, listener, src;
src = "<script src='file://" + __dirname + "/static/jquery-2.0.3.min.js'></script> <script>console.log('ok');</script>"; src = "<script src='file://" + __dirname + "/static/jquery-2.0.3.min.js'></script> <script>console.log('ok');</script>";
encoded = btoa(unescape(encodeURIComponent(src))); encoded = btoa(unescape(encodeURIComponent(src)));
listener = function(e) { listener = function(e) {
assert.equal(e.message, 'ok'); assert.equal(e.message, 'ok');
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.setAttribute('disablewebsecurity', ''); webview.setAttribute('disablewebsecurity', '');
webview.src = "data:text/html;base64," + encoded; webview.src = "data:text/html;base64," + encoded;
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('partition attribute', function() { describe('partition attribute', function() {
it('inserts no node symbols when not set', function(done) { it('inserts no node symbols when not set', function(done) {
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'undefined undefined undefined undefined'); assert.equal(e.message, 'undefined undefined undefined undefined');
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/c.html"; webview.src = "file://" + fixtures + "/pages/c.html";
webview.partition = 'test1'; webview.partition = 'test1';
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it('inserts node symbols when set', function(done) { it('inserts node symbols when set', function(done) {
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
assert.equal(e.message, 'function object object'); assert.equal(e.message, 'function object object');
return done(); done();
}); });
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
webview.src = "file://" + fixtures + "/pages/d.html"; webview.src = "file://" + fixtures + "/pages/d.html";
webview.partition = 'test2'; webview.partition = 'test2';
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it('isolates storage for different id', function(done) { it('isolates storage for different id', function(done) {
var listener; var listener;
listener = function(e) { listener = function(e) {
assert.equal(e.message, " 0"); assert.equal(e.message, " 0");
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
window.localStorage.setItem('test', 'one'); window.localStorage.setItem('test', 'one');
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.src = "file://" + fixtures + "/pages/partition/one.html"; webview.src = "file://" + fixtures + "/pages/partition/one.html";
webview.partition = 'test3'; webview.partition = 'test3';
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('uses current session storage when no id is provided', function(done) {
it('uses current session storage when no id is provided', function(done) {
var listener; var listener;
listener = function(e) { listener = function(e) {
assert.equal(e.message, "one 1"); assert.equal(e.message, "one 1");
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
window.localStorage.setItem('test', 'one'); window.localStorage.setItem('test', 'one');
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.src = "file://" + fixtures + "/pages/partition/one.html"; webview.src = "file://" + fixtures + "/pages/partition/one.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('allowpopups attribute', function() { describe('allowpopups attribute', function() {
it('can not open new window when not set', function(done) { it('can not open new window when not set', function(done) {
var listener; var listener;
listener = function(e) { listener = function(e) {
assert.equal(e.message, 'null'); assert.equal(e.message, 'null');
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.src = "file://" + fixtures + "/pages/window-open-hide.html"; webview.src = "file://" + fixtures + "/pages/window-open-hide.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('can open new window when set', function(done) {
it('can open new window when set', function(done) {
var listener; var listener;
listener = function(e) { listener = function(e) {
assert.equal(e.message, 'window'); assert.equal(e.message, 'window');
webview.removeEventListener('console-message', listener); webview.removeEventListener('console-message', listener);
return done(); done();
}; };
webview.addEventListener('console-message', listener); webview.addEventListener('console-message', listener);
webview.setAttribute('allowpopups', 'on'); webview.setAttribute('allowpopups', 'on');
webview.src = "file://" + fixtures + "/pages/window-open-hide.html"; webview.src = "file://" + fixtures + "/pages/window-open-hide.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('new-window event', function() { describe('new-window event', function() {
it('emits when window.open is called', function(done) { it('emits when window.open is called', function(done) {
webview.addEventListener('new-window', function(e) { webview.addEventListener('new-window', function(e) {
assert.equal(e.url, 'http://host/'); assert.equal(e.url, 'http://host/');
assert.equal(e.frameName, 'host'); assert.equal(e.frameName, 'host');
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/window-open.html"; webview.src = "file://" + fixtures + "/pages/window-open.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('emits when link with target is called', function(done) {
it('emits when link with target is called', function(done) {
webview.addEventListener('new-window', function(e) { webview.addEventListener('new-window', function(e) {
assert.equal(e.url, 'http://host/'); assert.equal(e.url, 'http://host/');
assert.equal(e.frameName, 'target'); assert.equal(e.frameName, 'target');
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/target-name.html"; webview.src = "file://" + fixtures + "/pages/target-name.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('ipc-message event', function() { describe('ipc-message event', function() {
return it('emits when guest sends a ipc message to browser', function(done) { it('emits when guest sends a ipc message to browser', function(done) {
webview.addEventListener('ipc-message', function(e) { webview.addEventListener('ipc-message', function(e) {
assert.equal(e.channel, 'channel'); assert.equal(e.channel, 'channel');
assert.deepEqual(e.args, ['arg1', 'arg2']); assert.deepEqual(e.args, ['arg1', 'arg2']);
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/ipc-message.html"; webview.src = "file://" + fixtures + "/pages/ipc-message.html";
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('page-title-set event', function() { describe('page-title-set event', function() {
return it('emits when title is set', function(done) { it('emits when title is set', function(done) {
webview.addEventListener('page-title-set', function(e) { webview.addEventListener('page-title-set', function(e) {
assert.equal(e.title, 'test'); assert.equal(e.title, 'test');
assert(e.explicitSet); assert(e.explicitSet);
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/a.html"; webview.src = "file://" + fixtures + "/pages/a.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('page-favicon-updated event', function() { describe('page-favicon-updated event', function() {
return it('emits when favicon urls are received', function(done) { it('emits when favicon urls are received', function(done) {
webview.addEventListener('page-favicon-updated', function(e) { webview.addEventListener('page-favicon-updated', function(e) {
var pageUrl; var pageUrl;
assert.equal(e.favicons.length, 2); assert.equal(e.favicons.length, 2);
pageUrl = process.platform === 'win32' ? 'file:///C:/favicon.png' : 'file:///favicon.png'; pageUrl = process.platform === 'win32' ? 'file:///C:/favicon.png' : 'file:///favicon.png';
assert.equal(e.favicons[0], pageUrl); assert.equal(e.favicons[0], pageUrl);
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/a.html"; webview.src = "file://" + fixtures + "/pages/a.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('will-navigate event', function() { describe('will-navigate event', function() {
return it('emits when a url that leads to oustide of the page is clicked', function(done) { it('emits when a url that leads to oustide of the page is clicked', function(done) {
webview.addEventListener('will-navigate', function(e) { webview.addEventListener('will-navigate', function(e) {
assert.equal(e.url, "http://host/"); assert.equal(e.url, "http://host/");
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/webview-will-navigate.html"; webview.src = "file://" + fixtures + "/pages/webview-will-navigate.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('did-navigate event', function() { describe('did-navigate event', function() {
var p, pageUrl; var p, pageUrl;
p = path.join(fixtures, 'pages', 'webview-will-navigate.html'); p = path.join(fixtures, 'pages', 'webview-will-navigate.html');
@ -336,13 +358,14 @@ describe('<webview> tag', function() {
slashes: true, slashes: true,
pathname: p pathname: p
}); });
return it('emits when a url that leads to outside of the page is clicked', function(done) {
it('emits when a url that leads to outside of the page is clicked', function(done) {
webview.addEventListener('did-navigate', function(e) { webview.addEventListener('did-navigate', function(e) {
assert.equal(e.url, pageUrl); assert.equal(e.url, pageUrl);
return done(); done();
}); });
webview.src = pageUrl; webview.src = pageUrl;
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('did-navigate-in-page event', function() { describe('did-navigate-in-page event', function() {
@ -357,20 +380,22 @@ describe('<webview> tag', function() {
}); });
webview.addEventListener('did-navigate-in-page', function(e) { webview.addEventListener('did-navigate-in-page', function(e) {
assert.equal(e.url, pageUrl + "#test_content"); assert.equal(e.url, pageUrl + "#test_content");
return done(); done();
}); });
webview.src = pageUrl; webview.src = pageUrl;
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it('emits when window.history.replaceState is called', function(done) { it('emits when window.history.replaceState is called', function(done) {
webview.addEventListener('did-navigate-in-page', function(e) { webview.addEventListener('did-navigate-in-page', function(e) {
assert.equal(e.url, "http://host/"); assert.equal(e.url, "http://host/");
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/webview-did-navigate-in-page-with-history.html"; webview.src = "file://" + fixtures + "/pages/webview-did-navigate-in-page-with-history.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('emits when window.location.hash is changed', function(done) {
it('emits when window.location.hash is changed', function(done) {
var p, pageUrl; var p, pageUrl;
p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html'); p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html');
p = p.replace(/\\/g, '/'); p = p.replace(/\\/g, '/');
@ -381,94 +406,100 @@ describe('<webview> tag', function() {
}); });
webview.addEventListener('did-navigate-in-page', function(e) { webview.addEventListener('did-navigate-in-page', function(e) {
assert.equal(e.url, pageUrl + "#test"); assert.equal(e.url, pageUrl + "#test");
return done(); done();
}); });
webview.src = pageUrl; webview.src = pageUrl;
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('close event', function() { describe('close event', function() {
return it('should fire when interior page calls window.close', function(done) { it('should fire when interior page calls window.close', function(done) {
webview.addEventListener('close', function() { webview.addEventListener('close', function() {
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/close.html"; webview.src = "file://" + fixtures + "/pages/close.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('devtools-opened event', function() { describe('devtools-opened event', function() {
return it('should fire when webview.openDevTools() is called', function(done) { it('should fire when webview.openDevTools() is called', function(done) {
var listener; var listener;
listener = function() { listener = function() {
webview.removeEventListener('devtools-opened', listener); webview.removeEventListener('devtools-opened', listener);
webview.closeDevTools(); webview.closeDevTools();
return done(); done();
}; };
webview.addEventListener('devtools-opened', listener); webview.addEventListener('devtools-opened', listener);
webview.addEventListener('dom-ready', function() { webview.addEventListener('dom-ready', function() {
return webview.openDevTools(); webview.openDevTools();
}); });
webview.src = "file://" + fixtures + "/pages/base-page.html"; webview.src = "file://" + fixtures + "/pages/base-page.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('devtools-closed event', function() { describe('devtools-closed event', function() {
return it('should fire when webview.closeDevTools() is called', function(done) { it('should fire when webview.closeDevTools() is called', function(done) {
var listener, listener2; var listener, listener2;
listener2 = function() { listener2 = function() {
webview.removeEventListener('devtools-closed', listener2); webview.removeEventListener('devtools-closed', listener2);
return done(); done();
}; };
listener = function() { listener = function() {
webview.removeEventListener('devtools-opened', listener); webview.removeEventListener('devtools-opened', listener);
return webview.closeDevTools(); webview.closeDevTools();
}; };
webview.addEventListener('devtools-opened', listener); webview.addEventListener('devtools-opened', listener);
webview.addEventListener('devtools-closed', listener2); webview.addEventListener('devtools-closed', listener2);
webview.addEventListener('dom-ready', function() { webview.addEventListener('dom-ready', function() {
return webview.openDevTools(); webview.openDevTools();
}); });
webview.src = "file://" + fixtures + "/pages/base-page.html"; webview.src = "file://" + fixtures + "/pages/base-page.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('devtools-focused event', function() { describe('devtools-focused event', function() {
return it('should fire when webview.openDevTools() is called', function(done) { it('should fire when webview.openDevTools() is called', function(done) {
var listener; var listener;
listener = function() { listener = function() {
webview.removeEventListener('devtools-focused', listener); webview.removeEventListener('devtools-focused', listener);
webview.closeDevTools(); webview.closeDevTools();
return done(); done();
}; };
webview.addEventListener('devtools-focused', listener); webview.addEventListener('devtools-focused', listener);
webview.addEventListener('dom-ready', function() { webview.addEventListener('dom-ready', function() {
return webview.openDevTools(); webview.openDevTools();
}); });
webview.src = "file://" + fixtures + "/pages/base-page.html"; webview.src = "file://" + fixtures + "/pages/base-page.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('<webview>.reload()', function() { describe('<webview>.reload()', function() {
return it('should emit beforeunload handler', function(done) { it('should emit beforeunload handler', function(done) {
var listener, listener2; var listener, listener2;
listener = function(e) { listener = function(e) {
assert.equal(e.channel, 'onbeforeunload'); assert.equal(e.channel, 'onbeforeunload');
webview.removeEventListener('ipc-message', listener); webview.removeEventListener('ipc-message', listener);
return done(); done();
}; };
listener2 = function() { listener2 = function() {
webview.reload(); webview.reload();
return webview.removeEventListener('did-finish-load', listener2); webview.removeEventListener('did-finish-load', listener2);
}; };
webview.addEventListener('ipc-message', listener); webview.addEventListener('ipc-message', listener);
webview.addEventListener('did-finish-load', listener2); webview.addEventListener('did-finish-load', listener2);
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
webview.src = "file://" + fixtures + "/pages/beforeunload-false.html"; webview.src = "file://" + fixtures + "/pages/beforeunload-false.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('<webview>.clearHistory()', function() { describe('<webview>.clearHistory()', function() {
return it('should clear the navigation history', function(done) { it('should clear the navigation history', function(done) {
var listener; var listener;
listener = function(e) { listener = function(e) {
assert.equal(e.channel, 'history'); assert.equal(e.channel, 'history');
@ -477,18 +508,19 @@ describe('<webview> tag', function() {
webview.clearHistory(); webview.clearHistory();
assert(!webview.canGoBack()); assert(!webview.canGoBack());
webview.removeEventListener('ipc-message', listener); webview.removeEventListener('ipc-message', listener);
return done(); done();
}; };
webview.addEventListener('ipc-message', listener); webview.addEventListener('ipc-message', listener);
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
webview.src = "file://" + fixtures + "/pages/history.html"; webview.src = "file://" + fixtures + "/pages/history.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('basic auth', function() { describe('basic auth', function() {
var auth; var auth;
auth = require('basic-auth'); auth = require('basic-auth');
return it('should authenticate with correct credentials', function(done) { it('should authenticate with correct credentials', function(done) {
var message, server; var message, server;
message = 'Authenticated'; message = 'Authenticated';
server = http.createServer(function(req, res) { server = http.createServer(function(req, res) {
@ -499,67 +531,77 @@ describe('<webview> tag', function() {
} else { } else {
res.end('failed'); res.end('failed');
} }
return server.close(); server.close();
}); });
return server.listen(0, '127.0.0.1', function() { server.listen(0, '127.0.0.1', function() {
var port; var port;
port = server.address().port; port = server.address().port;
webview.addEventListener('ipc-message', function(e) { webview.addEventListener('ipc-message', function(e) {
assert.equal(e.channel, message); assert.equal(e.channel, message);
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/basic-auth.html?port=" + port; webview.src = "file://" + fixtures + "/pages/basic-auth.html?port=" + port;
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
}); });
describe('dom-ready event', function() { describe('dom-ready event', function() {
return it('emits when document is loaded', function(done) { it('emits when document is loaded', function(done) {
var server; var server;
server = http.createServer(function() {}); server = http.createServer(function() {});
return server.listen(0, '127.0.0.1', function() { server.listen(0, '127.0.0.1', function() {
var port; var port;
port = server.address().port; port = server.address().port;
webview.addEventListener('dom-ready', function() { webview.addEventListener('dom-ready', function() {
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/dom-ready.html?port=" + port; webview.src = "file://" + fixtures + "/pages/dom-ready.html?port=" + port;
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
it('throws a custom error when an API method is called before the event is emitted', function() {
assert.throws(function () {
webview.stop();
}, 'Cannot call stop because the webContents is unavailable. The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.');
});
}); });
describe('executeJavaScript', function() { describe('executeJavaScript', function() {
if (process.env.TRAVIS !== 'true') { if (process.env.TRAVIS !== 'true') {
return; return;
} }
return it('should support user gesture', function(done) {
it('should support user gesture', function(done) {
var listener, listener2; var listener, listener2;
listener = function() { listener = function() {
webview.removeEventListener('enter-html-full-screen', listener); webview.removeEventListener('enter-html-full-screen', listener);
return done(); done();
}; };
listener2 = function() { listener2 = function() {
var jsScript; var jsScript;
jsScript = 'document.getElementsByTagName("video")[0].webkitRequestFullScreen()'; jsScript = 'document.getElementsByTagName("video")[0].webkitRequestFullScreen()';
webview.executeJavaScript(jsScript, true); webview.executeJavaScript(jsScript, true);
return webview.removeEventListener('did-finish-load', listener2); webview.removeEventListener('did-finish-load', listener2);
}; };
webview.addEventListener('enter-html-full-screen', listener); webview.addEventListener('enter-html-full-screen', listener);
webview.addEventListener('did-finish-load', listener2); webview.addEventListener('did-finish-load', listener2);
webview.src = "file://" + fixtures + "/pages/fullscreen.html"; webview.src = "file://" + fixtures + "/pages/fullscreen.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('sendInputEvent', function() { describe('sendInputEvent', function() {
it('can send keyboard event', function(done) { it('can send keyboard event', function(done) {
webview.addEventListener('ipc-message', function(e) { webview.addEventListener('ipc-message', function(e) {
assert.equal(e.channel, 'keyup'); assert.equal(e.channel, 'keyup');
assert.deepEqual(e.args, [67, true, false]); assert.deepEqual(e.args, [67, true, false]);
return done(); done();
}); });
webview.addEventListener('dom-ready', function() { webview.addEventListener('dom-ready', function() {
return webview.sendInputEvent({ webview.sendInputEvent({
type: 'keyup', type: 'keyup',
keyCode: 'c', keyCode: 'c',
modifiers: ['shift'] modifiers: ['shift']
@ -567,16 +609,17 @@ describe('<webview> tag', function() {
}); });
webview.src = "file://" + fixtures + "/pages/onkeyup.html"; webview.src = "file://" + fixtures + "/pages/onkeyup.html";
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
return it('can send mouse event', function(done) {
it('can send mouse event', function(done) {
webview.addEventListener('ipc-message', function(e) { webview.addEventListener('ipc-message', function(e) {
assert.equal(e.channel, 'mouseup'); assert.equal(e.channel, 'mouseup');
assert.deepEqual(e.args, [10, 20, false, true]); assert.deepEqual(e.args, [10, 20, false, true]);
return done(); done();
}); });
webview.addEventListener('dom-ready', function() { webview.addEventListener('dom-ready', function() {
return webview.sendInputEvent({ webview.sendInputEvent({
type: 'mouseup', type: 'mouseup',
modifiers: ['ctrl'], modifiers: ['ctrl'],
x: 10, x: 10,
@ -585,26 +628,28 @@ describe('<webview> tag', function() {
}); });
webview.src = "file://" + fixtures + "/pages/onmouseup.html"; webview.src = "file://" + fixtures + "/pages/onmouseup.html";
webview.setAttribute('nodeintegration', 'on'); webview.setAttribute('nodeintegration', 'on');
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('media-started-playing media-paused events', function() { describe('media-started-playing media-paused events', function() {
return it('emits when audio starts and stops playing', function(done) { it('emits when audio starts and stops playing', function(done) {
var audioPlayed; var audioPlayed;
audioPlayed = false; audioPlayed = false;
webview.addEventListener('media-started-playing', function() { webview.addEventListener('media-started-playing', function() {
return audioPlayed = true; audioPlayed = true;
}); });
webview.addEventListener('media-paused', function() { webview.addEventListener('media-paused', function() {
assert(audioPlayed); assert(audioPlayed);
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/audio.html"; webview.src = "file://" + fixtures + "/pages/audio.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('found-in-page event', function() { describe('found-in-page event', function() {
return it('emits when a request is made', function(done) { it('emits when a request is made', function(done) {
var listener, listener2, requestId; var listener, listener2, requestId;
requestId = null; requestId = null;
listener = function(e) { listener = function(e) {
@ -612,27 +657,29 @@ describe('<webview> tag', function() {
if (e.result.finalUpdate) { if (e.result.finalUpdate) {
assert.equal(e.result.matches, 3); assert.equal(e.result.matches, 3);
webview.stopFindInPage("clearSelection"); webview.stopFindInPage("clearSelection");
return done(); done();
} }
}; };
listener2 = function() { listener2 = function() {
return requestId = webview.findInPage("virtual"); requestId = webview.findInPage("virtual");
}; };
webview.addEventListener('found-in-page', listener); webview.addEventListener('found-in-page', listener);
webview.addEventListener('did-finish-load', listener2); webview.addEventListener('did-finish-load', listener2);
webview.src = "file://" + fixtures + "/pages/content.html"; webview.src = "file://" + fixtures + "/pages/content.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
xdescribe('did-change-theme-color event', function() { xdescribe('did-change-theme-color event', function() {
return it('emits when theme color changes', function(done) { it('emits when theme color changes', function(done) {
webview.addEventListener('did-change-theme-color', function() { webview.addEventListener('did-change-theme-color', function() {
return done(); done();
}); });
webview.src = "file://" + fixtures + "/pages/theme-color.html"; webview.src = "file://" + fixtures + "/pages/theme-color.html";
return document.body.appendChild(webview); document.body.appendChild(webview);
}); });
}); });
describe('permission-request event', function() { describe('permission-request event', function() {
function setUpRequestHandler(webview, requested_permission) { function setUpRequestHandler(webview, requested_permission) {
const session = require('electron').remote.session; const session = require('electron').remote.session;
@ -645,7 +692,7 @@ describe('<webview> tag', function() {
session.fromPartition(webview.partition).setPermissionRequestHandler(listener); session.fromPartition(webview.partition).setPermissionRequestHandler(listener);
} }
it ('emits when using navigator.getUserMedia api', function(done) { it('emits when using navigator.getUserMedia api', function(done) {
webview.addEventListener('ipc-message', function(e) { webview.addEventListener('ipc-message', function(e) {
assert(e.channel, 'message'); assert(e.channel, 'message');
assert(e.args, ['PermissionDeniedError']); assert(e.args, ['PermissionDeniedError']);
@ -658,7 +705,7 @@ describe('<webview> tag', function() {
document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it ('emits when using navigator.geolocation api', function(done) { it('emits when using navigator.geolocation api', function(done) {
webview.addEventListener('ipc-message', function(e) { webview.addEventListener('ipc-message', function(e) {
assert(e.channel, 'message'); assert(e.channel, 'message');
assert(e.args, ['ERROR(1): User denied Geolocation']); assert(e.args, ['ERROR(1): User denied Geolocation']);
@ -671,7 +718,7 @@ describe('<webview> tag', function() {
document.body.appendChild(webview); document.body.appendChild(webview);
}); });
it ('emits when using navigator.requestMIDIAccess api', function(done) { it('emits when using navigator.requestMIDIAccess api', function(done) {
webview.addEventListener('ipc-message', function(e) { webview.addEventListener('ipc-message', function(e) {
assert(e.channel, 'message'); assert(e.channel, 'message');
assert(e.args, ['SecurityError']); assert(e.args, ['SecurityError']);