UNPKG

tsd-lite-cli

Version:

Test runner for testing TypeScript typings. CLI over tsd-lite, a per-file version of tsd

178 lines (160 loc) 4.59 kB
/** @typedef {import("./run-one.js").TestError} TestError */ import path from "node:path" import { formatHrTime } from "./utils/node.js" import * as ttext from "./utils/terminal-text.js" /** * Format into TAP plan * * @param {object} props * @param {number} props.count * @param {string[]} props.patterns * @param {boolean} [props.hasColor] * * @example * formatPlan({ * count: 2, * patterns: ["src/*.test-d.ts"] * }) * // => "TAP version 14" * // => "1..2" * // => '# Matching patterns "src/*.test-d.ts"' */ const formatPlan = ({ count, patterns, hasColor = true }) => { let description = `# Matching patterns ${patterns .map(item => `"${item}"`) .join(",")}` if (hasColor) { description = ttext.blue.fg(description) } return [`TAP version 14`, `1..${count}`, description].join("\n") } /** * Emphasize the file name by contrasting it with the rest of the path * * @param {string} filePath * @returns {string} * * @example * highlightFileName("src/__tests__/index.test.js") * // => "src/__tests__/index.test.js" * // "^^^^^gray^^^^|^^^^white^^^^" */ const highlightFileName = filePath => { const fileName = path.basename(filePath) const folderName = path.dirname(filePath) return `${ttext.gray.fgSecondary(folderName)}/${ttext.white.fgSecondary( ttext.bold(fileName) )}` } /** * Format test file result to TAP format * * @param {object} props * @param {number} props.index * @param {object} props.result * @param {string} props.result.name * @param {[number, number]} props.result.duration * @param {TestError[]} props.result.errors * @param {boolean} [props.hasColor] * * @example * formatTest({ * name: "src/__tests__/index.test.js", * errors: [], * }) * // => "ok 1 - src/__tests__/index.test.js 0.8s" * * @example * formatTest({ * name: "src/__tests__/index.test.js", * errors: [ * { row: 1, column: 1, message: "Unexpected token" }, * ], * }) * // => "not ok 1 - src/__tests__/index.test.js 1.2s" * // => " ---" * // => " message: Unexpected token * // => " severity: fail" * // => " data:" * // => " line: 1" * // => " column: 1" * // => " ..." */ const formatTest = ({ index, result: { name, duration, errors }, hasColor = true, }) => { let testPointStatus = `${errors.length === 0 ? "ok" : "not ok"} ${index + 1}` let humanReadableDuration = formatHrTime(duration) let fileName = name if (hasColor) { testPointStatus = errors.length === 0 ? ttext.black.fg(ttext.green.bgSecondary(testPointStatus)) : ttext.black.fg(ttext.red.bgSecondary(testPointStatus)) fileName = highlightFileName(name) humanReadableDuration = ttext.gray.fgSecondary(humanReadableDuration) } const testPoint = `${testPointStatus} - ${fileName} ${humanReadableDuration}` const output = [testPoint] for (const error of errors) { const message = hasColor ? ttext.cyan.fg(error.message) : error.message output.push( ` ---`, ` message: ${message}`, ` severity: fail`, ` data:`, ` line: ${error.row}`, ` column: ${error.column}`, ` ...` ) } return output.join("\n") } /** * Format the summary of multiple tests to TAP format * * @param {object} props * @param {number} props.passCount * @param {number} props.failCount * @param {[number, number]} props.duration * @param {boolean} [props.hasColor] * * @example * formatSummary({ * passCount: 1, * failCount: 1, * duration: [5, 420000000] * }) * // => "# tests 2" * // => "# pass 1" * // => "# fail 1" * // => "# duration 5.42s" */ const formatSummary = ({ passCount, failCount, duration, hasColor = true }) => { const hasFailures = failCount > 0 const totalCount = passCount + failCount let [testsLine, passLine, failLine, durationLine] = [ `# tests ${totalCount}`, `# pass ${passCount}`, `# fail ${failCount}`, `# duration ${formatHrTime(duration)}`, ] if (hasColor) { testsLine = hasFailures ? ttext.red.fgSecondary(testsLine) : ttext.green.fgSecondary(testsLine) passLine = ttext.green.fgSecondary(passLine) failLine = hasFailures ? ttext.red.fgSecondary(failLine) : ttext.gray.fgSecondary(failLine) durationLine = ttext.gray.fgSecondary(durationLine) } return [testsLine, passLine, failLine, durationLine].join("\n") } export default { formatPlan, formatTest, formatSummary, }