diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index c1e831d59037..cf241bccbc71 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -13,6 +13,7 @@ import { promisify } from 'util'; import { ifit, ifdescribe, defer, delay } from './spec-helpers'; import { AddressInfo } from 'net'; import { PipeTransport } from './pipe-transport'; +import * as ws from 'ws'; const features = process._linkedBinding('electron_common_features'); @@ -678,13 +679,7 @@ describe('chromium features', () => { }); }); - describe('navigator.geolocation', () => { - before(function () { - if (!features.isFakeLocationProviderEnabled()) { - return this.skip(); - } - }); - + ifdescribe(features.isFakeLocationProviderEnabled())('navigator.geolocation', () => { it('returns error when permission is denied', async () => { const w = new BrowserWindow({ show: false, @@ -706,6 +701,17 @@ describe('chromium features', () => { const [, channel] = await message; expect(channel).to.equal('success', 'unexpected response from geolocation api'); }); + + it('returns position when permission is granted', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const position = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => + navigator.geolocation.getCurrentPosition( + x => resolve({coords: x.coords, timestamp: x.timestamp}), + reject))`); + expect(position).to.have.property('coords'); + expect(position).to.have.property('timestamp'); + }); }); describe('web workers', () => { @@ -726,6 +732,68 @@ describe('chromium features', () => { const [code] = await emittedOnce(appProcess, 'exit'); expect(code).to.equal(0); }); + + it('Worker can work', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new Worker('../workers/worker.js'); + const message = 'ping'; + const eventPromise = new Promise((resolve) => { worker.onmessage = resolve; }); + worker.postMessage(message); + eventPromise.then(t => t.data) + `); + expect(data).to.equal('ping'); + }); + + it('Worker has no node integration by default', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new Worker('../workers/worker_node.js'); + new Promise((resolve) => { worker.onmessage = e => resolve(e.data); }) + `); + expect(data).to.equal('undefined undefined undefined undefined'); + }); + + it('Worker has node integration with nodeIntegrationInWorker', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nodeIntegrationInWorker: true, contextIsolation: false } }); + w.loadURL(`file://${fixturesPath}/pages/worker.html`); + const [, data] = await emittedOnce(ipcMain, 'worker-result'); + expect(data).to.equal('object function object function'); + }); + + describe('SharedWorker', () => { + it('can work', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new SharedWorker('../workers/shared_worker.js'); + const message = 'ping'; + const eventPromise = new Promise((resolve) => { worker.port.onmessage = e => resolve(e.data); }); + worker.port.postMessage(message); + eventPromise + `); + expect(data).to.equal('ping'); + }); + + it('has no node integration by default', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new SharedWorker('../workers/shared_worker_node.js'); + new Promise((resolve) => { worker.port.onmessage = e => resolve(e.data); }) + `); + expect(data).to.equal('undefined undefined undefined undefined'); + }); + + it('has node integration with nodeIntegrationInWorker', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nodeIntegrationInWorker: true, contextIsolation: false } }); + w.loadURL(`file://${fixturesPath}/pages/shared_worker.html`); + const [, data] = await emittedOnce(ipcMain, 'worker-result'); + expect(data).to.equal('object function object function'); + }); + }); }); describe('form submit', () => { @@ -1613,6 +1681,116 @@ describe('chromium features', () => { }); }); }); + + describe('Badging API', () => { + it('does not crash', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + await w.webContents.executeJavaScript('navigator.setAppBadge(42)'); + await w.webContents.executeJavaScript('navigator.setAppBadge()'); + await w.webContents.executeJavaScript('navigator.clearAppBadge()'); + }); + }); + + describe('navigator.webkitGetUserMedia', () => { + it('calls its callbacks', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + await w.webContents.executeJavaScript(`new Promise((resolve) => { + navigator.webkitGetUserMedia({ + audio: true, + video: false + }, () => resolve(), + () => resolve()); + })`); + }); + }); + + describe('navigator.language', () => { + it('should not be empty', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL('about:blank'); + expect(await w.webContents.executeJavaScript('navigator.language')).to.not.equal(''); + }); + }); + + describe('heap snapshot', () => { + it('does not crash', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await w.webContents.executeJavaScript('process._linkedBinding(\'electron_common_v8_util\').takeHeapSnapshot()'); + }); + }); + + ifdescribe(process.platform !== 'win32' && process.platform !== 'linux')('webgl', () => { + it('can be gotten as context in canvas', async () => { + const w = new BrowserWindow({ show: false }); + w.loadURL('about:blank'); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const canWebglContextBeCreated = await w.webContents.executeJavaScript(` + document.createElement('canvas').getContext('webgl') != null; + `); + expect(canWebglContextBeCreated).to.be.true(); + }); + }); + + describe('iframe', () => { + it('does not have node integration', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const result = await w.webContents.executeJavaScript(` + const iframe = document.createElement('iframe') + iframe.src = './set-global.html'; + document.body.appendChild(iframe); + new Promise(resolve => iframe.onload = e => resolve(iframe.contentWindow.test)) + `); + expect(result).to.equal('undefined undefined undefined'); + }); + }); + + describe('websockets', () => { + it('has user agent', async () => { + const server = http.createServer(); + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); + const port = (server.address() as AddressInfo).port; + const wss = new ws.Server({ server: server }); + const finished = new Promise((resolve, reject) => { + wss.on('error', reject); + wss.on('connection', (ws, upgradeReq) => { + resolve(upgradeReq.headers['user-agent']); + }); + }); + const w = new BrowserWindow({ show: false }); + w.loadURL('about:blank'); + w.webContents.executeJavaScript(` + new WebSocket('ws://127.0.0.1:${port}'); + `); + expect(await finished).to.include('Electron'); + }); + }); + + describe('fetch', () => { + it('does not crash', async () => { + const server = http.createServer((req, res) => { + res.end('test'); + }); + defer(() => server.close()); + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); + const port = (server.address() as AddressInfo).port; + const w = new BrowserWindow({ show: false }); + w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const x = await w.webContents.executeJavaScript(` + fetch('http://127.0.0.1:${port}').then((res) => res.body.getReader()) + .then((reader) => { + return reader.read().then((r) => { + reader.cancel(); + return r.value; + }); + }) + `); + expect(x).to.deep.equal(new Uint8Array([116, 101, 115, 116])); + }); + }); }); describe('font fallback', () => { diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 154dffaff8eb..0ae511ac5985 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -2,7 +2,6 @@ const { expect } = require('chai'); const fs = require('fs'); const http = require('http'); const path = require('path'); -const ws = require('ws'); const url = require('url'); const ChildProcess = require('child_process'); const { ipcRenderer } = require('electron'); @@ -16,51 +15,6 @@ const features = process._linkedBinding('electron_common_features'); describe('chromium feature', () => { const fixtures = path.resolve(__dirname, 'fixtures'); - describe('Badging API', () => { - it('does not crash', () => { - expect(() => { - navigator.setAppBadge(42); - }).to.not.throw(); - expect(() => { - // setAppBadge with no argument should show dot - navigator.setAppBadge(); - }).to.not.throw(); - expect(() => { - navigator.clearAppBadge(); - }).to.not.throw(); - }); - }); - - describe('heap snapshot', () => { - it('does not crash', function () { - process._linkedBinding('electron_common_v8_util').takeHeapSnapshot(); - }); - }); - - describe('navigator.webkitGetUserMedia', () => { - it('calls its callbacks', (done) => { - navigator.webkitGetUserMedia({ - audio: true, - video: false - }, () => done(), - () => done()); - }); - }); - - describe('navigator.language', () => { - it('should not be empty', () => { - expect(navigator.language).to.not.equal(''); - }); - }); - - ifdescribe(features.isFakeLocationProviderEnabled())('navigator.geolocation', () => { - it('returns position when permission is granted', async () => { - const position = await new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject)); - expect(position).to.have.a.property('coords'); - expect(position).to.have.a.property('timestamp'); - }); - }); - describe('window.open', () => { it('inherit options of parent window', async () => { const message = waitForEvent(window, 'message'); @@ -208,105 +162,6 @@ describe('chromium feature', () => { }); }); - describe('webgl', () => { - before(function () { - if (process.platform === 'win32') { - this.skip(); - } - }); - - it('can be get as context in canvas', () => { - if (process.platform === 'linux') { - // FIXME(alexeykuzmin): Skip the test. - // this.skip() - return; - } - - const webgl = document.createElement('canvas').getContext('webgl'); - expect(webgl).to.not.be.null(); - }); - }); - - describe('web workers', () => { - it('Worker can work', async () => { - const worker = new Worker('../fixtures/workers/worker.js'); - const message = 'ping'; - const eventPromise = new Promise((resolve) => { worker.onmessage = resolve; }); - worker.postMessage(message); - const event = await eventPromise; - worker.terminate(); - expect(event.data).to.equal(message); - }); - - it('Worker has no node integration by default', async () => { - const worker = new Worker('../fixtures/workers/worker_node.js'); - const event = await new Promise((resolve) => { worker.onmessage = resolve; }); - worker.terminate(); - expect(event.data).to.equal('undefined undefined undefined undefined'); - }); - - it('Worker has node integration with nodeIntegrationInWorker', async () => { - const webview = new WebView(); - const eventPromise = waitForEvent(webview, 'ipc-message'); - webview.src = `file://${fixtures}/pages/worker.html`; - webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker, contextIsolation=no'); - document.body.appendChild(webview); - const event = await eventPromise; - webview.remove(); - expect(event.channel).to.equal('object function object function'); - }); - - describe('SharedWorker', () => { - it('can work', async () => { - const worker = new SharedWorker('../fixtures/workers/shared_worker.js'); - const message = 'ping'; - const eventPromise = new Promise((resolve) => { worker.port.onmessage = resolve; }); - worker.port.postMessage(message); - const event = await eventPromise; - expect(event.data).to.equal(message); - }); - - it('has no node integration by default', async () => { - const worker = new SharedWorker('../fixtures/workers/shared_worker_node.js'); - const event = await new Promise((resolve) => { worker.port.onmessage = resolve; }); - expect(event.data).to.equal('undefined undefined undefined undefined'); - }); - - it('has node integration with nodeIntegrationInWorker', async () => { - const webview = new WebView(); - webview.addEventListener('console-message', (e) => { - console.log(e); - }); - const eventPromise = waitForEvent(webview, 'ipc-message'); - webview.src = `file://${fixtures}/pages/shared_worker.html`; - webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker, contextIsolation=no'); - document.body.appendChild(webview); - const event = await eventPromise; - webview.remove(); - expect(event.channel).to.equal('object function object function'); - }); - }); - }); - - describe('iframe', () => { - let iframe = null; - - beforeEach(() => { - iframe = document.createElement('iframe'); - }); - - afterEach(() => { - document.body.removeChild(iframe); - }); - - it('does not have node integration', async () => { - iframe.src = `file://${fixtures}/pages/set-global.html`; - document.body.appendChild(iframe); - await waitForEvent(iframe, 'load'); - expect(iframe.contentWindow.test).to.equal('undefined undefined undefined'); - }); - }); - describe('storage', () => { describe('DOM storage quota increase', () => { ['localStorage', 'sessionStorage'].forEach((storageName) => { @@ -357,34 +212,6 @@ describe('chromium feature', () => { }); }); - describe('websockets', () => { - let wss = null; - let server = null; - const WebSocketServer = ws.Server; - - afterEach(() => { - wss.close(); - server.close(); - }); - - it('has user agent', (done) => { - server = http.createServer(); - server.listen(0, '127.0.0.1', () => { - const port = server.address().port; - wss = new WebSocketServer({ server: server }); - wss.on('error', done); - wss.on('connection', (ws, upgradeReq) => { - if (upgradeReq.headers['user-agent']) { - done(); - } else { - done('user agent is empty'); - } - }); - const socket = new WebSocket(`ws://127.0.0.1:${port}`); - }); - }); - }); - describe('Promise', () => { it('resolves correctly in Node.js calls', (done) => { class XElement extends HTMLElement {} @@ -413,25 +240,6 @@ describe('chromium feature', () => { }); }); - describe('fetch', () => { - it('does not crash', (done) => { - const server = http.createServer((req, res) => { - res.end('test'); - server.close(); - }); - server.listen(0, '127.0.0.1', () => { - const port = server.address().port; - fetch(`http://127.0.0.1:${port}`).then((res) => res.body.getReader()) - .then((reader) => { - reader.read().then((r) => { - reader.cancel(); - done(); - }); - }).catch((e) => done(e)); - }); - }); - }); - describe('window.alert(message, title)', () => { it('throws an exception when the arguments cannot be converted to strings', () => { expect(() => { diff --git a/spec/fixtures/pages/shared_worker.html b/spec/fixtures/pages/shared_worker.html index 7a0d0757ab26..5bd409d857b9 100644 --- a/spec/fixtures/pages/shared_worker.html +++ b/spec/fixtures/pages/shared_worker.html @@ -5,7 +5,7 @@ // Pass a random parameter to create independent worker. let worker = new SharedWorker(`../workers/shared_worker_node.js?a={Math.random()}`) worker.port.onmessage = function (event) { - ipcRenderer.sendToHost(event.data) + ipcRenderer.send('worker-result', event.data) } diff --git a/spec/fixtures/pages/worker.html b/spec/fixtures/pages/worker.html index c84ef52065e0..95aceac6c08a 100644 --- a/spec/fixtures/pages/worker.html +++ b/spec/fixtures/pages/worker.html @@ -4,7 +4,7 @@ const {ipcRenderer} = require('electron') let worker = new Worker(`../workers/worker_node.js`) worker.onmessage = function (event) { - ipcRenderer.sendToHost(event.data) + ipcRenderer.send('worker-result', event.data) worker.terminate() }