test: use node helpers for events.once and setTimeout promise (#37374)

This commit is contained in:
Jeremy Rose 2023-02-23 15:53:53 -08:00 committed by GitHub
parent 46c8b9c728
commit a3e3efe4c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 932 additions and 927 deletions

View file

@ -7,9 +7,9 @@ import * as fs from 'fs-extra';
import * as path from 'path';
import { promisify } from 'util';
import { app, BrowserWindow, Menu, session, net as electronNet } from 'electron/main';
import { emittedOnce } from './lib/events-helpers';
import { closeWindow, closeAllWindows } from './lib/window-helpers';
import { ifdescribe, ifit, listen, waitUntil } from './lib/spec-helpers';
import { once } from 'events';
import split = require('split')
const fixturesPath = path.resolve(__dirname, 'fixtures');
@ -169,7 +169,7 @@ describe('app module', () => {
if (appProcess && appProcess.stdout) {
appProcess.stdout.on('data', data => { output += data; });
}
const [code] = await emittedOnce(appProcess, 'exit');
const [code] = await once(appProcess, 'exit');
if (process.platform !== 'win32') {
expect(output).to.include('Exit event with code: 123');
@ -182,7 +182,7 @@ describe('app module', () => {
const electronPath = process.execPath;
appProcess = cp.spawn(electronPath, [appPath]);
const [code, signal] = await emittedOnce(appProcess, 'exit');
const [code, signal] = await once(appProcess, 'exit');
expect(signal).to.equal(null, 'exit signal should be null, if you see this please tag @MarshallOfSound');
expect(code).to.equal(123, 'exit code should be 123, if you see this please tag @MarshallOfSound');
@ -203,7 +203,7 @@ describe('app module', () => {
if (appProcess && appProcess.stdout) {
appProcess.stdout.on('data', () => appProcess!.kill());
}
const [code, signal] = await emittedOnce(appProcess, 'exit');
const [code, signal] = await once(appProcess, 'exit');
const message = `code:\n${code}\nsignal:\n${signal}`;
expect(code).to.equal(0, message);
@ -229,37 +229,37 @@ describe('app module', () => {
this.timeout(120000);
const appPath = path.join(fixturesPath, 'api', 'singleton-data');
const first = cp.spawn(process.execPath, [appPath]);
await emittedOnce(first.stdout, 'data');
await once(first.stdout, 'data');
// Start second app when received output.
const second = cp.spawn(process.execPath, [appPath]);
const [code2] = await emittedOnce(second, 'exit');
const [code2] = await once(second, 'exit');
expect(code2).to.equal(1);
const [code1] = await emittedOnce(first, 'exit');
const [code1] = await once(first, 'exit');
expect(code1).to.equal(0);
});
it('returns true when setting non-existent user data folder', async function () {
const appPath = path.join(fixturesPath, 'api', 'singleton-userdata');
const instance = cp.spawn(process.execPath, [appPath]);
const [code] = await emittedOnce(instance, 'exit');
const [code] = await once(instance, 'exit');
expect(code).to.equal(0);
});
async function testArgumentPassing (testArgs: SingleInstanceLockTestArgs) {
const appPath = path.join(fixturesPath, 'api', 'singleton-data');
const first = cp.spawn(process.execPath, [appPath, ...testArgs.args]);
const firstExited = emittedOnce(first, 'exit');
const firstExited = once(first, 'exit');
// Wait for the first app to boot.
const firstStdoutLines = first.stdout.pipe(split());
while ((await emittedOnce(firstStdoutLines, 'data')).toString() !== 'started') {
while ((await once(firstStdoutLines, 'data')).toString() !== 'started') {
// wait.
}
const additionalDataPromise = emittedOnce(firstStdoutLines, 'data');
const additionalDataPromise = once(firstStdoutLines, 'data');
const secondInstanceArgs = [process.execPath, appPath, ...testArgs.args, '--some-switch', 'some-arg'];
const second = cp.spawn(secondInstanceArgs[0], secondInstanceArgs.slice(1));
const secondExited = emittedOnce(second, 'exit');
const secondExited = once(second, 'exit');
const [code2] = await secondExited;
expect(code2).to.equal(1);
@ -427,7 +427,7 @@ describe('app module', () => {
it('is emitted when visiting a server with a self-signed cert', async () => {
const w = new BrowserWindow({ show: false });
w.loadURL(secureUrl);
await emittedOnce(app, 'certificate-error');
await once(app, 'certificate-error');
});
describe('when denied', () => {
@ -444,7 +444,7 @@ describe('app module', () => {
it('causes did-fail-load', async () => {
const w = new BrowserWindow({ show: false });
w.loadURL(secureUrl);
await emittedOnce(w.webContents, 'did-fail-load');
await once(w.webContents, 'did-fail-load');
});
});
});
@ -506,7 +506,7 @@ describe('app module', () => {
afterEach(() => closeWindow(w).then(() => { w = null as any; }));
it('should emit browser-window-focus event when window is focused', async () => {
const emitted = emittedOnce(app, 'browser-window-focus');
const emitted = once(app, 'browser-window-focus');
w = new BrowserWindow({ show: false });
w.emit('focus');
const [, window] = await emitted;
@ -514,7 +514,7 @@ describe('app module', () => {
});
it('should emit browser-window-blur event when window is blurred', async () => {
const emitted = emittedOnce(app, 'browser-window-blur');
const emitted = once(app, 'browser-window-blur');
w = new BrowserWindow({ show: false });
w.emit('blur');
const [, window] = await emitted;
@ -522,14 +522,14 @@ describe('app module', () => {
});
it('should emit browser-window-created event when window is created', async () => {
const emitted = emittedOnce(app, 'browser-window-created');
const emitted = once(app, 'browser-window-created');
w = new BrowserWindow({ show: false });
const [, window] = await emitted;
expect(window.id).to.equal(w.id);
});
it('should emit web-contents-created event when a webContents is created', async () => {
const emitted = emittedOnce(app, 'web-contents-created');
const emitted = once(app, 'web-contents-created');
w = new BrowserWindow({ show: false });
const [, webContents] = await emitted;
expect(webContents.id).to.equal(w.webContents.id);
@ -546,7 +546,7 @@ describe('app module', () => {
});
await w.loadURL('about:blank');
const emitted = emittedOnce(app, 'renderer-process-crashed');
const emitted = once(app, 'renderer-process-crashed');
w.webContents.executeJavaScript('process.crash()');
const [, webContents] = await emitted;
@ -564,7 +564,7 @@ describe('app module', () => {
});
await w.loadURL('about:blank');
const emitted = emittedOnce(app, 'render-process-gone');
const emitted = once(app, 'render-process-gone');
w.webContents.executeJavaScript('process.crash()');
const [, webContents, details] = await emitted;
@ -890,7 +890,7 @@ describe('app module', () => {
ifit(process.platform === 'win32')('detects disabled by TaskManager', async function () {
app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: true, args: ['arg1'] });
const appProcess = cp.spawn('reg', [...regAddArgs, '030000000000000000000000']);
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(app.getLoginItemSettings()).to.deep.equal({
openAtLogin: false,
openAsHidden: false,
@ -927,12 +927,12 @@ describe('app module', () => {
app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: false, args: ['arg1'] });
let appProcess = cp.spawn('reg', [...regAddArgs, '020000000000000000000000']);
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(app.getLoginItemSettings()).to.deep.equal(expectation);
app.setLoginItemSettings({ openAtLogin: true, name: 'additionalEntry', enabled: false, args: ['arg1'] });
appProcess = cp.spawn('reg', [...regAddArgs, '000000000000000000000000']);
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(app.getLoginItemSettings()).to.deep.equal(expectation);
});
});
@ -1290,7 +1290,7 @@ describe('app module', () => {
const appPath = path.join(fixturesPath, 'api', 'quit-app');
// App should exit with non 123 code.
const first = cp.spawn(process.execPath, [appPath, 'electron-test:?', 'abc']);
const [code] = await emittedOnce(first, 'exit');
const [code] = await once(first, 'exit');
expect(code).to.not.equal(123);
});
@ -1298,7 +1298,7 @@ describe('app module', () => {
const appPath = path.join(fixturesPath, 'api', 'quit-app');
// App should exit with code 123.
const first = cp.spawn(process.execPath, [appPath, 'e:\\abc', 'abc']);
const [code] = await emittedOnce(first, 'exit');
const [code] = await once(first, 'exit');
expect(code).to.equal(123);
});
@ -1306,7 +1306,7 @@ describe('app module', () => {
const appPath = path.join(fixturesPath, 'api', 'quit-app');
// App should exit with code 123.
const first = cp.spawn(process.execPath, [appPath, '--', 'http://electronjs.org', 'electron-test://testdata']);
const [code] = await emittedOnce(first, 'exit');
const [code] = await once(first, 'exit');
expect(code).to.equal(123);
});
});
@ -1432,7 +1432,7 @@ describe('app module', () => {
appProcess.stderr.on('data', (data) => {
errorData += data;
});
const [exitCode] = await emittedOnce(appProcess, 'exit');
const [exitCode] = await once(appProcess, 'exit');
if (exitCode === 0) {
try {
const [, json] = /HERE COMES THE JSON: (.+) AND THERE IT WAS/.exec(gpuInfoData)!;
@ -1949,7 +1949,7 @@ describe('default behavior', () => {
it('should emit a login event on app when a WebContents hits a 401', async () => {
const w = new BrowserWindow({ show: false });
w.loadURL(serverUrl);
const [, webContents] = await emittedOnce(app, 'login');
const [, webContents] = await once(app, 'login');
expect(webContents).to.equal(w.webContents);
});
});
@ -1976,7 +1976,7 @@ async function runTestApp (name: string, ...args: any[]) {
let output = '';
appProcess.stdout.on('data', (data) => { output += data; });
await emittedOnce(appProcess.stdout, 'end');
await once(appProcess.stdout, 'end');
return JSON.parse(output);
}

View file

@ -1,12 +1,12 @@
import { autoUpdater } from 'electron/main';
import { expect } from 'chai';
import { ifit, ifdescribe } from './lib/spec-helpers';
import { emittedOnce } from './lib/events-helpers';
import { once } from 'events';
ifdescribe(!process.mas)('autoUpdater module', function () {
describe('checkForUpdates', function () {
ifit(process.platform === 'win32')('emits an error on Windows if the feed URL is not set', async function () {
const errorEvent = emittedOnce(autoUpdater, 'error');
const errorEvent = once(autoUpdater, 'error');
autoUpdater.setFeedURL({ url: '' });
autoUpdater.checkForUpdates();
const [error] = await errorEvent;
@ -56,7 +56,7 @@ ifdescribe(!process.mas)('autoUpdater module', function () {
ifdescribe(process.platform === 'darwin' && process.arch !== 'arm64')('on Mac', function () {
it('emits an error when the application is unsigned', async () => {
const errorEvent = emittedOnce(autoUpdater, 'error');
const errorEvent = once(autoUpdater, 'error');
autoUpdater.setFeedURL({ url: '' });
const [error] = await errorEvent;
expect(error.message).equal('Could not get code signature for running application');
@ -80,7 +80,7 @@ ifdescribe(!process.mas)('autoUpdater module', function () {
describe('quitAndInstall', () => {
ifit(process.platform === 'win32')('emits an error on Windows when no update is available', async function () {
const errorEvent = emittedOnce(autoUpdater, 'error');
const errorEvent = once(autoUpdater, 'error');
autoUpdater.quitAndInstall();
const [error] = await errorEvent;
expect(error.message).to.equal('No update available, can\'t quit and install');

View file

@ -1,10 +1,10 @@
import { expect } from 'chai';
import * as path from 'path';
import { emittedOnce } from './lib/events-helpers';
import { BrowserView, BrowserWindow, screen, webContents } from 'electron/main';
import { closeWindow } from './lib/window-helpers';
import { defer, ifit, startRemoteControlApp } from './lib/spec-helpers';
import { areColorsSimilar, captureScreen, getPixelColor } from './lib/screen-helpers';
import { once } from 'events';
describe('BrowserView module', () => {
const fixtures = path.resolve(__dirname, 'fixtures');
@ -25,13 +25,13 @@ describe('BrowserView module', () => {
});
afterEach(async () => {
const p = emittedOnce(w.webContents, 'destroyed');
const p = once(w.webContents, 'destroyed');
await closeWindow(w);
w = null as any;
await p;
if (view && view.webContents) {
const p = emittedOnce(view.webContents, 'destroyed');
const p = once(view.webContents, 'destroyed');
view.webContents.destroy();
view = null as any;
await p;
@ -231,7 +231,7 @@ describe('BrowserView module', () => {
w.addBrowserView(view);
view.webContents.loadURL('about:blank');
await emittedOnce(view.webContents, 'did-finish-load');
await once(view.webContents, 'did-finish-load');
const w2 = new BrowserWindow({ show: false });
w2.addBrowserView(view);
@ -239,7 +239,7 @@ describe('BrowserView module', () => {
w.close();
view.webContents.loadURL(`file://${fixtures}/pages/blank.html`);
await emittedOnce(view.webContents, 'did-finish-load');
await once(view.webContents, 'did-finish-load');
// Clean up - the afterEach hook assumes the webContents on w is still alive.
w = new BrowserWindow({ show: false });
@ -326,7 +326,7 @@ describe('BrowserView module', () => {
app.quit();
});
});
const [code] = await emittedOnce(rc.process, 'exit');
const [code] = await once(rc.process, 'exit');
expect(code).to.equal(0);
});
@ -342,7 +342,7 @@ describe('BrowserView module', () => {
app.quit();
});
});
const [code] = await emittedOnce(rc.process, 'exit');
const [code] = await once(rc.process, 'exit');
expect(code).to.equal(0);
});
});

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,8 @@ import { expect } from 'chai';
import { app, contentTracing, TraceConfig, TraceCategoriesAndOptions } from 'electron/main';
import * as fs from 'fs';
import * as path from 'path';
import { ifdescribe, delay } from './lib/spec-helpers';
import { setTimeout } from 'timers/promises';
import { ifdescribe } from './lib/spec-helpers';
// FIXME: The tests are skipped on arm/arm64 and ia32.
ifdescribe(!(['arm', 'arm64', 'ia32'].includes(process.arch)))('contentTracing', () => {
@ -10,7 +11,7 @@ ifdescribe(!(['arm', 'arm64', 'ia32'].includes(process.arch)))('contentTracing',
await app.whenReady();
await contentTracing.startRecording(options);
await delay(recordTimeInMilliseconds);
await setTimeout(recordTimeInMilliseconds);
const resultFilePath = await contentTracing.stopRecording(outputFilePath);
return resultFilePath;
@ -131,7 +132,7 @@ ifdescribe(!(['arm', 'arm64', 'ia32'].includes(process.arch)))('contentTracing',
let n = 0;
const f = () => {};
while (+new Date() - start < 200 || n < 500) {
await delay(0);
await setTimeout(0);
f();
n++;
}

View file

@ -8,8 +8,8 @@ import * as path from 'path';
import * as cp from 'child_process';
import { closeWindow } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { listen } from './lib/spec-helpers';
import { once } from 'events';
const fixturesPath = path.resolve(__dirname, 'fixtures', 'api', 'context-bridge');
@ -45,7 +45,8 @@ describe('contextBridge', () => {
preload: path.resolve(fixturesPath, 'can-bind-preload.js')
}
});
const [, bound] = await emittedOnce(ipcMain, 'context-bridge-bound', () => w.loadFile(path.resolve(fixturesPath, 'empty.html')));
w.loadFile(path.resolve(fixturesPath, 'empty.html'));
const [, bound] = await once(ipcMain, 'context-bridge-bound');
expect(bound).to.equal(false);
});
@ -57,7 +58,8 @@ describe('contextBridge', () => {
preload: path.resolve(fixturesPath, 'can-bind-preload.js')
}
});
const [, bound] = await emittedOnce(ipcMain, 'context-bridge-bound', () => w.loadFile(path.resolve(fixturesPath, 'empty.html')));
w.loadFile(path.resolve(fixturesPath, 'empty.html'));
const [, bound] = await once(ipcMain, 'context-bridge-bound');
expect(bound).to.equal(true);
});
@ -105,7 +107,8 @@ describe('contextBridge', () => {
const getGCInfo = async (): Promise<{
trackedValues: number;
}> => {
const [, info] = await emittedOnce(ipcMain, 'gc-info', () => w.webContents.send('get-gc-info'));
w.webContents.send('get-gc-info');
const [, info] = await once(ipcMain, 'gc-info');
return info;
};
@ -686,7 +689,7 @@ describe('contextBridge', () => {
});
require('electron').ipcRenderer.send('window-ready-for-tasking');
});
const loadPromise = emittedOnce(ipcMain, 'window-ready-for-tasking');
const loadPromise = once(ipcMain, 'window-ready-for-tasking');
expect((await getGCInfo()).trackedValues).to.equal(0);
await callWithBindings((root: any) => {
root.example.track(root.example.getFunction());
@ -1263,7 +1266,7 @@ describe('ContextBridgeMutability', () => {
let output = '';
appProcess.stdout.on('data', data => { output += data; });
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(output).to.include('some-modified-text');
expect(output).to.include('obj-modified-prop');
@ -1276,7 +1279,7 @@ describe('ContextBridgeMutability', () => {
let output = '';
appProcess.stdout.on('data', data => { output += data; });
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(output).to.include('some-text');
expect(output).to.include('obj-prop');

View file

@ -3,12 +3,13 @@ import * as childProcess from 'child_process';
import * as http from 'http';
import * as Busboy from 'busboy';
import * as path from 'path';
import { ifdescribe, ifit, defer, startRemoteControlApp, delay, repeatedly, listen } from './lib/spec-helpers';
import { ifdescribe, ifit, defer, startRemoteControlApp, repeatedly, listen } from './lib/spec-helpers';
import { app } from 'electron/main';
import { crashReporter } from 'electron/common';
import { EventEmitter } from 'events';
import * as fs from 'fs';
import * as uuid from 'uuid';
import { setTimeout } from 'timers/promises';
const isWindowsOnArm = process.platform === 'win32' && process.arch === 'arm64';
const isLinuxOnArm = process.platform === 'linux' && process.arch.includes('arm');
@ -298,7 +299,7 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
ignoreSystemCrashHandler: true,
extra: { longParam: 'a'.repeat(100000) }
});
setTimeout(() => process.crash());
setTimeout().then(() => process.crash());
}, port);
const crash = await waitForCrash();
expect(stitchLongCrashParam(crash, 'longParam')).to.have.lengthOf(160 * 127, 'crash should have truncated longParam');
@ -320,7 +321,7 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
}
});
require('electron').crashReporter.addExtraParameter('c'.repeat(kKeyLengthMax + 10), 'value');
setTimeout(() => process.crash());
setTimeout().then(() => process.crash());
}, port, kKeyLengthMax);
const crash = await waitForCrash();
expect(crash).not.to.have.property('a'.repeat(kKeyLengthMax + 10));
@ -375,7 +376,7 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
waitForCrash().then(() => expect.fail('expected not to receive a dump'));
await runCrashApp('renderer', port, ['--no-upload']);
// wait a sec in case the crash reporter is about to upload a crash
await delay(1000);
await setTimeout(1000);
expect(getCrashes()).to.have.length(0);
});
@ -502,7 +503,7 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
function crash (processType: string, remotely: Function) {
if (processType === 'main') {
return remotely(() => {
setTimeout(() => { process.crash(); });
setTimeout().then(() => { process.crash(); });
});
} else if (processType === 'renderer') {
return remotely(() => {

View file

@ -3,8 +3,9 @@ import * as http from 'http';
import * as path from 'path';
import { BrowserWindow } from 'electron/main';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce, emittedUntil } from './lib/events-helpers';
import { emittedUntil } from './lib/events-helpers';
import { listen } from './lib/spec-helpers';
import { once } from 'events';
describe('debugger module', () => {
const fixtures = path.resolve(__dirname, 'fixtures');
@ -45,7 +46,7 @@ describe('debugger module', () => {
describe('debugger.detach', () => {
it('fires detach event', async () => {
const detach = emittedOnce(w.webContents.debugger, 'detach');
const detach = once(w.webContents.debugger, 'detach');
w.webContents.debugger.attach();
w.webContents.debugger.detach();
const [, reason] = await detach;
@ -55,7 +56,7 @@ describe('debugger module', () => {
it('doesn\'t disconnect an active devtools session', async () => {
w.webContents.loadURL('about:blank');
const detach = emittedOnce(w.webContents.debugger, 'detach');
const detach = once(w.webContents.debugger, 'detach');
w.webContents.debugger.attach();
w.webContents.openDevTools();
w.webContents.once('devtools-opened', () => {
@ -94,7 +95,7 @@ describe('debugger module', () => {
w.webContents.loadURL('about:blank');
w.webContents.debugger.attach();
const opened = emittedOnce(w.webContents, 'devtools-opened');
const opened = once(w.webContents, 'devtools-opened');
w.webContents.openDevTools();
await opened;
@ -183,7 +184,7 @@ describe('debugger module', () => {
it('uses empty sessionId by default', async () => {
w.webContents.loadURL('about:blank');
w.webContents.debugger.attach();
const onMessage = emittedOnce(w.webContents.debugger, 'message');
const onMessage = once(w.webContents.debugger, 'message');
await w.webContents.debugger.sendCommand('Target.setDiscoverTargets', { discover: true });
const [, method, params, sessionId] = await onMessage;
expect(method).to.equal('Target.targetCreated');

View file

@ -1,7 +1,8 @@
import { expect } from 'chai';
import { screen, desktopCapturer, BrowserWindow } from 'electron/main';
import { delay, ifdescribe, ifit } from './lib/spec-helpers';
import { emittedOnce } from './lib/events-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
import { ifdescribe, ifit } from './lib/spec-helpers';
import { closeAllWindows } from './lib/window-helpers';
@ -74,7 +75,7 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt
it('disabling thumbnail should return empty images', async () => {
const w2 = new BrowserWindow({ show: false, width: 200, height: 200, webPreferences: { contextIsolation: false } });
const wShown = emittedOnce(w2, 'show');
const wShown = once(w2, 'show');
w2.show();
await wShown;
@ -90,8 +91,8 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt
it('getMediaSourceId should match DesktopCapturerSource.id', async () => {
const w = new BrowserWindow({ show: false, width: 100, height: 100, webPreferences: { contextIsolation: false } });
const wShown = emittedOnce(w, 'show');
const wFocused = emittedOnce(w, 'focus');
const wShown = once(w, 'show');
const wFocused = once(w, 'focus');
w.show();
w.focus();
await wShown;
@ -121,8 +122,8 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt
it('getSources should not incorrectly duplicate window_id', async () => {
const w = new BrowserWindow({ show: false, width: 100, height: 100, webPreferences: { contextIsolation: false } });
const wShown = emittedOnce(w, 'show');
const wFocused = emittedOnce(w, 'focus');
const wShown = once(w, 'show');
const wFocused = once(w, 'focus');
w.show();
w.focus();
await wShown;
@ -176,8 +177,8 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt
// Show and focus all the windows.
for (const w of wList) {
const wShown = emittedOnce(w, 'show');
const wFocused = emittedOnce(w, 'focus');
const wShown = once(w, 'show');
const wFocused = once(w, 'focus');
w.show();
w.focus();
@ -227,7 +228,7 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt
w.focus();
w.moveAbove(next.getMediaSourceId());
// Ensure the window has time to move.
await delay(2000);
await setTimeout(2000);
}
}

View file

@ -1,7 +1,8 @@
import { expect } from 'chai';
import { dialog, BrowserWindow } from 'electron/main';
import { closeAllWindows } from './lib/window-helpers';
import { ifit, delay } from './lib/spec-helpers';
import { ifit } from './lib/spec-helpers';
import { setTimeout } from 'timers/promises';
describe('dialog module', () => {
describe('showOpenDialog', () => {
@ -139,7 +140,7 @@ describe('dialog module', () => {
const signal = controller.signal;
const w = new BrowserWindow();
const p = dialog.showMessageBox(w, { signal, message: 'i am message' });
await delay(500);
await setTimeout(500);
controller.abort();
const result = await p;
expect(result.response).to.equal(0);
@ -170,7 +171,7 @@ describe('dialog module', () => {
buttons: ['OK', 'Cancel'],
cancelId: 1
});
await delay(500);
await setTimeout(500);
controller.abort();
const result = await p;
expect(result.response).to.equal(1);

View file

@ -2,9 +2,9 @@ import { expect } from 'chai';
import * as path from 'path';
import * as cp from 'child_process';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { defer } from './lib/spec-helpers';
import { ipcMain, BrowserWindow } from 'electron/main';
import { once } from 'events';
describe('ipc main module', () => {
const fixtures = path.join(__dirname, 'fixtures');
@ -57,7 +57,7 @@ describe('ipc main module', () => {
let output = '';
appProcess.stdout.on('data', (data) => { output += data; });
await emittedOnce(appProcess.stdout, 'end');
await once(appProcess.stdout, 'end');
output = JSON.parse(output);
expect(output).to.deep.equal(['error']);

View file

@ -1,8 +1,8 @@
import { expect } from 'chai';
import * as path from 'path';
import { ipcMain, BrowserWindow, WebContents, WebPreferences, webContents } from 'electron/main';
import { emittedOnce } from './lib/events-helpers';
import { closeWindow } from './lib/window-helpers';
import { once } from 'events';
describe('ipcRenderer module', () => {
const fixtures = path.join(__dirname, 'fixtures');
@ -27,7 +27,7 @@ describe('ipcRenderer module', () => {
const { ipcRenderer } = require('electron')
ipcRenderer.send('message', ${JSON.stringify(obj)})
}`);
const [, received] = await emittedOnce(ipcMain, 'message');
const [, received] = await once(ipcMain, 'message');
expect(received).to.deep.equal(obj);
});
@ -37,7 +37,7 @@ describe('ipcRenderer module', () => {
const { ipcRenderer } = require('electron')
ipcRenderer.send('message', new Date(${JSON.stringify(isoDate)}))
}`);
const [, received] = await emittedOnce(ipcMain, 'message');
const [, received] = await once(ipcMain, 'message');
expect(received.toISOString()).to.equal(isoDate);
});
@ -47,7 +47,7 @@ describe('ipcRenderer module', () => {
const { ipcRenderer } = require('electron')
ipcRenderer.send('message', Buffer.from(${JSON.stringify(data)}))
}`);
const [, received] = await emittedOnce(ipcMain, 'message');
const [, received] = await once(ipcMain, 'message');
expect(received).to.be.an.instanceOf(Uint8Array);
expect(Buffer.from(data).equals(received)).to.be.true();
});
@ -88,7 +88,7 @@ describe('ipcRenderer module', () => {
const bar = { name: 'bar', child: child };
const array = [foo, bar];
const [, arrayValue, fooValue, barValue, childValue] = await emittedOnce(ipcMain, 'message');
const [, arrayValue, fooValue, barValue, childValue] = await once(ipcMain, 'message');
expect(arrayValue).to.deep.equal(array);
expect(fooValue).to.deep.equal(foo);
expect(barValue).to.deep.equal(bar);
@ -106,7 +106,7 @@ describe('ipcRenderer module', () => {
ipcRenderer.send('message', array, child)
}`);
const [, arrayValue, childValue] = await emittedOnce(ipcMain, 'message');
const [, arrayValue, childValue] = await once(ipcMain, 'message');
expect(arrayValue[0]).to.equal(5);
expect(arrayValue[1]).to.equal(arrayValue);

View file

@ -1,8 +1,7 @@
import { EventEmitter } from 'events';
import { EventEmitter, once } from 'events';
import { expect } from 'chai';
import { BrowserWindow, ipcMain, IpcMainInvokeEvent, MessageChannelMain, WebContents } from 'electron/main';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { defer, listen } from './lib/spec-helpers';
import * as path from 'path';
import * as http from 'http';
@ -120,7 +119,7 @@ describe('ipc module', () => {
/* never resolve */
}));
w.webContents.executeJavaScript(`(${rendererInvoke})()`);
const [, { error }] = await emittedOnce(ipcMain, 'result');
const [, { error }] = await once(ipcMain, 'result');
expect(error).to.match(/reply was never sent/);
});
});
@ -208,7 +207,7 @@ describe('ipc module', () => {
it('can send a port to the main process', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
const p = emittedOnce(ipcMain, 'port');
const p = once(ipcMain, 'port');
await w.webContents.executeJavaScript(`(${function () {
const channel = new MessageChannel();
require('electron').ipcRenderer.postMessage('port', 'hi', [channel.port1]);
@ -225,7 +224,7 @@ describe('ipc module', () => {
it('can sent a message without a transfer', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
const p = emittedOnce(ipcMain, 'port');
const p = once(ipcMain, 'port');
await w.webContents.executeJavaScript(`(${function () {
require('electron').ipcRenderer.postMessage('port', 'hi');
}})()`);
@ -238,7 +237,7 @@ describe('ipc module', () => {
it('can communicate between main and renderer', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
const p = emittedOnce(ipcMain, 'port');
const p = once(ipcMain, 'port');
await w.webContents.executeJavaScript(`(${function () {
const channel = new MessageChannel();
(channel.port2 as any).onmessage = (ev: any) => {
@ -252,7 +251,7 @@ describe('ipc module', () => {
const [port] = ev.ports;
port.start();
port.postMessage(42);
const [ev2] = await emittedOnce(port, 'message');
const [ev2] = await once(port, 'message');
expect(ev2.data).to.equal(84);
});
@ -267,11 +266,11 @@ describe('ipc module', () => {
require('electron').ipcRenderer.postMessage('port', '', [channel1.port1]);
}
w.webContents.executeJavaScript(`(${fn})()`);
const [{ ports: [port1] }] = await emittedOnce(ipcMain, 'port');
const [{ ports: [port1] }] = await once(ipcMain, 'port');
port1.start();
const [{ ports: [port2] }] = await emittedOnce(port1, 'message');
const [{ ports: [port2] }] = await once(port1, 'message');
port2.start();
const [{ data }] = await emittedOnce(port2, 'message');
const [{ data }] = await once(port2, 'message');
expect(data).to.equal('matryoshka');
});
@ -287,14 +286,14 @@ describe('ipc module', () => {
};
require('electron').ipcRenderer.postMessage('port', '', [channel.port1]);
}})()`);
const [{ ports: [port] }] = await emittedOnce(ipcMain, 'port');
const [{ ports: [port] }] = await once(ipcMain, 'port');
await w2.webContents.executeJavaScript(`(${function () {
require('electron').ipcRenderer.on('port', ({ ports: [port] }: any) => {
port.postMessage('a message');
});
}})()`);
w2.webContents.postMessage('port', '', [port]);
const [, data] = await emittedOnce(ipcMain, 'message received');
const [, data] = await once(ipcMain, 'message received');
expect(data).to.equal('a message');
});
@ -316,7 +315,7 @@ describe('ipc module', () => {
const { port1, port2 } = new MessageChannelMain();
w.webContents.postMessage('port', null, [port2]);
port1.close();
await emittedOnce(ipcMain, 'closed');
await once(ipcMain, 'closed');
});
it('is emitted when the other end of a port is garbage-collected', async () => {
@ -360,7 +359,7 @@ describe('ipc module', () => {
const { port1, port2 } = new MessageChannelMain();
port2.postMessage('hello');
port1.start();
const [ev] = await emittedOnce(port1, 'message');
const [ev] = await once(port1, 'message');
expect(ev.data).to.equal('hello');
});
@ -379,7 +378,7 @@ describe('ipc module', () => {
const { port1, port2 } = new MessageChannelMain();
port1.postMessage('hello');
w.webContents.postMessage('port', null, [port2]);
await emittedOnce(ipcMain, 'done');
await once(ipcMain, 'done');
});
it('can be passed over another channel', async () => {
@ -400,7 +399,7 @@ describe('ipc module', () => {
port1.postMessage(null, [port4]);
port3.postMessage('hello');
w.webContents.postMessage('port', null, [port2]);
const [, message] = await emittedOnce(ipcMain, 'done');
const [, message] = await once(ipcMain, 'done');
expect(message).to.equal('hello');
});
@ -481,7 +480,7 @@ describe('ipc module', () => {
});
}})()`);
postMessage(w.webContents)('foo', { some: 'message' });
const [, msg] = await emittedOnce(ipcMain, 'bar');
const [, msg] = await once(ipcMain, 'bar');
expect(msg).to.deep.equal({ some: 'message' });
});
@ -575,7 +574,7 @@ describe('ipc module', () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.send(\'test\', 42)');
const [, num] = await emittedOnce(w.webContents.ipc, 'test');
const [, num] = await once(w.webContents.ipc, 'test');
expect(num).to.equal(42);
});
@ -593,7 +592,7 @@ describe('ipc module', () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.postMessage(\'test\', null, [(new MessageChannel).port1])');
const [event] = await emittedOnce(w.webContents.ipc, 'test');
const [event] = await once(w.webContents.ipc, 'test');
expect(event.ports.length).to.equal(1);
});
@ -651,7 +650,7 @@ describe('ipc module', () => {
// Preloads don't run in about:blank windows, and file:// urls can't be loaded in iframes, so use a blank http page.
await w.loadURL(`data:text/html,<iframe src="http://localhost:${port}"></iframe>`);
w.webContents.mainFrame.frames[0].executeJavaScript('ipc.send(\'test\', 42)');
const [, arg] = await emittedOnce(w.webContents.ipc, 'test');
const [, arg] = await once(w.webContents.ipc, 'test');
expect(arg).to.equal(42);
});
});
@ -662,7 +661,7 @@ describe('ipc module', () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.send(\'test\', 42)');
const [, arg] = await emittedOnce(w.webContents.mainFrame.ipc, 'test');
const [, arg] = await once(w.webContents.mainFrame.ipc, 'test');
expect(arg).to.equal(42);
});
@ -680,7 +679,7 @@ describe('ipc module', () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.postMessage(\'test\', null, [(new MessageChannel).port1])');
const [event] = await emittedOnce(w.webContents.mainFrame.ipc, 'test');
const [event] = await once(w.webContents.mainFrame.ipc, 'test');
expect(event.ports.length).to.equal(1);
});
@ -752,7 +751,7 @@ describe('ipc module', () => {
await w.loadURL(`data:text/html,<iframe src="http://localhost:${port}"></iframe>`);
w.webContents.mainFrame.frames[0].executeJavaScript('ipc.send(\'test\', 42)');
w.webContents.mainFrame.ipc.on('test', () => { throw new Error('should not be called'); });
const [, arg] = await emittedOnce(w.webContents.mainFrame.frames[0].ipc, 'test');
const [, arg] = await once(w.webContents.mainFrame.frames[0].ipc, 'test');
expect(arg).to.equal(42);
});
});

View file

@ -3,9 +3,10 @@ import * as path from 'path';
import { expect } from 'chai';
import { BrowserWindow, Menu, MenuItem } from 'electron/main';
import { sortMenuItems } from '../lib/browser/api/menu-utils';
import { emittedOnce } from './lib/events-helpers';
import { ifit, delay } from './lib/spec-helpers';
import { ifit } from './lib/spec-helpers';
import { closeWindow } from './lib/window-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
const fixturesPath = path.resolve(__dirname, 'fixtures');
@ -817,7 +818,7 @@ describe('Menu module', function () {
menu.on('menu-will-close', () => { done(); });
menu.popup({ window: w });
// https://github.com/electron/electron/issues/19411
setTimeout(() => {
setTimeout().then(() => {
menu.closePopup();
});
});
@ -849,7 +850,7 @@ describe('Menu module', function () {
expect(x).to.equal(100);
expect(y).to.equal(101);
// https://github.com/electron/electron/issues/19411
setTimeout(() => {
setTimeout().then(() => {
menu.closePopup();
});
});
@ -857,7 +858,7 @@ describe('Menu module', function () {
it('works with a given BrowserWindow, no options, and a callback', (done) => {
menu.popup({ window: w, callback: () => done() });
// https://github.com/electron/electron/issues/19411
setTimeout(() => {
setTimeout().then(() => {
menu.closePopup();
});
});
@ -870,14 +871,14 @@ describe('Menu module', function () {
// eslint-disable-next-line no-undef
const wr = new WeakRef(menu);
await delay();
await setTimeout();
// Do garbage collection, since |menu| is not referenced in this closure
// it would be gone after next call.
const v8Util = process._linkedBinding('electron_common_v8_util');
v8Util.requestGarbageCollectionForTesting();
await delay();
await setTimeout();
// Try to receive menu from weak reference.
if (wr.deref()) {
@ -929,7 +930,7 @@ describe('Menu module', function () {
appProcess.stdout.on('data', data => { output += data; });
appProcess.stderr.on('data', data => { output += data; });
const [code] = await emittedOnce(appProcess, 'exit');
const [code] = await once(appProcess, 'exit');
if (!output.includes('Window has no menu')) {
console.log(code, output);
}

View file

@ -1,11 +1,12 @@
import { expect } from 'chai';
import { nativeTheme, systemPreferences, BrowserWindow, ipcMain } from 'electron/main';
import { once } from 'events';
import * as os from 'os';
import * as path from 'path';
import * as semver from 'semver';
import { setTimeout } from 'timers/promises';
import { delay, ifdescribe } from './lib/spec-helpers';
import { emittedOnce } from './lib/events-helpers';
import { ifdescribe } from './lib/spec-helpers';
import { closeAllWindows } from './lib/window-helpers';
describe('nativeTheme module', () => {
@ -19,7 +20,7 @@ describe('nativeTheme module', () => {
afterEach(async () => {
nativeTheme.themeSource = 'system';
// Wait for any pending events to emit
await delay(20);
await setTimeout(20);
closeAllWindows();
});
@ -37,10 +38,10 @@ describe('nativeTheme module', () => {
it('should emit the "updated" event when it is set and the resulting "shouldUseDarkColors" value changes', async () => {
nativeTheme.themeSource = 'light';
let updatedEmitted = emittedOnce(nativeTheme, 'updated');
let updatedEmitted = once(nativeTheme, 'updated');
nativeTheme.themeSource = 'dark';
await updatedEmitted;
updatedEmitted = emittedOnce(nativeTheme, 'updated');
updatedEmitted = once(nativeTheme, 'updated');
nativeTheme.themeSource = 'light';
await updatedEmitted;
});
@ -48,14 +49,14 @@ describe('nativeTheme module', () => {
it('should not emit the "updated" event when it is set and the resulting "shouldUseDarkColors" value is the same', async () => {
nativeTheme.themeSource = 'dark';
// Wait a few ticks to allow an async events to flush
await delay(20);
await setTimeout(20);
let called = false;
nativeTheme.once('updated', () => {
called = true;
});
nativeTheme.themeSource = 'dark';
// Wait a few ticks to allow an async events to flush
await delay(20);
await setTimeout(20);
expect(called).to.equal(false);
});
@ -83,15 +84,15 @@ describe('nativeTheme module', () => {
.addEventListener('change', () => require('electron').ipcRenderer.send('theme-change'))
`);
const originalSystemIsDark = await getPrefersColorSchemeIsDark(w);
let changePromise: Promise<any[]> = emittedOnce(ipcMain, 'theme-change');
let changePromise: Promise<any[]> = once(ipcMain, 'theme-change');
nativeTheme.themeSource = 'dark';
if (!originalSystemIsDark) await changePromise;
expect(await getPrefersColorSchemeIsDark(w)).to.equal(true);
changePromise = emittedOnce(ipcMain, 'theme-change');
changePromise = once(ipcMain, 'theme-change');
nativeTheme.themeSource = 'light';
await changePromise;
expect(await getPrefersColorSchemeIsDark(w)).to.equal(false);
changePromise = emittedOnce(ipcMain, 'theme-change');
changePromise = once(ipcMain, 'theme-change');
nativeTheme.themeSource = 'system';
if (originalSystemIsDark) await changePromise;
expect(await getPrefersColorSchemeIsDark(w)).to.equal(originalSystemIsDark);

View file

@ -7,7 +7,7 @@ import * as ChildProcess from 'child_process';
import { session, net } from 'electron/main';
import { Socket } from 'net';
import { ifit, listen } from './lib/spec-helpers';
import { emittedOnce } from './lib/events-helpers';
import { once } from 'events';
const appPath = path.join(__dirname, 'fixtures', 'api', 'net-log');
const dumpFile = path.join(os.tmpdir(), 'net_log.json');
@ -127,7 +127,7 @@ describe('netLog module', () => {
}
});
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(fs.existsSync(dumpFile)).to.be.true('dump file exists');
});
@ -142,7 +142,7 @@ describe('netLog module', () => {
}
});
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(fs.existsSync(dumpFile)).to.be.true('dump file exists');
expect(fs.existsSync(dumpFileDynamic)).to.be.true('dynamic dump file exists');
});
@ -156,7 +156,7 @@ describe('netLog module', () => {
}
});
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(fs.existsSync(dumpFileDynamic)).to.be.true('dynamic dump file exists');
});
});

View file

@ -4,8 +4,9 @@ import { net, session, ClientRequest, BrowserWindow, ClientRequestConstructorOpt
import * as http from 'http';
import * as url from 'url';
import { Socket } from 'net';
import { emittedOnce } from './lib/events-helpers';
import { defer, delay, listen } from './lib/spec-helpers';
import { defer, listen } from './lib/spec-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
// See https://github.com/nodejs/node/issues/40702.
dns.setDefaultResultOrder('ipv4first');
@ -412,9 +413,9 @@ describe('net module', () => {
const urlRequest = net.request(serverUrl);
// request close event
const closePromise = emittedOnce(urlRequest, 'close');
const closePromise = once(urlRequest, 'close');
// request finish event
const finishPromise = emittedOnce(urlRequest, 'close');
const finishPromise = once(urlRequest, 'close');
// request "response" event
const response = await getResponse(urlRequest);
response.on('error', (error: Error) => {
@ -1056,7 +1057,7 @@ describe('net module', () => {
urlRequest.on('response', () => {
expect.fail('unexpected response event');
});
const aborted = emittedOnce(urlRequest, 'abort');
const aborted = once(urlRequest, 'abort');
urlRequest.abort();
urlRequest.write('');
urlRequest.end();
@ -1086,10 +1087,10 @@ describe('net module', () => {
requestAbortEventEmitted = true;
});
await emittedOnce(urlRequest, 'close', () => {
urlRequest!.chunkedEncoding = true;
urlRequest!.write(randomString(kOneKiloByte));
});
const p = once(urlRequest, 'close');
urlRequest.chunkedEncoding = true;
urlRequest.write(randomString(kOneKiloByte));
await p;
expect(requestReceivedByServer).to.equal(true);
expect(requestAbortEventEmitted).to.equal(true);
});
@ -1119,7 +1120,7 @@ describe('net module', () => {
expect.fail('Unexpected error event');
});
urlRequest.end(randomString(kOneKiloByte));
await emittedOnce(urlRequest, 'abort');
await once(urlRequest, 'abort');
expect(requestFinishEventEmitted).to.equal(true);
expect(requestReceivedByServer).to.equal(true);
});
@ -1160,7 +1161,7 @@ describe('net module', () => {
expect.fail('Unexpected error event');
});
urlRequest.end(randomString(kOneKiloByte));
await emittedOnce(urlRequest, 'abort');
await once(urlRequest, 'abort');
expect(requestFinishEventEmitted).to.be.true('request should emit "finish" event');
expect(requestReceivedByServer).to.be.true('request should be received by the server');
expect(requestResponseEventEmitted).to.be.true('"response" event should be emitted');
@ -1192,7 +1193,7 @@ describe('net module', () => {
abortsEmitted++;
});
urlRequest.end(randomString(kOneKiloByte));
await emittedOnce(urlRequest, 'abort');
await once(urlRequest, 'abort');
expect(requestFinishEventEmitted).to.be.true('request should emit "finish" event');
expect(requestReceivedByServer).to.be.true('request should be received by server');
expect(abortsEmitted).to.equal(1, 'request should emit exactly 1 "abort" event');
@ -1214,7 +1215,7 @@ describe('net module', () => {
});
const eventHandlers = Promise.all([
bodyCheckPromise,
emittedOnce(urlRequest, 'close')
once(urlRequest, 'close')
]);
urlRequest.end();
@ -1445,7 +1446,7 @@ describe('net module', () => {
urlRequest.end();
urlRequest.on('redirect', () => { urlRequest.abort(); });
urlRequest.on('error', () => {});
await emittedOnce(urlRequest, 'abort');
await once(urlRequest, 'abort');
});
it('should not follow redirect when mode is error', async () => {
@ -1459,7 +1460,7 @@ describe('net module', () => {
redirect: 'error'
});
urlRequest.end();
await emittedOnce(urlRequest, 'error');
await once(urlRequest, 'error');
});
it('should follow redirect when handler calls callback', async () => {
@ -1559,7 +1560,7 @@ describe('net module', () => {
const nodeRequest = http.request(nodeServerUrl);
const nodeResponse = await getResponse(nodeRequest as any) as any as http.ServerResponse;
const netRequest = net.request(netServerUrl);
const responsePromise = emittedOnce(netRequest, 'response');
const responsePromise = once(netRequest, 'response');
// TODO(@MarshallOfSound) - FIXME with #22730
nodeResponse.pipe(netRequest as any);
const [netResponse] = await responsePromise;
@ -1576,7 +1577,7 @@ describe('net module', () => {
const netRequest = net.request({ url: serverUrl, method: 'POST' });
expect(netRequest.getUploadProgress()).to.have.property('active', false);
netRequest.end(Buffer.from('hello'));
const [position, total] = await emittedOnce(netRequest, 'upload-progress');
const [position, total] = await once(netRequest, 'upload-progress');
expect(netRequest.getUploadProgress()).to.deep.equal({ active: true, started: true, current: position, total });
});
@ -1586,7 +1587,7 @@ describe('net module', () => {
});
const urlRequest = net.request(serverUrl);
urlRequest.end();
const [error] = await emittedOnce(urlRequest, 'error');
const [error] = await once(urlRequest, 'error');
expect(error.message).to.equal('net::ERR_EMPTY_RESPONSE');
});
@ -1597,7 +1598,7 @@ describe('net module', () => {
});
const urlRequest = net.request(serverUrl);
urlRequest.end(randomBuffer(kOneMegaByte));
const [error] = await emittedOnce(urlRequest, 'error');
const [error] = await once(urlRequest, 'error');
expect(error.message).to.be.oneOf(['net::ERR_FAILED', 'net::ERR_CONNECTION_RESET', 'net::ERR_CONNECTION_ABORTED']);
});
@ -1609,14 +1610,14 @@ describe('net module', () => {
const urlRequest = net.request(serverUrl);
urlRequest.end();
await emittedOnce(urlRequest, 'close');
await once(urlRequest, 'close');
await new Promise((resolve, reject) => {
['finish', 'abort', 'close', 'error'].forEach(evName => {
urlRequest.on(evName as any, () => {
reject(new Error(`Unexpected ${evName} event`));
});
});
setTimeout(resolve, 50);
setTimeout(50).then(resolve);
});
});
@ -1902,7 +1903,7 @@ describe('net module', () => {
port: serverUrl.port
};
const nodeRequest = http.request(nodeOptions);
const nodeResponsePromise = emittedOnce(nodeRequest, 'response');
const nodeResponsePromise = once(nodeRequest, 'response');
// TODO(@MarshallOfSound) - FIXME with #22730
(netResponse as any).pipe(nodeRequest);
const [nodeResponse] = await nodeResponsePromise;
@ -1929,7 +1930,7 @@ describe('net module', () => {
const urlRequest = net.request(serverUrl);
urlRequest.on('response', () => {});
urlRequest.end();
await delay(2000);
await setTimeout(2000);
// TODO(nornagon): I think this ought to max out at 20, but in practice
// it seems to exceed that sometimes. This is at 25 to avoid test flakes,
// but we should investigate if there's actually something broken here and
@ -2159,7 +2160,7 @@ describe('net module', () => {
it('should reject body promise when stream fails', async () => {
const serverUrl = await respondOnce.toSingleURL((request, response) => {
response.write('first chunk');
setTimeout(() => response.destroy());
setTimeout().then(() => response.destroy());
});
const r = await net.fetch(serverUrl);
expect(r.status).to.equal(200);

View file

@ -1,6 +1,6 @@
import { expect } from 'chai';
import { Notification } from 'electron/main';
import { emittedOnce } from './lib/events-helpers';
import { once } from 'events';
import { ifit } from './lib/spec-helpers';
describe('Notification module', () => {
@ -123,12 +123,12 @@ describe('Notification module', () => {
silent: true
});
{
const e = emittedOnce(n, 'show');
const e = once(n, 'show');
n.show();
await e;
}
{
const e = emittedOnce(n, 'close');
const e = once(n, 'close');
n.close();
await e;
}
@ -139,7 +139,7 @@ describe('Notification module', () => {
toastXml: 'not xml'
});
{
const e = emittedOnce(n, 'failed');
const e = once(n, 'failed');
n.show();
await e;
}

View file

@ -8,8 +8,9 @@
// python-dbusmock.
import { expect } from 'chai';
import * as dbus from 'dbus-native';
import { ifdescribe, delay } from './lib/spec-helpers';
import { ifdescribe } from './lib/spec-helpers';
import { promisify } from 'util';
import { setTimeout } from 'timers/promises';
describe('powerMonitor', () => {
let logindMock: any, dbusMockPowerMonitor: any, getCalls: any, emitSignal: any, reset: any;
@ -59,7 +60,7 @@ describe('powerMonitor', () => {
while (retriesRemaining-- > 0) {
calls = await getCalls();
if (calls.length > 0) break;
await delay(1000);
await setTimeout(1000);
}
expect(calls).to.be.an('array').that.has.lengthOf(1);
expect(calls[0].slice(1)).to.deep.equal([

View file

@ -7,11 +7,11 @@ import * as http from 'http';
import * as fs from 'fs';
import * as qs from 'querystring';
import * as stream from 'stream';
import { EventEmitter } from 'events';
import { EventEmitter, once } from 'events';
import { closeAllWindows, closeWindow } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { WebmGenerator } from './lib/video-helpers';
import { delay, listen } from './lib/spec-helpers';
import { listen } from './lib/spec-helpers';
import { setTimeout } from 'timers/promises';
const fixturesPath = path.resolve(__dirname, 'fixtures');
@ -37,7 +37,7 @@ function getStream (chunkSize = text.length, data: Buffer | string = text) {
const body = new stream.PassThrough();
async function sendChunks () {
await delay(0); // the stream protocol API breaks if you send data immediately.
await setTimeout(0); // the stream protocol API breaks if you send data immediately.
let buf = Buffer.from(data as any); // nodejs typings are wrong, Buffer.from can take a Buffer
for (;;) {
body.push(buf.slice(0, chunkSize));
@ -46,7 +46,7 @@ function getStream (chunkSize = text.length, data: Buffer | string = text) {
break;
}
// emulate some network delay
await delay(10);
await setTimeout(10);
}
body.push(null);
}
@ -499,7 +499,7 @@ describe('protocol module', () => {
data: createStream()
});
});
const hasEndedPromise = emittedOnce(events, 'end');
const hasEndedPromise = once(events, 'end');
ajax(protocolName + '://fake-host').catch(() => {});
await hasEndedPromise;
});
@ -520,8 +520,8 @@ describe('protocol module', () => {
events.emit('respond');
});
const hasRespondedPromise = emittedOnce(events, 'respond');
const hasClosedPromise = emittedOnce(events, 'close');
const hasRespondedPromise = once(events, 'respond');
const hasClosedPromise = once(events, 'close');
ajax(protocolName + '://fake-host').catch(() => {});
await hasRespondedPromise;
await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'fetch.html'));
@ -713,7 +713,7 @@ describe('protocol module', () => {
it('can execute redirects', async () => {
interceptStreamProtocol('http', (request, callback) => {
if (request.url.indexOf('http://fake-host') === 0) {
setTimeout(() => {
setTimeout(300).then(() => {
callback({
data: '',
statusCode: 302,
@ -721,7 +721,7 @@ describe('protocol module', () => {
Location: 'http://fake-redirect'
}
});
}, 300);
});
} else {
expect(request.url.indexOf('http://fake-redirect')).to.equal(0);
callback(getStream(1, 'redirect'));
@ -734,14 +734,14 @@ describe('protocol module', () => {
it('should discard post data after redirection', async () => {
interceptStreamProtocol('http', (request, callback) => {
if (request.url.indexOf('http://fake-host') === 0) {
setTimeout(() => {
setTimeout(300).then(() => {
callback({
statusCode: 302,
headers: {
Location: 'http://fake-redirect'
}
});
}, 300);
});
} else {
expect(request.url.indexOf('http://fake-redirect')).to.equal(0);
callback(getStream(3, request.method));
@ -770,7 +770,7 @@ describe('protocol module', () => {
let stderr = '';
appProcess.stdout.on('data', data => { process.stdout.write(data); stdout += data; });
appProcess.stderr.on('data', data => { process.stderr.write(data); stderr += data; });
const [code] = await emittedOnce(appProcess, 'exit');
const [code] = await once(appProcess, 'exit');
if (code !== 0) {
console.log('Exit code : ', code);
console.log('stdout : ', stdout);
@ -979,13 +979,13 @@ describe('protocol module', () => {
newContents.on('console-message', (e, level, message) => consoleMessages.push(message));
try {
newContents.loadURL(standardScheme + '://fake-host');
const [, response] = await emittedOnce(ipcMain, 'response');
const [, response] = await once(ipcMain, 'response');
expect(response).to.deep.equal(expected);
expect(consoleMessages.join('\n')).to.match(expectedConsole);
} finally {
// This is called in a timeout to avoid a crash that happens when
// calling destroy() in a microtask.
setTimeout(() => {
setTimeout().then(() => {
newContents.destroy();
});
}
@ -1082,12 +1082,12 @@ describe('protocol module', () => {
try {
newContents.loadURL(testingScheme + '://fake-host');
const [, response] = await emittedOnce(ipcMain, 'result');
const [, response] = await once(ipcMain, 'result');
expect(response).to.deep.equal(expected);
} finally {
// This is called in a timeout to avoid a crash that happens when
// calling destroy() in a microtask.
setTimeout(() => {
setTimeout().then(() => {
newContents.destroy();
});
}

View file

@ -2,9 +2,9 @@ import * as cp from 'child_process';
import * as path from 'path';
import { safeStorage } from 'electron/main';
import { expect } from 'chai';
import { emittedOnce } from './lib/events-helpers';
import { ifdescribe } from './lib/spec-helpers';
import * as fs from 'fs-extra';
import { once } from 'events';
/* isEncryptionAvailable returns false in Linux when running CI due to a mocked dbus. This stops
* Chrome from reaching the system's keyring or libsecret. When running the tests with config.store
@ -24,7 +24,7 @@ describe('safeStorage module', () => {
appProcess.stdout.on('data', data => { output += data; });
appProcess.stderr.on('data', data => { output += data; });
const code = (await emittedOnce(appProcess, 'exit'))[0] ?? 1;
const code = (await once(appProcess, 'exit'))[0] ?? 1;
if (code !== 0 && output) {
console.log(output);
@ -98,7 +98,7 @@ ifdescribe(process.platform !== 'linux')('safeStorage module', () => {
encryptAppProcess.stderr.on('data', data => { stdout += data; });
try {
await emittedOnce(encryptAppProcess, 'exit');
await once(encryptAppProcess, 'exit');
const appPath = path.join(fixturesPath, 'api', 'safe-storage', 'decrypt-app');
const relaunchedAppProcess = cp.spawn(process.execPath, [appPath]);
@ -107,7 +107,7 @@ ifdescribe(process.platform !== 'linux')('safeStorage module', () => {
relaunchedAppProcess.stdout.on('data', data => { output += data; });
relaunchedAppProcess.stderr.on('data', data => { output += data; });
const [code] = await emittedOnce(relaunchedAppProcess, 'exit');
const [code] = await once(relaunchedAppProcess, 'exit');
if (!output.includes('plaintext')) {
console.log(code, output);

View file

@ -4,8 +4,8 @@ import * as path from 'path';
import { session, webContents, WebContents } from 'electron/main';
import { expect } from 'chai';
import { v4 } from 'uuid';
import { emittedOnce, emittedNTimes } from './lib/events-helpers';
import { listen } from './lib/spec-helpers';
import { on, once } from 'events';
const partition = 'service-workers-spec';
@ -50,7 +50,8 @@ describe('session.serviceWorkers', () => {
});
it('should report one as running once you load a page with a service worker', async () => {
await emittedOnce(ses.serviceWorkers, 'console-message', () => w.loadURL(`${baseUrl}/index.html`));
w.loadURL(`${baseUrl}/index.html`);
await once(ses.serviceWorkers, 'console-message');
const workers = ses.serviceWorkers.getAllRunning();
const ids = Object.keys(workers) as any[] as number[];
expect(ids).to.have.lengthOf(1, 'should have one worker running');
@ -59,7 +60,8 @@ describe('session.serviceWorkers', () => {
describe('getFromVersionID()', () => {
it('should report the correct script url and scope', async () => {
const eventInfo = await emittedOnce(ses.serviceWorkers, 'console-message', () => w.loadURL(`${baseUrl}/index.html`));
w.loadURL(`${baseUrl}/index.html`);
const eventInfo = await once(ses.serviceWorkers, 'console-message');
const details: Electron.MessageDetails = eventInfo[1];
const worker = ses.serviceWorkers.getFromVersionID(details.versionId);
expect(worker).to.not.equal(null);
@ -71,11 +73,11 @@ describe('session.serviceWorkers', () => {
describe('console-message event', () => {
it('should correctly keep the source, message and level', async () => {
const messages: Record<string, Electron.MessageDetails> = {};
const events = await emittedNTimes(ses.serviceWorkers, 'console-message', 4, () => w.loadURL(`${baseUrl}/logs.html`));
for (const event of events) {
messages[event[1].message] = event[1];
expect(event[1]).to.have.property('source', 'console-api');
w.loadURL(`${baseUrl}/logs.html`);
for await (const [, details] of on(ses.serviceWorkers, 'console-message')) {
messages[details.message] = details;
expect(details).to.have.property('source', 'console-api');
if (Object.keys(messages).length >= 4) break;
}
expect(messages).to.have.property('log log');

View file

@ -8,8 +8,9 @@ import { app, session, BrowserWindow, net, ipcMain, Session, webFrameMain, WebFr
import * as send from 'send';
import * as auth from 'basic-auth';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { defer, delay, listen } from './lib/spec-helpers';
import { defer, listen } from './lib/spec-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
/* The whole session API doesn't use standard callbacks */
/* eslint-disable standard/no-callback-literal */
@ -184,11 +185,11 @@ describe('session module', () => {
const name = 'foo';
const value = 'bar';
const a = emittedOnce(cookies, 'changed');
const a = once(cookies, 'changed');
await cookies.set({ url, name, value, expirationDate: (+new Date()) / 1000 + 120 });
const [, setEventCookie, setEventCause, setEventRemoved] = await a;
const b = emittedOnce(cookies, 'changed');
const b = once(cookies, 'changed');
await cookies.remove(url, name);
const [, removeEventCookie, removeEventCause, removeEventRemoved] = await b;
@ -331,7 +332,7 @@ describe('session module', () => {
customSession = session.fromPartition(partitionName);
await customSession.protocol.registerStringProtocol(protocolName, handler);
w.loadURL(`${protocolName}://fake-host`);
await emittedOnce(ipcMain, 'hello');
await once(ipcMain, 'hello');
});
});
@ -345,7 +346,7 @@ describe('session module', () => {
if (!created) {
// Work around for https://github.com/electron/electron/issues/26166 to
// reduce flake
await delay(100);
await setTimeout(100);
created = true;
}
});
@ -654,7 +655,7 @@ describe('session module', () => {
const w = new BrowserWindow({ show: false, webPreferences: { session: ses } });
await expect(w.loadURL(serverUrl), 'first load').to.eventually.be.rejectedWith(/ERR_FAILED/);
await emittedOnce(w.webContents, 'did-stop-loading');
await once(w.webContents, 'did-stop-loading');
await expect(w.loadURL(serverUrl + '/test'), 'second load').to.eventually.be.rejectedWith(/ERR_FAILED/);
expect(w.webContents.getTitle()).to.equal(serverUrl + '/test');
expect(numVerificationRequests).to.equal(1);
@ -667,7 +668,7 @@ describe('session module', () => {
const req = net.request({ url: serverUrl, session: ses1, credentials: 'include' });
req.end();
setTimeout(() => {
setTimeout().then(() => {
ses2.setCertificateVerifyProc((opts, callback) => callback(0));
});
await expect(new Promise<void>((resolve, reject) => {
@ -963,7 +964,7 @@ describe('session module', () => {
length: 5242880
};
const w = new BrowserWindow({ show: false });
const p = emittedOnce(w.webContents.session, 'will-download');
const p = once(w.webContents.session, 'will-download');
w.webContents.session.createInterruptedDownload(options);
const [, item] = await p;
expect(item.getState()).to.equal('interrupted');
@ -1070,7 +1071,7 @@ describe('session module', () => {
cb(`<html><script>(${remote})()</script></html>`);
});
const result = emittedOnce(require('electron').ipcMain, 'message');
const result = once(require('electron').ipcMain, 'message');
function remote () {
(navigator as any).requestMIDIAccess({ sysex: true }).then(() => {}, (err: any) => {
@ -1197,7 +1198,7 @@ describe('session module', () => {
document.body.appendChild(iframe);
null;
`);
const [,, frameProcessId, frameRoutingId] = await emittedOnce(w.webContents, 'did-frame-finish-load');
const [,, frameProcessId, frameRoutingId] = await once(w.webContents, 'did-frame-finish-load');
const state = await readClipboardPermission(webFrameMain.fromId(frameProcessId, frameRoutingId));
expect(state).to.equal('granted');
expect(handlerDetails!.requestingUrl).to.equal(loadUrl);
@ -1260,7 +1261,7 @@ describe('session module', () => {
describe('session-created event', () => {
it('is emitted when a session is created', async () => {
const sessionCreated = emittedOnce(app, 'session-created');
const sessionCreated = once(app, 'session-created');
const session1 = session.fromPartition('' + Math.random());
const [session2] = await sessionCreated;
expect(session1).to.equal(session2);

View file

@ -1,13 +1,13 @@
import { BrowserWindow, app } from 'electron/main';
import { shell } from 'electron/common';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { ifdescribe, ifit, listen } from './lib/spec-helpers';
import * as http from 'http';
import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import { expect } from 'chai';
import { once } from 'events';
describe('shell module', () => {
describe('shell.openExternal()', () => {
@ -45,7 +45,7 @@ describe('shell module', () => {
// https://github.com/electron/electron/pull/19969#issuecomment-526278890),
// so use a blur event as a crude proxy.
const w = new BrowserWindow({ show: true });
requestReceived = emittedOnce(w, 'blur');
requestReceived = once(w, 'blur');
} else {
const server = http.createServer((req, res) => {
res.end();

View file

@ -1,10 +1,11 @@
import { expect } from 'chai';
import * as path from 'path';
import * as http from 'http';
import { emittedNTimes, emittedOnce } from './lib/events-helpers';
import { emittedNTimes } from './lib/events-helpers';
import { closeWindow } from './lib/window-helpers';
import { app, BrowserWindow, ipcMain } from 'electron/main';
import { ifdescribe, listen } from './lib/spec-helpers';
import { once } from 'events';
describe('renderer nodeIntegrationInSubFrames', () => {
const generateTests = (description: string, webPreferences: any) => {
@ -57,7 +58,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
const detailsPromise = emittedNTimes(ipcMain, 'preload-ran', 2);
w.loadFile(path.resolve(__dirname, `fixtures/sub-frames/frame-container${fixtureSuffix}.html`));
const [event1] = await detailsPromise;
const pongPromise = emittedOnce(ipcMain, 'preload-pong');
const pongPromise = once(ipcMain, 'preload-pong');
event1[0].reply('preload-ping');
const [, frameId] = await pongPromise;
expect(frameId).to.equal(event1[0].frameId);
@ -67,7 +68,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
const detailsPromise = emittedNTimes(ipcMain, 'preload-ran', 2);
w.loadFile(path.resolve(__dirname, `fixtures/sub-frames/frame-container${fixtureSuffix}.html`));
const [event1] = await detailsPromise;
const pongPromise = emittedOnce(ipcMain, 'preload-pong');
const pongPromise = once(ipcMain, 'preload-pong');
event1[0].senderFrame.send('preload-ping');
const [, frameId] = await pongPromise;
expect(frameId).to.equal(event1[0].frameId);
@ -77,7 +78,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
const detailsPromise = emittedNTimes(ipcMain, 'preload-ran', 2);
w.loadFile(path.resolve(__dirname, `fixtures/sub-frames/frame-container${fixtureSuffix}.html`));
const [, event2] = await detailsPromise;
const pongPromise = emittedOnce(ipcMain, 'preload-pong');
const pongPromise = once(ipcMain, 'preload-pong');
event2[0].reply('preload-ping');
const [, frameId] = await pongPromise;
expect(frameId).to.equal(event2[0].frameId);
@ -87,7 +88,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
const detailsPromise = emittedNTimes(ipcMain, 'preload-ran', 2);
w.loadFile(path.resolve(__dirname, `fixtures/sub-frames/frame-container${fixtureSuffix}.html`));
const [, event2] = await detailsPromise;
const pongPromise = emittedOnce(ipcMain, 'preload-pong');
const pongPromise = once(ipcMain, 'preload-pong');
event2[0].senderFrame.send('preload-ping');
const [, frameId] = await pongPromise;
expect(frameId).to.equal(event2[0].frameId);
@ -97,7 +98,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
const detailsPromise = emittedNTimes(ipcMain, 'preload-ran', 3);
w.loadFile(path.resolve(__dirname, `fixtures/sub-frames/frame-with-frame-container${fixtureSuffix}.html`));
const [, , event3] = await detailsPromise;
const pongPromise = emittedOnce(ipcMain, 'preload-pong');
const pongPromise = once(ipcMain, 'preload-pong');
event3[0].reply('preload-ping');
const [, frameId] = await pongPromise;
expect(frameId).to.equal(event3[0].frameId);
@ -107,7 +108,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
const detailsPromise = emittedNTimes(ipcMain, 'preload-ran', 3);
w.loadFile(path.resolve(__dirname, `fixtures/sub-frames/frame-with-frame-container${fixtureSuffix}.html`));
const [, , event3] = await detailsPromise;
const pongPromise = emittedOnce(ipcMain, 'preload-pong');
const pongPromise = once(ipcMain, 'preload-pong');
event3[0].senderFrame.send('preload-ping');
const [, frameId] = await pongPromise;
expect(frameId).to.equal(event3[0].frameId);
@ -201,8 +202,8 @@ describe('renderer nodeIntegrationInSubFrames', () => {
});
it('should not load preload scripts', async () => {
const promisePass = emittedOnce(ipcMain, 'webview-loaded');
const promiseFail = emittedOnce(ipcMain, 'preload-in-frame').then(() => {
const promisePass = once(ipcMain, 'webview-loaded');
const promiseFail = once(ipcMain, 'preload-in-frame').then(() => {
throw new Error('preload loaded in internal frame');
});
await w.loadURL('about:blank');

View file

@ -2,9 +2,9 @@ import { expect } from 'chai';
import * as childProcess from 'child_process';
import * as path from 'path';
import { BrowserWindow, MessageChannelMain, utilityProcess } from 'electron/main';
import { emittedOnce } from './lib/events-helpers';
import { ifit } from './lib/spec-helpers';
import { closeWindow } from './lib/window-helpers';
import { once } from 'events';
const fixturesPath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process');
const isWindowsOnArm = process.platform === 'win32' && process.arch === 'arm64';
@ -55,12 +55,12 @@ describe('utilityProcess module', () => {
describe('lifecycle events', () => {
it('emits \'spawn\' when child process successfully launches', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'empty.js'));
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
});
it('emits \'exit\' when child process exits gracefully', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'empty.js'));
const [code] = await emittedOnce(child, 'exit');
const [code] = await once(child, 'exit');
expect(code).to.equal(0);
});
@ -68,28 +68,28 @@ describe('utilityProcess module', () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'crash.js'));
// Do not check for exit code in this case,
// SIGSEGV code can be 139 or 11 across our different CI pipeline.
await emittedOnce(child, 'exit');
await once(child, 'exit');
});
it('emits \'exit\' corresponding to the child process', async () => {
const child1 = utilityProcess.fork(path.join(fixturesPath, 'endless.js'));
await emittedOnce(child1, 'spawn');
await once(child1, 'spawn');
const child2 = utilityProcess.fork(path.join(fixturesPath, 'crash.js'));
await emittedOnce(child2, 'exit');
await once(child2, 'exit');
expect(child1.kill()).to.be.true();
await emittedOnce(child1, 'exit');
await once(child1, 'exit');
});
it('emits \'exit\' when there is uncaught exception', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'exception.js'));
const [code] = await emittedOnce(child, 'exit');
const [code] = await once(child, 'exit');
expect(code).to.equal(1);
});
it('emits \'exit\' when process.exit is called', async () => {
const exitCode = 2;
const child = utilityProcess.fork(path.join(fixturesPath, 'custom-exit.js'), [`--exitCode=${exitCode}`]);
const [code] = await emittedOnce(child, 'exit');
const [code] = await once(child, 'exit');
expect(code).to.equal(exitCode);
});
});
@ -99,16 +99,16 @@ describe('utilityProcess module', () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'endless.js'), [], {
serviceName: 'endless'
});
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.kill()).to.be.true();
await emittedOnce(child, 'exit');
await once(child, 'exit');
});
});
describe('pid property', () => {
it('is valid when child process launches successfully', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'empty.js'));
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.pid).to.not.be.null();
});
@ -121,33 +121,33 @@ describe('utilityProcess module', () => {
describe('stdout property', () => {
it('is null when child process launches with default stdio', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'log.js'));
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.stdout).to.be.null();
expect(child.stderr).to.be.null();
await emittedOnce(child, 'exit');
await once(child, 'exit');
});
it('is null when child process launches with ignore stdio configuration', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'log.js'), [], {
stdio: 'ignore'
});
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.stdout).to.be.null();
expect(child.stderr).to.be.null();
await emittedOnce(child, 'exit');
await once(child, 'exit');
});
it('is valid when child process launches with pipe stdio configuration', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'log.js'), [], {
stdio: 'pipe'
});
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.stdout).to.not.be.null();
let log = '';
child.stdout!.on('data', (chunk) => {
log += chunk.toString('utf8');
});
await emittedOnce(child, 'exit');
await once(child, 'exit');
expect(log).to.equal('hello\n');
});
});
@ -155,32 +155,32 @@ describe('utilityProcess module', () => {
describe('stderr property', () => {
it('is null when child process launches with default stdio', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'log.js'));
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.stdout).to.be.null();
expect(child.stderr).to.be.null();
await emittedOnce(child, 'exit');
await once(child, 'exit');
});
it('is null when child process launches with ignore stdio configuration', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'log.js'), [], {
stdio: 'ignore'
});
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.stderr).to.be.null();
await emittedOnce(child, 'exit');
await once(child, 'exit');
});
ifit(!isWindowsOnArm)('is valid when child process launches with pipe stdio configuration', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'log.js'), [], {
stdio: ['ignore', 'pipe', 'pipe']
});
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.stderr).to.not.be.null();
let log = '';
child.stderr!.on('data', (chunk) => {
log += chunk.toString('utf8');
});
await emittedOnce(child, 'exit');
await once(child, 'exit');
expect(log).to.equal('world');
});
});
@ -189,25 +189,25 @@ describe('utilityProcess module', () => {
it('establishes a default ipc channel with the child process', async () => {
const result = 'I will be echoed.';
const child = utilityProcess.fork(path.join(fixturesPath, 'post-message.js'));
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
child.postMessage(result);
const [data] = await emittedOnce(child, 'message');
const [data] = await once(child, 'message');
expect(data).to.equal(result);
const exit = emittedOnce(child, 'exit');
const exit = once(child, 'exit');
expect(child.kill()).to.be.true();
await exit;
});
it('supports queuing messages on the receiving end', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'post-message-queue.js'));
const p = emittedOnce(child, 'spawn');
const p = once(child, 'spawn');
child.postMessage('This message');
child.postMessage(' is');
child.postMessage(' queued');
await p;
const [data] = await emittedOnce(child, 'message');
const [data] = await once(child, 'message');
expect(data).to.equal('This message is queued');
const exit = emittedOnce(child, 'exit');
const exit = once(child, 'exit');
expect(child.kill()).to.be.true();
await exit;
});
@ -270,7 +270,7 @@ describe('utilityProcess module', () => {
const appProcess = childProcess.spawn(process.execPath, [path.join(fixturesPath, 'inherit-stdout'), `--payload=${result}`]);
let output = '';
appProcess.stdout.on('data', (data: Buffer) => { output += data; });
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(output).to.equal(result);
});
@ -279,7 +279,7 @@ describe('utilityProcess module', () => {
const appProcess = childProcess.spawn(process.execPath, [path.join(fixturesPath, 'inherit-stderr'), `--payload=${result}`]);
let output = '';
appProcess.stderr.on('data', (data: Buffer) => { output += data; });
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
expect(output).to.include(result);
});
@ -297,12 +297,12 @@ describe('utilityProcess module', () => {
w.webContents.postMessage('port', result, [rendererPort]);
// Send renderer and main channel port to utility process.
const child = utilityProcess.fork(path.join(fixturesPath, 'receive-message.js'));
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
child.postMessage('', [childPort1]);
const [data] = await emittedOnce(child, 'message');
const [data] = await once(child, 'message');
expect(data).to.equal(result);
// Cleanup.
const exit = emittedOnce(child, 'exit');
const exit = once(child, 'exit');
expect(child.kill()).to.be.true();
await exit;
await closeWindow(w);
@ -310,10 +310,10 @@ describe('utilityProcess module', () => {
ifit(process.platform === 'linux')('allows executing a setuid binary with child_process', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'suid.js'));
await emittedOnce(child, 'spawn');
const [data] = await emittedOnce(child, 'message');
await once(child, 'spawn');
const [data] = await once(child, 'message');
expect(data).to.not.be.empty();
const exit = emittedOnce(child, 'exit');
const exit = once(child, 'exit');
expect(child.kill()).to.be.true();
await exit;
});
@ -327,7 +327,7 @@ describe('utilityProcess module', () => {
});
let output = '';
appProcess.stdout.on('data', (data: Buffer) => { output += data; });
await emittedOnce(appProcess.stdout, 'end');
await once(appProcess.stdout, 'end');
const result = process.platform === 'win32' ? '\r\nparent' : 'parent';
expect(output).to.equal(result);
});
@ -341,7 +341,7 @@ describe('utilityProcess module', () => {
});
let output = '';
appProcess.stdout.on('data', (data: Buffer) => { output += data; });
await emittedOnce(appProcess.stdout, 'end');
await once(appProcess.stdout, 'end');
const result = process.platform === 'win32' ? '\r\nchild' : 'child';
expect(output).to.equal(result);
});
@ -351,13 +351,13 @@ describe('utilityProcess module', () => {
cwd: fixturesPath,
stdio: ['ignore', 'pipe', 'ignore']
});
await emittedOnce(child, 'spawn');
await once(child, 'spawn');
expect(child.stdout).to.not.be.null();
let log = '';
child.stdout!.on('data', (chunk) => {
log += chunk.toString('utf8');
});
await emittedOnce(child, 'exit');
await once(child, 'exit');
expect(log).to.equal('hello\n');
});
});

View file

@ -4,9 +4,10 @@ import * as path from 'path';
import * as fs from 'fs';
import * as http from 'http';
import { BrowserWindow, ipcMain, webContents, session, app, BrowserView } from 'electron/main';
import { emittedOnce } from './lib/events-helpers';
import { closeAllWindows } from './lib/window-helpers';
import { ifdescribe, delay, defer, waitUntil, listen } from './lib/spec-helpers';
import { ifdescribe, defer, waitUntil, listen } from './lib/spec-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
const pdfjs = require('pdfjs-dist');
const fixturesPath = path.resolve(__dirname, 'fixtures');
@ -23,11 +24,11 @@ describe('webContents module', () => {
});
w.loadFile(path.join(fixturesPath, 'pages', 'webview-zoom-factor.html'));
await emittedOnce(w.webContents, 'did-attach-webview');
await once(w.webContents, 'did-attach-webview');
w.webContents.openDevTools();
await emittedOnce(w.webContents, 'devtools-opened');
await once(w.webContents, 'devtools-opened');
const all = webContents.getAllWebContents().sort((a, b) => {
return a.id - b.id;
@ -94,7 +95,7 @@ describe('webContents module', () => {
expect.fail('should not have fired');
});
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-undefined.html'));
const wait = emittedOnce(w, 'closed');
const wait = once(w, 'closed');
w.close();
await wait;
});
@ -110,7 +111,7 @@ describe('webContents module', () => {
});
await view.webContents.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-undefined.html'));
const wait = emittedOnce(w, 'closed');
const wait = once(w, 'closed');
w.close();
await wait;
});
@ -119,7 +120,7 @@ describe('webContents module', () => {
const w = new BrowserWindow({ show: false });
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-false.html'));
w.close();
await emittedOnce(w.webContents, 'will-prevent-unload');
await once(w.webContents, 'will-prevent-unload');
});
it('emits if beforeunload returns false in a BrowserView', async () => {
@ -130,14 +131,14 @@ describe('webContents module', () => {
await view.webContents.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-false.html'));
w.close();
await emittedOnce(view.webContents, 'will-prevent-unload');
await once(view.webContents, 'will-prevent-unload');
});
it('supports calling preventDefault on will-prevent-unload events in a BrowserWindow', async () => {
const w = new BrowserWindow({ show: false });
w.webContents.once('will-prevent-unload', event => event.preventDefault());
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-false.html'));
const wait = emittedOnce(w, 'closed');
const wait = once(w, 'closed');
w.close();
await wait;
});
@ -171,9 +172,9 @@ describe('webContents module', () => {
}
});
w.loadFile(path.join(fixturesPath, 'pages', 'send-after-node.html'));
setTimeout(() => {
setTimeout(50).then(() => {
w.webContents.send('test');
}, 50);
});
});
});
@ -362,7 +363,7 @@ describe('webContents module', () => {
it('resolves when navigating within the page', async () => {
await w.loadFile(path.join(fixturesPath, 'pages', 'base-page.html'));
await delay();
await setTimeout();
await expect(w.loadURL(w.getURL() + '#foo')).to.eventually.be.fulfilled();
});
@ -494,11 +495,11 @@ describe('webContents module', () => {
await w.loadFile(path.join(__dirname, 'fixtures', 'blank.html'));
expect(webContents.getFocusedWebContents().id).to.equal(w.webContents.id);
const devToolsOpened = emittedOnce(w.webContents, 'devtools-opened');
const devToolsOpened = once(w.webContents, 'devtools-opened');
w.webContents.openDevTools();
await devToolsOpened;
expect(webContents.getFocusedWebContents().id).to.equal(w.webContents.devToolsWebContents!.id);
const devToolsClosed = emittedOnce(w.webContents, 'devtools-closed');
const devToolsClosed = once(w.webContents, 'devtools-closed');
w.webContents.closeDevTools();
await devToolsClosed;
expect(webContents.getFocusedWebContents().id).to.equal(w.webContents.id);
@ -511,14 +512,14 @@ describe('webContents module', () => {
w.webContents.inspectElement(100, 100);
// For some reason we have to wait for two focused events...?
await emittedOnce(w.webContents, 'devtools-focused');
await once(w.webContents, 'devtools-focused');
expect(() => { webContents.getFocusedWebContents(); }).to.not.throw();
// Work around https://github.com/electron/electron/issues/19985
await delay();
await setTimeout();
const devToolsClosed = emittedOnce(w.webContents, 'devtools-closed');
const devToolsClosed = once(w.webContents, 'devtools-closed');
w.webContents.closeDevTools();
await devToolsClosed;
expect(() => { webContents.getFocusedWebContents(); }).to.not.throw();
@ -530,7 +531,7 @@ describe('webContents module', () => {
it('sets arbitrary webContents as devtools', async () => {
const w = new BrowserWindow({ show: false });
const devtools = new BrowserWindow({ show: false });
const promise = emittedOnce(devtools.webContents, 'dom-ready');
const promise = once(devtools.webContents, 'dom-ready');
w.webContents.setDevToolsWebContents(devtools.webContents);
w.webContents.openDevTools();
await promise;
@ -564,11 +565,11 @@ describe('webContents module', () => {
oscillator.connect(context.destination)
oscillator.start()
`);
let p = emittedOnce(w.webContents, '-audio-state-changed');
let p = once(w.webContents, '-audio-state-changed');
w.webContents.executeJavaScript('context.resume()');
await p;
expect(w.webContents.isCurrentlyAudible()).to.be.true();
p = emittedOnce(w.webContents, '-audio-state-changed');
p = once(w.webContents, '-audio-state-changed');
w.webContents.executeJavaScript('oscillator.stop()');
await p;
expect(w.webContents.isCurrentlyAudible()).to.be.false();
@ -579,15 +580,15 @@ describe('webContents module', () => {
afterEach(closeAllWindows);
it('can show window with activation', async () => {
const w = new BrowserWindow({ show: false });
const focused = emittedOnce(w, 'focus');
const focused = once(w, 'focus');
w.show();
await focused;
expect(w.isFocused()).to.be.true();
const blurred = emittedOnce(w, 'blur');
const blurred = once(w, 'blur');
w.webContents.openDevTools({ mode: 'detach', activate: true });
await Promise.all([
emittedOnce(w.webContents, 'devtools-opened'),
emittedOnce(w.webContents, 'devtools-focused')
once(w.webContents, 'devtools-opened'),
once(w.webContents, 'devtools-focused')
]);
await blurred;
expect(w.isFocused()).to.be.false();
@ -595,7 +596,7 @@ describe('webContents module', () => {
it('can show window without activation', async () => {
const w = new BrowserWindow({ show: false });
const devtoolsOpened = emittedOnce(w.webContents, 'devtools-opened');
const devtoolsOpened = once(w.webContents, 'devtools-opened');
w.webContents.openDevTools({ mode: 'detach', activate: false });
await devtoolsOpened;
expect(w.webContents.isDevToolsOpened()).to.be.true();
@ -629,7 +630,7 @@ describe('webContents module', () => {
if (opts.meta) modifiers.push('meta');
if (opts.isAutoRepeat) modifiers.push('isAutoRepeat');
const p = emittedOnce(w.webContents, 'before-input-event');
const p = once(w.webContents, 'before-input-event');
w.webContents.sendInputEvent({
type: opts.type,
keyCode: opts.keyCode,
@ -712,7 +713,7 @@ describe('webContents module', () => {
modifiers: ['control', 'meta']
});
const [, zoomDirection] = await emittedOnce(w.webContents, 'zoom-changed');
const [, zoomDirection] = await once(w.webContents, 'zoom-changed');
expect(zoomDirection).to.equal('in');
};
@ -735,7 +736,7 @@ describe('webContents module', () => {
modifiers: ['control', 'meta']
});
const [, zoomDirection] = await emittedOnce(w.webContents, 'zoom-changed');
const [, zoomDirection] = await once(w.webContents, 'zoom-changed');
expect(zoomDirection).to.equal('out');
};
@ -752,7 +753,7 @@ describe('webContents module', () => {
afterEach(closeAllWindows);
it('can send keydown events', async () => {
const keydown = emittedOnce(ipcMain, 'keydown');
const keydown = once(ipcMain, 'keydown');
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'A' });
const [, key, code, keyCode, shiftKey, ctrlKey, altKey] = await keydown;
expect(key).to.equal('a');
@ -764,7 +765,7 @@ describe('webContents module', () => {
});
it('can send keydown events with modifiers', async () => {
const keydown = emittedOnce(ipcMain, 'keydown');
const keydown = once(ipcMain, 'keydown');
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Z', modifiers: ['shift', 'ctrl'] });
const [, key, code, keyCode, shiftKey, ctrlKey, altKey] = await keydown;
expect(key).to.equal('Z');
@ -776,7 +777,7 @@ describe('webContents module', () => {
});
it('can send keydown events with special keys', async () => {
const keydown = emittedOnce(ipcMain, 'keydown');
const keydown = once(ipcMain, 'keydown');
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Tab', modifiers: ['alt'] });
const [, key, code, keyCode, shiftKey, ctrlKey, altKey] = await keydown;
expect(key).to.equal('Tab');
@ -788,7 +789,7 @@ describe('webContents module', () => {
});
it('can send char events', async () => {
const keypress = emittedOnce(ipcMain, 'keypress');
const keypress = once(ipcMain, 'keypress');
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'A' });
w.webContents.sendInputEvent({ type: 'char', keyCode: 'A' });
const [, key, code, keyCode, shiftKey, ctrlKey, altKey] = await keypress;
@ -801,7 +802,7 @@ describe('webContents module', () => {
});
it('can send char events with modifiers', async () => {
const keypress = emittedOnce(ipcMain, 'keypress');
const keypress = once(ipcMain, 'keypress');
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Z' });
w.webContents.sendInputEvent({ type: 'char', keyCode: 'Z', modifiers: ['shift', 'ctrl'] });
const [, key, code, keyCode, shiftKey, ctrlKey, altKey] = await keypress;
@ -839,7 +840,7 @@ describe('webContents module', () => {
it('supports inspecting an element in the devtools', async () => {
const w = new BrowserWindow({ show: false });
w.loadURL('about:blank');
const event = emittedOnce(w.webContents, 'devtools-opened');
const event = once(w.webContents, 'devtools-opened');
w.webContents.inspectElement(10, 10);
await event;
});
@ -882,7 +883,7 @@ describe('webContents module', () => {
});
const moveFocusToDevTools = async (win: BrowserWindow) => {
const devToolsOpened = emittedOnce(win.webContents, 'devtools-opened');
const devToolsOpened = once(win.webContents, 'devtools-opened');
win.webContents.openDevTools({ mode: 'right' });
await devToolsOpened;
win.webContents.devToolsWebContents!.focus();
@ -895,7 +896,7 @@ describe('webContents module', () => {
const w = new BrowserWindow({ show: false });
await w.loadURL('about:blank');
await moveFocusToDevTools(w);
const focusPromise = emittedOnce(w.webContents, 'focus');
const focusPromise = once(w.webContents, 'focus');
w.webContents.focus();
await expect(focusPromise).to.eventually.be.fulfilled();
});
@ -907,7 +908,7 @@ describe('webContents module', () => {
const w = new BrowserWindow({ show: true });
await w.loadURL('about:blank');
w.webContents.focus();
const blurPromise = emittedOnce(w.webContents, 'blur');
const blurPromise = once(w.webContents, 'blur');
await moveFocusToDevTools(w);
await expect(blurPromise).to.eventually.be.fulfilled();
});
@ -1175,9 +1176,9 @@ describe('webContents module', () => {
it('can persist when it contains iframe', (done) => {
const w = new BrowserWindow({ show: false });
const server = http.createServer((req, res) => {
setTimeout(() => {
setTimeout(200).then(() => {
res.end();
}, 200);
});
});
server.listen(0, '127.0.0.1', () => {
const url = 'http://127.0.0.1:' + (server.address() as AddressInfo).port;
@ -1208,7 +1209,7 @@ describe('webContents module', () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
const w2 = new BrowserWindow({ show: false });
const temporaryZoomSet = emittedOnce(ipcMain, 'temporary-zoom-set');
const temporaryZoomSet = once(ipcMain, 'temporary-zoom-set');
w.loadFile(path.join(fixturesPath, 'pages', 'webframe-zoom.html'));
await temporaryZoomSet;
@ -1232,7 +1233,7 @@ describe('webContents module', () => {
before(async () => {
server = http.createServer((req, res) => {
setTimeout(() => res.end('hey'), 0);
setTimeout().then(() => res.end('hey'));
});
serverUrl = (await listen(server)).url;
crossSiteUrl = serverUrl.replace('127.0.0.1', 'localhost');
@ -1249,12 +1250,12 @@ describe('webContents module', () => {
webFrame.setZoomLevel(0.6)
ipcRenderer.send('zoom-level-set', webFrame.getZoomLevel())
`;
const zoomLevelPromise = emittedOnce(ipcMain, 'zoom-level-set');
const zoomLevelPromise = once(ipcMain, 'zoom-level-set');
await w.loadURL(serverUrl);
await w.webContents.executeJavaScript(source);
let [, zoomLevel] = await zoomLevelPromise;
expect(zoomLevel).to.equal(0.6);
const loadPromise = emittedOnce(w.webContents, 'did-finish-load');
const loadPromise = once(w.webContents, 'did-finish-load');
await w.loadURL(crossSiteUrl);
await loadPromise;
zoomLevel = w.webContents.zoomLevel;
@ -1285,7 +1286,7 @@ describe('webContents module', () => {
it('can get opener with window.open()', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
const childPromise = once(w.webContents, 'did-create-window');
w.webContents.executeJavaScript('window.open("about:blank")', true);
const [childWindow] = await childPromise;
expect(childWindow.webContents.opener).to.equal(w.webContents.mainFrame);
@ -1293,7 +1294,7 @@ describe('webContents module', () => {
it('has no opener when using "noopener"', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
const childPromise = once(w.webContents, 'did-create-window');
w.webContents.executeJavaScript('window.open("about:blank", undefined, "noopener")', true);
const [childWindow] = await childPromise;
expect(childWindow.webContents.opener).to.be.null();
@ -1301,7 +1302,7 @@ describe('webContents module', () => {
it('can get opener with a[target=_blank][rel=opener]', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
const childPromise = once(w.webContents, 'did-create-window');
w.webContents.executeJavaScript(`(function() {
const a = document.createElement('a');
a.target = '_blank';
@ -1315,7 +1316,7 @@ describe('webContents module', () => {
it('has no opener with a[target=_blank][rel=noopener]', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
const childPromise = once(w.webContents, 'did-create-window');
w.webContents.executeJavaScript(`(function() {
const a = document.createElement('a');
a.target = '_blank';
@ -1350,7 +1351,7 @@ describe('webContents module', () => {
res.end();
}
};
setTimeout(respond, 0);
setTimeout().then(respond);
});
serverUrl = (await listen(server)).url;
crossSiteUrl = serverUrl.replace('127.0.0.1', 'localhost');
@ -1373,7 +1374,7 @@ describe('webContents module', () => {
w.webContents.removeListener('current-render-view-deleted' as any, renderViewDeletedHandler);
w.close();
});
const destroyed = emittedOnce(w.webContents, 'destroyed');
const destroyed = once(w.webContents, 'destroyed');
w.loadURL(`${serverUrl}/redirect-cross-site`);
await destroyed;
expect(currentRenderViewDeletedEmitted).to.be.false('current-render-view-deleted was emitted');
@ -1383,7 +1384,7 @@ describe('webContents module', () => {
const parentWindow = new BrowserWindow({ show: false });
let currentRenderViewDeletedEmitted = false;
let childWindow: BrowserWindow | null = null;
const destroyed = emittedOnce(parentWindow.webContents, 'destroyed');
const destroyed = once(parentWindow.webContents, 'destroyed');
const renderViewDeletedHandler = () => {
currentRenderViewDeletedEmitted = true;
};
@ -1411,7 +1412,7 @@ describe('webContents module', () => {
w.webContents.on('did-finish-load', () => {
w.close();
});
const destroyed = emittedOnce(w.webContents, 'destroyed');
const destroyed = once(w.webContents, 'destroyed');
w.loadURL(`${serverUrl}/redirect-cross-site`);
await destroyed;
expect(currentRenderViewDeletedEmitted).to.be.true('current-render-view-deleted wasn\'t emitted');
@ -1426,7 +1427,7 @@ describe('webContents module', () => {
w.webContents.on('did-finish-load', () => {
w.close();
});
const destroyed = emittedOnce(w.webContents, 'destroyed');
const destroyed = once(w.webContents, 'destroyed');
w.loadURL(`${serverUrl}/redirect-cross-site`);
await destroyed;
const expectedRenderViewDeletedEventCount = 1;
@ -1477,7 +1478,7 @@ describe('webContents module', () => {
it('forcefullyCrashRenderer() crashes the process with reason=killed||crashed', async () => {
expect(w.webContents.isCrashed()).to.equal(false);
const crashEvent = emittedOnce(w.webContents, 'render-process-gone');
const crashEvent = once(w.webContents, 'render-process-gone');
w.webContents.forcefullyCrashRenderer();
const [, details] = await crashEvent;
expect(details.reason === 'killed' || details.reason === 'crashed').to.equal(true, 'reason should be killed || crashed');
@ -1543,7 +1544,7 @@ describe('webContents module', () => {
const originalEmit = contents.emit.bind(contents);
contents.emit = (...args) => { return originalEmit(...args); };
contents.once(e.name as any, () => contents.destroy());
const destroyed = emittedOnce(contents, 'destroyed');
const destroyed = once(contents, 'destroyed');
contents.loadURL(serverUrl + e.url);
await destroyed;
});
@ -1596,7 +1597,7 @@ describe('webContents module', () => {
require('electron').ipcRenderer.send('message', 'Hello World!')
`);
const [, channel, message] = await emittedOnce(w.webContents, 'ipc-message');
const [, channel, message] = await once(w.webContents, 'ipc-message');
expect(channel).to.equal('message');
expect(message).to.equal('Hello World!');
});
@ -1708,7 +1709,7 @@ describe('webContents module', () => {
}
});
const promise = emittedOnce(w.webContents, 'preload-error');
const promise = once(w.webContents, 'preload-error');
w.loadURL('about:blank');
const [, preloadPath, error] = await promise;
@ -1727,7 +1728,7 @@ describe('webContents module', () => {
}
});
const promise = emittedOnce(w.webContents, 'preload-error');
const promise = once(w.webContents, 'preload-error');
w.loadURL('about:blank');
const [, preloadPath, error] = await promise;
@ -1746,7 +1747,7 @@ describe('webContents module', () => {
}
});
const promise = emittedOnce(w.webContents, 'preload-error');
const promise = once(w.webContents, 'preload-error');
w.loadURL('about:blank');
const [, preloadPath, error] = await promise;
@ -2061,7 +2062,7 @@ describe('webContents module', () => {
it('can get multiple shared workers', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
const ready = emittedOnce(ipcMain, 'ready');
const ready = once(ipcMain, 'ready');
w.loadFile(path.join(fixturesPath, 'api', 'shared-worker', 'shared-worker.html'));
await ready;
@ -2075,17 +2076,17 @@ describe('webContents module', () => {
it('can inspect a specific shared worker', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
const ready = emittedOnce(ipcMain, 'ready');
const ready = once(ipcMain, 'ready');
w.loadFile(path.join(fixturesPath, 'api', 'shared-worker', 'shared-worker.html'));
await ready;
const sharedWorkers = w.webContents.getAllSharedWorkers();
const devtoolsOpened = emittedOnce(w.webContents, 'devtools-opened');
const devtoolsOpened = once(w.webContents, 'devtools-opened');
w.webContents.inspectSharedWorkerById(sharedWorkers[0].id);
await devtoolsOpened;
const devtoolsClosed = emittedOnce(w.webContents, 'devtools-closed');
const devtoolsClosed = once(w.webContents, 'devtools-closed');
w.webContents.closeDevTools();
await devtoolsClosed;
});
@ -2202,9 +2203,9 @@ describe('webContents module', () => {
const bw = new BrowserWindow({ show: false });
await bw.loadURL('about:blank');
bw.webContents.executeJavaScript('child = window.open("", "", "show=no"); null');
const [, child] = await emittedOnce(app, 'web-contents-created');
const [, child] = await once(app, 'web-contents-created');
bw.webContents.executeJavaScript('child.document.title = "new title"');
const [, title] = await emittedOnce(child, 'page-title-updated');
const [, title] = await once(child, 'page-title-updated');
expect(title).to.equal('new title');
});
});
@ -2212,7 +2213,7 @@ describe('webContents module', () => {
describe('crashed event', () => {
it('does not crash main process when destroying WebContents in it', async () => {
const contents = (webContents as typeof ElectronInternal.WebContents).create({ nodeIntegration: true });
const crashEvent = emittedOnce(contents, 'render-process-gone');
const crashEvent = once(contents, 'render-process-gone');
await contents.loadURL('about:blank');
contents.forcefullyCrashRenderer();
await crashEvent;
@ -2226,7 +2227,7 @@ describe('webContents module', () => {
const w = new BrowserWindow({ show: false });
await w.loadFile(path.join(fixturesPath, 'pages', 'base-page.html'));
const promise = emittedOnce(w.webContents, 'context-menu');
const promise = once(w.webContents, 'context-menu');
// Simulate right-click to create context-menu event.
const opts = { x: 0, y: 0, button: 'right' as any };
@ -2247,7 +2248,7 @@ describe('webContents module', () => {
it('closes when close() is called', async () => {
const w = (webContents as typeof ElectronInternal.WebContents).create();
const destroyed = emittedOnce(w, 'destroyed');
const destroyed = once(w, 'destroyed');
w.close();
await destroyed;
expect(w.isDestroyed()).to.be.true();
@ -2256,7 +2257,7 @@ describe('webContents module', () => {
it('closes when close() is called after loading a page', async () => {
const w = (webContents as typeof ElectronInternal.WebContents).create();
await w.loadURL('about:blank');
const destroyed = emittedOnce(w, 'destroyed');
const destroyed = once(w, 'destroyed');
w.close();
await destroyed;
expect(w.isDestroyed()).to.be.true();
@ -2280,7 +2281,7 @@ describe('webContents module', () => {
it('causes its parent browserwindow to be closed', async () => {
const w = new BrowserWindow({ show: false });
await w.loadURL('about:blank');
const closed = emittedOnce(w, 'closed');
const closed = once(w, 'closed');
w.webContents.close();
await closed;
expect(w.isDestroyed()).to.be.true();
@ -2291,7 +2292,7 @@ describe('webContents module', () => {
await w.loadURL('about:blank');
await w.executeJavaScript('window.onbeforeunload = () => "hello"; null');
w.on('will-prevent-unload', () => { throw new Error('unexpected will-prevent-unload'); });
const destroyed = emittedOnce(w, 'destroyed');
const destroyed = once(w, 'destroyed');
w.close();
await destroyed;
expect(w.isDestroyed()).to.be.true();
@ -2301,7 +2302,7 @@ describe('webContents module', () => {
const w = (webContents as typeof ElectronInternal.WebContents).create();
await w.loadURL('about:blank');
await w.executeJavaScript('window.onbeforeunload = () => "hello"; null');
const willPreventUnload = emittedOnce(w, 'will-prevent-unload');
const willPreventUnload = once(w, 'will-prevent-unload');
w.close({ waitForBeforeUnload: true });
await willPreventUnload;
expect(w.isDestroyed()).to.be.false();
@ -2312,7 +2313,7 @@ describe('webContents module', () => {
await w.loadURL('about:blank');
await w.executeJavaScript('window.onbeforeunload = () => "hello"; null');
w.once('will-prevent-unload', e => e.preventDefault());
const destroyed = emittedOnce(w, 'destroyed');
const destroyed = once(w, 'destroyed');
w.close({ waitForBeforeUnload: true });
await destroyed;
expect(w.isDestroyed()).to.be.true();
@ -2325,7 +2326,7 @@ describe('webContents module', () => {
const w = new BrowserWindow({ show: false });
w.loadURL('about:blank');
w.webContents.executeJavaScript('window.moveTo(100, 100)', true);
const [, rect] = await emittedOnce(w.webContents, 'content-bounds-updated');
const [, rect] = await once(w.webContents, 'content-bounds-updated');
const { width, height } = w.getBounds();
expect(rect).to.deep.equal({
x: 100,
@ -2342,7 +2343,7 @@ describe('webContents module', () => {
const w = new BrowserWindow({ show: false });
w.loadURL('about:blank');
w.webContents.executeJavaScript('window.resizeTo(100, 100)', true);
const [, rect] = await emittedOnce(w.webContents, 'content-bounds-updated');
const [, rect] = await once(w.webContents, 'content-bounds-updated');
const { x, y } = w.getBounds();
expect(rect).to.deep.equal({
x,

View file

@ -4,8 +4,10 @@ import * as path from 'path';
import * as url from 'url';
import { BrowserWindow, WebFrameMain, webFrameMain, ipcMain, app, WebContents } from 'electron/main';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce, emittedNTimes } from './lib/events-helpers';
import { defer, delay, ifit, listen, waitUntil } from './lib/spec-helpers';
import { emittedNTimes } from './lib/events-helpers';
import { defer, ifit, listen, waitUntil } from './lib/spec-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
describe('webFrameMain module', () => {
const fixtures = path.resolve(__dirname, 'fixtures');
@ -141,7 +143,7 @@ describe('webFrameMain module', () => {
it('should show parent origin when child page is about:blank', async () => {
const w = new BrowserWindow({ show: false });
await w.loadFile(path.join(fixtures, 'pages', 'blank.html'));
const webContentsCreated: Promise<[unknown, WebContents]> = emittedOnce(app, 'web-contents-created') as any;
const webContentsCreated: Promise<[unknown, WebContents]> = once(app, 'web-contents-created') as any;
expect(w.webContents.mainFrame.origin).to.equal('file://');
await w.webContents.executeJavaScript('window.open("", null, "show=false"), null');
const [, childWebContents] = await webContentsCreated;
@ -161,7 +163,7 @@ describe('webFrameMain module', () => {
expect(mainFrame.origin).to.equal(serverA.url.replace(/\/$/, ''));
const [childFrame] = mainFrame.frames;
expect(childFrame.origin).to.equal(serverB.url.replace(/\/$/, ''));
const webContentsCreated: Promise<[unknown, WebContents]> = emittedOnce(app, 'web-contents-created') as any;
const webContentsCreated: Promise<[unknown, WebContents]> = once(app, 'web-contents-created') as any;
await childFrame.executeJavaScript('window.open("", null, "show=false"), null');
const [, childWebContents] = await webContentsCreated;
expect(childWebContents.mainFrame.origin).to.equal(childFrame.origin);
@ -257,7 +259,7 @@ describe('webFrameMain module', () => {
await webFrame.executeJavaScript('window.TEMP = 1', false);
expect(webFrame.reload()).to.be.true();
await emittedOnce(w.webContents, 'dom-ready');
await once(w.webContents, 'dom-ready');
expect(await webFrame.executeJavaScript('window.TEMP', false)).to.be.null();
});
});
@ -273,7 +275,7 @@ describe('webFrameMain module', () => {
});
await w.loadURL('about:blank');
const webFrame = w.webContents.mainFrame;
const pongPromise = emittedOnce(ipcMain, 'preload-pong');
const pongPromise = once(ipcMain, 'preload-pong');
webFrame.send('preload-ping');
const [, routingId] = await pongPromise;
expect(routingId).to.equal(webFrame.routingId);
@ -293,7 +295,7 @@ describe('webFrameMain module', () => {
const { mainFrame } = w.webContents;
w.destroy();
// Wait for WebContents, and thus RenderFrameHost, to be destroyed.
await delay();
await setTimeout();
expect(() => mainFrame.url).to.throw();
});
@ -314,7 +316,7 @@ describe('webFrameMain module', () => {
// Keep reference to mainFrame alive throughout crash and recovery.
const { mainFrame } = w.webContents;
await w.webContents.loadURL(server.url);
const crashEvent = emittedOnce(w.webContents, 'render-process-gone');
const crashEvent = once(w.webContents, 'render-process-gone');
w.webContents.forcefullyCrashRenderer();
await crashEvent;
await w.webContents.loadURL(server.url);
@ -330,11 +332,11 @@ describe('webFrameMain module', () => {
// Keep reference to mainFrame alive throughout crash and recovery.
const { mainFrame } = w.webContents;
await w.webContents.loadURL(server.url);
const crashEvent = emittedOnce(w.webContents, 'render-process-gone');
const crashEvent = once(w.webContents, 'render-process-gone');
w.webContents.forcefullyCrashRenderer();
await crashEvent;
// A short wait seems to be required to reproduce the crash.
await delay(100);
await setTimeout(100);
await w.webContents.loadURL(crossOriginUrl);
// Log just to keep mainFrame in scope.
console.log('mainFrame.url', mainFrame.url);
@ -366,7 +368,7 @@ describe('webFrameMain module', () => {
describe('"frame-created" event', () => {
it('emits when the main frame is created', async () => {
const w = new BrowserWindow({ show: false });
const promise = emittedOnce(w.webContents, 'frame-created');
const promise = once(w.webContents, 'frame-created');
w.webContents.loadFile(path.join(subframesPath, 'frame.html'));
const [, details] = await promise;
expect(details.frame).to.equal(w.webContents.mainFrame);
@ -406,7 +408,7 @@ describe('webFrameMain module', () => {
describe('"dom-ready" event', () => {
it('emits for top-level frame', async () => {
const w = new BrowserWindow({ show: false });
const promise = emittedOnce(w.webContents.mainFrame, 'dom-ready');
const promise = once(w.webContents.mainFrame, 'dom-ready');
w.webContents.loadURL('about:blank');
await promise;
});

View file

@ -1,8 +1,8 @@
import { expect } from 'chai';
import * as path from 'path';
import { BrowserWindow, ipcMain, WebContents } from 'electron/main';
import { emittedOnce } from './lib/events-helpers';
import { defer } from './lib/spec-helpers';
import { once } from 'events';
describe('webFrame module', () => {
const fixtures = path.resolve(__dirname, 'fixtures');
@ -17,7 +17,7 @@ describe('webFrame module', () => {
}
});
defer(() => w.close());
const isSafe = emittedOnce(ipcMain, 'executejs-safe');
const isSafe = once(ipcMain, 'executejs-safe');
w.loadURL('about:blank');
const [, wasSafe] = await isSafe;
expect(wasSafe).to.equal(true);
@ -33,7 +33,7 @@ describe('webFrame module', () => {
}
});
defer(() => w.close());
const execError = emittedOnce(ipcMain, 'executejs-safe');
const execError = once(ipcMain, 'executejs-safe');
w.loadURL('about:blank');
const [, error] = await execError;
expect(error).to.not.equal(null, 'Error should not be null');

View file

@ -6,8 +6,8 @@ import * as url from 'url';
import * as WebSocket from 'ws';
import { ipcMain, protocol, session, WebContents, webContents } from 'electron/main';
import { Socket } from 'net';
import { emittedOnce } from './lib/events-helpers';
import { listen } from './lib/spec-helpers';
import { once } from 'events';
const fixturesPath = path.resolve(__dirname, 'fixtures');
@ -545,7 +545,7 @@ describe('webRequest module', () => {
});
contents.loadFile(path.join(fixturesPath, 'api', 'webrequest.html'), { query: { port: `${port}` } });
await emittedOnce(ipcMain, 'websocket-success');
await once(ipcMain, 'websocket-success');
expect(receivedHeaders['/websocket'].Upgrade[0]).to.equal('websocket');
expect(receivedHeaders['/'].foo1[0]).to.equal('bar1');

View file

@ -4,9 +4,9 @@ import * as url from 'url';
import { Worker } from 'worker_threads';
import { BrowserWindow, ipcMain } from 'electron/main';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { getRemoteContext, ifdescribe, itremote, useRemoteContext } from './lib/spec-helpers';
import * as importedFs from 'fs';
import { once } from 'events';
const features = process._linkedBinding('electron_common_features');
@ -32,7 +32,7 @@ describe('asar package', () => {
}
});
const p = path.resolve(asarDir, 'web.asar', 'index.html');
const dirnameEvent = emittedOnce(ipcMain, 'dirname');
const dirnameEvent = once(ipcMain, 'dirname');
w.loadFile(p);
const [, dirname] = await dirnameEvent;
expect(dirname).to.equal(path.dirname(p));
@ -53,7 +53,7 @@ describe('asar package', () => {
}
});
const p = path.resolve(asarDir, 'script.asar', 'index.html');
const ping = emittedOnce(ipcMain, 'ping');
const ping = once(ipcMain, 'ping');
w.loadFile(p);
const [, message] = await ping;
expect(message).to.equal('pong');
@ -77,7 +77,7 @@ describe('asar package', () => {
});
const p = path.resolve(asarDir, 'video.asar', 'index.html');
w.loadFile(p);
const [, message, error] = await emittedOnce(ipcMain, 'asar-video');
const [, message, error] = await once(ipcMain, 'asar-video');
if (message === 'ended') {
expect(error).to.be.null();
} else if (message === 'error') {
@ -1514,7 +1514,7 @@ describe('asar package', function () {
/*
ifit(features.isRunAsNodeEnabled())('is available in forked scripts', async function () {
const child = ChildProcess.fork(path.join(fixtures, 'module', 'original-fs.js'));
const message = emittedOnce(child, 'message');
const message = once(child, 'message');
child.send('message');
const [msg] = await message;
expect(msg).to.equal('object');

View file

@ -1,8 +1,8 @@
import { BrowserWindow } from 'electron';
import * as path from 'path';
import { delay } from './lib/spec-helpers';
import { expect } from 'chai';
import { closeAllWindows } from './lib/window-helpers';
import { setTimeout } from 'timers/promises';
const fixturesPath = path.resolve(__dirname, 'fixtures');
@ -17,7 +17,7 @@ describe('autofill', () => {
const inputText = 'clap';
for (const keyCode of inputText) {
w.webContents.sendInputEvent({ type: 'char', keyCode });
await delay(100);
await setTimeout(100);
}
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Down' });
@ -36,7 +36,7 @@ describe('autofill', () => {
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Tab' });
w.webContents.sendInputEvent({ type: 'keyDown', keyCode });
w.webContents.sendInputEvent({ type: 'char', keyCode });
await delay(100);
await setTimeout(100);
}
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Tab' });

View file

@ -1,6 +1,5 @@
import { expect } from 'chai';
import { BrowserWindow, WebContents, webFrameMain, session, ipcMain, app, protocol, webContents } from 'electron/main';
import { emittedOnce } from './lib/events-helpers';
import { closeAllWindows } from './lib/window-helpers';
import * as https from 'https';
import * as http from 'http';
@ -8,11 +7,12 @@ import * as path from 'path';
import * as fs from 'fs';
import * as url from 'url';
import * as ChildProcess from 'child_process';
import { EventEmitter } from 'events';
import { EventEmitter, once } from 'events';
import { promisify } from 'util';
import { ifit, ifdescribe, defer, delay, itremote, listen } from './lib/spec-helpers';
import { ifit, ifdescribe, defer, itremote, listen } from './lib/spec-helpers';
import { PipeTransport } from './pipe-transport';
import * as ws from 'ws';
import { setTimeout } from 'timers/promises';
const features = process._linkedBinding('electron_common_features');
@ -64,7 +64,7 @@ describe('reporting api', () => {
show: false
});
try {
const reportGenerated = emittedOnce(reports, 'report');
const reportGenerated = once(reports, 'report');
await bw.loadURL(url);
const [report] = await reportGenerated;
expect(report).to.be.an('array');
@ -86,7 +86,7 @@ describe('window.postMessage', () => {
it('sets the source and origin correctly', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL(`file://${fixturesPath}/pages/window-open-postMessage-driver.html`);
const [, message] = await emittedOnce(ipcMain, 'complete');
const [, message] = await once(ipcMain, 'complete');
expect(message.data).to.equal('testing');
expect(message.origin).to.equal('file://');
expect(message.sourceEqualsOpener).to.equal(true);
@ -108,11 +108,11 @@ describe('focus handling', () => {
}
});
const webviewReady = emittedOnce(w.webContents, 'did-attach-webview');
const webviewReady = once(w.webContents, 'did-attach-webview');
await w.loadFile(path.join(fixturesPath, 'pages', 'tab-focus-loop-elements.html'));
const [, wvContents] = await webviewReady;
webviewContents = wvContents;
await emittedOnce(webviewContents, 'did-finish-load');
await once(webviewContents, 'did-finish-load');
w.focus();
});
@ -123,7 +123,7 @@ describe('focus handling', () => {
});
const expectFocusChange = async () => {
const [, focusedElementId] = await emittedOnce(ipcMain, 'focus-changed');
const [, focusedElementId] = await once(ipcMain, 'focus-changed');
return focusedElementId;
};
@ -224,7 +224,7 @@ describe('web security', () => {
it('engages CORB when web security is not disabled', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { webSecurity: true, nodeIntegration: true, contextIsolation: false } });
const p = emittedOnce(ipcMain, 'success');
const p = once(ipcMain, 'success');
await w.loadURL(`data:text/html,<script>
const s = document.createElement('script')
s.src = "${serverUrl}"
@ -238,7 +238,7 @@ describe('web security', () => {
it('bypasses CORB when web security is disabled', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { webSecurity: false, nodeIntegration: true, contextIsolation: false } });
const p = emittedOnce(ipcMain, 'success');
const p = once(ipcMain, 'success');
await w.loadURL(`data:text/html,
<script>
window.onerror = (e) => { require('electron').ipcRenderer.send('success', e) }
@ -249,7 +249,7 @@ describe('web security', () => {
it('engages CORS when web security is not disabled', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { webSecurity: true, nodeIntegration: true, contextIsolation: false } });
const p = emittedOnce(ipcMain, 'response');
const p = once(ipcMain, 'response');
await w.loadURL(`data:text/html,<script>
(async function() {
try {
@ -266,7 +266,7 @@ describe('web security', () => {
it('bypasses CORS when web security is disabled', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { webSecurity: false, nodeIntegration: true, contextIsolation: false } });
const p = emittedOnce(ipcMain, 'response');
const p = once(ipcMain, 'response');
await w.loadURL(`data:text/html,<script>
(async function() {
try {
@ -371,7 +371,7 @@ describe('web security', () => {
console.log('success')
}
</script>`);
const [,, message] = await emittedOnce(w.webContents, 'console-message');
const [,, message] = await once(w.webContents, 'console-message');
expect(message).to.equal('success');
});
});
@ -410,7 +410,7 @@ describe('command line switches', () => {
let stderr = '';
appProcess.stderr.on('data', (data) => { stderr += data; });
const [code, signal] = await emittedOnce(appProcess, 'exit');
const [code, signal] = await once(appProcess, 'exit');
if (code !== 0) {
throw new Error(`Process exited with code "${code}" signal "${signal}" output "${output}" stderr "${stderr}"`);
}
@ -471,7 +471,7 @@ describe('command line switches', () => {
const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream];
const pipe = new PipeTransport(stdio[3], stdio[4]);
pipe.send({ id: 1, method: 'Browser.close', params: {} });
await emittedOnce(appProcess, 'exit');
await once(appProcess, 'exit');
});
});
@ -533,7 +533,7 @@ describe('chromium features', () => {
let output = '';
fpsProcess.stdout.on('data', data => { output += data; });
await emittedOnce(fpsProcess, 'exit');
await once(fpsProcess, 'exit');
expect(output).to.include(fps.join(','));
});
@ -545,7 +545,7 @@ describe('chromium features', () => {
let output = '';
fpsProcess.stdout.on('data', data => { output += data; });
await emittedOnce(fpsProcess, 'exit');
await once(fpsProcess, 'exit');
expect(output).to.include(fps.join(','));
});
@ -711,7 +711,7 @@ describe('chromium features', () => {
contextIsolation: false
}
});
const message = emittedOnce(w.webContents, 'ipc-message');
const message = once(w.webContents, 'ipc-message');
w.webContents.session.setPermissionRequestHandler((wc, permission, callback) => {
if (permission === 'geolocation') {
callback(false);
@ -751,7 +751,7 @@ describe('chromium features', () => {
appProcess = ChildProcess.spawn(process.execPath, [appPath]);
const [code] = await emittedOnce(appProcess, 'exit');
const [code] = await once(appProcess, 'exit');
expect(code).to.equal(0);
});
@ -781,7 +781,7 @@ describe('chromium features', () => {
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');
const [, data] = await once(ipcMain, 'worker-result');
expect(data).to.equal('object function object function');
});
@ -863,7 +863,7 @@ describe('chromium features', () => {
await w.loadFile(path.join(fixturesPath, 'pages', 'form-with-data.html'));
const loadPromise = emittedOnce(w.webContents, 'did-finish-load');
const loadPromise = once(w.webContents, 'did-finish-load');
w.webContents.executeJavaScript(`
const form = document.querySelector('form')
@ -887,7 +887,7 @@ describe('chromium features', () => {
await w.loadFile(path.join(fixturesPath, 'pages', 'form-with-data.html'));
const windowCreatedPromise = emittedOnce(app, 'browser-window-created');
const windowCreatedPromise = once(app, 'browser-window-created');
w.webContents.executeJavaScript(`
const form = document.querySelector('form')
@ -919,7 +919,7 @@ describe('chromium features', () => {
defer(() => { w.close(); });
const promise = emittedOnce(app, 'browser-window-created');
const promise = once(app, 'browser-window-created');
w.loadFile(path.join(fixturesPath, 'pages', 'window-open.html'));
const [, newWindow] = await promise;
expect(newWindow.isVisible()).to.equal(true);
@ -955,7 +955,7 @@ describe('chromium features', () => {
w.webContents.executeJavaScript(`
{ b = window.open('devtools://devtools/bundled/inspector.html', '', 'nodeIntegration=no,show=no'); null }
`);
const [, contents] = await emittedOnce(app, 'web-contents-created');
const [, contents] = await once(app, 'web-contents-created');
const typeofProcessGlobal = await contents.executeJavaScript('typeof process');
expect(typeofProcessGlobal).to.equal('undefined');
});
@ -966,7 +966,7 @@ describe('chromium features', () => {
w.webContents.executeJavaScript(`
{ b = window.open('about:blank', '', 'nodeIntegration=no,show=no'); null }
`);
const [, contents] = await emittedOnce(app, 'web-contents-created');
const [, contents] = await once(app, 'web-contents-created');
const typeofProcessGlobal = await contents.executeJavaScript('typeof process');
expect(typeofProcessGlobal).to.equal('undefined');
});
@ -983,12 +983,12 @@ describe('chromium features', () => {
w.webContents.executeJavaScript(`
{ b = window.open(${JSON.stringify(windowUrl)}, '', 'javascript=no,show=no'); null }
`);
const [, contents] = await emittedOnce(app, 'web-contents-created');
await emittedOnce(contents, 'did-finish-load');
const [, contents] = await once(app, 'web-contents-created');
await once(contents, 'did-finish-load');
// Click link on page
contents.sendInputEvent({ type: 'mouseDown', clickCount: 1, x: 1, y: 1 });
contents.sendInputEvent({ type: 'mouseUp', clickCount: 1, x: 1, y: 1 });
const [, window] = await emittedOnce(app, 'browser-window-created');
const [, window] = await once(app, 'browser-window-created');
const preferences = window.webContents.getLastWebPreferences();
expect(preferences.javascript).to.be.false();
});
@ -1003,8 +1003,8 @@ describe('chromium features', () => {
const w = new BrowserWindow({ show: false });
w.webContents.loadFile(path.resolve(__dirname, 'fixtures', 'blank.html'));
w.webContents.executeJavaScript(`{ b = window.open(${JSON.stringify(targetURL)}); null }`);
const [, window] = await emittedOnce(app, 'browser-window-created');
await emittedOnce(window.webContents, 'did-finish-load');
const [, window] = await once(app, 'browser-window-created');
await once(window.webContents, 'did-finish-load');
expect(await w.webContents.executeJavaScript('b.location.href')).to.equal(targetURL);
});
@ -1012,30 +1012,30 @@ describe('chromium features', () => {
const w = new BrowserWindow({ show: false });
w.webContents.loadFile(path.resolve(__dirname, 'fixtures', 'blank.html'));
w.webContents.executeJavaScript('{ b = window.open("about:blank"); null }');
const [, { webContents }] = await emittedOnce(app, 'browser-window-created');
await emittedOnce(webContents, 'did-finish-load');
const [, { webContents }] = await once(app, 'browser-window-created');
await once(webContents, 'did-finish-load');
// When it loads, redirect
w.webContents.executeJavaScript(`{ b.location = ${JSON.stringify(`file://${fixturesPath}/pages/base-page.html`)}; null }`);
await emittedOnce(webContents, 'did-finish-load');
await once(webContents, 'did-finish-load');
});
it('defines a window.location.href setter', async () => {
const w = new BrowserWindow({ show: false });
w.webContents.loadFile(path.resolve(__dirname, 'fixtures', 'blank.html'));
w.webContents.executeJavaScript('{ b = window.open("about:blank"); null }');
const [, { webContents }] = await emittedOnce(app, 'browser-window-created');
await emittedOnce(webContents, 'did-finish-load');
const [, { webContents }] = await once(app, 'browser-window-created');
await once(webContents, 'did-finish-load');
// When it loads, redirect
w.webContents.executeJavaScript(`{ b.location.href = ${JSON.stringify(`file://${fixturesPath}/pages/base-page.html`)}; null }`);
await emittedOnce(webContents, 'did-finish-load');
await once(webContents, 'did-finish-load');
});
it('open a blank page when no URL is specified', async () => {
const w = new BrowserWindow({ show: false });
w.loadURL('about:blank');
w.webContents.executeJavaScript('{ b = window.open(); null }');
const [, { webContents }] = await emittedOnce(app, 'browser-window-created');
await emittedOnce(webContents, 'did-finish-load');
const [, { webContents }] = await once(app, 'browser-window-created');
await once(webContents, 'did-finish-load');
expect(await w.webContents.executeJavaScript('b.location.href')).to.equal('about:blank');
});
@ -1043,8 +1043,8 @@ describe('chromium features', () => {
const w = new BrowserWindow({ show: false });
w.loadURL('about:blank');
w.webContents.executeJavaScript('{ b = window.open(\'\'); null }');
const [, { webContents }] = await emittedOnce(app, 'browser-window-created');
await emittedOnce(webContents, 'did-finish-load');
const [, { webContents }] = await once(app, 'browser-window-created');
await once(webContents, 'did-finish-load');
expect(await w.webContents.executeJavaScript('b.location.href')).to.equal('about:blank');
});
@ -1145,7 +1145,7 @@ describe('chromium features', () => {
}
});
w.loadFile(path.join(fixturesPath, 'pages', 'window-opener.html'));
const [, channel, opener] = await emittedOnce(w.webContents, 'ipc-message');
const [, channel, opener] = await once(w.webContents, 'ipc-message');
expect(channel).to.equal('opener');
expect(opener).to.equal(null);
});
@ -1267,8 +1267,9 @@ describe('chromium features', () => {
}
});
w.loadFile(path.join(fixturesPath, 'pages', 'media-id-reset.html'));
const [, firstDeviceIds] = await emittedOnce(ipcMain, 'deviceIds');
const [, secondDeviceIds] = await emittedOnce(ipcMain, 'deviceIds', () => w.webContents.reload());
const [, firstDeviceIds] = await once(ipcMain, 'deviceIds');
w.webContents.reload();
const [, secondDeviceIds] = await once(ipcMain, 'deviceIds');
expect(firstDeviceIds).to.deep.equal(secondDeviceIds);
});
@ -1283,9 +1284,10 @@ describe('chromium features', () => {
}
});
w.loadFile(path.join(fixturesPath, 'pages', 'media-id-reset.html'));
const [, firstDeviceIds] = await emittedOnce(ipcMain, 'deviceIds');
const [, firstDeviceIds] = await once(ipcMain, 'deviceIds');
await ses.clearStorageData({ storages: ['cookies'] });
const [, secondDeviceIds] = await emittedOnce(ipcMain, 'deviceIds', () => w.webContents.reload());
w.webContents.reload();
const [, secondDeviceIds] = await once(ipcMain, 'deviceIds');
expect(firstDeviceIds).to.not.deep.equal(secondDeviceIds);
});
@ -1477,35 +1479,35 @@ describe('chromium features', () => {
});
it('cannot access localStorage', async () => {
const response = emittedOnce(ipcMain, 'local-storage-response');
const response = once(ipcMain, 'local-storage-response');
contents.loadURL(protocolName + '://host/localStorage');
const [, error] = await response;
expect(error).to.equal('Failed to read the \'localStorage\' property from \'Window\': Access is denied for this document.');
});
it('cannot access sessionStorage', async () => {
const response = emittedOnce(ipcMain, 'session-storage-response');
const response = once(ipcMain, 'session-storage-response');
contents.loadURL(`${protocolName}://host/sessionStorage`);
const [, error] = await response;
expect(error).to.equal('Failed to read the \'sessionStorage\' property from \'Window\': Access is denied for this document.');
});
it('cannot access WebSQL database', async () => {
const response = emittedOnce(ipcMain, 'web-sql-response');
const response = once(ipcMain, 'web-sql-response');
contents.loadURL(`${protocolName}://host/WebSQL`);
const [, error] = await response;
expect(error).to.equal('Failed to execute \'openDatabase\' on \'Window\': Access to the WebDatabase API is denied in this context.');
});
it('cannot access indexedDB', async () => {
const response = emittedOnce(ipcMain, 'indexed-db-response');
const response = once(ipcMain, 'indexed-db-response');
contents.loadURL(`${protocolName}://host/indexedDB`);
const [, error] = await response;
expect(error).to.equal('Failed to execute \'open\' on \'IDBFactory\': access to the Indexed Database API is denied in this context.');
});
it('cannot access cookie', async () => {
const response = emittedOnce(ipcMain, 'cookie-response');
const response = once(ipcMain, 'cookie-response');
contents.loadURL(`${protocolName}://host/cookie`);
const [, error] = await response;
expect(error).to.equal('Failed to set the \'cookie\' property on \'Document\': Access is denied for this document.');
@ -1529,7 +1531,7 @@ describe('chromium features', () => {
res.end();
}
};
setTimeout(respond, 0);
setTimeout().then(respond);
});
serverUrl = (await listen(server)).url;
serverCrossSiteUrl = serverUrl.replace('127.0.0.1', 'localhost');
@ -1599,7 +1601,7 @@ describe('chromium features', () => {
contextIsolation: false
});
contents.loadURL(origin);
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
const [, error] = await once(ipcMain, 'web-sql-response');
expect(error).to.be.null();
});
@ -1611,7 +1613,7 @@ describe('chromium features', () => {
contextIsolation: false
});
contents.loadURL(origin);
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
const [, error] = await once(ipcMain, 'web-sql-response');
expect(error).to.equal(securityError);
});
@ -1623,7 +1625,7 @@ describe('chromium features', () => {
contextIsolation: false
});
contents.loadURL(origin);
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
const [, error] = await once(ipcMain, 'web-sql-response');
expect(error).to.equal(securityError);
const dbName = 'random';
const result = await contents.executeJavaScript(`
@ -1654,9 +1656,9 @@ describe('chromium features', () => {
}
});
w.webContents.loadURL(origin);
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
const [, error] = await once(ipcMain, 'web-sql-response');
expect(error).to.be.null();
const webviewResult = emittedOnce(ipcMain, 'web-sql-response');
const webviewResult = once(ipcMain, 'web-sql-response');
await w.webContents.executeJavaScript(`
new Promise((resolve, reject) => {
const webview = new WebView();
@ -1684,7 +1686,7 @@ describe('chromium features', () => {
}
});
w.webContents.loadURL('data:text/html,<html></html>');
const webviewResult = emittedOnce(ipcMain, 'web-sql-response');
const webviewResult = once(ipcMain, 'web-sql-response');
await w.webContents.executeJavaScript(`
new Promise((resolve, reject) => {
const webview = new WebView();
@ -1711,9 +1713,9 @@ describe('chromium features', () => {
}
});
w.webContents.loadURL(origin);
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
const [, error] = await once(ipcMain, 'web-sql-response');
expect(error).to.be.null();
const webviewResult = emittedOnce(ipcMain, 'web-sql-response');
const webviewResult = once(ipcMain, 'web-sql-response');
await w.webContents.executeJavaScript(`
new Promise((resolve, reject) => {
const webview = new WebView();
@ -1753,7 +1755,7 @@ describe('chromium features', () => {
// failed to detect a real problem (perhaps related to DOM storage data caching)
// wherein calling `getItem` immediately after `setItem` would appear to work
// but then later (e.g. next tick) it would not.
await delay(1);
await setTimeout(1);
try {
const storedLength = await w.webContents.executeJavaScript(`${storageName}.getItem(${JSON.stringify(testKeyName)}).length`);
expect(storedLength).to.equal(length);
@ -1803,22 +1805,22 @@ describe('chromium features', () => {
const w = new BrowserWindow({ show: false });
w.loadURL(pdfSource);
await emittedOnce(w.webContents, 'did-finish-load');
await once(w.webContents, 'did-finish-load');
});
it('opens when loading a pdf resource as top level navigation', async () => {
const w = new BrowserWindow({ show: false });
w.loadURL(pdfSource);
const [, contents] = await emittedOnce(app, 'web-contents-created');
await emittedOnce(contents, 'did-navigate');
const [, contents] = await once(app, 'web-contents-created');
await once(contents, 'did-navigate');
expect(contents.getURL()).to.equal('chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html');
});
it('opens when loading a pdf resource in a iframe', async () => {
const w = new BrowserWindow({ show: false });
w.loadFile(path.join(__dirname, 'fixtures', 'pages', 'pdf-in-iframe.html'));
const [, contents] = await emittedOnce(app, 'web-contents-created');
await emittedOnce(contents, 'did-navigate');
const [, contents] = await once(app, 'web-contents-created');
await once(contents, 'did-navigate');
expect(contents.getURL()).to.equal('chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html');
});
});
@ -1831,7 +1833,7 @@ describe('chromium features', () => {
// History should have current page by now.
expect((w.webContents as any).length()).to.equal(1);
const waitCommit = emittedOnce(w.webContents, 'navigation-entry-committed');
const waitCommit = once(w.webContents, 'navigation-entry-committed');
w.webContents.executeJavaScript('window.history.pushState({}, "")');
await waitCommit;
// Initial page + pushed state.
@ -1844,15 +1846,15 @@ describe('chromium features', () => {
const w = new BrowserWindow({ show: false });
w.loadURL('data:text/html,<iframe sandbox="allow-scripts"></iframe>');
await Promise.all([
emittedOnce(w.webContents, 'navigation-entry-committed'),
emittedOnce(w.webContents, 'did-frame-navigate'),
emittedOnce(w.webContents, 'did-navigate')
once(w.webContents, 'navigation-entry-committed'),
once(w.webContents, 'did-frame-navigate'),
once(w.webContents, 'did-navigate')
]);
w.webContents.executeJavaScript('window.history.pushState(1, "")');
await Promise.all([
emittedOnce(w.webContents, 'navigation-entry-committed'),
emittedOnce(w.webContents, 'did-navigate-in-page')
once(w.webContents, 'navigation-entry-committed'),
once(w.webContents, 'did-navigate-in-page')
]);
(w.webContents as any).once('navigation-entry-committed', () => {
@ -2287,7 +2289,7 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
});
ifit(process.platform !== 'darwin')('can fullscreen from out-of-process iframes (non-macOS)', async () => {
const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange');
const fullscreenChange = once(ipcMain, 'fullscreenChange');
const html =
`<iframe style="width: 0" frameborder=0 src="${crossSiteUrl}" allowfullscreen></iframe>`;
w.loadURL(`data:text/html,${html}`);
@ -2302,7 +2304,7 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
"document.querySelector('iframe').contentWindow.postMessage('exitFullscreen', '*')"
);
await delay(500);
await setTimeout(500);
const width = await w.webContents.executeJavaScript(
"document.querySelector('iframe').offsetWidth"
@ -2311,8 +2313,8 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
});
ifit(process.platform === 'darwin')('can fullscreen from out-of-process iframes (macOS)', async () => {
await emittedOnce(w, 'enter-full-screen');
const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange');
await once(w, 'enter-full-screen');
const fullscreenChange = once(ipcMain, 'fullscreenChange');
const html =
`<iframe style="width: 0" frameborder=0 src="${crossSiteUrl}" allowfullscreen></iframe>`;
w.loadURL(`data:text/html,${html}`);
@ -2326,7 +2328,7 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
await w.webContents.executeJavaScript(
"document.querySelector('iframe').contentWindow.postMessage('exitFullscreen', '*')"
);
await emittedOnce(w.webContents, 'leave-html-full-screen');
await once(w.webContents, 'leave-html-full-screen');
const width = await w.webContents.executeJavaScript(
"document.querySelector('iframe').offsetWidth"
@ -2334,14 +2336,14 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
expect(width).to.equal(0);
w.setFullScreen(false);
await emittedOnce(w, 'leave-full-screen');
await once(w, 'leave-full-screen');
});
// TODO(jkleinsc) fix this flaky test on WOA
ifit(process.platform !== 'win32' || process.arch !== 'arm64')('can fullscreen from in-process iframes', async () => {
if (process.platform === 'darwin') await emittedOnce(w, 'enter-full-screen');
if (process.platform === 'darwin') await once(w, 'enter-full-screen');
const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange');
const fullscreenChange = once(ipcMain, 'fullscreenChange');
w.loadFile(path.join(fixturesPath, 'pages', 'fullscreen-ipif.html'));
await fullscreenChange;
@ -2644,7 +2646,7 @@ ifdescribe((process.platform !== 'linux' || app.isUnityRunning()))('navigator.se
async function waitForBadgeCount (value: number) {
let badgeCount = app.getBadgeCount();
while (badgeCount !== value) {
await delay(10);
await setTimeout(10);
badgeCount = app.getBadgeCount();
}
return badgeCount;
@ -2839,7 +2841,7 @@ describe('navigator.hid', () => {
const grantedDevices = await w.webContents.executeJavaScript('navigator.hid.getDevices()');
expect(grantedDevices).to.not.be.empty();
w.loadURL(serverUrl);
const [,,,,, frameProcessId, frameRoutingId] = await emittedOnce(w.webContents, 'did-frame-navigate');
const [,,,,, frameProcessId, frameRoutingId] = await once(w.webContents, 'did-frame-navigate');
const frame = webFrameMain.fromId(frameProcessId, frameRoutingId);
expect(!!frame).to.be.true();
if (frame) {
@ -3039,7 +3041,7 @@ describe('navigator.usb', () => {
const grantedDevices = await w.webContents.executeJavaScript('navigator.usb.getDevices()');
expect(grantedDevices).to.not.be.empty();
w.loadURL(serverUrl);
const [,,,,, frameProcessId, frameRoutingId] = await emittedOnce(w.webContents, 'did-frame-navigate');
const [,,,,, frameProcessId, frameRoutingId] = await once(w.webContents, 'did-frame-navigate');
const frame = webFrameMain.fromId(frameProcessId, frameRoutingId);
expect(!!frame).to.be.true();
if (frame) {

View file

@ -5,8 +5,9 @@ import * as http from 'http';
import * as path from 'path';
import * as fs from 'fs';
import * as WebSocket from 'ws';
import { emittedOnce, emittedNTimes, emittedUntil } from './lib/events-helpers';
import { emittedNTimes, emittedUntil } from './lib/events-helpers';
import { ifit, listen } from './lib/spec-helpers';
import { once } from 'events';
const uuid = require('uuid');
@ -53,7 +54,7 @@ describe('chrome extensions', () => {
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
await w.loadURL('about:blank');
const promise = emittedOnce(app, 'web-contents-created');
const promise = once(app, 'web-contents-created');
await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
const args: any = await promise;
const wc: Electron.WebContents = args[1];
@ -73,7 +74,7 @@ describe('chrome extensions', () => {
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
await w.loadURL('about:blank');
const promise = emittedOnce(app, 'web-contents-created');
const promise = once(app, 'web-contents-created');
await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
const args: any = await promise;
const wc: Electron.WebContents = args[1];
@ -151,7 +152,7 @@ describe('chrome extensions', () => {
it('emits extension lifecycle events', async () => {
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
const loadedPromise = emittedOnce(customSession, 'extension-loaded');
const loadedPromise = once(customSession, 'extension-loaded');
const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
const [, loadedExtension] = await loadedPromise;
const [, readyExtension] = await emittedUntil(customSession, 'extension-ready', (event: Event, extension: Extension) => {
@ -161,7 +162,7 @@ describe('chrome extensions', () => {
expect(loadedExtension).to.deep.equal(extension);
expect(readyExtension).to.deep.equal(extension);
const unloadedPromise = emittedOnce(customSession, 'extension-unloaded');
const unloadedPromise = once(customSession, 'extension-unloaded');
await customSession.removeExtension(extension.id);
const [, unloadedExtension] = await unloadedPromise;
expect(unloadedExtension).to.deep.equal(extension);
@ -199,7 +200,7 @@ describe('chrome extensions', () => {
let w: BrowserWindow;
let extension: Extension;
const exec = async (name: string) => {
const p = emittedOnce(ipcMain, 'success');
const p = once(ipcMain, 'success');
await w.webContents.executeJavaScript(`exec('${name}')`);
const [, result] = await p;
return result;
@ -224,7 +225,7 @@ describe('chrome extensions', () => {
describe('chrome.runtime', () => {
let w: BrowserWindow;
const exec = async (name: string) => {
const p = emittedOnce(ipcMain, 'success');
const p = once(ipcMain, 'success');
await w.webContents.executeJavaScript(`exec('${name}')`);
const [, result] = await p;
return result;
@ -262,7 +263,7 @@ describe('chrome extensions', () => {
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-storage'));
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true, contextIsolation: false } });
try {
const p = emittedOnce(ipcMain, 'storage-success');
const p = once(ipcMain, 'storage-success');
await w.loadURL(url);
const [, v] = await p;
expect(v).to.equal('value');
@ -352,7 +353,7 @@ describe('chrome extensions', () => {
const message = { method: 'executeScript', args: ['1 + 2'] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [,, responseString] = await emittedOnce(w.webContents, 'console-message');
const [,, responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
expect(response).to.equal(3);
@ -366,7 +367,7 @@ describe('chrome extensions', () => {
const message = { method: 'connectTab', args: [portName] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [,, responseString] = await emittedOnce(w.webContents, 'console-message');
const [,, responseString] = await once(w.webContents, 'console-message');
const response = responseString.split(',');
expect(response[0]).to.equal(portName);
expect(response[1]).to.equal('howdy');
@ -379,7 +380,7 @@ describe('chrome extensions', () => {
const message = { method: 'sendMessage', args: ['Hello World!'] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [,, responseString] = await emittedOnce(w.webContents, 'console-message');
const [,, responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
expect(response.message).to.equal('Hello World!');
@ -393,12 +394,12 @@ describe('chrome extensions', () => {
const w2 = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
await w2.loadURL('about:blank');
const w2Navigated = emittedOnce(w2.webContents, 'did-navigate');
const w2Navigated = once(w2.webContents, 'did-navigate');
const message = { method: 'update', args: [w2.webContents.id, { url }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [,, responseString] = await emittedOnce(w.webContents, 'console-message');
const [,, responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
await w2Navigated;
@ -416,7 +417,7 @@ describe('chrome extensions', () => {
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true, contextIsolation: false } });
try {
w.loadURL(url);
const [, resp] = await emittedOnce(ipcMain, 'bg-page-message-response');
const [, resp] = await once(ipcMain, 'bg-page-message-response');
expect(resp.message).to.deep.equal({ some: 'message' });
expect(resp.sender.id).to.be.a('string');
expect(resp.sender.origin).to.equal(url);
@ -455,18 +456,18 @@ describe('chrome extensions', () => {
it('has session in background page', async () => {
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
const promise = emittedOnce(app, 'web-contents-created');
const promise = once(app, 'web-contents-created');
const { id } = await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
const [, bgPageContents] = await promise;
expect(bgPageContents.getType()).to.equal('backgroundPage');
await emittedOnce(bgPageContents, 'did-finish-load');
await once(bgPageContents, 'did-finish-load');
expect(bgPageContents.getURL()).to.equal(`chrome-extension://${id}/_generated_background_page.html`);
expect(bgPageContents.session).to.not.equal(undefined);
});
it('can open devtools of background page', async () => {
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
const promise = emittedOnce(app, 'web-contents-created');
const promise = once(app, 'web-contents-created');
await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
const [, bgPageContents] = await promise;
expect(bgPageContents.getType()).to.equal('backgroundPage');
@ -508,7 +509,7 @@ describe('chrome extensions', () => {
ifit(process.platform !== 'win32' || process.arch !== 'arm64')('loads a devtools extension', async () => {
const customSession = session.fromPartition(`persist:${uuid.v4()}`);
customSession.loadExtension(path.join(fixtures, 'extensions', 'devtools-extension'));
const winningMessage = emittedOnce(ipcMain, 'winning');
const winningMessage = once(ipcMain, 'winning');
const w = new BrowserWindow({ show: true, webPreferences: { session: customSession, nodeIntegration: true, contextIsolation: false } });
await w.loadURL(url);
w.webContents.openDevTools();

View file

@ -1,6 +1,8 @@
const { app } = require('electron');
const http = require('http');
const v8 = require('v8');
// eslint-disable-next-line camelcase
const promises_1 = require('timers/promises');
if (app.commandLine.hasSwitch('boot-eval')) {
// eslint-disable-next-line no-eval

View file

@ -1,5 +1,5 @@
import { once } from 'events';
import * as walkdir from 'walkdir';
import { emittedOnce } from './lib/events-helpers';
export async function getFiles (directoryPath: string, { filter = null }: {filter?: ((file: string) => boolean) | null} = {}) {
const files: string[] = [];
@ -9,6 +9,6 @@ export async function getFiles (directoryPath: string, { filter = null }: {filte
walker.on('file', (file) => {
if (!filter || filter(file)) { files.push(file); }
});
await emittedOnce(walker, 'end');
await once(walker, 'end');
return files;
}

View file

@ -1,7 +1,7 @@
import { BrowserWindow } from 'electron';
import { expect, assert } from 'chai';
import { closeAllWindows } from './lib/window-helpers';
const { emittedOnce } = require('./lib/events-helpers');
import { once } from 'events';
describe('webContents.setWindowOpenHandler', () => {
let browserWindow: BrowserWindow;
@ -173,13 +173,13 @@ describe('webContents.setWindowOpenHandler', () => {
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
});
await emittedOnce(browserWindow.webContents, 'did-create-window');
await once(browserWindow.webContents, 'did-create-window');
});
it('can change webPreferences of child windows', async () => {
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { defaultFontSize: 30 } } }));
const didCreateWindow = emittedOnce(browserWindow.webContents, 'did-create-window');
const didCreateWindow = once(browserWindow.webContents, 'did-create-window');
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
const [childWindow] = await didCreateWindow;

View file

@ -3,53 +3,21 @@
* with events in async/await manner.
*/
/**
* @param {!EventTarget} target
* @param {string} eventName
* @return {!Promise<!Event>}
*/
export const waitForEvent = (target: EventTarget, eventName: string) => {
return new Promise(resolve => {
target.addEventListener(eventName, resolve, { once: true });
});
};
/**
* @param {!EventEmitter} emitter
* @param {string} eventName
* @return {!Promise<!Array>} With Event as the first item.
*/
export const emittedOnce = (emitter: NodeJS.EventEmitter, eventName: string, trigger?: () => void) => {
return emittedNTimes(emitter, eventName, 1, trigger).then(([result]) => result);
};
import { on } from 'events';
export const emittedNTimes = async (emitter: NodeJS.EventEmitter, eventName: string, times: number, trigger?: () => void) => {
const events: any[][] = [];
const p = new Promise<any[][]>(resolve => {
const handler = (...args: any[]) => {
events.push(args);
if (events.length === times) {
emitter.removeListener(eventName, handler);
resolve(events);
}
};
emitter.on(eventName, handler);
});
if (trigger) {
await Promise.resolve(trigger());
const iter = on(emitter, eventName);
if (trigger) await Promise.resolve(trigger());
for await (const args of iter) {
events.push(args);
if (events.length === times) { break; }
}
return p;
return events;
};
export const emittedUntil = async (emitter: NodeJS.EventEmitter, eventName: string, untilFn: Function) => {
const p = new Promise<any[]>(resolve => {
const handler = (...args: any[]) => {
if (untilFn(...args)) {
emitter.removeListener(eventName, handler);
resolve(args);
}
};
emitter.on(eventName, handler);
});
return p;
for await (const args of on(emitter, eventName)) {
if (untilFn(...args)) { return args; }
}
};

View file

@ -21,8 +21,6 @@ const addOnly = <T>(fn: Function): T => {
export const ifit = (condition: boolean) => (condition ? it : addOnly<TestFunction>(it.skip));
export const ifdescribe = (condition: boolean) => (condition ? describe : addOnly<SuiteFunction>(describe.skip));
export const delay = (time: number = 0) => new Promise(resolve => setTimeout(resolve, time));
type CleanupFunction = (() => void) | (() => Promise<void>)
const cleanupFunctions: CleanupFunction[] = [];
export async function runCleanupFunctions () {
@ -183,6 +181,7 @@ export async function itremote (name: string, fn: Function, args?: any[]) {
const { ok, message } = await w.webContents.executeJavaScript(`(async () => {
try {
const chai_1 = require('chai')
const promises_1 = require('timers/promises')
chai_1.use(require('chai-as-promised'))
chai_1.use(require('dirty-chai'))
await (${fn})(...${JSON.stringify(args ?? [])})

View file

@ -1,6 +1,6 @@
import { expect } from 'chai';
import { BrowserWindow } from 'electron/main';
import { emittedOnce } from './events-helpers';
import { once } from 'events';
async function ensureWindowIsClosed (window: BrowserWindow | null) {
if (window && !window.isDestroyed()) {
@ -10,7 +10,7 @@ async function ensureWindowIsClosed (window: BrowserWindow | null) {
// <webview> children which need to be destroyed first. In that case, we
// await the 'closed' event which signals the complete shutdown of the
// window.
const isClosed = emittedOnce(window, 'closed');
const isClosed = once(window, 'closed');
window.destroy();
await isClosed;
} else {

View file

@ -1,11 +1,11 @@
import { app } from 'electron';
import { expect } from 'chai';
import { emittedOnce } from './lib/events-helpers';
import { startRemoteControlApp, ifdescribe } from './lib/spec-helpers';
import * as fs from 'fs/promises';
import * as path from 'path';
import * as uuid from 'uuid';
import { once } from 'events';
function isTestingBindingAvailable () {
try {
@ -87,7 +87,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => {
setTimeout(() => { app.quit(); });
return app.getPath('userData');
});
await emittedOnce(rc.process, 'exit');
await once(rc.process, 'exit');
const logFilePath = path.join(userDataDir, 'electron_debug.log');
const stat = await fs.stat(logFilePath);
expect(stat.isFile()).to.be.true();
@ -103,7 +103,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => {
setTimeout(() => { app.quit(); });
return app.getPath('userData');
});
await emittedOnce(rc.process, 'exit');
await once(rc.process, 'exit');
const logFilePath = path.join(userDataDir, 'electron_debug.log');
const stat = await fs.stat(logFilePath);
expect(stat.isFile()).to.be.true();
@ -118,7 +118,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => {
process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
setTimeout(() => { require('electron').app.quit(); });
});
await emittedOnce(rc.process, 'exit');
await once(rc.process, 'exit');
const stat = await fs.stat(logFilePath);
expect(stat.isFile()).to.be.true();
const contents = await fs.readFile(logFilePath, 'utf8');
@ -132,7 +132,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => {
process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
setTimeout(() => { require('electron').app.quit(); });
});
await emittedOnce(rc.process, 'exit');
await once(rc.process, 'exit');
const stat = await fs.stat(logFilePath);
expect(stat.isFile()).to.be.true();
const contents = await fs.readFile(logFilePath, 'utf8');
@ -146,7 +146,7 @@ ifdescribe(isTestingBindingAvailable())('logging', () => {
process._linkedBinding('electron_common_testing').log(0, 'LATER_LOG');
setTimeout(() => { require('electron').app.quit(); });
});
await emittedOnce(rc.process, 'exit');
await once(rc.process, 'exit');
const stat = await fs.stat(logFilePath);
expect(stat.isFile()).to.be.true();
const contents = await fs.readFile(logFilePath, 'utf8');

View file

@ -4,8 +4,8 @@ import * as fs from 'fs';
import { BrowserWindow } from 'electron/main';
import { ifdescribe, ifit } from './lib/spec-helpers';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import * as childProcess from 'child_process';
import { once } from 'events';
const Module = require('module');
@ -30,7 +30,7 @@ describe('modules support', () => {
ifit(features.isRunAsNodeEnabled())('can be required in node binary', async function () {
const child = childProcess.fork(path.join(fixtures, 'module', 'echo.js'));
const [msg] = await emittedOnce(child, 'message');
const [msg] = await once(child, 'message');
expect(msg).to.equal('ok');
});
@ -62,7 +62,7 @@ describe('modules support', () => {
ifit(features.isRunAsNodeEnabled())('can be required in node binary', async function () {
const child = childProcess.fork(path.join(fixtures, 'module', 'uv-dlopen.js'));
const [exitCode] = await emittedOnce(child, 'exit');
const [exitCode] = await once(child, 'exit');
expect(exitCode).to.equal(0);
});
});

View file

@ -3,10 +3,10 @@ import * as childProcess from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import * as util from 'util';
import { emittedOnce } from './lib/events-helpers';
import { getRemoteContext, ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers';
import { webContents } from 'electron/main';
import { EventEmitter } from 'stream';
import { once } from 'events';
const features = process._linkedBinding('electron_common_features');
const mainFixturesPath = path.resolve(__dirname, 'fixtures');
@ -18,7 +18,7 @@ describe('node feature', () => {
describe('child_process.fork', () => {
it('Works in browser process', async () => {
const child = childProcess.fork(path.join(fixtures, 'module', 'ping.js'));
const message = emittedOnce(child, 'message');
const message = once(child, 'message');
child.send('message');
const [msg] = await message;
expect(msg).to.equal('message');
@ -104,7 +104,7 @@ describe('node feature', () => {
it('has the electron version in process.versions', async () => {
const source = 'process.send(process.versions)';
const forked = require('child_process').fork('--eval', [source]);
const [message] = await emittedOnce(forked, 'message');
const [message] = await once(forked, 'message');
expect(message)
.to.have.own.property('electron')
.that.is.a('string')
@ -158,7 +158,7 @@ describe('node feature', () => {
cwd: path.join(mainFixturesPath, 'apps', 'libuv-hang'),
stdio: 'inherit'
});
const [code] = await emittedOnce(appProcess, 'close');
const [code] = await once(appProcess, 'close');
expect(code).to.equal(0);
});
@ -546,7 +546,7 @@ describe('node feature', () => {
const env = { ...process.env, NODE_OPTIONS: '--v8-options' };
child = childProcess.spawn(process.execPath, { env });
exitPromise = emittedOnce(child, 'exit');
exitPromise = once(child, 'exit');
let output = '';
let success = false;
@ -609,7 +609,7 @@ describe('node feature', () => {
};
// App should exit with code 1.
const child = childProcess.spawn(process.execPath, [appPath], { env });
const [code] = await emittedOnce(child, 'exit');
const [code] = await once(child, 'exit');
expect(code).to.equal(1);
});
@ -622,7 +622,7 @@ describe('node feature', () => {
};
// App should exit with code 0.
const child = childProcess.spawn(process.execPath, [appPath], { env });
const [code] = await emittedOnce(child, 'exit');
const [code] = await once(child, 'exit');
expect(code).to.equal(0);
});
});
@ -642,7 +642,7 @@ describe('node feature', () => {
child = childProcess.spawn(process.execPath, ['--force-fips'], {
env: { ELECTRON_RUN_AS_NODE: 'true' }
});
exitPromise = emittedOnce(child, 'exit');
exitPromise = once(child, 'exit');
let output = '';
const cleanup = () => {
@ -723,7 +723,7 @@ describe('node feature', () => {
child = childProcess.spawn(process.execPath, ['--inspect=17364', path.join(fixtures, 'module', 'run-as-node.js')], {
env: { ELECTRON_RUN_AS_NODE: 'true' }
});
exitPromise = emittedOnce(child, 'exit');
exitPromise = once(child, 'exit');
let output = '';
const listener = (data: Buffer) => { output += data; };
@ -734,7 +734,7 @@ describe('node feature', () => {
child.stderr.on('data', listener);
child.stdout.on('data', listener);
await emittedOnce(child, 'exit');
await once(child, 'exit');
cleanup();
if (/^Debugger listening on ws:/m.test(output)) {
expect(output.trim()).to.contain(':17364', 'should be listening on port 17364');
@ -745,13 +745,13 @@ describe('node feature', () => {
it('Does not start the v8 inspector when --inspect is after a -- argument', async () => {
child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'noop.js'), '--', '--inspect']);
exitPromise = emittedOnce(child, 'exit');
exitPromise = once(child, 'exit');
let output = '';
const listener = (data: Buffer) => { output += data; };
child.stderr.on('data', listener);
child.stdout.on('data', listener);
await emittedOnce(child, 'exit');
await once(child, 'exit');
if (output.trim().startsWith('Debugger listening on ws://')) {
throw new Error('Inspector was started when it should not have been');
}
@ -762,7 +762,7 @@ describe('node feature', () => {
child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'delay-exit'), '--inspect=0'], {
stdio: ['ipc']
}) as childProcess.ChildProcessWithoutNullStreams;
exitPromise = emittedOnce(child, 'exit');
exitPromise = once(child, 'exit');
const cleanup = () => {
child.stderr.removeListener('data', listener);
@ -809,9 +809,9 @@ describe('node feature', () => {
env: { ELECTRON_RUN_AS_NODE: 'true' },
stdio: ['ipc']
}) as childProcess.ChildProcessWithoutNullStreams;
exitPromise = emittedOnce(child, 'exit');
exitPromise = once(child, 'exit');
const [{ cmd, debuggerEnabled, success }] = await emittedOnce(child, 'message');
const [{ cmd, debuggerEnabled, success }] = await once(child, 'message');
expect(cmd).to.equal('assert');
expect(debuggerEnabled).to.be.true();
expect(success).to.be.true();
@ -828,7 +828,7 @@ describe('node feature', () => {
const child = childProcess.spawn(process.execPath, [scriptPath], {
env: { ELECTRON_RUN_AS_NODE: 'true' }
});
const [code, signal] = await emittedOnce(child, 'exit');
const [code, signal] = await once(child, 'exit');
expect(code).to.equal(0);
expect(signal).to.equal(null);
child.kill();

View file

@ -8,7 +8,8 @@ import { BrowserWindow, WebPreferences } from 'electron/main';
import { closeWindow } from './lib/window-helpers';
import { emittedUntil } from './lib/events-helpers';
import { delay, listen } from './lib/spec-helpers';
import { listen } from './lib/spec-helpers';
import { setTimeout } from 'timers/promises';
const messageContainsSecurityWarning = (event: Event, level: number, message: string) => {
return message.indexOf('Electron Security Warning') > -1;
@ -140,7 +141,7 @@ describe('security warnings', () => {
w.webContents.on('console-message', () => {
didNotWarn = false;
});
await delay(500);
await setTimeout(500);
expect(didNotWarn).to.equal(true);
});

View file

@ -5,8 +5,9 @@ import * as path from 'path';
import * as fs from 'fs';
import * as http from 'http';
import { closeWindow } from './lib/window-helpers';
import { emittedOnce } from './lib/events-helpers';
import { ifit, ifdescribe, delay, listen } from './lib/spec-helpers';
import { ifit, ifdescribe, listen } from './lib/spec-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
const features = process._linkedBinding('electron_common_features');
const v8Util = process._linkedBinding('electron_common_v8_util');
@ -17,7 +18,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
let w: BrowserWindow;
async function rightClick () {
const contextMenuPromise = emittedOnce(w.webContents, 'context-menu');
const contextMenuPromise = once(w.webContents, 'context-menu');
w.webContents.sendInputEvent({
type: 'mouseDown',
button: 'right',
@ -35,7 +36,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
const timeout = (process.env.IS_ASAN ? 180 : 10) * 1000;
let contextMenuParams = await rightClick();
while (!fn(contextMenuParams) && (Date.now() - now < timeout)) {
await delay(100);
await setTimeout(100);
contextMenuParams = await rightClick();
}
return contextMenuParams;
@ -107,7 +108,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
ifit(shouldRun)('should detect incorrectly spelled words as incorrect after disabling all languages and re-enabling', async () => {
w.webContents.session.setSpellCheckerLanguages([]);
await delay(500);
await setTimeout(500);
w.webContents.session.setSpellCheckerLanguages(['en-US']);
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"');
await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()');
@ -147,13 +148,13 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
// spellCheckerEnabled is sent to renderer asynchronously and there is
// no event notifying when it is finished, so wait a little while to
// ensure the setting has been changed in renderer.
await delay(500);
await setTimeout(500);
expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(false);
w.webContents.session.spellCheckerEnabled = true;
v8Util.runUntilIdle();
expect(w.webContents.session.spellCheckerEnabled).to.be.true();
await delay(500);
await setTimeout(500);
expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true);
});
});

View file

@ -3,9 +3,10 @@ import * as cp from 'child_process';
import { BrowserWindow, BrowserWindowConstructorOptions, ipcMain } from 'electron/main';
import * as path from 'path';
import { emittedOnce } from './lib/events-helpers';
import { closeWindow } from './lib/window-helpers';
import { ifdescribe, delay } from './lib/spec-helpers';
import { ifdescribe } from './lib/spec-helpers';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
// visibilityState specs pass on linux with a real window manager but on CI
// the environment does not let these specs pass
@ -35,7 +36,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
itWithOptions('should be visible when the window is initially shown by default', {}, async () => {
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('visible');
});
@ -43,7 +44,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
show: true
}, async () => {
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('visible');
});
@ -51,7 +52,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
show: false
}, async () => {
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('hidden');
});
@ -60,7 +61,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
}, async () => {
w.show();
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('visible');
});
@ -70,40 +71,42 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
// TODO(MarshallOfSound): Figure out if we can work around this 1 tick issue for users
if (process.platform === 'darwin') {
// Wait for a tick, the window being "shown" takes 1 tick on macOS
await delay(10000);
await setTimeout(10000);
}
w.hide();
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('hidden');
});
itWithOptions('should be toggle between visible and hidden as the window is hidden and shown', {}, async () => {
load();
const [, initialState] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, initialState] = await once(ipcMain, 'initial-visibility-state');
expect(initialState).to.equal('visible');
w.hide();
await emittedOnce(ipcMain, 'visibility-change-hidden');
await once(ipcMain, 'visibility-change-hidden');
w.show();
await emittedOnce(ipcMain, 'visibility-change-visible');
await once(ipcMain, 'visibility-change-visible');
});
itWithOptions('should become hidden when a window is minimized', {}, async () => {
load();
const [, initialState] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, initialState] = await once(ipcMain, 'initial-visibility-state');
expect(initialState).to.equal('visible');
w.minimize();
await emittedOnce(ipcMain, 'visibility-change-hidden', () => w.minimize());
const p = once(ipcMain, 'visibility-change-hidden');
w.minimize();
await p;
});
itWithOptions('should become visible when a window is restored', {}, async () => {
load();
const [, initialState] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, initialState] = await once(ipcMain, 'initial-visibility-state');
expect(initialState).to.equal('visible');
w.minimize();
await emittedOnce(ipcMain, 'visibility-change-hidden');
await once(ipcMain, 'visibility-change-hidden');
w.restore();
await emittedOnce(ipcMain, 'visibility-change-visible');
await once(ipcMain, 'visibility-change-visible');
});
describe('on platforms that support occlusion detection', () => {
@ -141,7 +144,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
height: 200
});
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('visible');
});
@ -158,7 +161,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
height: 200
});
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('visible');
});
@ -170,7 +173,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
}, async function () {
this.timeout(240000);
load();
const [, state] = await emittedOnce(ipcMain, 'initial-visibility-state');
const [, state] = await once(ipcMain, 'initial-visibility-state');
expect(state).to.equal('visible');
makeOtherWindow({
x: 0,
@ -178,7 +181,7 @@ ifdescribe(process.platform !== 'linux')('document.visibilityState', () => {
width: 300,
height: 300
});
await emittedOnce(ipcMain, 'visibility-change-hidden');
await once(ipcMain, 'visibility-change-hidden');
});
});
});

View file

@ -2,11 +2,13 @@ import * as path from 'path';
import * as url from 'url';
import { BrowserWindow, session, ipcMain, app, WebContents } from 'electron/main';
import { closeAllWindows } from './lib/window-helpers';
import { emittedOnce, emittedUntil } from './lib/events-helpers';
import { ifit, ifdescribe, delay, defer, itremote, useRemoteContext, listen } from './lib/spec-helpers';
import { emittedUntil } from './lib/events-helpers';
import { ifit, ifdescribe, defer, itremote, useRemoteContext, listen } from './lib/spec-helpers';
import { expect } from 'chai';
import * as http from 'http';
import * as auth from 'basic-auth';
import { once } from 'events';
import { setTimeout } from 'timers/promises';
declare let WebView: any;
const features = process._linkedBinding('electron_common_features');
@ -85,7 +87,7 @@ describe('<webview> tag', function () {
}
});
w.loadFile(path.join(fixtures, 'pages', 'webview-no-script.html'));
await emittedOnce(ipcMain, 'pong');
await once(ipcMain, 'pong');
});
it('works with sandbox', async () => {
@ -97,7 +99,7 @@ describe('<webview> tag', function () {
}
});
w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html'));
await emittedOnce(ipcMain, 'pong');
await once(ipcMain, 'pong');
});
it('works with contextIsolation', async () => {
@ -109,7 +111,7 @@ describe('<webview> tag', function () {
}
});
w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html'));
await emittedOnce(ipcMain, 'pong');
await once(ipcMain, 'pong');
});
it('works with contextIsolation + sandbox', async () => {
@ -122,7 +124,7 @@ describe('<webview> tag', function () {
}
});
w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html'));
await emittedOnce(ipcMain, 'pong');
await once(ipcMain, 'pong');
});
it('works with Trusted Types', async () => {
@ -133,7 +135,7 @@ describe('<webview> tag', function () {
}
});
w.loadFile(path.join(fixtures, 'pages', 'webview-trusted-types.html'));
await emittedOnce(ipcMain, 'pong');
await once(ipcMain, 'pong');
});
it('is disabled by default', async () => {
@ -145,7 +147,7 @@ describe('<webview> tag', function () {
}
});
const webview = emittedOnce(ipcMain, 'webview');
const webview = once(ipcMain, 'webview');
w.loadFile(path.join(fixtures, 'pages', 'webview-no-script.html'));
const [, type] = await webview;
@ -163,11 +165,11 @@ describe('<webview> tag', function () {
it('updates when the window is shown after the ready-to-show event', async () => {
const w = new BrowserWindow({ show: false });
const readyToShowSignal = emittedOnce(w, 'ready-to-show');
const pongSignal1 = emittedOnce(ipcMain, 'pong');
const readyToShowSignal = once(w, 'ready-to-show');
const pongSignal1 = once(ipcMain, 'pong');
w.loadFile(path.join(fixtures, 'pages', 'webview-visibilitychange.html'));
await pongSignal1;
const pongSignal2 = emittedOnce(ipcMain, 'pong');
const pongSignal2 = once(ipcMain, 'pong');
await readyToShowSignal;
w.show();
@ -179,13 +181,13 @@ describe('<webview> tag', function () {
it('inherits the parent window visibility state and receives visibilitychange events', async () => {
const w = new BrowserWindow({ show: false });
w.loadFile(path.join(fixtures, 'pages', 'webview-visibilitychange.html'));
const [, visibilityState, hidden] = await emittedOnce(ipcMain, 'pong');
const [, visibilityState, hidden] = await once(ipcMain, 'pong');
expect(visibilityState).to.equal('hidden');
expect(hidden).to.be.true();
// We have to start waiting for the event
// before we ask the webContents to resize.
const getResponse = emittedOnce(ipcMain, 'pong');
const getResponse = once(ipcMain, 'pong');
w.webContents.emit('-window-visibility-change', 'visible');
return getResponse.then(([, visibilityState, hidden]) => {
@ -206,8 +208,8 @@ describe('<webview> tag', function () {
contextIsolation: false
}
});
const didAttachWebview = emittedOnce(w.webContents, 'did-attach-webview');
const webviewDomReady = emittedOnce(ipcMain, 'webview-dom-ready');
const didAttachWebview = once(w.webContents, 'did-attach-webview');
const webviewDomReady = once(ipcMain, 'webview-dom-ready');
w.loadFile(path.join(fixtures, 'pages', 'webview-did-attach-event.html'));
const [, webContents] = await didAttachWebview;
@ -305,7 +307,7 @@ describe('<webview> tag', function () {
});
});
const [, { runtimeId, tabId }] = await emittedOnce(ipcMain, 'answer');
const [, { runtimeId, tabId }] = await once(ipcMain, 'answer');
expect(runtimeId).to.match(/^[a-z]{32}$/);
expect(tabId).to.equal(childWebContentsId);
await w.webContents.executeJavaScript('webview.closeDevTools()');
@ -340,7 +342,7 @@ describe('<webview> tag', function () {
contextIsolation: false
}
});
const zoomEventPromise = emittedOnce(ipcMain, 'webview-parent-zoom-level');
const zoomEventPromise = once(ipcMain, 'webview-parent-zoom-level');
w.loadFile(path.join(fixtures, 'pages', 'webview-zoom-factor.html'));
const [, zoomFactor, zoomLevel] = await zoomEventPromise;
@ -417,7 +419,7 @@ describe('<webview> tag', function () {
});
w.loadFile(path.join(fixtures, 'pages', 'webview-origin-zoom-level.html'));
const [, zoomLevel] = await emittedOnce(ipcMain, 'webview-origin-zoom-level');
const [, zoomLevel] = await once(ipcMain, 'webview-origin-zoom-level');
expect(zoomLevel).to.equal(2.0);
});
@ -432,8 +434,8 @@ describe('<webview> tag', function () {
contextIsolation: false
}
});
const attachPromise = emittedOnce(w.webContents, 'did-attach-webview');
const readyPromise = emittedOnce(ipcMain, 'dom-ready');
const attachPromise = once(w.webContents, 'did-attach-webview');
const readyPromise = once(ipcMain, 'dom-ready');
w.loadFile(path.join(fixtures, 'pages', 'webview-zoom-inherited.html'));
const [, webview] = await attachPromise;
await readyPromise;
@ -451,7 +453,7 @@ describe('<webview> tag', function () {
contextIsolation: false
}
});
const attachPromise = emittedOnce(w.webContents, 'did-attach-webview');
const attachPromise = once(w.webContents, 'did-attach-webview');
await w.loadFile(path.join(fixtures, 'pages', 'webview-zoom-inherited.html'));
await attachPromise;
await w.webContents.executeJavaScript('view.remove()');
@ -470,9 +472,9 @@ describe('<webview> tag', function () {
}
});
const attachPromise = emittedOnce(w.webContents, 'did-attach-webview');
const loadPromise = emittedOnce(w.webContents, 'did-finish-load');
const readyPromise = emittedOnce(ipcMain, 'webview-ready');
const attachPromise = once(w.webContents, 'did-attach-webview');
const loadPromise = once(w.webContents, 'did-finish-load');
const readyPromise = once(ipcMain, 'webview-ready');
w.loadFile(path.join(__dirname, 'fixtures', 'webview', 'fullscreen', 'main.html'));
@ -485,7 +487,7 @@ describe('<webview> tag', function () {
afterEach(async () => {
// The leaving animation is un-observable but can interfere with future tests
// Specifically this is async on macOS but can be on other platforms too
await delay(1000);
await setTimeout(1000);
closeAllWindows();
});
@ -494,13 +496,13 @@ describe('<webview> tag', function () {
const [w, webview] = await loadWebViewWindow();
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.false();
const parentFullscreen = emittedOnce(ipcMain, 'fullscreenchange');
const parentFullscreen = once(ipcMain, 'fullscreenchange');
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
await parentFullscreen;
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true();
const close = emittedOnce(w, 'closed');
const close = once(w, 'closed');
w.close();
await close;
});
@ -509,9 +511,9 @@ describe('<webview> tag', function () {
const [w, webview] = await loadWebViewWindow();
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.false();
const parentFullscreen = emittedOnce(ipcMain, 'fullscreenchange');
const enterHTMLFS = emittedOnce(w.webContents, 'enter-html-full-screen');
const leaveHTMLFS = emittedOnce(w.webContents, 'leave-html-full-screen');
const parentFullscreen = once(ipcMain, 'fullscreenchange');
const enterHTMLFS = once(w.webContents, 'enter-html-full-screen');
const leaveHTMLFS = once(w.webContents, 'leave-html-full-screen');
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true();
@ -519,7 +521,7 @@ describe('<webview> tag', function () {
await webview.executeJavaScript('document.exitFullscreen()');
await Promise.all([enterHTMLFS, leaveHTMLFS, parentFullscreen]);
const close = emittedOnce(w, 'closed');
const close = once(w, 'closed');
w.close();
await close;
});
@ -527,17 +529,17 @@ describe('<webview> tag', function () {
// FIXME(zcbenz): Fullscreen events do not work on Linux.
ifit(process.platform !== 'linux')('exiting fullscreen should unfullscreen window', async () => {
const [w, webview] = await loadWebViewWindow();
const enterFullScreen = emittedOnce(w, 'enter-full-screen');
const enterFullScreen = once(w, 'enter-full-screen');
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
await enterFullScreen;
const leaveFullScreen = emittedOnce(w, 'leave-full-screen');
const leaveFullScreen = once(w, 'leave-full-screen');
await webview.executeJavaScript('document.exitFullscreen()', true);
await leaveFullScreen;
await delay(0);
await setTimeout();
expect(w.isFullScreen()).to.be.false();
const close = emittedOnce(w, 'closed');
const close = once(w, 'closed');
w.close();
await close;
});
@ -545,17 +547,17 @@ describe('<webview> tag', function () {
// Sending ESC via sendInputEvent only works on Windows.
ifit(process.platform === 'win32')('pressing ESC should unfullscreen window', async () => {
const [w, webview] = await loadWebViewWindow();
const enterFullScreen = emittedOnce(w, 'enter-full-screen');
const enterFullScreen = once(w, 'enter-full-screen');
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
await enterFullScreen;
const leaveFullScreen = emittedOnce(w, 'leave-full-screen');
const leaveFullScreen = once(w, 'leave-full-screen');
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Escape' });
await leaveFullScreen;
await delay(0);
await setTimeout();
expect(w.isFullScreen()).to.be.false();
const close = emittedOnce(w, 'closed');
const close = once(w, 'closed');
w.close();
await close;
});
@ -570,24 +572,24 @@ describe('<webview> tag', function () {
}
});
const didAttachWebview = emittedOnce(w.webContents, 'did-attach-webview');
const didAttachWebview = once(w.webContents, 'did-attach-webview');
w.loadFile(path.join(fixtures, 'pages', 'webview-did-attach-event.html'));
const [, webContents] = await didAttachWebview;
const enterFSWindow = emittedOnce(w, 'enter-html-full-screen');
const enterFSWebview = emittedOnce(webContents, 'enter-html-full-screen');
const enterFSWindow = once(w, 'enter-html-full-screen');
const enterFSWebview = once(webContents, 'enter-html-full-screen');
await webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
await enterFSWindow;
await enterFSWebview;
const leaveFSWindow = emittedOnce(w, 'leave-html-full-screen');
const leaveFSWebview = emittedOnce(webContents, 'leave-html-full-screen');
const leaveFSWindow = once(w, 'leave-html-full-screen');
const leaveFSWebview = once(webContents, 'leave-html-full-screen');
webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Escape' });
await leaveFSWebview;
await leaveFSWindow;
const close = emittedOnce(w, 'closed');
const close = once(w, 'closed');
w.close();
await close;
});
@ -595,14 +597,14 @@ describe('<webview> tag', function () {
it('should support user gesture', async () => {
const [w, webview] = await loadWebViewWindow();
const waitForEnterHtmlFullScreen = emittedOnce(webview, 'enter-html-full-screen');
const waitForEnterHtmlFullScreen = once(webview, 'enter-html-full-screen');
const jsScript = "document.querySelector('video').webkitRequestFullscreen()";
webview.executeJavaScript(jsScript, true);
await waitForEnterHtmlFullScreen;
const close = emittedOnce(w, 'closed');
const close = once(w, 'closed');
w.close();
await close;
});
@ -625,7 +627,7 @@ describe('<webview> tag', function () {
src: `file://${path.join(fixtures, 'api', 'native-window-open-blank.html')}`
});
const [, content] = await emittedOnce(ipcMain, 'answer');
const [, content] = await once(ipcMain, 'answer');
expect(content).to.equal('Hello');
});
@ -638,7 +640,7 @@ describe('<webview> tag', function () {
src: `file://${path.join(fixtures, 'api', 'native-window-open-file.html')}`
});
const [, content] = await emittedOnce(ipcMain, 'answer');
const [, content] = await once(ipcMain, 'answer');
expect(content).to.equal('Hello');
});
@ -650,7 +652,7 @@ describe('<webview> tag', function () {
src: `file://${path.join(fixtures, 'api', 'native-window-open-no-allowpopups.html')}`
});
const [, { windowOpenReturnedNull }] = await emittedOnce(ipcMain, 'answer');
const [, { windowOpenReturnedNull }] = await once(ipcMain, 'answer');
expect(windowOpenReturnedNull).to.be.true();
});
@ -663,7 +665,7 @@ describe('<webview> tag', function () {
src: `file://${path.join(fixtures, 'api', 'native-window-open-cross-origin.html')}`
});
const [, content] = await emittedOnce(ipcMain, 'answer');
const [, content] = await once(ipcMain, 'answer');
const expectedContent =
'Blocked a frame with origin "file://" from accessing a cross-origin frame.';
@ -678,7 +680,7 @@ describe('<webview> tag', function () {
src: `file://${fixtures}/pages/window-open.html`
});
await emittedOnce(app, 'browser-window-created');
await once(app, 'browser-window-created');
});
it('emits a web-contents-created event', async () => {
@ -699,7 +701,7 @@ describe('<webview> tag', function () {
allowpopups: 'on',
src: `file://${path.join(fixtures, 'api', 'native-window-open-noopener.html')}`
});
await emittedOnce(app, 'browser-window-created');
await once(app, 'browser-window-created');
});
});
@ -719,7 +721,7 @@ describe('<webview> tag', function () {
webpreferences: 'contextIsolation=yes'
});
const [, data] = await emittedOnce(ipcMain, 'isolated-world');
const [, data] = await once(ipcMain, 'isolated-world');
expect(data).to.deep.equal({
preloadContext: {
preloadProperty: 'number',
@ -784,55 +786,55 @@ describe('<webview> tag', function () {
// "PermissionDeniedError". It should be re-enabled if we find a way to mock
// the presence of a microphone & camera.
xit('emits when using navigator.getUserMedia api', async () => {
const errorFromRenderer = emittedOnce(ipcMain, 'message');
const errorFromRenderer = once(ipcMain, 'message');
loadWebView(w.webContents, {
src: `file://${fixtures}/pages/permissions/media.html`,
partition,
nodeintegration: 'on'
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, webViewContents] = await once(app, 'web-contents-created');
setUpRequestHandler(webViewContents.id, 'media');
const [, errorName] = await errorFromRenderer;
expect(errorName).to.equal('PermissionDeniedError');
});
it('emits when using navigator.geolocation api', async () => {
const errorFromRenderer = emittedOnce(ipcMain, 'message');
const errorFromRenderer = once(ipcMain, 'message');
loadWebView(w.webContents, {
src: `file://${fixtures}/pages/permissions/geolocation.html`,
partition,
nodeintegration: 'on',
webpreferences: 'contextIsolation=no'
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, webViewContents] = await once(app, 'web-contents-created');
setUpRequestHandler(webViewContents.id, 'geolocation');
const [, error] = await errorFromRenderer;
expect(error).to.equal('User denied Geolocation');
});
it('emits when using navigator.requestMIDIAccess without sysex api', async () => {
const errorFromRenderer = emittedOnce(ipcMain, 'message');
const errorFromRenderer = once(ipcMain, 'message');
loadWebView(w.webContents, {
src: `file://${fixtures}/pages/permissions/midi.html`,
partition,
nodeintegration: 'on',
webpreferences: 'contextIsolation=no'
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, webViewContents] = await once(app, 'web-contents-created');
setUpRequestHandler(webViewContents.id, 'midi');
const [, error] = await errorFromRenderer;
expect(error).to.equal('SecurityError');
});
it('emits when using navigator.requestMIDIAccess with sysex api', async () => {
const errorFromRenderer = emittedOnce(ipcMain, 'message');
const errorFromRenderer = once(ipcMain, 'message');
loadWebView(w.webContents, {
src: `file://${fixtures}/pages/permissions/midi-sysex.html`,
partition,
nodeintegration: 'on',
webpreferences: 'contextIsolation=no'
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, webViewContents] = await once(app, 'web-contents-created');
setUpRequestHandler(webViewContents.id, 'midiSysex');
const [, error] = await errorFromRenderer;
expect(error).to.equal('SecurityError');
@ -843,19 +845,19 @@ describe('<webview> tag', function () {
src: 'magnet:test',
partition
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, webViewContents] = await once(app, 'web-contents-created');
await setUpRequestHandler(webViewContents.id, 'openExternal');
});
it('emits when using Notification.requestPermission', async () => {
const errorFromRenderer = emittedOnce(ipcMain, 'message');
const errorFromRenderer = once(ipcMain, 'message');
loadWebView(w.webContents, {
src: `file://${fixtures}/pages/permissions/notification.html`,
partition,
nodeintegration: 'on',
webpreferences: 'contextIsolation=no'
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, webViewContents] = await once(app, 'web-contents-created');
await setUpRequestHandler(webViewContents.id, 'notifications');
@ -1141,12 +1143,12 @@ describe('<webview> tag', function () {
w.setAttribute('preload', `file://${fixtures}/module/preload-ipc.js`);
w.setAttribute('src', `file://${fixtures}/pages/ipc-message.html`);
document.body.appendChild(w);
const { frameId } = await new Promise(resolve => w.addEventListener('ipc-message', resolve, { once: true }));
const { frameId } = await new Promise<any>(resolve => w.addEventListener('ipc-message', resolve, { once: true }));
const message = 'boom!';
w.sendToFrame(frameId, 'ping', message);
const { channel, args } = await new Promise(resolve => w.addEventListener('ipc-message', resolve, { once: true }));
const { channel, args } = await new Promise<any>(resolve => w.addEventListener('ipc-message', resolve, { once: true }));
expect(channel).to.equal('pong');
expect(args).to.deep.equal([message]);
@ -1642,7 +1644,7 @@ describe('<webview> tag', function () {
itremote('does not emit when src is not changed', async () => {
const webview = new WebView();
document.body.appendChild(webview);
await new Promise(resolve => setTimeout(resolve));
await setTimeout();
const expectedErrorMessage = 'The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.';
expect(() => { webview.stop(); }).to.throw(expectedErrorMessage);
});