ci/woodpecker/pr/config Pipeline was successful
ci/woodpecker/pr/hledger Pipeline was successful
ci/woodpecker/pr/jobs Pipeline was successful
ci/woodpecker/pr/snapshots Pipeline was successful
ci/woodpecker/pr/web Pipeline was successful
ci/woodpecker/pr/worker Pipeline was successful
ci/woodpecker/push/config Pipeline was successful
ci/woodpecker/push/hledger Pipeline was successful
ci/woodpecker/push/jobs Pipeline was successful
ci/woodpecker/push/snapshots Pipeline was successful
ci/woodpecker/push/web Pipeline was successful
ci/woodpecker/push/worker Pipeline was successful
75 lines
2.4 KiB
JavaScript
75 lines
2.4 KiB
JavaScript
import { spawn } from 'node:child_process';
|
|
import { randomUUID } from 'node:crypto';
|
|
import { once } from 'node:events';
|
|
import { rm } from 'node:fs/promises';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { prepareBrowserFixture } from './fixture.js';
|
|
|
|
// App-owned test deployment: no personal config and no reused SQLite/data files.
|
|
const deployment =
|
|
process.env.HLEDGER_TEST_DEPLOYMENT ?? join(tmpdir(), `hledger-browser-${randomUUID()}`);
|
|
const { configPath } = await prepareBrowserFixture(deployment);
|
|
|
|
const children = [];
|
|
let stopping = false;
|
|
async function stop(code) {
|
|
if (stopping) return;
|
|
stopping = true;
|
|
const exits = children.map((child) =>
|
|
child.pid === undefined || child.exitCode !== null || child.signalCode !== null
|
|
? Promise.resolve()
|
|
: once(child, 'exit')
|
|
);
|
|
for (const child of children) child.kill('SIGTERM');
|
|
const deadline = setTimeout(() => {
|
|
for (const child of children) child.kill('SIGKILL');
|
|
}, 5_000);
|
|
await Promise.all(exits);
|
|
clearTimeout(deadline);
|
|
await rm(deployment, { recursive: true, force: true });
|
|
process.exit(code);
|
|
}
|
|
process.once('SIGINT', () => void stop(0));
|
|
process.once('SIGTERM', () => void stop(0));
|
|
|
|
function start(relativeEntry, environment) {
|
|
const entry = fileURLToPath(new URL(relativeEntry, import.meta.url));
|
|
const child = spawn(process.execPath, [entry], {
|
|
env: { ...process.env, ...environment, CONFIG_PATH: configPath },
|
|
stdio: 'inherit'
|
|
});
|
|
children.push(child);
|
|
child.once('error', () => void stop(1));
|
|
child.once('exit', () => {
|
|
if (!stopping) void stop(1);
|
|
});
|
|
}
|
|
|
|
start('../../worker/dist/src/index.js', { WORKER_PORT: '4193' });
|
|
try {
|
|
let ready = false;
|
|
for (let attempt = 0; attempt < 100 && !ready; attempt++) {
|
|
ready = await fetch('http://127.0.0.1:4193/healthz', {
|
|
signal: AbortSignal.timeout(1_000)
|
|
})
|
|
.then((response) => response.ok)
|
|
.catch(() => false);
|
|
if (!ready) await delay(100);
|
|
}
|
|
if (!ready) throw new Error('Fixture worker did not become ready.');
|
|
start('./web.js', {
|
|
HOST: '127.0.0.1',
|
|
PORT: '3000',
|
|
ADDRESS_HEADER: 'x-real-ip',
|
|
PROTOCOL_HEADER: 'x-forwarded-proto',
|
|
HOST_HEADER: '',
|
|
PORT_HEADER: ''
|
|
});
|
|
} catch {
|
|
console.error('Browser fixture startup failed. Build both apps and check hledger 1.99.5.');
|
|
await stop(1);
|
|
}
|