diff --git a/spec-main/api-crash-reporter-spec.ts b/spec-main/api-crash-reporter-spec.ts index 707c3502be0e..847e77a092f6 100644 --- a/spec-main/api-crash-reporter-spec.ts +++ b/spec-main/api-crash-reporter-spec.ts @@ -3,27 +3,17 @@ import * as childProcess from 'child_process'; import * as http from 'http'; import * as Busboy from 'busboy'; import * as path from 'path'; -import { ifdescribe, ifit } from './spec-helpers'; +import { ifdescribe, ifit, defer, startRemoteControlApp } from './spec-helpers'; import { app } from 'electron/main'; import { crashReporter } from 'electron/common'; import { AddressInfo } from 'net'; import { EventEmitter } from 'events'; import * as fs from 'fs'; -import * as v8 from 'v8'; import * as uuid from 'uuid'; const isWindowsOnArm = process.platform === 'win32' && process.arch === 'arm64'; const isLinuxOnArm = process.platform === 'linux' && process.arch.includes('arm'); -const afterTest: ((() => void) | (() => Promise))[] = []; -async function cleanup () { - for (const cleanup of afterTest) { - const r = cleanup(); - if (r instanceof Promise) { await r; } - } - afterTest.length = 0; -} - type CrashInfo = { prod: string ver: string @@ -57,49 +47,6 @@ function checkCrash (expectedProcessType: string, fields: CrashInfo) { } } -const startRemoteControlApp = async () => { - const appPath = path.join(__dirname, 'fixtures', 'apps', 'remote-control'); - const appProcess = childProcess.spawn(process.execPath, [appPath]); - appProcess.stderr.on('data', d => { - process.stderr.write(d); - }); - const port = await new Promise(resolve => { - appProcess.stdout.on('data', d => { - const m = /Listening: (\d+)/.exec(d.toString()); - if (m && m[1] != null) { - resolve(Number(m[1])); - } - }); - }); - function remoteEval (js: string): any { - return new Promise((resolve, reject) => { - const req = http.request({ - host: '127.0.0.1', - port, - method: 'POST' - }, res => { - const chunks = [] as Buffer[]; - res.on('data', chunk => { chunks.push(chunk); }); - res.on('end', () => { - const ret = v8.deserialize(Buffer.concat(chunks)); - if (Object.prototype.hasOwnProperty.call(ret, 'error')) { - reject(new Error(`remote error: ${ret.error}\n\nTriggered at:`)); - } else { - resolve(ret.result); - } - }); - }); - req.write(js); - req.end(); - }); - } - function remotely (script: Function, ...args: any[]): Promise { - return remoteEval(`(${script})(...${JSON.stringify(args)})`); - } - afterTest.push(() => { appProcess.kill('SIGINT'); }); - return { remoteEval, remotely }; -}; - const startServer = async () => { const crashes: CrashInfo[] = []; function getCrashes () { return crashes; } @@ -145,7 +92,7 @@ const startServer = async () => { const port = (server.address() as AddressInfo).port; - afterTest.push(() => { server.close(); }); + defer(() => { server.close(); }); return { getCrashes, port, waitForCrash }; }; @@ -188,8 +135,6 @@ function waitForNewFileInDir (dir: string): Promise { // TODO(nornagon): Fix tests on linux/arm. ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_TESTS)('crashReporter module', function () { - afterEach(cleanup); - describe('should send minidump', () => { it('when renderer crashes', async () => { const { port, waitForCrash } = await startServer(); diff --git a/spec-main/api-net-spec.ts b/spec-main/api-net-spec.ts index 5c5a2e1b334c..989fa9356620 100644 --- a/spec-main/api-net-spec.ts +++ b/spec-main/api-net-spec.ts @@ -4,6 +4,7 @@ import * as http from 'http'; import * as url from 'url'; import { AddressInfo, Socket } from 'net'; import { emittedOnce } from './events-helpers'; +import { defer } from './spec-helpers'; const kOneKiloByte = 1024; const kOneMegaByte = kOneKiloByte * kOneKiloByte; @@ -22,13 +23,6 @@ function randomString (length: number) { return buffer.toString(); } -const cleanupTasks: (() => void)[] = []; - -function cleanUp () { - cleanupTasks.forEach(t => t()); - cleanupTasks.length = 0; -} - async function getResponse (urlRequest: Electron.ClientRequest) { return new Promise((resolve, reject) => { urlRequest.on('error', reject); @@ -70,7 +64,7 @@ function respondNTimes (fn: http.RequestListener, n: number): Promise { }); const sockets: Socket[] = []; server.on('connection', s => sockets.push(s)); - cleanupTasks.push(() => { + defer(() => { server.close(); sockets.forEach(s => s.destroy()); }); @@ -118,7 +112,6 @@ describe('net module', () => { beforeEach(() => { routeFailure = false; }); - afterEach(cleanUp); afterEach(async function () { await session.defaultSession.clearCache(); if (routeFailure && this.test) { diff --git a/spec-main/index.js b/spec-main/index.js index 1d91c189ec64..a90a35a5aa3e 100644 --- a/spec-main/index.js +++ b/spec-main/index.js @@ -110,4 +110,8 @@ app.whenReady().then(async () => { chai.use(require('dirty-chai')); const runner = mocha.run(cb); + const { runCleanupFunctions } = require('./spec-helpers'); + runner.on('test end', () => { + runCleanupFunctions(); + }); }); diff --git a/spec-main/spec-helpers.ts b/spec-main/spec-helpers.ts index 4cdeae33669a..1bf85622db9f 100644 --- a/spec-main/spec-helpers.ts +++ b/spec-main/spec-helpers.ts @@ -1,4 +1,78 @@ +import * as childProcess from 'child_process'; +import * as path from 'path'; +import * as http from 'http'; +import * as v8 from 'v8'; + export const ifit = (condition: boolean) => (condition ? it : it.skip); export const ifdescribe = (condition: boolean) => (condition ? describe : describe.skip); export const delay = (time: number) => new Promise(resolve => setTimeout(resolve, time)); + +type CleanupFunction = (() => void) | (() => Promise) +const cleanupFunctions: CleanupFunction[] = []; +export async function runCleanupFunctions () { + for (const cleanup of cleanupFunctions) { + const r = cleanup(); + if (r instanceof Promise) { await r; } + } + cleanupFunctions.length = 0; +} + +export function defer (f: CleanupFunction) { + cleanupFunctions.push(f); +} + +class RemoteControlApp { + process: childProcess.ChildProcess; + port: number; + + constructor (proc: childProcess.ChildProcess, port: number) { + this.process = proc; + this.port = port; + } + + remoteEval = (js: string): Promise => { + return new Promise((resolve, reject) => { + const req = http.request({ + host: '127.0.0.1', + port: this.port, + method: 'POST' + }, res => { + const chunks = [] as Buffer[]; + res.on('data', chunk => { chunks.push(chunk); }); + res.on('end', () => { + const ret = v8.deserialize(Buffer.concat(chunks)); + if (Object.prototype.hasOwnProperty.call(ret, 'error')) { + reject(new Error(`remote error: ${ret.error}\n\nTriggered at:`)); + } else { + resolve(ret.result); + } + }); + }); + req.write(js); + req.end(); + }); + } + + remotely = (script: Function, ...args: any[]): Promise => { + return this.remoteEval(`(${script})(...${JSON.stringify(args)})`); + } +} + +export async function startRemoteControlApp () { + const appPath = path.join(__dirname, 'fixtures', 'apps', 'remote-control'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + appProcess.stderr.on('data', d => { + process.stderr.write(d); + }); + const port = await new Promise(resolve => { + appProcess.stdout.on('data', d => { + const m = /Listening: (\d+)/.exec(d.toString()); + if (m && m[1] != null) { + resolve(Number(m[1])); + } + }); + }); + defer(() => { appProcess.kill('SIGINT'); }); + return new RemoteControlApp(appProcess, port); +}