first-base 0.2.0 → 1.4.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 +13 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -33
- package/dist/index.js.flow +2 -0
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -111,6 +111,19 @@ run.write("2 + 2\n"); // Write 2 + 2 then press enter
|
|
|
111
111
|
await run.outputContains("4");
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
+
### `RunContext#close(stream: 'stdin' | 'stdout' | 'stderr')`
|
|
115
|
+
|
|
116
|
+
Close one of the processes's associated stdio streams.
|
|
117
|
+
|
|
118
|
+
#### Usage
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
const run = spawn("node", ["-i"]); // start Node.js REPL
|
|
122
|
+
await run.outputContains("> "); // Wait until prompt appears
|
|
123
|
+
run.close("stdin"); // Like pressing Ctrl+D; sends EOF
|
|
124
|
+
await run.completion;
|
|
125
|
+
```
|
|
126
|
+
|
|
114
127
|
### `RunContext#kill(signal?: string)`
|
|
115
128
|
|
|
116
129
|
Kills the process. If no signal is specified, it defaults to `"SIGINT"`.
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type Options = {
|
|
|
8
8
|
shell?: boolean | string;
|
|
9
9
|
windowsVerbatimArguments?: boolean;
|
|
10
10
|
windowsHide?: boolean;
|
|
11
|
+
pty?: boolean;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
export type RunContext = {
|
|
@@ -23,6 +24,7 @@ export type RunContext = {
|
|
|
23
24
|
clearOutputContainsBuffer(): void;
|
|
24
25
|
// TODO: Should be string | Buffer, but idk how to use Buffer since they might not be using node types
|
|
25
26
|
write(data: any): void;
|
|
27
|
+
close(stream: "stdin" | "stdout" | "stderr"): void;
|
|
26
28
|
kill(signal?: string): void;
|
|
27
29
|
};
|
|
28
30
|
|
package/dist/index.js
CHANGED
|
@@ -1,37 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
function _typeof(
|
|
4
|
-
|
|
3
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
5
4
|
var normalSpawn = require("child_process").spawn;
|
|
5
|
+
var ptySpawn = require("node-pty").spawn;
|
|
6
|
+
var stripAnsi = require("strip-ansi");
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
// Run a child process and return a "run context" object
|
|
8
9
|
// to interact with it. Function signature is the same as
|
|
9
10
|
// child_process spawn, except you can pass `pty: true` in
|
|
10
11
|
// options to run the process in a psuedo-tty.
|
|
11
|
-
|
|
12
|
-
|
|
13
12
|
var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
14
13
|
var args;
|
|
15
14
|
var options;
|
|
16
|
-
|
|
17
15
|
if (Array.isArray(argsOrOptions)) {
|
|
18
16
|
args = argsOrOptions;
|
|
19
17
|
} else if (_typeof(argsOrOptions) === "object") {
|
|
20
18
|
options = argsOrOptions;
|
|
21
19
|
}
|
|
22
|
-
|
|
23
20
|
if (passedOptions && !options) {
|
|
24
21
|
options = passedOptions;
|
|
25
22
|
}
|
|
26
|
-
|
|
27
23
|
if (!args) {
|
|
28
24
|
args = [];
|
|
29
25
|
}
|
|
30
|
-
|
|
31
26
|
if (!options) {
|
|
32
27
|
options = {};
|
|
33
28
|
}
|
|
34
|
-
|
|
35
29
|
var child;
|
|
36
30
|
var stdin;
|
|
37
31
|
var stdout;
|
|
@@ -41,15 +35,12 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
41
35
|
var _debug = false;
|
|
42
36
|
var outputContainsBuffer = "";
|
|
43
37
|
var pendingOutputContainsRequests = new Set();
|
|
44
|
-
|
|
45
38
|
var debugLog = function debugLog() {
|
|
46
39
|
if (_debug) {
|
|
47
40
|
var _console;
|
|
48
|
-
|
|
49
41
|
(_console = console).log.apply(_console, arguments);
|
|
50
42
|
}
|
|
51
43
|
};
|
|
52
|
-
|
|
53
44
|
var runContext = {
|
|
54
45
|
result: {
|
|
55
46
|
// All of the stdout and stderr the process has written so far.
|
|
@@ -75,17 +66,14 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
75
66
|
var request = {
|
|
76
67
|
value: value
|
|
77
68
|
};
|
|
78
|
-
|
|
79
69
|
request.resolve = function () {
|
|
80
|
-
pendingOutputContainsRequests
|
|
70
|
+
pendingOutputContainsRequests["delete"](request);
|
|
81
71
|
resolve();
|
|
82
72
|
};
|
|
83
|
-
|
|
84
73
|
request.reject = function () {
|
|
85
|
-
pendingOutputContainsRequests
|
|
74
|
+
pendingOutputContainsRequests["delete"](request);
|
|
86
75
|
reject();
|
|
87
76
|
};
|
|
88
|
-
|
|
89
77
|
pendingOutputContainsRequests.add(request);
|
|
90
78
|
});
|
|
91
79
|
},
|
|
@@ -96,23 +84,48 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
96
84
|
write: function write(data) {
|
|
97
85
|
stdin.write(data);
|
|
98
86
|
},
|
|
87
|
+
// Call this function to close stdin, stdout, or stderr.
|
|
88
|
+
close: function close(stream) {
|
|
89
|
+
switch (String(stream).toLowerCase()) {
|
|
90
|
+
case "stdin":
|
|
91
|
+
{
|
|
92
|
+
stdin.end();
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "stdout":
|
|
96
|
+
{
|
|
97
|
+
stdout.end();
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case "stderr":
|
|
101
|
+
{
|
|
102
|
+
stderr.end();
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
default:
|
|
106
|
+
{
|
|
107
|
+
throw new Error("Invalid stream name: '".concat(stream, "'. Valid names are 'stdin', 'stdout', or 'stderr'."));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
99
111
|
// Call this function to send a signal to the child process.
|
|
100
112
|
// You can pass "SIGTERM", "SIGKILL", etc. Defaults to "SIGINT".
|
|
101
113
|
kill: function kill() {
|
|
102
114
|
var signal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "SIGINT";
|
|
103
|
-
|
|
104
115
|
if (running) {
|
|
105
116
|
child.kill(signal);
|
|
106
117
|
}
|
|
107
|
-
|
|
108
118
|
if (unreffable) {
|
|
109
119
|
unreffable.unref();
|
|
110
120
|
}
|
|
111
121
|
}
|
|
112
122
|
};
|
|
113
|
-
|
|
114
123
|
if (options.pty) {
|
|
115
|
-
|
|
124
|
+
child = ptySpawn(cmd, args, options);
|
|
125
|
+
stdin = child;
|
|
126
|
+
stdout = child;
|
|
127
|
+
stderr = null; // no way to tell between stdout and stderr with pty
|
|
128
|
+
unreffable = child.socket;
|
|
116
129
|
} else {
|
|
117
130
|
child = normalSpawn(cmd, args, options);
|
|
118
131
|
stdin = child.stdin;
|
|
@@ -120,9 +133,7 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
120
133
|
stderr = child.stderr;
|
|
121
134
|
unreffable = child;
|
|
122
135
|
}
|
|
123
|
-
|
|
124
136
|
running = true;
|
|
125
|
-
|
|
126
137
|
var checkForPendingOutputRequestsToResolve = function checkForPendingOutputRequestsToResolve() {
|
|
127
138
|
pendingOutputContainsRequests.forEach(function (request) {
|
|
128
139
|
if (typeof request.value === "string") {
|
|
@@ -136,16 +147,13 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
136
147
|
}
|
|
137
148
|
});
|
|
138
149
|
};
|
|
139
|
-
|
|
140
150
|
stdout.setEncoding("utf-8");
|
|
141
|
-
|
|
142
151
|
var handleStdoutData = function handleStdoutData(data) {
|
|
143
152
|
runContext.result.stdout += data;
|
|
144
153
|
outputContainsBuffer += data;
|
|
145
154
|
debugLog("STDOUT: ".concat(data.toString()));
|
|
146
155
|
checkForPendingOutputRequestsToResolve();
|
|
147
156
|
};
|
|
148
|
-
|
|
149
157
|
if (stdout.onData) {
|
|
150
158
|
// the pty instance returned by node-pty
|
|
151
159
|
// requires attaching handlers differently
|
|
@@ -153,11 +161,11 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
153
161
|
} else {
|
|
154
162
|
stdout.on("data", handleStdoutData);
|
|
155
163
|
}
|
|
156
|
-
|
|
157
164
|
if (stderr) {
|
|
158
|
-
stderr.setEncoding("utf-8");
|
|
159
|
-
// so we don't need to deal with onData here:
|
|
165
|
+
stderr.setEncoding("utf-8");
|
|
160
166
|
|
|
167
|
+
// this is never a pty instance,
|
|
168
|
+
// so we don't need to deal with onData here:
|
|
161
169
|
stderr.on("data", function (data) {
|
|
162
170
|
runContext.result.stderr += data;
|
|
163
171
|
outputContainsBuffer += data;
|
|
@@ -165,7 +173,6 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
165
173
|
checkForPendingOutputRequestsToResolve();
|
|
166
174
|
});
|
|
167
175
|
}
|
|
168
|
-
|
|
169
176
|
runContext.completion = new Promise(function (resolve) {
|
|
170
177
|
var finish = function finish(reason) {
|
|
171
178
|
debugLog("Process ".concat(reason));
|
|
@@ -176,7 +183,6 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
176
183
|
request.reject(new Error("Child process ".concat(reason, " before its output contained the requested content: ").concat(request.value)));
|
|
177
184
|
});
|
|
178
185
|
};
|
|
179
|
-
|
|
180
186
|
child.once("exit", function (code) {
|
|
181
187
|
runContext.result.code = code;
|
|
182
188
|
finish("exited");
|
|
@@ -188,7 +194,6 @@ var spawn = function spawn(cmd, argsOrOptions, passedOptions) {
|
|
|
188
194
|
});
|
|
189
195
|
return runContext;
|
|
190
196
|
};
|
|
191
|
-
|
|
192
197
|
module.exports = {
|
|
193
198
|
spawn: spawn
|
|
194
199
|
};
|
package/dist/index.js.flow
CHANGED
|
@@ -9,6 +9,7 @@ export type Options = {
|
|
|
9
9
|
shell?: ?boolean | string,
|
|
10
10
|
windowsVerbatimArguments?: ?boolean,
|
|
11
11
|
windowsHide?: ?boolean,
|
|
12
|
+
pty?: ?boolean,
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export type RunContext = {
|
|
@@ -23,6 +24,7 @@ export type RunContext = {
|
|
|
23
24
|
outputContains(value: string | RegExp): Promise<void>,
|
|
24
25
|
clearOutputContainsBuffer(): void,
|
|
25
26
|
write(data: string | Buffer): void,
|
|
27
|
+
close(stream: "stdin" | "stdout" | "stderr"): void,
|
|
26
28
|
kill(signal?: string): void,
|
|
27
29
|
};
|
|
28
30
|
|
package/package.json
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "first-base",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Integration testing for CLI applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": "https://github.com/suchipi/first-base",
|
|
7
|
-
"author": "Lily
|
|
7
|
+
"author": "Lily Skye <me@suchipi.com>",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"dependencies": {
|
|
10
|
+
"node-pty": "^1.0.0",
|
|
10
11
|
"strip-ansi": "^5.0.0"
|
|
11
12
|
},
|
|
12
13
|
"devDependencies": {
|
|
13
|
-
"@babel/cli": "^7.
|
|
14
|
-
"@babel/core": "^7.
|
|
15
|
-
"@babel/preset-env": "^7.
|
|
14
|
+
"@babel/cli": "^7.23.4",
|
|
15
|
+
"@babel/core": "^7.23.7",
|
|
16
|
+
"@babel/preset-env": "^7.23.8",
|
|
16
17
|
"babel-core": "^7.0.0-bridge.0",
|
|
17
|
-
"babel-jest": "^
|
|
18
|
-
"eslint": "^
|
|
19
|
-
"eslint-config-unobtrusive": "^1.2.
|
|
20
|
-
"eslint-plugin-import": "^2.
|
|
21
|
-
"jest": "^
|
|
22
|
-
"prettier": "^
|
|
18
|
+
"babel-jest": "^29.7.0",
|
|
19
|
+
"eslint": "^8.56.0",
|
|
20
|
+
"eslint-config-unobtrusive": "^1.2.5",
|
|
21
|
+
"eslint-plugin-import": "^2.29.1",
|
|
22
|
+
"jest": "^29.7.0",
|
|
23
|
+
"prettier": "^3.2.4"
|
|
23
24
|
},
|
|
24
25
|
"scripts": {
|
|
25
26
|
"build": "mkdir -p dist; rm -rf dist/*; babel src/index.js --out-dir dist && cp src/index.js.flow dist/ && cp src/index.d.ts dist/",
|