UNPKG

@epic-web/app-launcher

Version:

Utility for launching your applications on a per-test basis.

57 lines 2.15 kB
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