UNPKG

@epic-web/app-launcher

Version:

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

64 lines 2.33 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 const kLaunch = Symbol('kLaunch'); export class AppProcess { options; io; [kUrl]; constructor(options) { this.options = options; } 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; } /** * Spawns the child process with the configured application. * @note This method must never be used publicly. Use `launcher.run()` instead. */ async [kLaunch]() { const [command, ...args] = this.options.command.split(' '); invariant(command != null, 'Failed to launch application: "command" could not be parsed'); this.io = spawn(command, args, { 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; } /** * Stop the running application. */ async dispose() { invariant(this.io != null, 'Failed to dispose of a launched application: application is not running. Did you forget to run `await launcher.run()`?'); // The application has been exited by other means (e.g. unhandled exception). if (this.io.exitCode !== null) { return; } const exitPromise = new DeferredPromise(); this.io.once('exit', (exitCode) => { if (exitCode === 0) { exitPromise.resolve(); return; } exitPromise.reject(new Error(`Process exited with code ${exitCode}`)); }); if (!this.io.kill('SIGINT')) { exitPromise.reject('SIGINT did not succeed'); } await exitPromise; } async [Symbol.asyncDispose]() { await this.dispose(); } } //# sourceMappingURL=app-process.js.map