@jakechampion/cli-testing-library
Version:
Small but powerful library for testing CLI the way it is used by people.
187 lines (186 loc) • 7.49 kB
JavaScript
;
/** @license CLI testing library
* Copyright (c) Georgy Marchuk.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepareEnvironment = exports.relative = exports.fsAccess = exports.fsReadDir = exports.fsMakeTempDir = exports.fsMakeDir = exports.fsRemoveDir = exports.fsRemove = exports.fsWrite = exports.fsRead = exports.copy = void 0;
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const util_1 = require("util");
const os_1 = require("os");
const Output_1 = require("./Output");
const utils_1 = require("./utils");
const createExecute_1 = require("./createExecute");
const keyToHEx_1 = require("./keyToHEx");
exports.copy = (0, util_1.promisify)(fs_1.copyFile);
exports.fsRead = (0, util_1.promisify)(fs_1.readFile);
exports.fsWrite = (0, util_1.promisify)(fs_1.writeFile);
exports.fsRemove = (0, util_1.promisify)(fs_1.unlink);
exports.fsRemoveDir = (0, util_1.promisify)(fs_1.rmdir);
exports.fsMakeDir = (0, util_1.promisify)(fs_1.mkdir);
exports.fsMakeTempDir = (0, util_1.promisify)(fs_1.mkdtemp);
exports.fsReadDir = (0, util_1.promisify)(fs_1.readdir);
exports.fsAccess = (0, util_1.promisify)(fs_1.access);
const relative = (p) => path_1.default.resolve(__dirname, p);
exports.relative = relative;
const prepareEnvironment = async () => {
const hasCalledCleanup = { current: false };
const startedTasks = [];
const tempDir = await (0, exports.fsMakeTempDir)(path_1.default.join((0, os_1.tmpdir)(), 'cli-testing-library-'));
const relative = (p) => path_1.default.resolve(tempDir, p);
const cleanup = async () => {
hasCalledCleanup.current = true;
startedTasks.forEach((task) => {
task.current?.kill(0);
task.current?.stdin.end();
task.current?.stdin.destroy();
task.current?.stdout.destroy();
task.current?.stderr.destroy();
task.current = null;
});
await (0, exports.fsRemoveDir)(tempDir, { recursive: true });
};
try {
const execute = async (runner, command, runFrom) => {
const output = new Output_1.Output();
const currentProcessRef = { current: null };
const scopedExecute = (0, createExecute_1.createExecute)(tempDir, output, currentProcessRef);
startedTasks.push(currentProcessRef);
return await scopedExecute(runner, command, runFrom);
};
const spawn = async (runner, command, runFrom) => {
const output = new Output_1.Output();
const currentProcessRef = { current: null };
const exitCodeRef = { current: null };
let currentProcessPromise = null;
const scopedExecute = (0, createExecute_1.createExecute)(tempDir, output, currentProcessRef, exitCodeRef);
startedTasks.push(currentProcessRef);
currentProcessPromise = scopedExecute(runner, command, runFrom);
const waitForText = (input) => {
return new Promise((resolve) => {
const handler = (value) => {
if (value.toString().includes(input)) {
resolve({
type: 'stdout',
line: value.toString(),
});
output.off(handler);
}
};
output.on(handler);
});
};
const wait = (delay) => {
return new Promise((resolve) => {
setTimeout(resolve, delay);
});
};
const waitForFinish = async () => {
if (currentProcessPromise) {
currentProcessRef.current?.stdin.end();
return currentProcessPromise;
}
return new Promise((resolve) => {
resolve({
code: exitCodeRef.current,
stdout: output.stdout,
stderr: output.stderr,
});
});
};
const writeText = async (input) => {
return new Promise((resolve) => {
if ((0, utils_1.checkRunningProcess)(currentProcessRef)) {
currentProcessRef.current.stdin.write(input, () => resolve());
}
});
};
const pressKey = async (input) => {
return new Promise((resolve) => {
if ((0, utils_1.checkRunningProcess)(currentProcessRef)) {
currentProcessRef.current.stdin.write((0, keyToHEx_1.keyToHEx)(input), () => {
resolve();
});
}
});
};
const kill = (signal) => {
if ((0, utils_1.checkRunningProcess)(currentProcessRef)) {
currentProcessRef.current.kill(signal);
}
};
const debug = () => {
const handler = (value, type) => {
process[type].write(value);
};
output.on(handler);
};
return {
wait,
waitForFinish,
waitForText,
pressKey,
writeText,
kill,
debug,
getStdout: () => output.stdout,
getStderr: () => output.stderr,
getExitCode: () => exitCodeRef.current,
};
};
const exists = async (path) => {
try {
await (0, exports.fsAccess)(relative(path));
return true;
}
catch {
return false;
}
};
const makeDir = async (path) => {
await (0, exports.fsMakeDir)(relative(path), { recursive: true });
};
const writeFile = async (p, content) => {
const dir = path_1.default.dirname(relative(p));
if (!(await exists(dir))) {
await makeDir(dir);
}
await (0, exports.fsWrite)(relative(p), content);
};
const readFile = async (path) => {
return (await (0, exports.fsRead)(relative(path))).toString();
};
const removeFile = async (path) => {
return await (0, exports.fsRemove)(relative(path));
};
const removeDir = async (path) => {
return await (0, exports.fsRemoveDir)(relative(path));
};
const ls = async (path) => {
return await (0, exports.fsReadDir)(path ? relative(path) : tempDir);
};
return {
path: tempDir,
cleanup,
writeFile,
readFile,
removeFile,
removeDir,
ls,
exists,
makeDir,
execute,
spawn,
};
}
catch (e) {
await cleanup();
throw e;
}
};
exports.prepareEnvironment = prepareEnvironment;