Merge pull request #4430 from atom/dont-crash-when-missing-ipc-channel

Don't crash when IPC channel is missing
This commit is contained in:
Kevin Sawicki 2016-02-11 13:28:08 -08:00
commit 174a492cdb
2 changed files with 157 additions and 102 deletions

View file

@ -76,8 +76,11 @@ let wrapWebContents = function(webContents) {
// WebContents::send(channel, args..) // WebContents::send(channel, args..)
webContents.send = function() { webContents.send = function() {
var args, channel; var args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
channel = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; var channel = arguments[0];
if (channel == null) {
throw new Error('Missing required channel argument');
}
return this._send(channel, slice.call(args)); return this._send(channel, slice.call(args));
}; };

View file

@ -14,29 +14,31 @@ const BrowserWindow = remote.require('electron').BrowserWindow;
const isCI = remote.getGlobal('isCi'); const isCI = remote.getGlobal('isCi');
describe('browser-window module', function() { describe('browser-window module', function() {
var fixtures, w; var fixtures = path.resolve(__dirname, 'fixtures');
fixtures = path.resolve(__dirname, 'fixtures'); var w = null;
w = null;
beforeEach(function() { beforeEach(function() {
if (w != null) { if (w != null) {
w.destroy(); w.destroy();
} }
return w = new BrowserWindow({ w = new BrowserWindow({
show: false, show: false,
width: 400, width: 400,
height: 400 height: 400
}); });
}); });
afterEach(function() { afterEach(function() {
if (w != null) { if (w != null) {
w.destroy(); w.destroy();
} }
return w = null; w = null;
}); });
describe('BrowserWindow.close()', function() { describe('BrowserWindow.close()', function() {
it('should emit unload handler', function(done) { it('should emit unload handler', function(done) {
w.webContents.on('did-finish-load', function() { w.webContents.on('did-finish-load', function() {
return w.close(); w.close();
}); });
w.on('closed', function() { w.on('closed', function() {
var content, test; var content, test;
@ -44,20 +46,22 @@ describe('browser-window module', function() {
content = fs.readFileSync(test); content = fs.readFileSync(test);
fs.unlinkSync(test); fs.unlinkSync(test);
assert.equal(String(content), 'unload'); assert.equal(String(content), 'unload');
return done(); done();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'unload.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'unload.html'));
}); });
return it('should emit beforeunload handler', function(done) {
it('should emit beforeunload handler', function(done) {
w.on('onbeforeunload', function() { w.on('onbeforeunload', function() {
return done(); done();
}); });
w.webContents.on('did-finish-load', function() { w.webContents.on('did-finish-load', function() {
return w.close(); w.close();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false.html'));
}); });
}); });
describe('window.close()', function() { describe('window.close()', function() {
it('should emit unload handler', function(done) { it('should emit unload handler', function(done) {
w.on('closed', function() { w.on('closed', function() {
@ -66,104 +70,113 @@ describe('browser-window module', function() {
content = fs.readFileSync(test); content = fs.readFileSync(test);
fs.unlinkSync(test); fs.unlinkSync(test);
assert.equal(String(content), 'close'); assert.equal(String(content), 'close');
return done(); done();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'close.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'close.html'));
}); });
return it('should emit beforeunload handler', function(done) {
it('should emit beforeunload handler', function(done) {
w.on('onbeforeunload', function() { w.on('onbeforeunload', function() {
return done(); done();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html'));
}); });
}); });
describe('BrowserWindow.destroy()', function() { describe('BrowserWindow.destroy()', function() {
return it('prevents users to access methods of webContents', function() { it('prevents users to access methods of webContents', function() {
var webContents; var webContents;
webContents = w.webContents; webContents = w.webContents;
w.destroy(); w.destroy();
return assert.throws((function() { assert.throws((function() {
return webContents.getId(); webContents.getId();
}), /Object has been destroyed/); }), /Object has been destroyed/);
}); });
}); });
describe('BrowserWindow.loadURL(url)', function() { describe('BrowserWindow.loadURL(url)', function() {
it('should emit did-start-loading event', function(done) { it('should emit did-start-loading event', function(done) {
w.webContents.on('did-start-loading', function() { w.webContents.on('did-start-loading', function() {
return done(); done();
}); });
return w.loadURL('about:blank'); w.loadURL('about:blank');
}); });
return it('should emit did-fail-load event', function(done) {
it('should emit did-fail-load event', function(done) {
w.webContents.on('did-fail-load', function() { w.webContents.on('did-fail-load', function() {
return done(); done();
}); });
return w.loadURL('file://a.txt'); w.loadURL('file://a.txt');
}); });
}); });
describe('BrowserWindow.show()', function() { describe('BrowserWindow.show()', function() {
return it('should focus on window', function() { it('should focus on window', function() {
if (isCI) { if (isCI) {
return; return;
} }
w.show(); w.show();
return assert(w.isFocused()); assert(w.isFocused());
}); });
}); });
describe('BrowserWindow.showInactive()', function() { describe('BrowserWindow.showInactive()', function() {
return it('should not focus on window', function() { it('should not focus on window', function() {
w.showInactive(); w.showInactive();
return assert(!w.isFocused()); assert(!w.isFocused());
}); });
}); });
describe('BrowserWindow.focus()', function() { describe('BrowserWindow.focus()', function() {
return it('does not make the window become visible', function() { it('does not make the window become visible', function() {
assert.equal(w.isVisible(), false); assert.equal(w.isVisible(), false);
w.focus(); w.focus();
return assert.equal(w.isVisible(), false); assert.equal(w.isVisible(), false);
}); });
}); });
describe('BrowserWindow.capturePage(rect, callback)', function() { describe('BrowserWindow.capturePage(rect, callback)', function() {
return it('calls the callback with a Buffer', function(done) { it('calls the callback with a Buffer', function(done) {
return w.capturePage({ w.capturePage({
x: 0, x: 0,
y: 0, y: 0,
width: 100, width: 100,
height: 100 height: 100
}, function(image) { }, function(image) {
assert.equal(image.isEmpty(), true); assert.equal(image.isEmpty(), true);
return done(); done();
}); });
}); });
}); });
describe('BrowserWindow.setSize(width, height)', function() { describe('BrowserWindow.setSize(width, height)', function() {
return it('sets the window size', function(done) { it('sets the window size', function(done) {
var size; var size = [300, 400];
size = [300, 400];
w.once('resize', function() { w.once('resize', function() {
var newSize; var newSize = w.getSize();
newSize = w.getSize();
assert.equal(newSize[0], size[0]); assert.equal(newSize[0], size[0]);
assert.equal(newSize[1], size[1]); assert.equal(newSize[1], size[1]);
return done(); done();
}); });
return w.setSize(size[0], size[1]); w.setSize(size[0], size[1]);
}); });
}); });
describe('BrowserWindow.setPosition(x, y)', function() { describe('BrowserWindow.setPosition(x, y)', function() {
return it('sets the window position', function(done) { it('sets the window position', function(done) {
var pos; var pos = [10, 10];
pos = [10, 10];
w.once('move', function() { w.once('move', function() {
var newPos; var newPos;
newPos = w.getPosition(); newPos = w.getPosition();
assert.equal(newPos[0], pos[0]); assert.equal(newPos[0], pos[0]);
assert.equal(newPos[1], pos[1]); assert.equal(newPos[1], pos[1]);
return done(); done();
}); });
return w.setPosition(pos[0], pos[1]); w.setPosition(pos[0], pos[1]);
}); });
}); });
describe('BrowserWindow.setContentSize(width, height)', function() { describe('BrowserWindow.setContentSize(width, height)', function() {
it('sets the content size', function() { it('sets the content size', function() {
var after, size; var after, size;
@ -171,9 +184,10 @@ describe('browser-window module', function() {
w.setContentSize(size[0], size[1]); w.setContentSize(size[0], size[1]);
after = w.getContentSize(); after = w.getContentSize();
assert.equal(after[0], size[0]); assert.equal(after[0], size[0]);
return assert.equal(after[1], size[1]); assert.equal(after[1], size[1]);
}); });
return it('works for framless window', function() {
it('works for framless window', function() {
var after, size; var after, size;
w.destroy(); w.destroy();
w = new BrowserWindow({ w = new BrowserWindow({
@ -186,14 +200,16 @@ describe('browser-window module', function() {
w.setContentSize(size[0], size[1]); w.setContentSize(size[0], size[1]);
after = w.getContentSize(); after = w.getContentSize();
assert.equal(after[0], size[0]); assert.equal(after[0], size[0]);
return assert.equal(after[1], size[1]); assert.equal(after[1], size[1]);
}); });
}); });
describe('BrowserWindow.fromId(id)', function() { describe('BrowserWindow.fromId(id)', function() {
return it('returns the window with id', function() { it('returns the window with id', function() {
return assert.equal(w.id, BrowserWindow.fromId(w.id).id); assert.equal(w.id, BrowserWindow.fromId(w.id).id);
}); });
}); });
describe('"useContentSize" option', function() { describe('"useContentSize" option', function() {
it('make window created with content size when used', function() { it('make window created with content size when used', function() {
var contentSize; var contentSize;
@ -206,15 +222,16 @@ describe('browser-window module', function() {
}); });
contentSize = w.getContentSize(); contentSize = w.getContentSize();
assert.equal(contentSize[0], 400); assert.equal(contentSize[0], 400);
return assert.equal(contentSize[1], 400); assert.equal(contentSize[1], 400);
}); });
it('make window created with window size when not used', function() { it('make window created with window size when not used', function() {
var size; var size = w.getSize();
size = w.getSize();
assert.equal(size[0], 400); assert.equal(size[0], 400);
return assert.equal(size[1], 400); assert.equal(size[1], 400);
}); });
return it('works for framless window', function() {
it('works for framless window', function() {
var contentSize, size; var contentSize, size;
w.destroy(); w.destroy();
w = new BrowserWindow({ w = new BrowserWindow({
@ -229,9 +246,10 @@ describe('browser-window module', function() {
assert.equal(contentSize[1], 400); assert.equal(contentSize[1], 400);
size = w.getSize(); size = w.getSize();
assert.equal(size[0], 400); assert.equal(size[0], 400);
return assert.equal(size[1], 400); assert.equal(size[1], 400);
}); });
}); });
describe('"title-bar-style" option', function() { describe('"title-bar-style" option', function() {
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
return; return;
@ -239,6 +257,7 @@ describe('browser-window module', function() {
if (parseInt(os.release().split('.')[0]) < 14) { if (parseInt(os.release().split('.')[0]) < 14) {
return; return;
} }
it('creates browser window with hidden title bar', function() { it('creates browser window with hidden title bar', function() {
var contentSize; var contentSize;
w.destroy(); w.destroy();
@ -249,9 +268,10 @@ describe('browser-window module', function() {
titleBarStyle: 'hidden' titleBarStyle: 'hidden'
}); });
contentSize = w.getContentSize(); contentSize = w.getContentSize();
return assert.equal(contentSize[1], 400); assert.equal(contentSize[1], 400);
}); });
return it('creates browser window with hidden inset title bar', function() {
it('creates browser window with hidden inset title bar', function() {
var contentSize; var contentSize;
w.destroy(); w.destroy();
w = new BrowserWindow({ w = new BrowserWindow({
@ -261,30 +281,34 @@ describe('browser-window module', function() {
titleBarStyle: 'hidden-inset' titleBarStyle: 'hidden-inset'
}); });
contentSize = w.getContentSize(); contentSize = w.getContentSize();
return assert.equal(contentSize[1], 400); assert.equal(contentSize[1], 400);
}); });
}); });
describe('"enableLargerThanScreen" option', function() { describe('"enableLargerThanScreen" option', function() {
if (process.platform === 'linux') { if (process.platform === 'linux') {
return; return;
} }
beforeEach(function() { beforeEach(function() {
w.destroy(); w.destroy();
return w = new BrowserWindow({ w = new BrowserWindow({
show: true, show: true,
width: 400, width: 400,
height: 400, height: 400,
enableLargerThanScreen: true enableLargerThanScreen: true
}); });
}); });
it('can move the window out of screen', function() { it('can move the window out of screen', function() {
var after; var after;
w.setPosition(-10, -10); w.setPosition(-10, -10);
after = w.getPosition(); after = w.getPosition();
assert.equal(after[0], -10); assert.equal(after[0], -10);
return assert.equal(after[1], -10); assert.equal(after[1], -10);
}); });
return it('can set the window larger than screen', function() {
it('can set the window larger than screen', function() {
var after, size; var after, size;
size = screen.getPrimaryDisplay().size; size = screen.getPrimaryDisplay().size;
size.width += 100; size.width += 100;
@ -292,21 +316,22 @@ describe('browser-window module', function() {
w.setSize(size.width, size.height); w.setSize(size.width, size.height);
after = w.getSize(); after = w.getSize();
assert.equal(after[0], size.width); assert.equal(after[0], size.width);
return assert.equal(after[1], size.height); assert.equal(after[1], size.height);
}); });
}); });
describe('"web-preferences" option', function() { describe('"web-preferences" option', function() {
afterEach(function() { afterEach(function() {
return ipcMain.removeAllListeners('answer'); ipcMain.removeAllListeners('answer');
}); });
describe('"preload" option', function() { describe('"preload" option', function() {
return it('loads the script before other scripts in window', function(done) { it('loads the script before other scripts in window', function(done) {
var preload; var preload;
preload = path.join(fixtures, 'module', 'set-global.js'); preload = path.join(fixtures, 'module', 'set-global.js');
ipcMain.once('answer', function(event, test) { ipcMain.once('answer', function(event, test) {
assert.equal(test, 'preload'); assert.equal(test, 'preload');
return done(); done();
}); });
w.destroy(); w.destroy();
w = new BrowserWindow({ w = new BrowserWindow({
@ -315,16 +340,17 @@ describe('browser-window module', function() {
preload: preload preload: preload
} }
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'preload.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'preload.html'));
}); });
}); });
return describe('"node-integration" option', function() {
return it('disables node integration when specified to false', function(done) { describe('"node-integration" option', function() {
it('disables node integration when specified to false', function(done) {
var preload; var preload;
preload = path.join(fixtures, 'module', 'send-later.js'); preload = path.join(fixtures, 'module', 'send-later.js');
ipcMain.once('answer', function(event, test) { ipcMain.once('answer', function(event, test) {
assert.equal(test, 'undefined'); assert.equal(test, 'undefined');
return done(); done();
}); });
w.destroy(); w.destroy();
w = new BrowserWindow({ w = new BrowserWindow({
@ -334,107 +360,121 @@ describe('browser-window module', function() {
nodeIntegration: false nodeIntegration: false
} }
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'blank.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'blank.html'));
}); });
}); });
}); });
describe('beforeunload handler', function() { describe('beforeunload handler', function() {
it('returning true would not prevent close', function(done) { it('returning true would not prevent close', function(done) {
w.on('closed', function() { w.on('closed', function() {
return done(); done();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-true.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-true.html'));
}); });
it('returning non-empty string would not prevent close', function(done) { it('returning non-empty string would not prevent close', function(done) {
w.on('closed', function() { w.on('closed', function() {
return done(); done();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-string.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-string.html'));
}); });
it('returning false would prevent close', function(done) { it('returning false would prevent close', function(done) {
w.on('onbeforeunload', function() { w.on('onbeforeunload', function() {
return done(); done();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html'));
}); });
return it('returning empty string would prevent close', function(done) {
it('returning empty string would prevent close', function(done) {
w.on('onbeforeunload', function() { w.on('onbeforeunload', function() {
return done(); done();
}); });
return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html')); w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html'));
}); });
}); });
describe('new-window event', function() { describe('new-window event', function() {
if (isCI && process.platform === 'darwin') { if (isCI && process.platform === 'darwin') {
return; return;
} }
it('emits when window.open is called', function(done) { it('emits when window.open is called', function(done) {
w.webContents.once('new-window', function(e, url, frameName) { w.webContents.once('new-window', function(e, url, frameName) {
e.preventDefault(); e.preventDefault();
assert.equal(url, 'http://host/'); assert.equal(url, 'http://host/');
assert.equal(frameName, 'host'); assert.equal(frameName, 'host');
return done(); done();
}); });
return w.loadURL("file://" + fixtures + "/pages/window-open.html"); w.loadURL("file://" + fixtures + "/pages/window-open.html");
}); });
return it('emits when link with target is called', function(done) {
it('emits when link with target is called', function(done) {
this.timeout(10000); this.timeout(10000);
w.webContents.once('new-window', function(e, url, frameName) { w.webContents.once('new-window', function(e, url, frameName) {
e.preventDefault(); e.preventDefault();
assert.equal(url, 'http://host/'); assert.equal(url, 'http://host/');
assert.equal(frameName, 'target'); assert.equal(frameName, 'target');
return done(); done();
}); });
return w.loadURL("file://" + fixtures + "/pages/target-name.html"); w.loadURL("file://" + fixtures + "/pages/target-name.html");
}); });
}); });
describe('maximize event', function() { describe('maximize event', function() {
if (isCI) { if (isCI) {
return; return;
} }
return it('emits when window is maximized', function(done) {
it('emits when window is maximized', function(done) {
this.timeout(10000); this.timeout(10000);
w.once('maximize', function() { w.once('maximize', function() {
return done(); done();
}); });
w.show(); w.show();
return w.maximize(); w.maximize();
}); });
}); });
describe('unmaximize event', function() { describe('unmaximize event', function() {
if (isCI) { if (isCI) {
return; return;
} }
return it('emits when window is unmaximized', function(done) {
it('emits when window is unmaximized', function(done) {
this.timeout(10000); this.timeout(10000);
w.once('unmaximize', function() { w.once('unmaximize', function() {
return done(); done();
}); });
w.show(); w.show();
w.maximize(); w.maximize();
return w.unmaximize(); w.unmaximize();
}); });
}); });
describe('minimize event', function() { describe('minimize event', function() {
if (isCI) { if (isCI) {
return; return;
} }
return it('emits when window is minimized', function(done) {
it('emits when window is minimized', function(done) {
this.timeout(10000); this.timeout(10000);
w.once('minimize', function() { w.once('minimize', function() {
return done(); done();
}); });
w.show(); w.show();
return w.minimize(); w.minimize();
}); });
}); });
xdescribe('beginFrameSubscription method', function() { xdescribe('beginFrameSubscription method', function() {
return it('subscribes frame updates', function(done) { it('subscribes frame updates', function(done) {
w.loadURL("file://" + fixtures + "/api/blank.html"); w.loadURL("file://" + fixtures + "/api/blank.html");
return w.webContents.beginFrameSubscription(function(data) { w.webContents.beginFrameSubscription(function(data) {
assert.notEqual(data.length, 0); assert.notEqual(data.length, 0);
w.webContents.endFrameSubscription(); w.webContents.endFrameSubscription();
return done(); done();
}); });
}); });
}); });
@ -472,13 +512,13 @@ describe('browser-window module', function() {
}); });
describe('BrowserWindow options argument is optional', function() { describe('BrowserWindow options argument is optional', function() {
return it('should create a window with default size (800x600)', function() { it('should create a window with default size (800x600)', function() {
var size; var size;
w.destroy(); w.destroy();
w = new BrowserWindow(); w = new BrowserWindow();
size = w.getSize(); size = w.getSize();
assert.equal(size[0], 800); assert.equal(size[0], 800);
return assert.equal(size[1], 600); assert.equal(size[1], 600);
}); });
}); });
@ -618,4 +658,16 @@ describe('browser-window module', function() {
}); });
}); });
}); });
describe('window.webContents.send(channel, args...)', function() {
it('throws an error when the channel is missing', function() {
assert.throws(function() {
w.webContents.send();
}, 'Missing required channel argument');
assert.throws(function() {
w.webContents.send(null);
}, 'Missing required channel argument');
});
});
}); });