Files
Twitch-VOD-Manager/scripts/smoke-test-packaged-launch.js

92 lines
3.3 KiB
JavaScript

const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawn, spawnSync } = require('child_process');
const root = path.resolve(__dirname, '..');
const packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
function packagedExecutablePath() {
if (process.env.PACKAGED_APP_PATH) return path.resolve(process.env.PACKAGED_APP_PATH);
return path.join(root, 'release', 'win-unpacked', `${packageJson.build.productName}.exe`);
}
function terminateProcessTree(child) {
if (!child || child.exitCode !== null) return;
if (process.platform === 'win32') {
spawnSync('taskkill', ['/pid', String(child.pid), '/t', '/f'], { windowsHide: true, stdio: 'ignore' });
return;
}
child.kill('SIGTERM');
}
async function verifyPackagedLaunch(executablePath = packagedExecutablePath(), readyMs = 5000) {
if (process.platform !== 'win32') throw new Error('Packaged launch smoke requires Windows');
if (!fs.statSync(executablePath).isFile()) throw new Error(`Packaged executable is missing: ${executablePath}`);
const environmentRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'tvm-packaged-launch-'));
const userDataDir = path.join(environmentRoot, 'userdata');
const programDataDir = path.join(environmentRoot, 'programdata');
const appDataDir = path.join(environmentRoot, 'appdata');
const localAppDataDir = path.join(environmentRoot, 'localappdata');
const tempDir = path.join(environmentRoot, 'temp');
for (const directory of [userDataDir, programDataDir, appDataDir, localAppDataDir, tempDir]) {
fs.mkdirSync(directory, { recursive: true });
}
let output = '';
const child = spawn(executablePath, [
`--user-data-dir=${userDataDir}`,
'--proxy-server=http://127.0.0.1:1',
'--host-resolver-rules=MAP * ~NOTFOUND, EXCLUDE localhost'
], {
cwd: path.dirname(executablePath),
env: {
...process.env,
PROGRAMDATA: programDataDir,
APPDATA: appDataDir,
LOCALAPPDATA: localAppDataDir,
TEMP: tempDir,
TMP: tempDir,
HTTP_PROXY: 'http://127.0.0.1:1',
HTTPS_PROXY: 'http://127.0.0.1:1',
ALL_PROXY: 'http://127.0.0.1:1',
NO_PROXY: ''
},
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true
});
const capture = (chunk) => {
output = `${output}${chunk}`.slice(-32768);
};
child.stdout.on('data', capture);
child.stderr.on('data', capture);
try {
const result = await Promise.race([
new Promise((resolve, reject) => {
child.once('error', reject);
child.once('exit', (code, signal) => resolve({ code, signal }));
}),
new Promise((resolve) => setTimeout(() => resolve(null), readyMs))
]);
if (result) throw new Error(`Packaged app exited before readiness: ${JSON.stringify({ ...result, output })}`);
return { executablePath, readyMs };
} finally {
terminateProcessTree(child);
await fs.promises.rm(environmentRoot, { recursive: true, force: true, maxRetries: 10, retryDelay: 250 });
}
}
if (require.main === module) {
verifyPackagedLaunch()
.then((result) => console.log(JSON.stringify({ failures: [], result }, null, 2)))
.catch((error) => {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});
}
module.exports = { packagedExecutablePath, verifyPackagedLaunch };