forked from rstackjs/rstack-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcliTest.ts
More file actions
120 lines (102 loc) · 3.31 KB
/
Copy pathcliTest.ts
File metadata and controls
120 lines (102 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { type ChildProcess, type SpawnOptions, spawn as nodeSpawn } from 'node:child_process';
import path from 'node:path';
import { prepareDist as basePrepareDist } from '@rstackjs/test-utils';
import { test as baseTest } from 'rstack/test';
import { execCli as baseExecCli, type ExecCli, RSTACK_BIN_PATH } from './cli.ts';
import { type ExtendedLogHelper, proxyConsole } from './logs.ts';
type Exec = (
command: string,
options?: SpawnOptions,
) => {
childProcess: ChildProcess;
};
type PrepareDist = (distFolderName?: string) => Promise<string>;
export type CliTestFixtures = {
cwd: string;
exec: Exec;
execCli: ExecCli;
execCliAsync: Exec;
logHelper: ExtendedLogHelper;
prepareDist: PrepareDist;
};
type CliTest = ReturnType<typeof baseTest.extend<CliTestFixtures>>;
function makeBox(title: string) {
const border = `-------- Logs from: "${title}" --------`;
return {
header: `\n${border}\n`,
footer: `${border}\n`,
};
}
const setupExecOptions = <T extends SpawnOptions>(options: T, cwd: string): T => {
// inherit process.env from current process
const { NODE_ENV: _, ...restEnv } = process.env;
options.env ||= {};
options.env = { ...restEnv, ...options.env };
options.cwd ||= cwd;
return options;
};
export const test: CliTest = baseTest.extend<CliTestFixtures>({
cwd: async ({ expect }, use) => {
const { testPath } = expect.getState();
if (!testPath) {
throw new Error('Unable to resolve current test file path from expect state.');
}
await use(path.dirname(testPath));
},
prepareDist: async ({ cwd }, use) => {
const prepareDist: PrepareDist = (distFolderName = 'dist') =>
basePrepareDist(path.join(cwd, distFolderName));
await use(prepareDist);
},
logHelper: [
async ({ onTestFailed, task }, use) => {
const logHelper = proxyConsole();
onTestFailed(() => {
if (logHelper.logs.length) {
const { header, footer } = makeBox(task.name);
logHelper.restore();
console.log(header);
logHelper.printCapturedLogs();
console.log(footer);
}
});
await use(logHelper);
logHelper.restore();
},
{ auto: true },
],
execCli: async ({ cwd, logHelper }, use) => {
const execCli: ExecCli = (command, options = {}) =>
baseExecCli(command, { ...options, cwd: options.cwd ?? cwd, logHelper });
await use(execCli);
},
exec: async ({ cwd, logHelper }, use) => {
const closes: Array<() => void> = [];
const exec: Exec = (command, options = {}) => {
const childProcess = nodeSpawn(command, setupExecOptions({ shell: true, ...options }, cwd));
const onData = (data: Buffer) => {
logHelper.addLog(data.toString());
};
childProcess.stdout?.on('data', onData);
childProcess.stderr?.on('data', onData);
closes.push(() => {
childProcess.stdout?.off('data', onData);
childProcess.stderr?.off('data', onData);
childProcess.kill();
});
return { childProcess };
};
try {
await use(exec);
} finally {
for (const close of closes) {
close();
}
}
},
execCliAsync: async ({ exec }, use) => {
const execCliAsync: Exec = (command, options = {}) =>
exec(`node "${RSTACK_BIN_PATH}" ${command}`, options);
await use(execCliAsync);
},
});