@jterrazz/test 12.2.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -14
- package/dist/checker.js +554 -48
- package/dist/index.d.ts +102 -88
- package/dist/index.js +16 -14
- package/dist/literate.js +156 -164
- package/dist/match.js +60 -180
- package/dist/oxlint.cjs +83 -11
- package/dist/oxlint.js +83 -11
- package/dist/queue.js +1 -1
- package/dist/spec-document.js +536 -0
- package/dist/vitest.d.ts +3 -3
- package/dist/vitest.js +16 -15
- package/package.json +6 -4
- package/schema/spec.schema.json +179 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Scalar } from "yaml";
|
|
1
2
|
import { DeepMockProxy } from "vitest-mock-extended";
|
|
2
3
|
//#region src/core/matching/match.d.ts
|
|
3
4
|
/**
|
|
@@ -390,9 +391,20 @@ type CliEnv = Record<string, null | string>;
|
|
|
390
391
|
* Abstract command interface for specification runners.
|
|
391
392
|
* Implement this to plug in your command execution strategy.
|
|
392
393
|
*/
|
|
394
|
+
/**
|
|
395
|
+
* What one invocation is handed beyond its arguments — the two per-run inputs a
|
|
396
|
+
* spec document may state. Both are absent by default: the child gets an
|
|
397
|
+
* immediately-closed stdin (never a TTY) and the adapter's own timeout.
|
|
398
|
+
*/
|
|
399
|
+
interface CliInput {
|
|
400
|
+
/** Written to the child's stdin, which is then closed. */
|
|
401
|
+
stdin?: string;
|
|
402
|
+
/** Milliseconds after which the run is killed (exit code 124). */
|
|
403
|
+
timeout?: number;
|
|
404
|
+
}
|
|
393
405
|
interface CliPort {
|
|
394
406
|
/** Execute a command with the given arguments in the given working directory. */
|
|
395
|
-
exec: (args: string, cwd: string, env?: CliEnv) => Promise<CliOutput>;
|
|
407
|
+
exec: (args: string, cwd: string, env?: CliEnv, input?: CliInput) => Promise<CliOutput>;
|
|
396
408
|
/** Run a long-running process and wait for a pattern or timeout. */
|
|
397
409
|
watch: (args: string, cwd: string, options: ExecOptions, env?: CliEnv) => Promise<CliOutput>;
|
|
398
410
|
}
|
|
@@ -928,24 +940,25 @@ declare class HttpResult extends BaseResult {
|
|
|
928
940
|
//#endregion
|
|
929
941
|
//#region src/core/specification/cli/literate.d.ts
|
|
930
942
|
/**
|
|
931
|
-
* Running a
|
|
932
|
-
* servers, every
|
|
943
|
+
* Running a `<case>.spec.yaml` document: one scenario, one working directory,
|
|
944
|
+
* one set of servers, every run executed and asserted.
|
|
933
945
|
*
|
|
934
946
|
* The engine composes pieces that already exist rather than adding a second of
|
|
935
947
|
* anything — {@link copyPlan} for `fixture:`, the runner's own command adapter
|
|
936
|
-
* for each
|
|
937
|
-
*
|
|
938
|
-
* What is new here is only the ORCHESTRATION the chain cannot express:
|
|
939
|
-
* commands sharing one working directory, each asserted, none stopping
|
|
948
|
+
* for each run, {@link ServeAdapter} for `serve:`, the `{{token}}` engine for
|
|
949
|
+
* every comparison, and {@link mergeTextPreservingPlaceholders} for the
|
|
950
|
+
* rewrite. What is new here is only the ORCHESTRATION the chain cannot express:
|
|
951
|
+
* several commands sharing one working directory, each asserted, none stopping
|
|
952
|
+
* the run.
|
|
940
953
|
*/
|
|
941
954
|
/**
|
|
942
|
-
* A server a
|
|
943
|
-
*
|
|
955
|
+
* A server a document may start by name (`serve: mcp`), registered once per app
|
|
956
|
+
* in the `serve` option of `specification.cli()`.
|
|
944
957
|
*/
|
|
945
958
|
interface LiterateServeRegistration {
|
|
946
959
|
/** Shell command that starts the server, run from the project root. */
|
|
947
960
|
command: string;
|
|
948
|
-
/** The variable the resolved URL is bound to in every
|
|
961
|
+
/** The variable the resolved URL is bound to in every run's child env. */
|
|
949
962
|
env: string;
|
|
950
963
|
/**
|
|
951
964
|
* Matched against the server's output; the FIRST capture group is the port
|
|
@@ -955,15 +968,15 @@ interface LiterateServeRegistration {
|
|
|
955
968
|
/** Builds the URL bound to {@link env} from the announced port. */
|
|
956
969
|
url: (port: number) => string;
|
|
957
970
|
}
|
|
958
|
-
/** Per-call options for {@link
|
|
971
|
+
/** Per-call options for {@link runSpecDocument} / `cli.run()`. */
|
|
959
972
|
interface LiterateRunFlags {
|
|
960
973
|
/**
|
|
961
|
-
* Opt this
|
|
962
|
-
* written under `TEST_UPDATE=1`: its mismatch still throws its diff.
|
|
963
|
-
* is what makes a DELIBERATELY-WRONG `.
|
|
964
|
-
* is the subject of a negative test — survive an update run
|
|
965
|
-
* being silently corrected into a passing file. The
|
|
966
|
-
* `toMatch(name, { frozen: true })`.
|
|
974
|
+
* Opt this document OUT of the update-mode rewrite. A frozen document is
|
|
975
|
+
* NEVER written under `TEST_UPDATE=1`: its mismatch still throws its diff.
|
|
976
|
+
* That is what makes a DELIBERATELY-WRONG `.spec.yaml` — one whose failure
|
|
977
|
+
* rendering is the subject of a negative test — survive an update run
|
|
978
|
+
* instead of being silently corrected into a passing file. The document's
|
|
979
|
+
* mirror of `toMatch(name, { frozen: true })`.
|
|
967
980
|
*/
|
|
968
981
|
frozen?: boolean;
|
|
969
982
|
}
|
|
@@ -1178,7 +1191,7 @@ interface SpecificationConfig {
|
|
|
1178
1191
|
*/
|
|
1179
1192
|
dockerTestRunId?: string;
|
|
1180
1193
|
/**
|
|
1181
|
-
* Named environment SETS a
|
|
1194
|
+
* Named environment SETS a spec document may name by bare word
|
|
1182
1195
|
* (`env: frozen`). Declared once per app in `specification.cli()`.
|
|
1183
1196
|
*/
|
|
1184
1197
|
envSets?: Record<string, CliEnv>;
|
|
@@ -1188,12 +1201,12 @@ interface SpecificationConfig {
|
|
|
1188
1201
|
*/
|
|
1189
1202
|
interceptDisabledReason?: string;
|
|
1190
1203
|
jobs?: JobHandle[];
|
|
1191
|
-
/** The project root — the working directory a
|
|
1204
|
+
/** The project root — the working directory a document's `serve:` command runs from. */
|
|
1192
1205
|
root?: string;
|
|
1193
1206
|
server?: ServerPort;
|
|
1194
1207
|
/**
|
|
1195
|
-
* Named servers a
|
|
1196
|
-
*
|
|
1208
|
+
* Named servers a spec document may start (`serve: [mcp]`). Declared once
|
|
1209
|
+
* per app in `specification.cli()`.
|
|
1197
1210
|
*/
|
|
1198
1211
|
serveRegistry?: Record<string, LiterateServeRegistration>;
|
|
1199
1212
|
/**
|
|
@@ -1285,11 +1298,11 @@ interface CliSpecification<DatabaseKey extends string = string> {
|
|
|
1285
1298
|
*/
|
|
1286
1299
|
exec: (args?: string | string[], options?: ExecOptions) => Promise<CliResult>;
|
|
1287
1300
|
/**
|
|
1288
|
-
* Run a
|
|
1289
|
-
* servers) and every
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1301
|
+
* Run a `<case>.spec.yaml` document — its ground (fixtures, env sets,
|
|
1302
|
+
* servers) and every run, each asserted — and resolve with the LAST run's
|
|
1303
|
+
* result, so a `.test.ts` can add an assertion the document cannot express
|
|
1304
|
+
* (a directory golden, a grep). The path is relative to the test file's own
|
|
1305
|
+
* directory, where the document lives.
|
|
1293
1306
|
*/
|
|
1294
1307
|
run: (file: string, options?: LiterateRunFlags) => Promise<CliResult>;
|
|
1295
1308
|
}
|
|
@@ -1926,83 +1939,84 @@ declare const specification: {
|
|
|
1926
1939
|
website: typeof startWebsite;
|
|
1927
1940
|
};
|
|
1928
1941
|
//#endregion
|
|
1929
|
-
//#region src/core/literate/
|
|
1942
|
+
//#region src/core/literate/spec-document.d.ts
|
|
1930
1943
|
/**
|
|
1931
|
-
*
|
|
1932
|
-
*
|
|
1933
|
-
* A literate spec is ONE scenario in one file: a header of `key: value` lines
|
|
1934
|
-
* (the narrative and the ground the run stands on), a blank line, then one or
|
|
1935
|
-
* more `$ <argv>` blocks holding the expected exit code and streams.
|
|
1936
|
-
*
|
|
1937
|
-
* test: refuses to guess when it is run outside the checkout
|
|
1938
|
-
* given: a workdir with no home/ + apps/ pair anywhere above it
|
|
1939
|
-
* then: the error names where the command has to be run
|
|
1940
|
-
* fixture: $FIXTURES/repositories-stub/
|
|
1941
|
-
* env: frozen TERRA_ORIGIN=http://127.0.0.1:9
|
|
1942
|
-
* serve: mcp MCP_STUB_WITHHOLD=get-article
|
|
1943
|
-
*
|
|
1944
|
-
* $ terra git repositories
|
|
1945
|
-
* exit: 1
|
|
1946
|
-
* --- stderr
|
|
1947
|
-
* Error: no directory with home/ and apps/ above the current directory
|
|
1948
|
-
*
|
|
1949
|
-
* The shape mirrors the `.http` grammar (a start section, then a body split at
|
|
1950
|
-
* the first blank line) so a reader who knows one knows the other. The parser
|
|
1951
|
-
* is pure text: it resolves nothing, runs nothing, and knows no filesystem.
|
|
1944
|
+
* The facets a document may describe. `cli` is the only one implemented; the
|
|
1945
|
+
* key exists so a second facet can arrive without a second grammar.
|
|
1952
1946
|
*/
|
|
1953
|
-
|
|
1954
|
-
type
|
|
1947
|
+
declare const SPEC_KINDS: readonly ["cli"];
|
|
1948
|
+
type SpecKind = (typeof SPEC_KINDS)[number];
|
|
1949
|
+
/** One `env:` entry — a bare word naming a registered set, or a `KEY=value` pair. */
|
|
1950
|
+
type SpecEnvToken = {
|
|
1955
1951
|
key: string;
|
|
1956
1952
|
kind: 'pair';
|
|
1953
|
+
line: number;
|
|
1957
1954
|
value: string;
|
|
1958
1955
|
} | {
|
|
1959
1956
|
kind: 'set';
|
|
1957
|
+
line: number;
|
|
1960
1958
|
name: string;
|
|
1961
1959
|
};
|
|
1962
|
-
/** One `serve:`
|
|
1963
|
-
interface
|
|
1960
|
+
/** One `serve:` entry — a registered server plus the extra env it is started with. */
|
|
1961
|
+
interface SpecServeEntry {
|
|
1964
1962
|
env: Record<string, string>;
|
|
1965
1963
|
line: number;
|
|
1966
1964
|
name: string;
|
|
1967
1965
|
}
|
|
1968
|
-
/**
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
* to move between the file and this type without a translation table. The
|
|
1973
|
-
* thenable hazard the linter guards is not reachable here — a header is data
|
|
1974
|
-
* read out of a `LiterateSpec`, never a value the framework awaits.
|
|
1975
|
-
*/
|
|
1976
|
-
interface LiterateHeader {
|
|
1977
|
-
/** `env:` lines, flattened to their tokens in declaration order. */
|
|
1978
|
-
env: LiterateEnvToken[];
|
|
1979
|
-
/** `fixture:` paths, in declaration order (they layer). */
|
|
1980
|
-
fixtures: string[];
|
|
1981
|
-
given: string;
|
|
1982
|
-
/** `serve:` lines, in declaration order. */
|
|
1983
|
-
serve: LiterateServeEntry[];
|
|
1984
|
-
/** The vitest test title. */
|
|
1985
|
-
test: string;
|
|
1986
|
-
then: string;
|
|
1966
|
+
/** One `fixture:` entry — a path with the line it was declared on. */
|
|
1967
|
+
interface SpecFixture {
|
|
1968
|
+
line: number;
|
|
1969
|
+
path: string;
|
|
1987
1970
|
}
|
|
1988
|
-
/**
|
|
1989
|
-
interface
|
|
1990
|
-
/**
|
|
1991
|
-
argv: string;
|
|
1992
|
-
exitCode: number;
|
|
1993
|
-
/** 1-based line of the `$ ` line in the source file. */
|
|
1971
|
+
/** An expected stream: its text, and the first line of that text in the file. */
|
|
1972
|
+
interface SpecStream {
|
|
1973
|
+
/** 1-based line the scalar's content starts on — where a token defect is reported. */
|
|
1994
1974
|
line: number;
|
|
1995
|
-
|
|
1996
|
-
stderr: null | string;
|
|
1997
|
-
/** Expected stdout, verbatim (no trailing newline). */
|
|
1998
|
-
stdout: string;
|
|
1975
|
+
text: string;
|
|
1999
1976
|
}
|
|
2000
|
-
/**
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
1977
|
+
/** One `files:` assertion, keyed by a workdir-relative path. */
|
|
1978
|
+
type SpecFileAssertion = {
|
|
1979
|
+
contains: SpecStream[];
|
|
1980
|
+
equals: null | SpecStream;
|
|
1981
|
+
kind: 'content';
|
|
1982
|
+
line: number;
|
|
1983
|
+
path: string;
|
|
1984
|
+
} | {
|
|
1985
|
+
kind: 'absent';
|
|
1986
|
+
line: number;
|
|
1987
|
+
path: string;
|
|
1988
|
+
} | {
|
|
1989
|
+
kind: 'exists';
|
|
1990
|
+
line: number;
|
|
1991
|
+
path: string;
|
|
1992
|
+
};
|
|
1993
|
+
/** One run: a command, what it must exit with, and what it must have produced. */
|
|
1994
|
+
interface SpecRun {
|
|
1995
|
+
command: string;
|
|
1996
|
+
/** 1-based line of the `command:` key — the frame a failure points at. */
|
|
1997
|
+
commandLine: number;
|
|
1998
|
+
exitCode: number;
|
|
1999
|
+
files: SpecFileAssertion[];
|
|
2000
|
+
/** `null` when the key is absent, which asserts an empty stream. */
|
|
2001
|
+
stderr: null | SpecStream;
|
|
2002
|
+
/** Written to the child then closed; `null` keeps the empty-pipe EOF. */
|
|
2003
|
+
stdin: null | string;
|
|
2004
|
+
stdout: null | SpecStream;
|
|
2005
|
+
timeout: null | number;
|
|
2006
|
+
/** Only ever on the LAST run — a long-running command ends the session. */
|
|
2007
|
+
waitFor: null | string;
|
|
2008
|
+
}
|
|
2009
|
+
/** A parsed `<case>.spec.yaml`. */
|
|
2010
|
+
interface SpecDocument {
|
|
2011
|
+
/** The vitest test title. */
|
|
2012
|
+
description: string;
|
|
2013
|
+
/** 1-based line of the `description:` key. */
|
|
2014
|
+
descriptionLine: number;
|
|
2015
|
+
env: SpecEnvToken[];
|
|
2016
|
+
fixtures: SpecFixture[];
|
|
2017
|
+
kind: SpecKind;
|
|
2018
|
+
runs: SpecRun[];
|
|
2019
|
+
serve: SpecServeEntry[];
|
|
2006
2020
|
}
|
|
2007
2021
|
//#endregion
|
|
2008
2022
|
//#region src/integrations/docker/docker-lookup.d.ts
|
|
@@ -2463,4 +2477,4 @@ declare module 'vitest' {
|
|
|
2463
2477
|
}
|
|
2464
2478
|
}
|
|
2465
2479
|
//#endregion
|
|
2466
|
-
export { type ApiHandle, type ApiSpecification, type ApiSpecificationOptions, BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, type CaptureScope, type CliEnv, type CliHandle, type CliOutput, type CliPort, CliResult, type CliSpecification, type CliSpecificationOptions, ContainerAccessor, type ContainerPort, type Contract, type ContractInput, type ContractRequest, type ContractResponder, type ContractResponse, type ContractResponseValue, type Contracts, type DatabaseKeys, type DatabasePort, type DeviceOpenOptions, type DevicePort, type DeviceScreen, DirectoryAccessor, type DockerSpecConfig, type ElementKind, type ElementMatch, type ElementOptions, type ElementRef, type ExecOptions, FetchResult, type FileAccessor, FilesystemAccessor, type HonoApp, type HttpContractFilter, type HttpResponseInit, HttpResult, type IsolationStrategy, type JobHandle, type JobsHandle, type JobsSpecification, type JobsSpecificationOptions, JsonAccessor, type LandmarkKind, type
|
|
2480
|
+
export { type ApiHandle, type ApiSpecification, type ApiSpecificationOptions, BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, type CaptureScope, type CliEnv, type CliHandle, type CliInput, type CliOutput, type CliPort, CliResult, type CliSpecification, type CliSpecificationOptions, ContainerAccessor, type ContainerPort, type Contract, type ContractInput, type ContractRequest, type ContractResponder, type ContractResponse, type ContractResponseValue, type Contracts, type DatabaseKeys, type DatabasePort, type DeviceOpenOptions, type DevicePort, type DeviceScreen, DirectoryAccessor, type DockerSpecConfig, type ElementKind, type ElementMatch, type ElementOptions, type ElementRef, type ExecOptions, FetchResult, type FileAccessor, FilesystemAccessor, type HonoApp, type HttpContractFilter, type HttpResponseInit, HttpResult, type IsolationStrategy, type JobHandle, type JobsHandle, type JobsSpecification, type JobsSpecificationOptions, JsonAccessor, type LandmarkKind, type LiterateRunFlags, type LiterateServeRegistration, type MatchFixtureOptions, type MatchableRequest, Matcher, type MatcherKind, type MobileBackendOptions, type MobileElementKind, type MobileElementMatch, type MobileElementRef, type MobileHandle, type MobileScenario, type MobileSpecification, type MobileSpecificationOptions, type MobileVisitor, type MockDatePort, type MockPort, Orchestrator, PageResult, type PostgresOptions, type RedisOptions, ResponseAccessor, type ScreenNode, ScreenResult, type ServeOptions, type ServerPort, type ServerResponse, type ServiceHandle, type ServiceRecord, type SpecDocument, type SpecEnvToken, type SpecFileAssertion, type SpecFixture, type SpecKind, type SpecRun, type SpecServeEntry, type SpecStream, type SpecificationConfig, type SpecificationMode, type SqliteOptions, TableAccessor, TextAccessor, type TextFilter, type VisitScenario, type Visitor, type WebsiteBackendOptions, type WebsiteHandle, type WebsiteSpecification, type WebsiteSpecificationOptions, anthropic, banner, button, complementary, content, contentinfo, defineContract, defineContracts, field, findContainersByLabel, form, heading, http, inspectContainer, link, main, match, mockOf, mockOfDate, navigation, openai, postgres, redis, region, removeContainers, search, specification, sqlite, testId, text, within };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as match, n as Matcher, t as CaptureScope } from "./match.js";
|
|
2
|
-
import {
|
|
1
|
+
import { a as copyPlan, i as match, n as Matcher, t as CaptureScope } from "./match.js";
|
|
2
|
+
import { C as formatResponseDiff, E as formatTableDiff, M as structuralEquals, N as structuralSubset, O as mergePreservingPlaceholders, P as textEquals, S as formatDirectoryDiff, T as formatStdoutDiff, _ as getCallerDir, a as shouldUpdateSnapshots, b as diffDirectories, c as BaseResult, d as inspectContainer, f as removeContainers, g as text, h as TextAccessor, i as UPDATE_HINT, j as renderExpected, k as mergeTextPreservingPlaceholders, l as validateDatabaseOption, m as JsonAccessor, o as ContainerAccessor, p as TableAccessor, r as ServeAdapter, s as CliResult, t as runSpecDocument, u as findContainersByLabel, v as FilesystemAccessor, w as formatStartupReport, x as walkDirectory, y as DirectoryAccessor } from "./literate.js";
|
|
3
3
|
import { a as isContract, i as defineContracts, n as contractsOf, o as isContracts, r as defineContract, t as ContractQueue } from "./queue.js";
|
|
4
4
|
import { closeSync, copyFileSync, cpSync, existsSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, readdirSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -1222,18 +1222,18 @@ var SpecificationBuilder = class {
|
|
|
1222
1222
|
});
|
|
1223
1223
|
}
|
|
1224
1224
|
/**
|
|
1225
|
-
* Run a
|
|
1226
|
-
* result. The whole file
|
|
1227
|
-
* servers, and every
|
|
1225
|
+
* Run a `<case>.spec.yaml` document and resolve with the LAST run's
|
|
1226
|
+
* result. The whole file executes in ONE working directory with ONE set of
|
|
1227
|
+
* servers, and every run is asserted — unlike `.exec([...])`, a non-zero
|
|
1228
1228
|
* exit does not stop the sequence, because here each exit code is part of
|
|
1229
|
-
* what the
|
|
1229
|
+
* what the document states.
|
|
1230
1230
|
*
|
|
1231
|
-
* Setup chained BEFORE the call layers underneath the
|
|
1232
|
-
* chained `.fixture()` is copied first, the
|
|
1233
|
-
* it, and
|
|
1231
|
+
* Setup chained BEFORE the call layers underneath the document's own
|
|
1232
|
+
* ground: a chained `.fixture()` is copied first, the document's `fixture:`
|
|
1233
|
+
* entries over it, and its `env:` wins over a chained `.env()`.
|
|
1234
1234
|
*
|
|
1235
1235
|
* @example
|
|
1236
|
-
* const result = await cli.run('no-estate.
|
|
1236
|
+
* const result = await cli.run('no-estate.spec.yaml');
|
|
1237
1237
|
* await expect(result.directory('out')).toMatch('scaffold');
|
|
1238
1238
|
*/
|
|
1239
1239
|
run(file, options) {
|
|
@@ -1492,7 +1492,7 @@ var SpecificationBuilder = class {
|
|
|
1492
1492
|
}
|
|
1493
1493
|
runLiterateAction(workDir, file, options) {
|
|
1494
1494
|
const filePath = resolve(this.testDir, file);
|
|
1495
|
-
return
|
|
1495
|
+
return runSpecDocument({
|
|
1496
1496
|
baseEnv: this.childEnv(workDir),
|
|
1497
1497
|
frozen: options?.frozen,
|
|
1498
1498
|
config: this.config,
|
|
@@ -2206,21 +2206,23 @@ var ExecAdapter = class {
|
|
|
2206
2206
|
constructor(command) {
|
|
2207
2207
|
this.command = command;
|
|
2208
2208
|
}
|
|
2209
|
-
async exec(args, cwd, extraEnv) {
|
|
2209
|
+
async exec(args, cwd, extraEnv, input) {
|
|
2210
2210
|
const env = buildEnv(extraEnv);
|
|
2211
2211
|
const result = spawnSync(`${this.command} ${args}`, [], {
|
|
2212
2212
|
cwd,
|
|
2213
2213
|
encoding: "utf8",
|
|
2214
2214
|
env,
|
|
2215
|
+
input: input?.stdin,
|
|
2215
2216
|
shell: true,
|
|
2216
2217
|
stdio: [
|
|
2217
2218
|
"pipe",
|
|
2218
2219
|
"pipe",
|
|
2219
2220
|
"pipe"
|
|
2220
|
-
]
|
|
2221
|
+
],
|
|
2222
|
+
timeout: input?.timeout
|
|
2221
2223
|
});
|
|
2222
2224
|
return {
|
|
2223
|
-
exitCode: result.status ?? 1,
|
|
2225
|
+
exitCode: result.error?.code === "ETIMEDOUT" ? 124 : result.status ?? 1,
|
|
2224
2226
|
stderr: result.stderr ?? "",
|
|
2225
2227
|
stdout: result.stdout ?? ""
|
|
2226
2228
|
};
|