mirror of
https://github.com/electron/electron.git
synced 2026-01-10 07:58:08 -05:00
see if this cleans up the tests
This commit is contained in:
@@ -225,15 +225,7 @@ jobs:
|
||||
cd src\electron
|
||||
echo ELECTRON_TEST_RESULTS_DIR=$PWD\junit >> $env:GITHUB_ENV
|
||||
# Get which tests are on this shard
|
||||
if ('${{ matrix.shard }}' -eq '1') {
|
||||
$tests_files='spec\api-web-contents-spec.ts spec\webview-spec.ts'
|
||||
} elseif ('${{ matrix.shard }}' -eq '2') {
|
||||
$tests_files='spec\webview-spec.ts spec\api-ipc-spec.ts'
|
||||
} elseif ('${{ matrix.shard }}' -eq '3') {
|
||||
$tests_files='spec\webview-spec.ts spec\api-native-image-spec.ts'
|
||||
} elseif ('${{ matrix.shard }}' -eq '4') {
|
||||
$tests_files='spec\api-web-contents-spec.ts spec\api-menu-item-spec.ts'
|
||||
}
|
||||
$tests_files=node script\split-tests ${{ matrix.shard }} 4
|
||||
echo tests_files=$tests_files >> $env:GITHUB_ENV
|
||||
if ('${{ inputs.target-arch }}' -eq 'x86') {
|
||||
echo npm_config_arch=ia32 >> $env:GITHUB_ENV
|
||||
|
||||
@@ -206,6 +206,7 @@ describe('BrowserWindow module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
const events = [
|
||||
@@ -370,6 +371,7 @@ describe('BrowserWindow module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('should emit did-start-loading event', async () => {
|
||||
@@ -533,6 +535,7 @@ describe('BrowserWindow module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('allows the window to be closed from the event listener', async () => {
|
||||
@@ -651,6 +654,7 @@ describe('BrowserWindow module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('allows the window to be closed from the event listener', (done) => {
|
||||
@@ -839,6 +843,7 @@ describe('BrowserWindow module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
it('is emitted on redirects', async () => {
|
||||
const willRedirect = once(w.webContents, 'will-redirect');
|
||||
@@ -935,6 +940,10 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
url = (await listen(server)).url;
|
||||
});
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
it('for initial navigation, event order is consistent', async () => {
|
||||
const firedEvents: string[] = [];
|
||||
const expectedEventOrder = [
|
||||
@@ -3565,6 +3574,7 @@ describe('BrowserWindow module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('exposes ipcRenderer to preload script', async () => {
|
||||
@@ -5284,6 +5294,7 @@ describe('BrowserWindow module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('is true when the main frame is loading', async () => {
|
||||
|
||||
@@ -372,6 +372,7 @@ describe('session module', () => {
|
||||
afterEach(() => {
|
||||
if (server) {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
}
|
||||
customSession = null as any;
|
||||
});
|
||||
@@ -659,6 +660,7 @@ describe('session module', () => {
|
||||
|
||||
afterEach((done) => {
|
||||
server.close(done);
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
@@ -748,7 +750,7 @@ describe('session module', () => {
|
||||
describe('ses.clearAuthCache()', () => {
|
||||
it('can clear http auth info from cache', async () => {
|
||||
const ses = session.fromPartition('auth-cache');
|
||||
const server = http.createServer((req, res) => {
|
||||
let server = http.createServer((req, res) => {
|
||||
const credentials = auth(req);
|
||||
if (!credentials || credentials.name !== 'test' || credentials.pass !== 'test') {
|
||||
res.statusCode = 401;
|
||||
@@ -758,6 +760,10 @@ describe('session module', () => {
|
||||
res.end('authenticated');
|
||||
}
|
||||
});
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
const { port } = await listen(server);
|
||||
const fetch = (url: string) => new Promise((resolve, reject) => {
|
||||
const request = net.request({ url, session: ses });
|
||||
@@ -841,6 +847,13 @@ describe('session module', () => {
|
||||
};
|
||||
|
||||
describe('session.downloadURL', () => {
|
||||
let server: http.Server;
|
||||
afterEach(() => {
|
||||
if (server) {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
}
|
||||
});
|
||||
it('can perform a download', (done) => {
|
||||
session.defaultSession.once('will-download', function (e, item) {
|
||||
item.savePath = downloadFilePath;
|
||||
@@ -857,7 +870,7 @@ describe('session module', () => {
|
||||
});
|
||||
|
||||
it('can perform a download with a valid auth header', async () => {
|
||||
const server = http.createServer((req, res) => {
|
||||
server = http.createServer((req, res) => {
|
||||
const { authorization } = req.headers;
|
||||
if (!authorization || authorization !== 'Basic i-am-an-auth-header') {
|
||||
res.statusCode = 401;
|
||||
@@ -919,7 +932,7 @@ describe('session module', () => {
|
||||
});
|
||||
|
||||
it('correctly handles a download with an invalid auth header', async () => {
|
||||
const server = http.createServer((req, res) => {
|
||||
server = http.createServer((req, res) => {
|
||||
const { authorization } = req.headers;
|
||||
if (!authorization || authorization !== 'Basic i-am-an-auth-header') {
|
||||
res.statusCode = 401;
|
||||
@@ -963,6 +976,13 @@ describe('session module', () => {
|
||||
});
|
||||
|
||||
describe('webContents.downloadURL', () => {
|
||||
let server: http.Server;
|
||||
afterEach(() => {
|
||||
if (server) {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
}
|
||||
});
|
||||
it('can perform a download', (done) => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.webContents.session.once('will-download', function (e, item) {
|
||||
@@ -980,7 +1000,7 @@ describe('session module', () => {
|
||||
});
|
||||
|
||||
it('can perform a download with a valid auth header', async () => {
|
||||
const server = http.createServer((req, res) => {
|
||||
server = http.createServer((req, res) => {
|
||||
const { authorization } = req.headers;
|
||||
if (!authorization || authorization !== 'Basic i-am-an-auth-header') {
|
||||
res.statusCode = 401;
|
||||
@@ -1036,7 +1056,7 @@ describe('session module', () => {
|
||||
});
|
||||
|
||||
it('correctly handles a download and an invalid auth header', async () => {
|
||||
const server = http.createServer((req, res) => {
|
||||
server = http.createServer((req, res) => {
|
||||
const { authorization } = req.headers;
|
||||
if (!authorization || authorization !== 'Basic i-am-an-auth-header') {
|
||||
res.statusCode = 401;
|
||||
@@ -1255,11 +1275,15 @@ describe('session module', () => {
|
||||
|
||||
it('can be resumed', async () => {
|
||||
const downloadFilePath = path.join(fixtures, 'logo.png');
|
||||
const rangeServer = http.createServer((req, res) => {
|
||||
let rangeServer = http.createServer((req, res) => {
|
||||
const options = { root: fixtures };
|
||||
send(req, req.url!, options)
|
||||
.on('error', (error: any) => { throw error; }).pipe(res);
|
||||
});
|
||||
defer(() => {
|
||||
rangeServer.close();
|
||||
rangeServer = null as unknown as http.Server;
|
||||
});
|
||||
try {
|
||||
const { url } = await listen(rangeServer);
|
||||
const w = new BrowserWindow({ show: false });
|
||||
@@ -1327,6 +1351,7 @@ describe('session module', () => {
|
||||
});
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('cancels any pending requests when cleared', async () => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { closeAllWindows } from './lib/window-helpers';
|
||||
describe('shell module', () => {
|
||||
describe('shell.openExternal()', () => {
|
||||
let envVars: Record<string, string | undefined> = {};
|
||||
let server: http.Server;
|
||||
|
||||
beforeEach(function () {
|
||||
envVars = {
|
||||
@@ -31,8 +32,12 @@ describe('shell module', () => {
|
||||
process.env.BROWSER = envVars.browser;
|
||||
process.env.DISPLAY = envVars.display;
|
||||
}
|
||||
await closeAllWindows();
|
||||
if (server) {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
}
|
||||
});
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
async function urlOpened () {
|
||||
let url = 'http://127.0.0.1';
|
||||
@@ -50,7 +55,7 @@ describe('shell module', () => {
|
||||
const w = new BrowserWindow({ show: true });
|
||||
requestReceived = once(w, 'blur');
|
||||
} else {
|
||||
const server = http.createServer((req, res) => {
|
||||
server = http.createServer((req, res) => {
|
||||
res.end();
|
||||
});
|
||||
url = (await listen(server)).url;
|
||||
|
||||
@@ -349,6 +349,7 @@ describe('webContents module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('works after page load and during subframe load', async () => {
|
||||
@@ -391,6 +392,14 @@ describe('webContents module', () => {
|
||||
|
||||
describe('loadURL() promise API', () => {
|
||||
let w: BrowserWindow;
|
||||
let s: http.Server;
|
||||
|
||||
afterEach(() => {
|
||||
if (s) {
|
||||
s.close();
|
||||
s = null as unknown as http.Server;
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
w = new BrowserWindow({ show: false });
|
||||
@@ -494,19 +503,18 @@ describe('webContents module', () => {
|
||||
});
|
||||
|
||||
it('rejects if the load is aborted', async () => {
|
||||
const s = http.createServer(() => { /* never complete the request */ });
|
||||
s = http.createServer(() => { /* never complete the request */ });
|
||||
const { port } = await listen(s);
|
||||
const p = expect(w.loadURL(`http://127.0.0.1:${port}`)).to.eventually.be.rejectedWith(Error, /ERR_ABORTED/);
|
||||
// load a different file before the first load completes, causing the
|
||||
// first load to be aborted.
|
||||
await w.loadFile(path.join(fixturesPath, 'pages', 'base-page.html'));
|
||||
await p;
|
||||
s.close();
|
||||
});
|
||||
|
||||
it("doesn't reject when a subframe fails to load", async () => {
|
||||
let resp = null as unknown as http.ServerResponse;
|
||||
const s = http.createServer((req, res) => {
|
||||
s = http.createServer((req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/html' });
|
||||
res.write('<iframe src="http://err.name.not.resolved"></iframe>');
|
||||
resp = res;
|
||||
@@ -524,12 +532,11 @@ describe('webContents module', () => {
|
||||
await p;
|
||||
resp.end();
|
||||
await main;
|
||||
s.close();
|
||||
});
|
||||
|
||||
it("doesn't resolve when a subframe loads", async () => {
|
||||
let resp = null as unknown as http.ServerResponse;
|
||||
const s = http.createServer((req, res) => {
|
||||
s = http.createServer((req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/html' });
|
||||
res.write('<iframe src="about:blank"></iframe>');
|
||||
resp = res;
|
||||
@@ -548,7 +555,6 @@ describe('webContents module', () => {
|
||||
resp.destroy(); // cause the main request to fail
|
||||
await expect(main).to.eventually.be.rejected()
|
||||
.and.have.property('errno', -355); // ERR_INCOMPLETE_CHUNKED_ENCODING
|
||||
s.close();
|
||||
});
|
||||
|
||||
it('subsequent load failures reject each time', async () => {
|
||||
@@ -1521,11 +1527,15 @@ describe('webContents module', () => {
|
||||
|
||||
it('can persist when it contains iframe', (done) => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const server = http.createServer((req, res) => {
|
||||
let server = http.createServer((req, res) => {
|
||||
setTimeout(200).then(() => {
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
listen(server).then(({ url }) => {
|
||||
const content = `<iframe src=${url}></iframe>`;
|
||||
w.webContents.on('did-frame-finish-load', (e, isMainFrame) => {
|
||||
@@ -1538,8 +1548,6 @@ describe('webContents module', () => {
|
||||
done();
|
||||
} catch (e) {
|
||||
done(e);
|
||||
} finally {
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1586,6 +1594,7 @@ describe('webContents module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('cannot persist zoom level after navigation with webFrame', async () => {
|
||||
@@ -1745,6 +1754,7 @@ describe('webContents module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
@@ -1907,6 +1917,7 @@ describe('webContents module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
const events = [
|
||||
@@ -2016,19 +2027,21 @@ describe('webContents module', () => {
|
||||
afterEach(closeAllWindows);
|
||||
it('propagates referrer information to new target=_blank windows', (done) => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const server = http.createServer((req, res) => {
|
||||
let server = http.createServer((req, res) => {
|
||||
if (req.url === '/should_have_referrer') {
|
||||
try {
|
||||
expect(req.headers.referer).to.equal(`http://127.0.0.1:${(server.address() as AddressInfo).port}/`);
|
||||
return done();
|
||||
} catch (e) {
|
||||
return done(e);
|
||||
} finally {
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
res.end('<a id="a" href="/should_have_referrer" target="_blank">link</a>');
|
||||
});
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
listen(server).then(({ url }) => {
|
||||
w.webContents.once('did-finish-load', () => {
|
||||
w.webContents.setWindowOpenHandler(details => {
|
||||
@@ -2044,7 +2057,7 @@ describe('webContents module', () => {
|
||||
|
||||
it('propagates referrer information to windows opened with window.open', (done) => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const server = http.createServer((req, res) => {
|
||||
let server = http.createServer((req, res) => {
|
||||
if (req.url === '/should_have_referrer') {
|
||||
try {
|
||||
expect(req.headers.referer).to.equal(`http://127.0.0.1:${(server.address() as AddressInfo).port}/`);
|
||||
@@ -2055,6 +2068,10 @@ describe('webContents module', () => {
|
||||
}
|
||||
res.end('');
|
||||
});
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
listen(server).then(({ url }) => {
|
||||
w.webContents.once('did-finish-load', () => {
|
||||
w.webContents.setWindowOpenHandler(details => {
|
||||
@@ -2636,7 +2653,9 @@ describe('webContents module', () => {
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
proxyServer.close();
|
||||
proxyServer = null as unknown as http.Server;
|
||||
});
|
||||
|
||||
it('is emitted when navigating', async () => {
|
||||
|
||||
@@ -464,6 +464,9 @@ describe('webFrameMain module', () => {
|
||||
|
||||
it('is not emitted upon cross-origin navigation', async () => {
|
||||
const server = await createServer();
|
||||
defer(() => {
|
||||
server.server.close();
|
||||
});
|
||||
|
||||
const w = new BrowserWindow({ show: false });
|
||||
await w.webContents.loadURL(server.url);
|
||||
|
||||
@@ -2540,6 +2540,7 @@ describe('chromium features', () => {
|
||||
describe('websockets', () => {
|
||||
it('has user agent', async () => {
|
||||
const server = http.createServer();
|
||||
defer(() => server.close());
|
||||
const { port } = await listen(server);
|
||||
const wss = new ws.Server({ server });
|
||||
const finished = new Promise<string | undefined>((resolve, reject) => {
|
||||
@@ -3692,6 +3693,7 @@ describe('navigator.usb', () => {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('<body>');
|
||||
});
|
||||
defer(() => server.close());
|
||||
|
||||
serverUrl = (await listen(server)).url;
|
||||
|
||||
|
||||
146
spec/index.js
146
spec/index.js
@@ -1,117 +1,7 @@
|
||||
/* eslint-disable */
|
||||
const { app, protocol } = require('electron');
|
||||
const { createHook } = require('node:async_hooks');
|
||||
const childProcess = require('node:child_process');
|
||||
const { readFileSync } = require('node:fs');
|
||||
|
||||
const fs = require('node:fs');
|
||||
const { relative } = require('node:path');
|
||||
const path = require('node:path');
|
||||
const { fileURLToPath } = require('node:url');
|
||||
/* eslint-enable */
|
||||
|
||||
const IGNORED_TYPES = [
|
||||
'TIMERWRAP',
|
||||
'PROMISE',
|
||||
'PerformanceObserver',
|
||||
'RANDOMBYTESREQUEST'
|
||||
];
|
||||
|
||||
const asyncResources = new Map();
|
||||
const hook = createHook({
|
||||
init (asyncId, type, triggerAsyncId, resource) {
|
||||
if (IGNORED_TYPES.includes(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stacks = captureStackTraces().slice(1);
|
||||
|
||||
asyncResources.set(asyncId, {
|
||||
type,
|
||||
resource,
|
||||
stacks
|
||||
});
|
||||
},
|
||||
destroy (asyncId) {
|
||||
asyncResources.delete(asyncId);
|
||||
}
|
||||
});
|
||||
|
||||
hook.enable();
|
||||
|
||||
function whyIsNodeRunning (logger = console) {
|
||||
hook.disable();
|
||||
|
||||
const activeAsyncResources = Array.from(asyncResources.values())
|
||||
.filter(({ resource }) => resource.hasRef?.() ?? true);
|
||||
|
||||
logger.error(`There are ${activeAsyncResources.length} handle(s) keeping the process running.`);
|
||||
|
||||
for (const asyncResource of activeAsyncResources) {
|
||||
printStacks(asyncResource, logger);
|
||||
}
|
||||
}
|
||||
|
||||
function printStacks (asyncResource, logger) {
|
||||
const stacks = asyncResource.stacks.filter((stack) => {
|
||||
const fileName = stack.getFileName();
|
||||
return fileName !== null && !fileName.startsWith('node:');
|
||||
});
|
||||
|
||||
logger.error('');
|
||||
logger.error(`# ${asyncResource.type}`);
|
||||
|
||||
if (!stacks[0]) {
|
||||
logger.error('(unknown stack trace)');
|
||||
return;
|
||||
}
|
||||
|
||||
const maxLength = stacks.reduce((length, stack) => Math.max(length, formatLocation(stack).length), 0);
|
||||
|
||||
for (const stack of stacks) {
|
||||
const location = formatLocation(stack);
|
||||
const padding = ' '.repeat(maxLength - location.length);
|
||||
|
||||
try {
|
||||
const lines = readFileSync(normalizeFilePath(stack.getFileName()), 'utf-8').split(/\n|\r\n/);
|
||||
const line = lines[stack.getLineNumber() - 1].trim();
|
||||
|
||||
logger.error(`${location}${padding} - ${line}`);
|
||||
} catch (e) {
|
||||
logger.error(`${location}${padding} ${e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatLocation (stack) {
|
||||
const filePath = formatFilePath(stack.getFileName());
|
||||
return `${filePath}:${stack.getLineNumber()}`;
|
||||
}
|
||||
|
||||
function formatFilePath (filePath) {
|
||||
const absolutePath = normalizeFilePath(filePath);
|
||||
const relativePath = relative(process.cwd(), absolutePath);
|
||||
|
||||
return relativePath.startsWith('..') ? absolutePath : relativePath;
|
||||
}
|
||||
|
||||
function normalizeFilePath (filePath) {
|
||||
return filePath.startsWith('file://') ? fileURLToPath(filePath) : filePath;
|
||||
}
|
||||
|
||||
// See: https://v8.dev/docs/stack-trace-api
|
||||
function captureStackTraces () {
|
||||
const target = {};
|
||||
const original = Error.prepareStackTrace;
|
||||
|
||||
Error.prepareStackTrace = (error, stackTraces) => stackTraces; // eslint-disable-line
|
||||
Error.captureStackTrace(target, captureStackTraces);
|
||||
|
||||
const capturedTraces = target.stack;
|
||||
Error.prepareStackTrace = original;
|
||||
|
||||
return capturedTraces;
|
||||
}
|
||||
|
||||
const v8 = require('node:v8');
|
||||
|
||||
// We want to terminate on errors, not throw up a dialog
|
||||
@@ -279,42 +169,8 @@ app.whenReady().then(async () => {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fifteenMinutes = 15 * 60 * 1000;
|
||||
const testTimeout = setTimeout(async () => {
|
||||
console.log('Electron tests timed out after 15 minutes.');
|
||||
if (process.platform === 'win32') {
|
||||
const scArgs = [
|
||||
|
||||
'screen.png'
|
||||
];
|
||||
const ARTIFACT_DIR = path.join(__dirname, 'artifacts');
|
||||
fs.mkdirSync(ARTIFACT_DIR, { recursive: true });
|
||||
const { stdout, stderr } = childProcess.spawnSync(path.resolve(__dirname, '..', 'script', 'screenCapture.bat'), scArgs, {
|
||||
cwd: ARTIFACT_DIR,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
console.log(`screenCap: ${stdout} ${stderr}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}, fifteenMinutes);
|
||||
|
||||
const cb = () => {
|
||||
console.log('In SPEC CB');
|
||||
clearTimeout(testTimeout);
|
||||
console.log(`In SPEC CB, process next tick with failures: ${runner.failures} for ${process.platform}`);
|
||||
if (process.platform === 'win32') {
|
||||
const scBat = path.resolve(__dirname, '..', 'script', 'screenCapture.bat');
|
||||
/* const scArgs = [
|
||||
'screen.png'
|
||||
]; */
|
||||
const ARTIFACT_DIR = path.join(__dirname, 'spec', 'artifacts');
|
||||
fs.mkdirSync(ARTIFACT_DIR, { recursive: true });
|
||||
const { stdout, stderr } = childProcess.spawnSync(scBat, [], {
|
||||
cwd: ARTIFACT_DIR
|
||||
});
|
||||
console.log(`screenCap results ${stdout} ${stderr}`);
|
||||
}
|
||||
setImmediate(() => whyIsNodeRunning());
|
||||
process.exit(runner.failures);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,16 +3,128 @@ import { BrowserWindow } from 'electron/main';
|
||||
import { AssertionError } from 'chai';
|
||||
import { SuiteFunction, TestFunction } from 'mocha';
|
||||
|
||||
import { createHook } from 'node:async_hooks';
|
||||
import * as childProcess from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import * as http from 'node:http';
|
||||
import * as http2 from 'node:http2';
|
||||
import * as https from 'node:https';
|
||||
import * as net from 'node:net';
|
||||
import * as path from 'node:path';
|
||||
import { relative } from 'node:path';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import * as url from 'node:url';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as v8 from 'node:v8';
|
||||
|
||||
const IGNORED_TYPES = [
|
||||
'TIMERWRAP',
|
||||
'PROMISE',
|
||||
'PerformanceObserver',
|
||||
'RANDOMBYTESREQUEST'
|
||||
];
|
||||
|
||||
let asyncResources:Map<number, any>;
|
||||
let hook:any;
|
||||
|
||||
export function initWhyIsNodeRunning () {
|
||||
asyncResources = new Map();
|
||||
hook = createHook({
|
||||
init (asyncId, type, triggerAsyncId, resource) {
|
||||
if (IGNORED_TYPES.includes(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stacks = captureStackTraces().slice(1);
|
||||
|
||||
asyncResources.set(asyncId, {
|
||||
type,
|
||||
resource,
|
||||
stacks
|
||||
});
|
||||
},
|
||||
destroy (asyncId) {
|
||||
asyncResources.delete(asyncId);
|
||||
}
|
||||
});
|
||||
|
||||
hook.enable();
|
||||
}
|
||||
|
||||
export function whyIsNodeRunning () {
|
||||
hook.disable();
|
||||
|
||||
const activeAsyncResources = Array.from(asyncResources.values())
|
||||
.filter(({ resource }) => resource.hasRef?.() ?? true);
|
||||
|
||||
console.error(`There are ${activeAsyncResources.length} handle(s) keeping the process running.`);
|
||||
|
||||
for (const asyncResource of activeAsyncResources) {
|
||||
printStacks(asyncResource, console);
|
||||
}
|
||||
}
|
||||
|
||||
function printStacks (asyncResource:any, logger:any) {
|
||||
const stacks = asyncResource.stacks.filter((stack:any) => {
|
||||
const fileName = stack.getFileName();
|
||||
return fileName !== null && !fileName.startsWith('node:internal/async_hooks');
|
||||
});
|
||||
|
||||
logger.error('');
|
||||
logger.error(`# ${asyncResource.type}`);
|
||||
|
||||
if (!stacks[0]) {
|
||||
logger.error('(unknown stack trace)');
|
||||
return;
|
||||
}
|
||||
|
||||
const maxLength = stacks.reduce((length:any, stack:any) => Math.max(length, formatLocation(stack).length), 0);
|
||||
|
||||
for (const stack of stacks) {
|
||||
const location = formatLocation(stack);
|
||||
const padding = ' '.repeat(maxLength - location.length);
|
||||
|
||||
try {
|
||||
const lines = readFileSync(normalizeFilePath(stack.getFileName()), 'utf-8').split(/\n|\r\n/);
|
||||
const line = lines[stack.getLineNumber() - 1].trim();
|
||||
|
||||
logger.error(`${location}${padding} - ${line}`);
|
||||
} catch {
|
||||
logger.error(`${location}${padding}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatLocation (stack:any) {
|
||||
const filePath = formatFilePath(stack.getFileName());
|
||||
return `${filePath}:${stack.getLineNumber()}`;
|
||||
}
|
||||
|
||||
function formatFilePath (filePath:any) {
|
||||
const absolutePath = normalizeFilePath(filePath);
|
||||
const relativePath = relative(process.cwd(), absolutePath);
|
||||
|
||||
return relativePath.startsWith('..') ? absolutePath : relativePath;
|
||||
}
|
||||
|
||||
function normalizeFilePath (filePath:any) {
|
||||
return filePath.startsWith('file://') ? fileURLToPath(filePath) : filePath;
|
||||
}
|
||||
|
||||
// See: https://v8.dev/docs/stack-trace-api
|
||||
function captureStackTraces () {
|
||||
const target:any = {};
|
||||
const original = Error.prepareStackTrace;
|
||||
|
||||
Error.prepareStackTrace = (error, stackTraces) => stackTraces; // eslint-disable-line
|
||||
Error.captureStackTrace(target, captureStackTraces);
|
||||
|
||||
const capturedTraces = target.stack;
|
||||
Error.prepareStackTrace = original;
|
||||
|
||||
return capturedTraces;
|
||||
}
|
||||
|
||||
const addOnly = <T>(fn: Function): T => {
|
||||
const wrapped = (...args: any[]) => {
|
||||
return fn(...args);
|
||||
|
||||
@@ -1284,16 +1284,19 @@ describe('<webview> tag', function () {
|
||||
it('sets the referrer url', async () => {
|
||||
const referrer = 'http://github.com/';
|
||||
const received = await new Promise<string | undefined>((resolve, reject) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
let server = http.createServer((req, res) => {
|
||||
try {
|
||||
resolve(req.headers.referer);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
} finally {
|
||||
res.end();
|
||||
server.close();
|
||||
}
|
||||
});
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
listen(server).then(({ url }) => {
|
||||
loadWebView(w, {
|
||||
httpreferrer: referrer,
|
||||
@@ -1540,7 +1543,7 @@ describe('<webview> tag', function () {
|
||||
|
||||
describe('did-redirect-navigation event', () => {
|
||||
it('is emitted on redirects', async () => {
|
||||
const server = http.createServer((req, res) => {
|
||||
let server = http.createServer((req, res) => {
|
||||
if (req.url === '/302') {
|
||||
res.setHeader('Location', '/200');
|
||||
res.statusCode = 302;
|
||||
@@ -1550,7 +1553,10 @@ describe('<webview> tag', function () {
|
||||
}
|
||||
});
|
||||
const { url } = await listen(server);
|
||||
defer(() => { server.close(); });
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
const event = await loadWebViewAndWaitForEvent(w, {
|
||||
src: `${url}/302`
|
||||
}, 'did-redirect-navigation');
|
||||
@@ -1695,11 +1701,15 @@ describe('<webview> tag', function () {
|
||||
|
||||
describe('dom-ready event', () => {
|
||||
it('emits when document is loaded', async () => {
|
||||
const server = http.createServer(() => {});
|
||||
let server = http.createServer(() => {});
|
||||
const { port } = await listen(server);
|
||||
await loadWebViewAndWaitForEvent(w, {
|
||||
src: `file://${fixtures}/pages/dom-ready.html?port=${port}`
|
||||
}, 'dom-ready');
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
});
|
||||
|
||||
itremote('throws a custom error when an API method is called before the event is emitted', () => {
|
||||
@@ -2186,7 +2196,7 @@ describe('<webview> tag', function () {
|
||||
|
||||
it('should authenticate with correct credentials', async () => {
|
||||
const message = 'Authenticated';
|
||||
const server = http.createServer((req, res) => {
|
||||
let server = http.createServer((req, res) => {
|
||||
const credentials = auth(req)!;
|
||||
if (credentials.name === 'test' && credentials.pass === 'test') {
|
||||
res.end(message);
|
||||
@@ -2196,6 +2206,7 @@ describe('<webview> tag', function () {
|
||||
});
|
||||
defer(() => {
|
||||
server.close();
|
||||
server = null as unknown as http.Server;
|
||||
});
|
||||
const { port } = await listen(server);
|
||||
const e = await loadWebViewAndWaitForEvent(w, {
|
||||
|
||||
Reference in New Issue
Block a user