@epic-web/app-launcher
Version:
Utility for launching your applications on a per-test basis.
57 lines • 2.15 kB
JavaScript
import { spawn } from 'node:child_process';
import { DeferredPromise } from '@open-draft/deferred-promise';
import { invariant } from '@epic-web/invariant';
export const kUrl = Symbol('kUrl');
export class AppProcess {
options;
io;
controller;
[kUrl];
constructor(options) {
this.options = options;
this.controller = new AbortController();
}
get url() {
const url = this[kUrl];
invariant(url != null, 'Failed to get a URL of the launched application: application not running. Did you forget to call `await launcher.run()`?');
return url;
}
async launch() {
const [command, ...args] = this.options.command.split(' ');
invariant(command != null, 'Failed to launch application: "command" could not be parsed');
this.io = spawn(command, args, {
signal: this.controller.signal,
cwd: this.options.cwd,
env: {
...process.env,
...(this.options.env || {}),
},
});
const spawnPromise = new DeferredPromise();
this.io.once('spawn', () => spawnPromise.resolve());
this.io.once('error', (error) => spawnPromise.reject(error));
await spawnPromise;
return this.io;
}
async dispose() {
invariant(!this.controller.signal.aborted, 'Failed to dispose of a launched application: already disposed');
invariant(this.io != null, 'Failed to dispose of a launched application: application is not running. Did you forget to run `await launcher.run()`?');
if (this.io.exitCode !== null) {
return Promise.resolve();
}
const exitPromise = new DeferredPromise();
this.io.once('exit', (exitCode) => {
if (exitCode === 0) {
exitPromise.resolve();
return;
}
exitPromise.reject(new Error(`Process exited with code ${exitCode}`));
});
this.controller.abort();
await exitPromise;
}
async [Symbol.asyncDispose]() {
await this.dispose();
}
}
//# sourceMappingURL=app-process.js.map