@neurodevs/ndx-cli 1.1.1 → 1.1.3
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/build/__tests__/impl/commands/TestCommand.test.d.ts +2 -1
- package/build/__tests__/impl/commands/TestCommand.test.js +24 -4
- package/build/__tests__/impl/commands/TestCommand.test.js.map +1 -1
- package/build/impl/CliCommandRunner.d.ts +2 -1
- package/build/impl/CliCommandRunner.js +2 -1
- package/build/impl/CliCommandRunner.js.map +1 -1
- package/build/impl/commands/TestCommand.js +20 -1
- package/build/impl/commands/TestCommand.js.map +1 -1
- package/build/testDoubles/child_process/fakeSpawn.d.ts +11 -0
- package/build/testDoubles/child_process/fakeSpawn.js +16 -0
- package/build/testDoubles/child_process/fakeSpawn.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/impl/commands/TestCommand.test.ts +34 -6
- package/src/impl/CliCommandRunner.ts +2 -1
- package/src/impl/commands/TestCommand.ts +30 -3
- package/src/testDoubles/child_process/fakeSpawn.ts +34 -0
|
@@ -3,6 +3,7 @@ export default class TestCommandTest extends AbstractCommandRunnerTest {
|
|
|
3
3
|
private static instance;
|
|
4
4
|
protected static beforeEach(): Promise<void>;
|
|
5
5
|
protected static createsInstance(): Promise<void>;
|
|
6
|
-
protected static
|
|
6
|
+
protected static spawnsNodeWithTestRunnerScript(): Promise<void>;
|
|
7
|
+
protected static throwsIfSpawnExitsWithNonZeroCode(): Promise<void>;
|
|
7
8
|
private static run;
|
|
8
9
|
}
|
|
@@ -6,18 +6,35 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { assert, test } from '@neurodevs/node-tdd';
|
|
8
8
|
import AbstractCommandRunnerTest from '../../AbstractCommandRunnerTest.js';
|
|
9
|
-
import {
|
|
9
|
+
import fakeSpawn, { callsToSpawn, resetCallsToSpawn, setFakeSpawnExitCode, } from '../../../testDoubles/child_process/fakeSpawn.js';
|
|
10
|
+
import CliCommandRunner from '../../../impl/CliCommandRunner.js';
|
|
10
11
|
export default class TestCommandTest extends AbstractCommandRunnerTest {
|
|
11
12
|
static instance;
|
|
12
13
|
static async beforeEach() {
|
|
13
14
|
await super.beforeEach();
|
|
15
|
+
CliCommandRunner.spawn = fakeSpawn;
|
|
16
|
+
resetCallsToSpawn();
|
|
14
17
|
this.instance = await this.run();
|
|
15
18
|
}
|
|
16
19
|
static async createsInstance() {
|
|
17
20
|
assert.isTruthy(this.instance, `Failed to create instance for ${this.testCommand}!`);
|
|
18
21
|
}
|
|
19
|
-
static async
|
|
20
|
-
assert.
|
|
22
|
+
static async spawnsNodeWithTestRunnerScript() {
|
|
23
|
+
assert.isEqualDeep(callsToSpawn[0], {
|
|
24
|
+
command: 'node',
|
|
25
|
+
args: [
|
|
26
|
+
'node_modules/@neurodevs/node-tdd/build/workspace/testRunner.cli.js',
|
|
27
|
+
'--watchMode',
|
|
28
|
+
'standard',
|
|
29
|
+
],
|
|
30
|
+
options: {
|
|
31
|
+
stdio: 'inherit',
|
|
32
|
+
},
|
|
33
|
+
}, 'Did not spawn node as command!');
|
|
34
|
+
}
|
|
35
|
+
static async throwsIfSpawnExitsWithNonZeroCode() {
|
|
36
|
+
setFakeSpawnExitCode(1);
|
|
37
|
+
await assert.doesThrowAsync(() => this.run(), /Test runner exited with code 1/);
|
|
21
38
|
}
|
|
22
39
|
static async run() {
|
|
23
40
|
const instance = this.CliCommandRunner([this.testCommand]);
|
|
@@ -30,5 +47,8 @@ __decorate([
|
|
|
30
47
|
], TestCommandTest, "createsInstance", null);
|
|
31
48
|
__decorate([
|
|
32
49
|
test()
|
|
33
|
-
], TestCommandTest, "
|
|
50
|
+
], TestCommandTest, "spawnsNodeWithTestRunnerScript", null);
|
|
51
|
+
__decorate([
|
|
52
|
+
test()
|
|
53
|
+
], TestCommandTest, "throwsIfSpawnExitsWithNonZeroCode", null);
|
|
34
54
|
//# sourceMappingURL=TestCommand.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestCommand.test.js","sourceRoot":"","sources":["../../../../src/__tests__/impl/commands/TestCommand.test.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,yBAAyB,MAAM,oCAAoC,CAAA;AAC1E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"TestCommand.test.js","sourceRoot":"","sources":["../../../../src/__tests__/impl/commands/TestCommand.test.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,yBAAyB,MAAM,oCAAoC,CAAA;AAC1E,OAAO,SAAS,EAAE,EACd,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,GACvB,MAAM,iDAAiD,CAAA;AACxD,OAAO,gBAAgB,MAAM,mCAAmC,CAAA;AAEhE,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,yBAAyB;IAC1D,MAAM,CAAC,QAAQ,CAAe;IAE5B,MAAM,CAAC,KAAK,CAAC,UAAU;QAC7B,MAAM,KAAK,CAAC,UAAU,EAAE,CAAA;QAExB,gBAAgB,CAAC,KAAK,GAAG,SAAgB,CAAA;QACzC,iBAAiB,EAAE,CAAA;QAEnB,IAAI,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAA;IACpC,CAAC;IAGsB,AAAb,MAAM,CAAC,KAAK,CAAC,eAAe;QAClC,MAAM,CAAC,QAAQ,CACX,IAAI,CAAC,QAAQ,EACb,iCAAiC,IAAI,CAAC,WAAW,GAAG,CACvD,CAAA;IACL,CAAC;IAGsB,AAAb,MAAM,CAAC,KAAK,CAAC,8BAA8B;QACjD,MAAM,CAAC,WAAW,CACd,YAAY,CAAC,CAAC,CAAC,EACf;YACI,OAAO,EAAE,MAAM;YACf,IAAI,EAAE;gBACF,oEAAoE;gBACpE,aAAa;gBACb,UAAU;aACb;YACD,OAAO,EAAE;gBACL,KAAK,EAAE,SAAS;aACnB;SACJ,EACD,gCAAgC,CACnC,CAAA;IACL,CAAC;IAGsB,AAAb,MAAM,CAAC,KAAK,CAAC,iCAAiC;QACpD,oBAAoB,CAAC,CAAC,CAAC,CAAA;QAEvB,MAAM,MAAM,CAAC,cAAc,CACvB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAChB,gCAAgC,CACnC,CAAA;IACL,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,GAAG;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA;QAC1D,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAA;QAEpB,OAAO,QAAQ,CAAA;IACnB,CAAC;CACJ;AA1C0B;IADtB,IAAI,EAAE;4CAMN;AAGsB;IADtB,IAAI,EAAE;2DAiBN;AAGsB;IADtB,IAAI,EAAE;8DAQN"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { exec as execSync } from 'node:child_process';
|
|
1
|
+
import { exec as execSync, spawn } from 'node:child_process';
|
|
2
2
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
import prompts from 'prompts';
|
|
4
4
|
export default class CliCommandRunner implements CommandRunner {
|
|
5
5
|
static Class?: CommandRunnerConstructor;
|
|
6
6
|
static error: (...data: any[]) => void;
|
|
7
7
|
static exec: typeof execSync.__promisify__;
|
|
8
|
+
static spawn: typeof spawn;
|
|
8
9
|
static log: (...data: any[]) => void;
|
|
9
10
|
static mkdir: typeof mkdir;
|
|
10
11
|
static prompts: typeof prompts;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { exec as execSync } from 'node:child_process';
|
|
1
|
+
import { exec as execSync, spawn } from 'node:child_process';
|
|
2
2
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import prompts from 'prompts';
|
|
@@ -16,6 +16,7 @@ export default class CliCommandRunner {
|
|
|
16
16
|
static Class;
|
|
17
17
|
static error = console.error;
|
|
18
18
|
static exec = promisify(execSync);
|
|
19
|
+
static spawn = spawn;
|
|
19
20
|
static log = console.log;
|
|
20
21
|
static mkdir = mkdir;
|
|
21
22
|
static prompts = prompts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CliCommandRunner.js","sourceRoot":"","sources":["../../src/impl/CliCommandRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"CliCommandRunner.js","sourceRoot":"","sources":["../../src/impl/CliCommandRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,OAAO,OAAO,MAAM,SAAS,CAAA;AAE7B,OAAO,kBAAkB,MAAM,kCAAkC,CAAA;AACjE,OAAO,uBAAuB,MAAM,uCAAuC,CAAA;AAC3E,OAAO,iBAAiB,MAAM,iCAAiC,CAAA;AAC/D,OAAO,iBAAiB,MAAM,iCAAiC,CAAA;AAC/D,OAAO,oBAAoB,MAAM,oCAAoC,CAAA;AACrE,OAAO,eAAe,MAAM,+BAA+B,CAAA;AAC3D,OAAO,sBAAsB,MAAM,sCAAsC,CAAA;AACzE,OAAO,sBAAsB,MAAM,sCAAsC,CAAA;AACzE,OAAO,qBAAqB,MAAM,qCAAqC,CAAA;AACvE,OAAO,WAAW,MAAM,2BAA2B,CAAA;AAEnD,MAAM,CAAC,OAAO,OAAO,gBAAgB;IAC1B,MAAM,CAAC,KAAK,CAA2B;IACvC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;IAC5B,MAAM,CAAC,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;IACjC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,MAAM,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IACxB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,MAAM,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,MAAM,CAAC,SAAS,GAAG,SAAS,CAAA;IAE3B,IAAI,CAAU;IAEL,kBAAkB,GAAG,cAAc,CAAA;IACnC,wBAAwB,GAAG,mBAAmB,CAAA;IAC9C,iBAAiB,GAAG,aAAa,CAAA;IACjC,iBAAiB,GAAG,aAAa,CAAA;IACjC,oBAAoB,GAAG,gBAAgB,CAAA;IACvC,eAAe,GAAG,WAAW,CAAA;IAC7B,WAAW,GAAG,MAAM,CAAA;IACpB,aAAa,GAAG,IAAI,CAAA;IACpB,YAAY,GAAG,QAAQ,CAAA;IACvB,sBAAsB,GAAG,kBAAkB,CAAA;IAC3C,sBAAsB,GAAG,kBAAkB,CAAA;IAC3C,WAAW,GAAG,MAAM,CAAA;IACpB,qBAAqB,GAAG,iBAAiB,CAAA;IAEzC,iBAAiB,GAAG;QACjC,IAAI,CAAC,kBAAkB;QACvB,IAAI,CAAC,wBAAwB;QAC7B,IAAI,CAAC,iBAAiB;QACtB,IAAI,CAAC,iBAAiB;QACtB,IAAI,CAAC,oBAAoB;QACzB,IAAI,CAAC,eAAe;QACpB,IAAI,CAAC,WAAW;QAChB,IAAI,CAAC,aAAa;QAClB,IAAI,CAAC,YAAY;QACjB,IAAI,CAAC,sBAAsB;QAC3B,IAAI,CAAC,sBAAsB;QAC3B,IAAI,CAAC,WAAW;QAChB,IAAI,CAAC,qBAAqB;KAC7B,CAAA;IAED,YAAsB,IAAc;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IACpB,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,IAAc;QAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC;IAEM,KAAK,CAAC,GAAG;QACZ,IAAI,CAAC,4BAA4B,EAAE,CAAA;QACnC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAA;IAC3B,CAAC;IAEO,4BAA4B;QAChC,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,OAAO,qBAAqB,CAAC,CAAA;QACtE,CAAC;IACL,CAAC;IAED,IAAY,kBAAkB;QAC1B,OAAO,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACxD,CAAC;IAED,IAAY,OAAO;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,UAAU;QACpB,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,KAAK,IAAI,CAAC,kBAAkB;gBACxB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;gBACxB,MAAK;YACT,KAAK,IAAI,CAAC,wBAAwB;gBAC9B,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAA;gBAC7B,MAAK;YACT,KAAK,IAAI,CAAC,iBAAiB;gBACvB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAA;gBACvB,MAAK;YACT,KAAK,IAAI,CAAC,iBAAiB;gBACvB,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAA;gBAC7B,MAAK;YACT,KAAK,IAAI,CAAC,oBAAoB;gBAC1B,MAAM,IAAI,CAAC,aAAa,EAAE,CAAA;gBAC1B,MAAK;YACT,KAAK,IAAI,CAAC,eAAe;gBACrB,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;gBAC3B,MAAK;YACT,KAAK,IAAI,CAAC,sBAAsB;gBAC5B,MAAM,IAAI,CAAC,eAAe,EAAE,CAAA;gBAC5B,MAAK;YACT,KAAK,IAAI,CAAC,sBAAsB;gBAC5B,MAAM,IAAI,CAAC,eAAe,EAAE,CAAA;gBAC5B,MAAK;YACT,KAAK,IAAI,CAAC,WAAW;gBACjB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;gBACjB,MAAK;YACT,KAAK,IAAI,CAAC,qBAAqB;gBAC3B,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;gBAC3B,MAAK;YACT,KAAK,IAAI,CAAC,WAAW;gBACjB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;gBACjB,MAAK;YACT,KAAK,IAAI,CAAC,YAAY;gBAClB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;gBACjB,MAAK;YACT,KAAK,IAAI,CAAC,aAAa;gBACnB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;gBACjB,MAAK;QACb,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,WAAW;QACrB,MAAM,OAAO,GAAG,IAAI,kBAAkB,EAAE,CAAA;QACxC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC1B,MAAM,OAAO,GAAG,IAAI,uBAAuB,EAAE,CAAA;QAC7C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,UAAU;QACpB,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAA;QACvC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC1B,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAA;QACvC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,aAAa;QACvB,MAAM,OAAO,GAAG,IAAI,oBAAoB,EAAE,CAAA;QAC1C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,cAAc;QACxB,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;QACrC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,eAAe;QACzB,MAAM,OAAO,GAAG,IAAI,sBAAsB,EAAE,CAAA;QAC5C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,eAAe;QACzB,MAAM,OAAO,GAAG,IAAI,sBAAsB,EAAE,CAAA;QAC5C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,IAAI;QACd,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;QACjC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,cAAc;QACxB,MAAM,OAAO,GAAG,IAAI,qBAAqB,EAAE,CAAA;QAC3C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,CAAC;IAEO,KAAK,CAAC,IAAI;QACd,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC3B,CAAC;IAED,IAAY,GAAG;QACX,OAAO,gBAAgB,CAAC,GAAG,CAAA;IAC/B,CAAC;IAEgB,QAAQ,GAAG;;;;;;;;;;;;;;;;;KAiB3B,CAAA"}
|
|
@@ -1,7 +1,26 @@
|
|
|
1
|
+
import { access } from 'node:fs/promises';
|
|
1
2
|
import CliCommandRunner from '../CliCommandRunner.js';
|
|
2
3
|
export default class TestCommand {
|
|
3
4
|
async run() {
|
|
4
|
-
|
|
5
|
+
const localRunner = 'node_modules/@neurodevs/node-tdd/build/workspace/testRunner.cli.js';
|
|
6
|
+
const runnerPath = (await fileExists(localRunner))
|
|
7
|
+
? localRunner
|
|
8
|
+
: 'build/workspace/testRunner.cli.js';
|
|
9
|
+
await new Promise((resolve, reject) => {
|
|
10
|
+
const child = CliCommandRunner.spawn('node', [runnerPath, '--watchMode', 'standard'], { stdio: 'inherit' });
|
|
11
|
+
child.on('close', (code) => code === 0
|
|
12
|
+
? resolve()
|
|
13
|
+
: reject(new Error(`Test runner exited with code ${code}`)));
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function fileExists(path) {
|
|
18
|
+
try {
|
|
19
|
+
await access(path);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
5
24
|
}
|
|
6
25
|
}
|
|
7
26
|
//# sourceMappingURL=TestCommand.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestCommand.js","sourceRoot":"","sources":["../../../src/impl/commands/TestCommand.ts"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,MAAM,wBAAwB,CAAA;AAErD,MAAM,CAAC,OAAO,OAAO,WAAW;IACrB,KAAK,CAAC,GAAG;QACZ,gBAAgB,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"TestCommand.js","sourceRoot":"","sources":["../../../src/impl/commands/TestCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC,OAAO,gBAAgB,MAAM,wBAAwB,CAAA;AAErD,MAAM,CAAC,OAAO,OAAO,WAAW;IACrB,KAAK,CAAC,GAAG;QACZ,MAAM,WAAW,GACb,oEAAoE,CAAA;QAExE,MAAM,UAAU,GAAG,CAAC,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;YAC9C,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,mCAAmC,CAAA;QAEzC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAChC,MAAM,EACN,CAAC,UAAU,EAAE,aAAa,EAAE,UAAU,CAAC,EACvC,EAAE,KAAK,EAAE,SAAS,EAAE,CACvB,CAAA;YACD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAmB,EAAE,EAAE,CACtC,IAAI,KAAK,CAAC;gBACN,CAAC,CAAC,OAAO,EAAE;gBACX,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC,CAClE,CAAA;QACL,CAAC,CAAC,CAAA;IACN,CAAC;CACJ;AAED,KAAK,UAAU,UAAU,CAAC,IAAY;IAClC,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;QAClB,OAAO,IAAI,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SpawnOptions } from 'node:child_process';
|
|
2
|
+
export interface SpawnCall {
|
|
3
|
+
command: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
options?: SpawnOptions;
|
|
6
|
+
}
|
|
7
|
+
export declare let callsToSpawn: SpawnCall[];
|
|
8
|
+
export declare function resetCallsToSpawn(): void;
|
|
9
|
+
export declare let fakeSpawnExitCode: number;
|
|
10
|
+
export declare function setFakeSpawnExitCode(code: number): void;
|
|
11
|
+
export default function fakeSpawn(command: string, args: string[], options?: SpawnOptions): any;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
export let callsToSpawn = [];
|
|
3
|
+
export function resetCallsToSpawn() {
|
|
4
|
+
callsToSpawn = [];
|
|
5
|
+
}
|
|
6
|
+
export let fakeSpawnExitCode = 0;
|
|
7
|
+
export function setFakeSpawnExitCode(code) {
|
|
8
|
+
fakeSpawnExitCode = code;
|
|
9
|
+
}
|
|
10
|
+
export default function fakeSpawn(command, args, options) {
|
|
11
|
+
callsToSpawn.push({ command, args, options });
|
|
12
|
+
const emitter = new EventEmitter();
|
|
13
|
+
process.nextTick(() => emitter.emit('close', fakeSpawnExitCode));
|
|
14
|
+
return emitter;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=fakeSpawn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fakeSpawn.js","sourceRoot":"","sources":["../../../src/testDoubles/child_process/fakeSpawn.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAQ1C,MAAM,CAAC,IAAI,YAAY,GAAgB,EAAE,CAAA;AAEzC,MAAM,UAAU,iBAAiB;IAC7B,YAAY,GAAG,EAAE,CAAA;AACrB,CAAC;AAED,MAAM,CAAC,IAAI,iBAAiB,GAAG,CAAC,CAAA;AAEhC,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC7C,iBAAiB,GAAG,IAAI,CAAA;AAC5B,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,CAC7B,OAAe,EACf,IAAc,EACd,OAAsB;IAEtB,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAE7C,MAAM,OAAO,GAAG,IAAI,YAAY,EAAE,CAAA;IAElC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAA;IAEhE,OAAO,OAAc,CAAA;AACzB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neurodevs/ndx-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "CLI tools for the Neurodevs ecosystem.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@neurodevs/eslint-config-ndx": "^1.0.1",
|
|
51
51
|
"@neurodevs/fake-node-core": "^0.12.0",
|
|
52
52
|
"@neurodevs/generate-id": "^1.1.2",
|
|
53
|
-
"@neurodevs/node-tdd": "^
|
|
53
|
+
"@neurodevs/node-tdd": "^3.0.1",
|
|
54
54
|
"@neurodevs/prettier-config-ndx": "^1.0.2",
|
|
55
55
|
"@types/prompts": "^2.4.9",
|
|
56
56
|
"typescript": "^5.9.2"
|
|
@@ -2,7 +2,12 @@ import { assert, test } from '@neurodevs/node-tdd'
|
|
|
2
2
|
|
|
3
3
|
import { CommandRunner } from '../../../impl/CliCommandRunner.js'
|
|
4
4
|
import AbstractCommandRunnerTest from '../../AbstractCommandRunnerTest.js'
|
|
5
|
-
import {
|
|
5
|
+
import fakeSpawn, {
|
|
6
|
+
callsToSpawn,
|
|
7
|
+
resetCallsToSpawn,
|
|
8
|
+
setFakeSpawnExitCode,
|
|
9
|
+
} from '../../../testDoubles/child_process/fakeSpawn.js'
|
|
10
|
+
import CliCommandRunner from '../../../impl/CliCommandRunner.js'
|
|
6
11
|
|
|
7
12
|
export default class TestCommandTest extends AbstractCommandRunnerTest {
|
|
8
13
|
private static instance: CommandRunner
|
|
@@ -10,6 +15,9 @@ export default class TestCommandTest extends AbstractCommandRunnerTest {
|
|
|
10
15
|
protected static async beforeEach() {
|
|
11
16
|
await super.beforeEach()
|
|
12
17
|
|
|
18
|
+
CliCommandRunner.spawn = fakeSpawn as any
|
|
19
|
+
resetCallsToSpawn()
|
|
20
|
+
|
|
13
21
|
this.instance = await this.run()
|
|
14
22
|
}
|
|
15
23
|
|
|
@@ -22,11 +30,31 @@ export default class TestCommandTest extends AbstractCommandRunnerTest {
|
|
|
22
30
|
}
|
|
23
31
|
|
|
24
32
|
@test()
|
|
25
|
-
protected static async
|
|
26
|
-
assert.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
protected static async spawnsNodeWithTestRunnerScript() {
|
|
34
|
+
assert.isEqualDeep(
|
|
35
|
+
callsToSpawn[0],
|
|
36
|
+
{
|
|
37
|
+
command: 'node',
|
|
38
|
+
args: [
|
|
39
|
+
'node_modules/@neurodevs/node-tdd/build/workspace/testRunner.cli.js',
|
|
40
|
+
'--watchMode',
|
|
41
|
+
'standard',
|
|
42
|
+
],
|
|
43
|
+
options: {
|
|
44
|
+
stdio: 'inherit',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
'Did not spawn node as command!'
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@test()
|
|
52
|
+
protected static async throwsIfSpawnExitsWithNonZeroCode() {
|
|
53
|
+
setFakeSpawnExitCode(1)
|
|
54
|
+
|
|
55
|
+
await assert.doesThrowAsync(
|
|
56
|
+
() => this.run(),
|
|
57
|
+
/Test runner exited with code 1/
|
|
30
58
|
)
|
|
31
59
|
}
|
|
32
60
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { exec as execSync } from 'node:child_process'
|
|
1
|
+
import { exec as execSync, spawn } from 'node:child_process'
|
|
2
2
|
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
3
|
import { promisify } from 'node:util'
|
|
4
4
|
|
|
@@ -19,6 +19,7 @@ export default class CliCommandRunner implements CommandRunner {
|
|
|
19
19
|
public static Class?: CommandRunnerConstructor
|
|
20
20
|
public static error = console.error
|
|
21
21
|
public static exec = promisify(execSync)
|
|
22
|
+
public static spawn = spawn
|
|
22
23
|
public static log = console.log
|
|
23
24
|
public static mkdir = mkdir
|
|
24
25
|
public static prompts = prompts
|
|
@@ -1,9 +1,36 @@
|
|
|
1
|
+
import { access } from 'node:fs/promises'
|
|
2
|
+
|
|
1
3
|
import CliCommandRunner from '../CliCommandRunner.js'
|
|
2
4
|
|
|
3
5
|
export default class TestCommand {
|
|
4
6
|
public async run() {
|
|
5
|
-
|
|
6
|
-
'
|
|
7
|
-
|
|
7
|
+
const localRunner =
|
|
8
|
+
'node_modules/@neurodevs/node-tdd/build/workspace/testRunner.cli.js'
|
|
9
|
+
|
|
10
|
+
const runnerPath = (await fileExists(localRunner))
|
|
11
|
+
? localRunner
|
|
12
|
+
: 'build/workspace/testRunner.cli.js'
|
|
13
|
+
|
|
14
|
+
await new Promise<void>((resolve, reject) => {
|
|
15
|
+
const child = CliCommandRunner.spawn(
|
|
16
|
+
'node',
|
|
17
|
+
[runnerPath, '--watchMode', 'standard'],
|
|
18
|
+
{ stdio: 'inherit' }
|
|
19
|
+
)
|
|
20
|
+
child.on('close', (code: number | null) =>
|
|
21
|
+
code === 0
|
|
22
|
+
? resolve()
|
|
23
|
+
: reject(new Error(`Test runner exited with code ${code}`))
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function fileExists(path: string): Promise<boolean> {
|
|
30
|
+
try {
|
|
31
|
+
await access(path)
|
|
32
|
+
return true
|
|
33
|
+
} catch {
|
|
34
|
+
return false
|
|
8
35
|
}
|
|
9
36
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SpawnOptions } from 'node:child_process'
|
|
2
|
+
import { EventEmitter } from 'node:events'
|
|
3
|
+
|
|
4
|
+
export interface SpawnCall {
|
|
5
|
+
command: string
|
|
6
|
+
args: string[]
|
|
7
|
+
options?: SpawnOptions
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export let callsToSpawn: SpawnCall[] = []
|
|
11
|
+
|
|
12
|
+
export function resetCallsToSpawn() {
|
|
13
|
+
callsToSpawn = []
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export let fakeSpawnExitCode = 0
|
|
17
|
+
|
|
18
|
+
export function setFakeSpawnExitCode(code: number) {
|
|
19
|
+
fakeSpawnExitCode = code
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default function fakeSpawn(
|
|
23
|
+
command: string,
|
|
24
|
+
args: string[],
|
|
25
|
+
options?: SpawnOptions
|
|
26
|
+
) {
|
|
27
|
+
callsToSpawn.push({ command, args, options })
|
|
28
|
+
|
|
29
|
+
const emitter = new EventEmitter()
|
|
30
|
+
|
|
31
|
+
process.nextTick(() => emitter.emit('close', fakeSpawnExitCode))
|
|
32
|
+
|
|
33
|
+
return emitter as any
|
|
34
|
+
}
|