UNPKG

@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
"use strict"; /** @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;