|
@@ -1,12 +1,15 @@
|
|
|
import { expect } from 'chai';
|
|
|
-import { app, session, BrowserWindow, ipcMain, WebContents, Extension } from 'electron/main';
|
|
|
+import { app, session, BrowserWindow, ipcMain, WebContents, Extension, Session } from 'electron/main';
|
|
|
import { closeAllWindows, closeWindow } from './window-helpers';
|
|
|
import * as http from 'http';
|
|
|
import { AddressInfo } from 'net';
|
|
|
import * as path from 'path';
|
|
|
import * as fs from 'fs';
|
|
|
+import * as WebSocket from 'ws';
|
|
|
import { emittedOnce, emittedNTimes } from './events-helpers';
|
|
|
|
|
|
+const uuid = require('uuid');
|
|
|
+
|
|
|
const fixtures = path.join(__dirname, 'fixtures');
|
|
|
|
|
|
describe('chrome extensions', () => {
|
|
@@ -15,6 +18,7 @@ describe('chrome extensions', () => {
|
|
|
// NB. extensions are only allowed on http://, https:// and ftp:// (!) urls by default.
|
|
|
let server: http.Server;
|
|
|
let url: string;
|
|
|
+ let port: string;
|
|
|
before(async () => {
|
|
|
server = http.createServer((req, res) => {
|
|
|
if (req.url === '/cors') {
|
|
@@ -22,8 +26,19 @@ describe('chrome extensions', () => {
|
|
|
}
|
|
|
res.end(emptyPage);
|
|
|
});
|
|
|
+
|
|
|
+ const wss = new WebSocket.Server({ noServer: true });
|
|
|
+ wss.on('connection', function connection (ws) {
|
|
|
+ ws.on('message', function incoming (message) {
|
|
|
+ if (message === 'foo') {
|
|
|
+ ws.send('bar');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
await new Promise(resolve => server.listen(0, '127.0.0.1', () => {
|
|
|
- url = `http://127.0.0.1:${(server.address() as AddressInfo).port}`;
|
|
|
+ port = String((server.address() as AddressInfo).port);
|
|
|
+ url = `http://127.0.0.1:${port}`;
|
|
|
resolve();
|
|
|
}));
|
|
|
});
|
|
@@ -84,7 +99,7 @@ describe('chrome extensions', () => {
|
|
|
// extension registry is redirected to the main session. so installing an
|
|
|
// extension in an in-memory session results in it being installed in the
|
|
|
// default session.
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
|
|
await w.loadURL(url);
|
|
@@ -95,7 +110,7 @@ describe('chrome extensions', () => {
|
|
|
it('serializes a loaded extension', async () => {
|
|
|
const extensionPath = path.join(fixtures, 'extensions', 'red-bg');
|
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(extensionPath, 'manifest.json'), 'utf-8'));
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
const extension = await customSession.loadExtension(extensionPath);
|
|
|
expect(extension.id).to.be.a('string');
|
|
|
expect(extension.name).to.be.a('string');
|
|
@@ -106,7 +121,7 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('removes an extension', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
const { id } = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
|
|
|
{
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
|
@@ -141,7 +156,7 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('lists loaded extensions in getAllExtensions', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
const e = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
|
|
|
expect(customSession.getAllExtensions()).to.deep.equal([e]);
|
|
|
customSession.removeExtension(e.id);
|
|
@@ -149,13 +164,13 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('gets an extension by id', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
const e = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
|
|
|
expect(customSession.getExtension(e.id)).to.deep.equal(e);
|
|
|
});
|
|
|
|
|
|
it('confines an extension to the session it was loaded in', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
|
|
|
const w = new BrowserWindow({ show: false }); // not in the session
|
|
|
await w.loadURL(url);
|
|
@@ -164,7 +179,7 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('loading an extension in a temporary session throws an error', async () => {
|
|
|
- const customSession = session.fromPartition(require('uuid').v4());
|
|
|
+ const customSession = session.fromPartition(uuid.v4());
|
|
|
await expect(customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'))).to.eventually.be.rejectedWith('Extensions cannot be loaded in a temporary session');
|
|
|
});
|
|
|
|
|
@@ -178,7 +193,7 @@ describe('chrome extensions', () => {
|
|
|
return result;
|
|
|
};
|
|
|
beforeEach(async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-i18n'));
|
|
|
w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
|
|
await w.loadURL(url);
|
|
@@ -203,7 +218,7 @@ describe('chrome extensions', () => {
|
|
|
return result;
|
|
|
};
|
|
|
beforeEach(async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-runtime'));
|
|
|
w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
|
|
await w.loadURL(url);
|
|
@@ -231,7 +246,7 @@ describe('chrome extensions', () => {
|
|
|
|
|
|
describe('chrome.storage', () => {
|
|
|
it('stores and retrieves a key', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-storage'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
|
|
try {
|
|
@@ -245,9 +260,75 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ describe('chrome.webRequest', () => {
|
|
|
+ function fetch (contents: WebContents, url: string) {
|
|
|
+ return contents.executeJavaScript(`fetch(${JSON.stringify(url)})`);
|
|
|
+ }
|
|
|
+
|
|
|
+ let customSession: Session;
|
|
|
+ let w: BrowserWindow;
|
|
|
+
|
|
|
+ beforeEach(() => {
|
|
|
+ customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
+ w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true, contextIsolation: true } });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('onBeforeRequest', () => {
|
|
|
+ it('can cancel http requests', async () => {
|
|
|
+ await w.loadURL(url);
|
|
|
+ await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-webRequest'));
|
|
|
+ await expect(fetch(w.webContents, url)).to.eventually.be.rejectedWith(TypeError);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('does not cancel http requests when no extension loaded', async () => {
|
|
|
+ await w.loadURL(url);
|
|
|
+ await expect(fetch(w.webContents, url)).to.not.be.rejectedWith(TypeError);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it('does not take precedence over Electron webRequest - http', async () => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ (async () => {
|
|
|
+ customSession.webRequest.onBeforeRequest((details, callback) => {
|
|
|
+ resolve();
|
|
|
+ callback({ cancel: true });
|
|
|
+ });
|
|
|
+ await w.loadURL(url);
|
|
|
+
|
|
|
+ await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-webRequest'));
|
|
|
+ fetch(w.webContents, url);
|
|
|
+ })();
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it('does not take precedence over Electron webRequest - WebSocket', () => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ (async () => {
|
|
|
+ customSession.webRequest.onBeforeSendHeaders(() => {
|
|
|
+ resolve();
|
|
|
+ });
|
|
|
+ await w.loadFile(path.join(fixtures, 'api', 'webrequest.html'), { query: { port } });
|
|
|
+ await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-webRequest-wss'));
|
|
|
+ })();
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('WebSocket', () => {
|
|
|
+ it('can be proxied', async () => {
|
|
|
+ await w.loadFile(path.join(fixtures, 'api', 'webrequest.html'), { query: { port } });
|
|
|
+ await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-webRequest-wss'));
|
|
|
+ customSession.webRequest.onSendHeaders((details) => {
|
|
|
+ if (details.url.startsWith('ws://')) {
|
|
|
+ expect(details.requestHeaders.foo).be.equal('bar');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
describe('chrome.tabs', () => {
|
|
|
it('executeScript', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-api'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
|
|
await w.loadURL(url);
|
|
@@ -262,12 +343,12 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('connect', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-api'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
|
|
await w.loadURL(url);
|
|
|
|
|
|
- const portName = require('uuid').v4();
|
|
|
+ const portName = uuid.v4();
|
|
|
const message = { method: 'connectTab', args: [portName] };
|
|
|
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
|
|
|
|
|
@@ -278,7 +359,7 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('sendMessage receives the response', async function () {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-api'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
|
|
await w.loadURL(url);
|
|
@@ -296,7 +377,7 @@ describe('chrome extensions', () => {
|
|
|
|
|
|
describe('background pages', () => {
|
|
|
it('loads a lazy background page when sending a message', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'lazy-background-page'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
|
|
try {
|
|
@@ -312,7 +393,7 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('can use extension.getBackgroundPage from a ui page', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
const { id } = await customSession.loadExtension(path.join(fixtures, 'extensions', 'lazy-background-page'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
|
|
await w.loadURL(`chrome-extension://${id}/page-get-background.html`);
|
|
@@ -321,7 +402,7 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('can use extension.getBackgroundPage from a ui page', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
const { id } = await customSession.loadExtension(path.join(fixtures, 'extensions', 'lazy-background-page'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
|
|
await w.loadURL(`chrome-extension://${id}/page-get-background.html`);
|
|
@@ -330,7 +411,7 @@ describe('chrome extensions', () => {
|
|
|
});
|
|
|
|
|
|
it('can use runtime.getBackgroundPage from a ui page', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
const { id } = await customSession.loadExtension(path.join(fixtures, 'extensions', 'lazy-background-page'));
|
|
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
|
|
await w.loadURL(`chrome-extension://${id}/page-runtime-get-background.html`);
|
|
@@ -390,7 +471,7 @@ describe('chrome extensions', () => {
|
|
|
};
|
|
|
|
|
|
it('loads a devtools extension', async () => {
|
|
|
- const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
|
|
+ const customSession = session.fromPartition(`persist:${uuid.v4()}`);
|
|
|
customSession.loadExtension(path.join(fixtures, 'extensions', 'devtools-extension'));
|
|
|
const winningMessage = emittedOnce(ipcMain, 'winning');
|
|
|
const w = new BrowserWindow({ show: true, webPreferences: { session: customSession, nodeIntegration: true } });
|