UNPKG

poku

Version:

🐷 Poku makes testing easy for Node.js, Bun, Deno, and you at the same time.

1,154 lines 52.2 kB
import { relative, resolve, extname, sep, join, normalize } from "node:path"; import process$1, { cwd as cwd$2, stdout, env, argv, platform, hrtime, exit as exit$1 } from "node:process"; import * as os from "node:os"; import { spawn } from "node:child_process"; import nodeAssert, { AssertionError, deepStrictEqual, deepEqual } from "node:assert"; import nodeAssert$1 from "node:assert/strict"; import { stat, readdir, readFile } from "node:fs/promises"; import { createConnection } from "node:net"; const SAFE_REGEXP = /[.*+{}[\]\\]/g, escapeRegExp = (value) => value.replace(SAFE_REGEXP, "\\$&"), getRuntime = () => typeof Deno < "u" ? "deno" : typeof Bun < "u" ? "bun" : "node", globalScope = globalThis, getSharedState = (name, initial) => { const stateKey = /* @__PURE__ */ Symbol.for(`@poku/${name}`); return globalScope[stateKey] === void 0 && (globalScope[stateKey] = initial), globalScope[stateKey]; }, cwd$1 = getSharedState("cwd", cwd$2()), indentation = getSharedState("indentation", { test: " ", stdio: " ", describeDepth: 0, itDepth: 0 }), results = getSharedState("results", { passed: 0, failed: 0, skipped: 0, todo: 0 }), BG_CODES = { white: "\x1B[7m\x1B[1m", black: "\x1B[40m\x1B[1m", grey: "\x1B[100m\x1B[1m", red: "\x1B[41m\x1B[1m", green: "\x1B[42m\x1B[1m", yellow: "\x1B[43m\x1B[1m", blue: "\x1B[44m\x1B[1m", magenta: "\x1B[45m\x1B[1m", cyan: "\x1B[46m\x1B[1m", brightRed: "\x1B[101m\x1B[1m", brightGreen: "\x1B[102m\x1B[1m", brightYellow: "\x1B[103m\x1B[1m", brightBlue: "\x1B[104m\x1B[1m", brightMagenta: "\x1B[105m\x1B[1m", brightCyan: "\x1B[106m\x1B[1m" }; class Formatter { constructor(text) { this.parts = "", this.text = text; } code(code) { return this.parts += `\x1B[${code}m`, this; } dim() { return this.parts += "\x1B[2m", this; } bold() { return this.parts += "\x1B[1m", this; } underline() { return this.parts += "\x1B[4m", this; } info() { return this.parts += "\x1B[94m", this; } italic() { return this.parts += "\x1B[3m", this; } success() { return this.parts += "\x1B[32m", this; } fail() { return this.parts += "\x1B[91m", this; } gray() { return this.parts += "\x1B[90m", this; } cyan() { return this.parts += "\x1B[96m", this; } bg(color) { return this.parts += BG_CODES[color], this; } [Symbol.toPrimitive]() { return `${this.parts}${this.text}\x1B[0m`; } } const format = (text) => new Formatter(text), SKIP_MARKER = "\x1B[94m\x1B[1m\u25EF", TODO_MARKER = "\x1B[96m\x1B[1m\u25CF", ANSI_RESET = "\x1B[0m", timeoutMessage = (ms) => `${format(`\u25CF Timeout: test file exceeded ${ms}ms limit`).fail().bold()}`, serialize = (value) => typeof value > "u" || typeof value == "function" || typeof value == "bigint" || typeof value == "symbol" || value instanceof RegExp ? String(value) : Array.isArray(value) ? value.map(serialize) : value instanceof Set ? Array.from(value).map(serialize) : value instanceof Map ? serialize(Object.fromEntries(value)) : value !== null && typeof value == "object" ? Object.fromEntries( Object.entries(value).map(([key, val]) => [key, serialize(val)]) ) : value, parserOutput = (options) => { const { output, result, debug } = options, pad2 = " ", isDebugOrFailed = debug || !result, outputs = []; let offset = 0; for (; offset < output.length; ) { const nextNewline = output.indexOf(` `, offset), lineEnd = nextNewline === -1 ? output.length : nextNewline; if (lineEnd > offset) { const line = output.substring(offset, lineEnd); line.includes(SKIP_MARKER) && results.skipped++, line.includes(TODO_MARKER) && results.todo++, line.trim().length > 0 && (isDebugOrFailed || line.indexOf("Exited with code") === -1 && line.includes(ANSI_RESET)) && outputs.push(`${pad2}${line}`); } offset = lineEnd + 1; } if (outputs.length !== 0) return outputs; }, parseResultType = (type) => { const result = serialize(type); return typeof result == "string" ? result : JSON.stringify(result, null, 2); }, charCode = { colon: 58, backslash: 92, space: 32, openParen: 40, zero: 48, nine: 57, upperA: 65, upperZ: 90, lowerA: 97, lowerZ: 122 }, FILE_PROTOCOL = "file://", FILE_PROTOCOL_LENGTH = FILE_PROTOCOL.length, INTERNAL_PATH = "poku/lib/", isAlpha = (code) => code >= charCode.upperA && code <= charCode.upperZ || code >= charCode.lowerA && code <= charCode.lowerZ, isDigit = (code) => code >= charCode.zero && code <= charCode.nine, findPathStart = (line) => { const protoIndex = line.indexOf(FILE_PROTOCOL); if (protoIndex !== -1) return protoIndex + FILE_PROTOCOL_LENGTH; const slashIndex = line.indexOf("/"); if (slashIndex === 0) return 0; if (slashIndex > 0 && (line.charCodeAt(slashIndex - 1) === charCode.space || line.charCodeAt(slashIndex - 1) === charCode.openParen)) return slashIndex; const length = line.length; for (let i = 0; i < length - 2; i++) if (isAlpha(line.charCodeAt(i)) && line.charCodeAt(i + 1) === charCode.colon && line.charCodeAt(i + 2) === charCode.backslash) return i; return -1; }, findLineColStart = (line, after) => { let position = -1; for (let i = line.length - 1; i > after; i--) line.charCodeAt(i) === charCode.colon && i + 1 < line.length && isDigit(line.charCodeAt(i + 1)) && (position = i); return position; }, findFileFromStack = (stack, options) => { if (!stack) return ""; const lines = stack.split(` `), skipInternal = options?.skipInternal; for (const line of lines) { if (skipInternal && line.indexOf(INTERNAL_PATH) !== -1) continue; const pathStart = findPathStart(line); if (pathStart === -1) continue; const colonPos = findLineColStart(line, pathStart); if (colonPos !== -1) { if (skipInternal) { const protoIndex = line.indexOf(FILE_PROTOCOL), start = protoIndex !== -1 ? protoIndex : pathStart; let end = line.length; for (; end > colonPos && !isDigit(line.charCodeAt(end - 1)); ) end--; return line.slice(start, end); } return line.slice(pathStart, colonPos); } } return ""; }, pad = (num) => String(num).padStart(2, "0"), parseTime = (date) => { const hours = pad(date.getHours()), minutes = pad(date.getMinutes()), seconds = pad(date.getSeconds()); return `${hours}:${minutes}:${seconds}`; }, parseTimeToSecs = (milliseconds) => (milliseconds / 1e3).toFixed(2), columns = Math.max((stdout.columns || 50) - 10, 40), hrLine = ` \x1B[2m\x1B[90m${"\u2500".repeat(columns)}\x1B[0m `, log$1 = (data) => { stdout.write(`${data} `); }, hr = () => { log$1(hrLine); }, ARROW_PASS = "\x1B[32m\x1B[1m\u203A\x1B[0m", ARROW_FAIL = "\x1B[91m\x1B[1m\u203A\x1B[0m", getIndent = () => indentation.test.repeat(indentation.describeDepth + indentation.itDepth), errors = getSharedState( "errors", [] ), poku$1 = { onRunStart() { }, onFileStart() { }, onDescribeAsTitle(title, options) { const { background, icon } = options ?? /* @__PURE__ */ Object.create(null), message = `${icon ?? "\u2630"} ${format(title).bold()}`; log$1( background ? format(` ${message} `).bg( typeof background == "string" ? background : "grey" ) : format(message).bold() ); }, onDescribeStart({ title }) { if (!title) return; const indent = getIndent(); log$1(`${indent}${format(`\u25CC ${title}`).bold().dim()}`); }, onDescribeEnd({ title, duration, success = !0 }) { const status = success ? "success" : "fail", indent = getIndent(); log$1( `${indent}${format(`\u25CF ${title}`)[status]().bold()} ${format( `\u203A ${duration.toFixed(6)}ms` )[status]().dim()}` ); }, onItStart({ title }) { if (!title) return; const indent = getIndent(); log$1(`${indent}${format(`\u25CC ${title}`).dim()}`); }, onItEnd({ title, duration, success = !0 }) { const status = success ? "success" : "fail", indent = getIndent(); log$1( `${indent}${format(`\u25CF ${title}`)[status]().bold()} ${format( `\u203A ${duration.toFixed(6)}ms` )[status]().dim()}` ); }, onAssertionSuccess({ message }) { const output = `${getIndent()}${format(`\u2714 ${message}`).success().bold()}`; log$1(output); }, onAssertionFailure({ assertOptions: options, error }) { let preIdentation = getIndent(); const { code, actual, expected, operator } = error, fileRef = findFileFromStack(error.stack, { skipInternal: !0 }), absolutePath = fileRef.indexOf("file://") === 0 ? fileRef.slice(7) : fileRef, file = relative(resolve(cwd$1), absolutePath); let message = ""; typeof options.message == "string" ? message = options.message : options.message instanceof Error ? message = options.message.message : typeof options.defaultMessage == "string" && (message = options.defaultMessage); const output = message?.trim().length > 0 ? format(`\u2718 ${message}`).fail().bold() : format("\u2718 Assertion Error").fail().bold(); if (log$1(`${preIdentation}${output}`), file && log$1(`${format(`${preIdentation} File`).dim()} ${file}`), log$1(`${format(`${preIdentation} Code`).dim()} ${code}`), log$1(`${format(`${preIdentation} Operator`).dim()} ${operator} `), !options?.hideDiff) { const splitActual = parseResultType(actual).split(` `), splitExpected = parseResultType(expected).split(` `); log$1(format(`${preIdentation} ${options?.actual ?? "Actual"}:`).dim()); for (const line of splitActual) log$1(`${preIdentation} ${format(line).fail().bold()}`); log$1( ` ${preIdentation} ${format(`${options?.expected ?? "Expected"}:`).dim()}` ); for (const line of splitExpected) log$1(`${preIdentation} ${format(line).success().bold()}`); preIdentation = ""; } options.throw && (console.error(error), hr()); }, onSkipFile({ message }) { log$1(format(`\u25EF ${message}`).info().bold()); }, onSkipModifier({ message }) { const indent = getIndent(); log$1(`${indent}${format(`\u25EF ${message}`).info().bold()}`); }, onTodoModifier({ message }) { const indent = getIndent(); log$1(`${indent}${format(`\u25CF ${message}`).cyan().bold()}`); }, onFileResult({ status, path, duration, output }) { stdout.write(` `), status ? (log$1( `${ARROW_PASS} ${format(path.relative).success().underline()} ${format( `\u203A ${duration.toFixed(6)}ms` ).success().dim()}` ), output && log$1(output)) : log$1( `${ARROW_FAIL} ${format(path.relative).fail().underline()} ${format( `\u203A ${duration.toFixed(6)}ms` ).fail().dim()}` ), status || (errors.push({ file: path.relative, output }), output && log$1(output)); }, onRunResult() { if (errors.length !== 0) { hr(), log$1( `${format(String(errors.length)).fail().bold()} ${format("test file(s) failed:").bold()} ` ); for (const i in errors) if (Object.prototype.hasOwnProperty.call(errors, i)) { const { file, output } = errors[i], index = +i; index > 0 && stdout.write(` `), log$1( `${format(`${index + 1})`).dim().bold()} ${format(file).underline()}` ), output && log$1(` ${output}`); } } }, onExit({ results: results2, timespan: timespan2 }) { const success = ` PASS \u203A ${results2.passed} `, failure = ` FAIL \u203A ${results2.failed} `, skips = ` SKIP \u203A ${results2.skipped} `, plans = ` TODO \u203A ${results2.todo} `, inline = results2.skipped === 0 || results2.todo === 0; let message = ""; inline ? (message += `${format(success).bg("green")} ${format(failure).bg(results2.failed === 0 ? "grey" : "brightRed")}`, results2.skipped && (message += ` ${format(skips).bg("brightBlue")}`), results2.todo && (message += ` ${format(plans).bg("brightBlue")}`)) : (message += `${format(success.trim()).success().bold()} `, message += results2.failed === 0 ? format(`${failure.trim()} `).bold() : `${format(failure.trim()).fail().bold()} `, message += `${format(skips.trim()).info().bold()} `, message += `${format(plans.trim()).info().bold()}`), hr(), log$1( `${format(`Start at \u203A ${format(`${parseTime(timespan2.started)}`).bold()}`).dim()}` ), log$1( `${format("Duration \u203A ").dim()}${format( `${timespan2.duration.toFixed(6)}ms` ).bold().dim()} ${format(`(\xB1${parseTimeToSecs(timespan2.duration)} seconds)`).dim()}` ), log$1( `${format(`Files \u203A ${format(String(results2.passed + results2.failed)).bold()}`).dim()}` ), log$1(` ${message} `); } }, createReporter = (events) => () => ({ ...poku$1, ...events }), classic = () => { const files = { passed: /* @__PURE__ */ new Map(), failed: /* @__PURE__ */ new Map() }; return createReporter({ onRunStart() { hr(), log$1(`${format("Running Tests").bold()} `); }, onFileStart() { }, onFileResult({ status, path, duration, output }) { status ? files.passed.set(path.relative, duration) : files.failed.set(path.relative, duration), output && log$1(output); }, onRunResult() { if (hr(), files.passed.size > 0 && files.failed.size === 0) { log$1( Array.from(files.passed).map( ([file, time]) => `${indentation.test}${format("\u2714").success()} ${format(`${file} ${format(`\u203A ${time.toFixed(6)}ms`).success()}`).dim()}` ).join(` `) ); return; } files.failed.size > 0 && log$1( Array.from(files.failed).map( ([file, time]) => `${indentation.test}${format("\u2718").fail()} ${format(`${file} ${format(`\u203A ${time.toFixed(6)}ms`).fail()}`).dim()}` ).join(` `) ); }, onExit(options) { const { code } = options; poku$1.onExit(options), log$1( `${format("Exited with code").dim()} ${format(String(code)).bold()[code === 0 ? "success" : "fail"]()} ` ); } })(); }, LABEL_FILES_PASSED = "\x1B[2mtest file(s) passed\x1B[0m", LABEL_FILES_FAILED = "\x1B[2mtest file(s) failed\x1B[0m", summaryFooter = (countFails, { timespan: timespan2, results: results2 }) => { countFails > 0 && hr(), log$1(`${format(String(results2.passed)).bold().dim()} ${LABEL_FILES_PASSED}`), log$1(`${format(String(results2.failed)).bold().dim()} ${LABEL_FILES_FAILED}`), log$1( `${format(`Finished in \xB1${parseTimeToSecs(timespan2.duration)} seconds`).dim()}` ); }, BADGE_PASS = "\x1B[102m\x1B[1m PASS \x1B[0m", BADGE_FAIL = "\x1B[101m\x1B[1m FAIL \x1B[0m", compact = () => { let countFails = 0; return createReporter({ onRunStart() { }, onFileStart() { }, onDescribeAsTitle() { }, onSkipFile() { }, onSkipModifier() { }, onTodoModifier() { }, onFileResult({ status, path, output }) { log$1(`${status ? BADGE_PASS : BADGE_FAIL} ${path.relative}`), status || (countFails++, errors.push({ file: path.relative, output })); }, onExit({ timespan: timespan2, results: results2 }) { summaryFooter(countFails, { timespan: timespan2, results: results2 }); } })(); }, DOT_PASS = ".", DOT_FAIL = "\x1B[1m\x1B[31mF\x1B[0m", dot = () => createReporter({ onRunStart() { hr(); }, onDescribeAsTitle() { }, onTodoModifier() { }, onSkipModifier() { }, onSkipFile() { }, onFileResult({ path, status, output }) { stdout.write(status ? DOT_PASS : DOT_FAIL), status || errors.push({ file: path.relative, output }); }, onRunResult(options) { stdout.write(` `), poku$1.onRunResult(options); } })(), focus = () => { let countFails = 0; return createReporter({ onRunStart() { }, onDescribeAsTitle() { }, onTodoModifier() { }, onSkipModifier() { }, onSkipFile() { }, onFileResult({ status, output }) { status || (countFails++, output && log$1(output)); }, onExit({ timespan: timespan2, results: results2 }) { summaryFooter(countFails, { timespan: timespan2, results: results2 }); } })(); }, reporter = { poku: () => poku$1, dot, compact, focus, classic }; var reporter$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, reporter }); const states = getSharedState("states", { isSinglePath: void 0 }), timespan = getSharedState("timespan", { started: void 0, finished: void 0, duration: 0 }), errorHoist = getSharedState("errorHoist", { depth: 0, failed: !1 }), VERSION = "4.3.2", deepOptions = getSharedState("deepOptions", []), GLOBAL = getSharedState("GLOBAL", { cwd: cwd$1, configs: { filter: void 0, exclude: void 0, concurrency: void 0, timeout: void 0, sequential: void 0, quiet: void 0, debug: void 0, failFast: void 0, isolation: void 0, deno: void 0, noExit: void 0, reporter: void 0, beforeEach: void 0, afterEach: void 0, testNamePattern: env.POKU_TEST_NAME_PATTERN ? new RegExp(escapeRegExp(env.POKU_TEST_NAME_PATTERN)) : void 0, testSkipPattern: env.POKU_TEST_SKIP_PATTERN ? new RegExp(escapeRegExp(env.POKU_TEST_SKIP_PATTERN)) : void 0 }, configFile: void 0, configsFromFile: /* @__PURE__ */ Object.create(null), reporter: reporter[env.POKU_REPORTER && env.POKU_REPORTER in reporter ? env.POKU_REPORTER : "poku"](), envFile: void 0, runtime: env.POKU_RUNTIME || getRuntime(), runAsOnly: !1 }), [, , ...processArgs] = argv, regexQuotes = /''|""/, getArg = (arg, prefix = "--", baseArgs = processArgs) => { const argPattern = `${prefix}${arg}=`, argValue = baseArgs.find((a) => a.startsWith(argPattern)); if (argValue) return argValue.slice(argPattern.length).replace(regexQuotes, ""); }, hasArg = (arg, prefix = "--", baseArgs = processArgs) => baseArgs.some((a) => a.startsWith(`${prefix}${arg}`)), getPaths = (prefix = "--", baseArgs = processArgs) => { let hasPaths = !1; const paths = []; for (const arg of baseArgs) arg.startsWith(prefix) || (hasPaths || (hasPaths = !0), paths.push(arg)); return hasPaths ? paths : void 0; }, argToArray = (arg, prefix = "--", baseArgs = processArgs) => { if (!hasArg(arg, prefix, baseArgs)) return; const argValue = getArg(arg, prefix, baseArgs); return argValue ? argValue.split(",").filter((a) => a) : []; }, hasOnly = hasArg("only"), availableParallelism = () => typeof os.availableParallelism == "function" ? os.availableParallelism() : os.cpus()?.length ?? 0, isWindows = platform === "win32", runner = (filename) => { const { configs, runtime } = GLOBAL; if (runtime === "bun") return ["bun"]; if (runtime === "deno") { const denoAllow = configs.deno?.allow ? configs.deno.allow.map((allow) => allow ? `--allow-${allow}` : "").filter((allow) => allow) : ["--allow-read", "--allow-env", "--allow-run", "--allow-net"], denoDeny = configs.deno?.deny ? configs.deno.deny.map((deny) => deny ? `--deny-${deny}` : "").filter((deny) => deny) : []; return ["deno", "run", ...denoAllow, ...denoDeny]; } const ext = extname(filename); return ext === ".ts" || ext === ".mts" || ext === ".cts" ? ["node", "--import=tsx"] : ["node"]; }, SCRIPT_COMMANDS = { npm: [isWindows ? "npm.cmd" : "npm", "run"], bun: ["bun", "run"], deno: ["deno", "task"], yarn: ["yarn"], pnpm: ["pnpm", "run"] }, scriptRunner = (runner2) => [ ...SCRIPT_COMMANDS[runner2] ?? SCRIPT_COMMANDS.npm ], eachCore = async (type, fileRelative) => { const { configs } = GLOBAL; if (typeof configs?.[type] != "function") return !0; const cb = configs[type], showLogs = !configs.quiet, cbName = cb.name !== type ? cb.name : "anonymous function"; showLogs && log$1( ` ${format("\u25EF").dim().info()} ${format(`${type}: ${cbName}`).dim().italic()}` ); try { return await cb(), !0; } catch (error) { return showLogs && (log$1( format(` \u2718 ${type} callback failed ${format(`\u203A ${cbName}`).dim()}`).fail().bold() ), log$1(format(` \u251C\u2500 Who's trying to run this ${type}?`).fail()), log$1( format(` \u2502 \u2514\u2500 ${format(fileRelative).fail().underline()}`).fail() ), error instanceof Error && (log$1(format(" \u251C\u2500 Message:").fail()), log$1(format(` \u2502 \u2514\u2500 ${error.message}`).fail()))), !1; } }, beforeEach$1 = (fileRelative) => GLOBAL.configs.beforeEach ? eachCore("beforeEach", fileRelative) : !0, afterEach$1 = (fileRelative) => GLOBAL.configs.afterEach ? eachCore("afterEach", fileRelative) : !0, STDIO_IPC = ["inherit", "pipe", "pipe", "ipc"], STDIO_DEFAULT = ["inherit", "pipe", "pipe"], runTestFile = async (path) => { const { configs } = GLOBAL; if (configs.isolation === "none") { const { runTestInProcess } = await import("./run-test-in-process.js"); return runTestInProcess(path); } const { cwd: cwd2, reporter: reporter2 } = GLOBAL; let command = [...runner(path), path, ...deepOptions]; const plugins = configs.plugins; if (plugins?.length) { for (const plugin of plugins) if (plugin.runner) { command = plugin.runner(command, path); break; } } const runtime = command.shift(), file = relative(cwd2, path), showLogs = !configs.quiet, outputChunks = []; let outputSize = 0; const stdOut = (data) => { outputSize < 10485760 && (outputChunks.push(data), outputSize += data.length); }, start = hrtime(); let end; return await beforeEach$1(file) ? (reporter2.onFileStart({ path: { relative: file, absolute: path } }), new Promise((resolve2) => { const child = spawn(runtime, command, { stdio: plugins?.some((plugin) => plugin.ipc) ? STDIO_IPC : STDIO_DEFAULT, shell: !1 }); if (child.stdout.setEncoding("utf8"), child.stderr.setEncoding("utf8"), child.stdout.on("data", stdOut), child.stderr.on("data", stdOut), plugins?.length) for (const plugin of plugins) plugin.onTestProcess && plugin.onTestProcess(child, path); let timedOut = !1, killTimer; configs.timeout && (killTimer = setTimeout(() => { timedOut = !0, outputChunks.push(timeoutMessage(configs.timeout)), setTimeout(() => child.kill("SIGTERM"), 250); }, configs.timeout)), child.on("close", async (code) => { killTimer && clearTimeout(killTimer), end = hrtime(start); const result = timedOut ? !1 : code === 0; if (showLogs) { const output = outputChunks.join(""), parsedOutputs = parserOutput({ output, result, debug: GLOBAL.configs.debug })?.join(` `), total = end[0] * 1e3 + end[1] / 1e6; reporter2.onFileResult({ status: result, path: { relative: file, absolute: path }, duration: total, output: parsedOutputs }); } if (!await afterEach$1(file)) { resolve2(!1); return; } resolve2(result); }), child.on("error", (err) => { killTimer && clearTimeout(killTimer), end = hrtime(start); const total = end[0] * 1e3 + end[1] / 1e6; showLogs && console.error(`Failed to start test: ${path}`, err), reporter2.onFileResult({ status: !1, path: { relative: file, absolute: path }, duration: total }), resolve2(!1); }); })) : !1; }, { cwd } = GLOBAL; hasOnly && deepOptions.push("--only"); const runTests = (files) => { let allPassed = !0, activeTests = 0, nextIndex = 0, resolveDone; const { configs } = GLOBAL, showLogs = !configs.quiet, failFastError = ` ${format("\u2139").fail()} ${format("failFast").bold()} is enabled`, totalFiles = files.length, concurrency = (() => { if (configs.sequential || configs.isolation === "none") return 1; const limit = configs.concurrency ?? availableParallelism(); return limit <= 0 ? totalFiles || 1 : limit; })(), done = new Promise((resolve2) => { resolveDone = (passed) => { resolve2(passed); }; }), runNext = async () => { if (nextIndex >= totalFiles && activeTests === 0) { resolveDone(allPassed); return; } if (nextIndex >= totalFiles) return; const filePath = files[nextIndex++]; activeTests++, await runTestFile(filePath) ? ++results.passed : (++results.failed, allPassed = !1, configs.failFast && (showLogs && (hr(), console.error(failFastError), log$1( ` ${format("File:").bold()} ${format(`./${relative(cwd, filePath)}`).fail()}` ), hr()), exit$1(1))), activeTests--, runNext(); }; for (let i = 0; i < concurrency; i++) runNext(); return done; }, exit = (code, quiet) => { const isPoku = results.passed > 0 || results.failed > 0; !quiet && isPoku && GLOBAL.reporter.onExit({ code, timespan, results }), process$1.exitCode = code === 0 ? 0 : 1; }; process$1.on("unhandledRejection", (err) => { err instanceof AssertionError || console.error("unhandledRejection", err), process$1.exitCode = 1; }); process$1.on("uncaughtException", (err) => { err instanceof AssertionError || console.error("uncaughtException", err), process$1.exitCode = 1; }); const regex$2 = { sep: /[/\\]+/g, pathLevel: /(\.\.(\/|\\|$))+/g, unusualChars: /[<>|^?*]+/g, absolutePath: /^[/\\]/, defaultFilter: /\.(test|spec)\./i }, sanitizePath = (input, ensureTarget) => { const sanitizedPath = input.replace(regex$2.sep, sep).replace(regex$2.pathLevel, "").replace(regex$2.unusualChars, ""); return ensureTarget ? sanitizedPath.replace(regex$2.absolutePath, `.${sep}`) : sanitizedPath; }, envFilter = env.FILTER?.trim() ? new RegExp(escapeRegExp(env.FILTER), "i") : void 0, getAllFilesInner = async (dirPath, files, filter, exclude) => { try { if ((await stat(dirPath)).isFile()) { const fullPath = sanitizePath(dirPath); if (fullPath.indexOf("node_modules") !== -1 || fullPath.indexOf(".git/") !== -1) return files; if (states?.isSinglePath) return files.add(fullPath), files; if (exclude) { for (const pattern of exclude) if (pattern.test(fullPath)) return files; } return filter.test(fullPath) && files.add(fullPath), files; } const entries = await readdir(sanitizePath(dirPath), { withFileTypes: !0 }), subdirs = []; for (const entry of entries) { if (entry.name === "node_modules" || entry.name === ".git") continue; const fullPath = join(dirPath, entry.name); exclude?.some((pattern) => pattern.test(fullPath)) || (entry.isFile() ? filter.test(fullPath) && files.add(fullPath) : entry.isDirectory() && subdirs.push(getAllFilesInner(fullPath, files, filter, exclude))); } return subdirs.length > 0 && await Promise.all(subdirs), files; } catch (error) { console.error(error), process.exit(1); } }, getAllFiles = (dirPath, files = /* @__PURE__ */ new Set(), configs) => { const filter = envFilter ?? (configs?.filter instanceof RegExp ? configs.filter : regex$2.defaultFilter), exclude = configs?.exclude ? Array.isArray(configs.exclude) ? configs.exclude : [configs.exclude] : void 0; return getAllFilesInner(dirPath, files, filter, exclude); }, listFiles = async (targetDir, configs) => Array.from(await getAllFiles(sanitizePath(targetDir), /* @__PURE__ */ new Set(), configs)); var listFiles$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, getAllFiles, listFiles, sanitizePath }); const onSigint = () => { stdout.write("\x1B[?25h"); }; process.once("SIGINT", onSigint); const poku = (async (targetPaths, configs) => { configs && (GLOBAL.configs = { ...GLOBAL.configs, ...configs }), env.POKU_RUNTIME = GLOBAL.runtime, typeof GLOBAL.configs.reporter == "string" && (env.POKU_REPORTER = GLOBAL.configs.reporter), timespan.started = /* @__PURE__ */ new Date(); const start = hrtime(), paths = Array.prototype.concat(targetPaths), showLogs = !GLOBAL.configs.quiet, { reporter: plugin } = GLOBAL.configs, { cwd: cwd2 } = GLOBAL; if (typeof plugin == "function") GLOBAL.reporter = plugin(GLOBAL.configs); else if (typeof plugin == "string" && plugin !== "poku") { const { reporter: reporter2 } = await Promise.resolve().then(function() { return reporter$1; }); plugin in reporter2 && (GLOBAL.reporter = reporter2[plugin]()); } const plugins = GLOBAL.configs.plugins; let pluginContext, fileDiscoverer; if (plugins?.length) { pluginContext = { configs: GLOBAL.configs, runtime: GLOBAL.runtime, cwd: GLOBAL.cwd, configFile: GLOBAL.configFile, runAsOnly: GLOBAL.runAsOnly, results, timespan, reporter: GLOBAL.reporter }; for (const plugin2 of plugins) !fileDiscoverer && plugin2.discoverFiles && (fileDiscoverer = plugin2.discoverFiles), plugin2.setup && await plugin2.setup(pluginContext); } const testFiles = fileDiscoverer ? await fileDiscoverer(paths, pluginContext) : (await Promise.all( paths.map((dir) => listFiles(join(cwd2, dir), GLOBAL.configs)) )).flat(1); showLogs && GLOBAL.reporter.onRunStart(); const code = await runTests(testFiles) ? 0 : 1, end = hrtime(start), total = end[0] * 1e3 + end[1] / 1e6; if (timespan.duration = total, timespan.finished = /* @__PURE__ */ new Date(), showLogs && GLOBAL.reporter.onRunResult({ code, timespan, results }), GLOBAL.configs.noExit || exit(code, GLOBAL.configs.quiet), plugins?.length && pluginContext) for (const plugin2 of plugins) plugin2.teardown && await plugin2.teardown(pluginContext); if (GLOBAL.configs.noExit) return code; }), assertProcessor = () => { const { reporter: reporter2 } = GLOBAL, handleSuccess = ({ message }) => { typeof message == "string" && reporter2.onAssertionSuccess({ message }); }, handleError = (error, options) => { throw process$1.exitCode = 1, error instanceof AssertionError && reporter2.onAssertionFailure({ assertOptions: options, error }), error; }; return { processAssert: (cb, options) => { try { cb(), handleSuccess(options); } catch (error) { handleError(error, options); } }, processAsyncAssert: async (cb, options) => { try { await cb(), handleSuccess(options); } catch (error) { handleError(error, options); } } }; }, { processAssert, processAsyncAssert } = assertProcessor(), isPredicate = (value) => typeof value == "function" || value instanceof RegExp || typeof value == "object", createAssert = (nodeAssert2) => { const ok = (value, message) => processAssert(() => nodeAssert2.ok(value), { message }); return Object.assign( ((value, message) => ok(value, message)), { ok, equal: (actual, expected, message) => { processAssert(() => nodeAssert2.equal(actual, expected), { message }); }, deepEqual: (actual, expected, message) => processAssert(() => nodeAssert2.deepEqual(actual, expected), { message }), strictEqual: (actual, expected, message) => processAssert(() => nodeAssert2.strictEqual(actual, expected), { message }), deepStrictEqual: (actual, expected, message) => processAssert(() => nodeAssert2.deepStrictEqual(actual, expected), { message }), doesNotMatch: (value, regExp, message) => { processAssert(() => nodeAssert2.doesNotMatch(value, regExp), { message, actual: "Value", expected: "RegExp", defaultMessage: "Value should not match regExp" }); }, doesNotReject: (async (block, errorOrMessage, message) => { await processAsyncAssert( async () => { isPredicate(errorOrMessage) ? await nodeAssert2.doesNotReject(block, errorOrMessage, message) : await nodeAssert2.doesNotReject(block, message); }, { message: typeof errorOrMessage == "string" ? errorOrMessage : message, defaultMessage: "Got unwanted rejection", hideDiff: !0, throw: !0 } ); }), throws: ((block, errorOrMessage, message) => { isPredicate(errorOrMessage) ? processAssert(() => nodeAssert2.throws(block, errorOrMessage), { message, defaultMessage: "Expected function to throw", hideDiff: !0 }) : processAssert(() => nodeAssert2.throws(block, message), { message: typeof errorOrMessage < "u" ? errorOrMessage : message, defaultMessage: "Expected function to throw", hideDiff: !0 }); }), doesNotThrow: ((block, errorOrMessage, message) => { processAssert( () => { if (isPredicate(errorOrMessage)) nodeAssert2.doesNotThrow(block, errorOrMessage, message); else { const msg = typeof errorOrMessage == "string" ? errorOrMessage : message; nodeAssert2.doesNotThrow(block, msg); } }, { message: typeof errorOrMessage == "string" ? errorOrMessage : message, defaultMessage: "Expected function not to throw", hideDiff: !0, throw: !0 } ); }), notEqual: (actual, expected, message) => processAssert(() => nodeAssert2.notEqual(actual, expected), { message }), notDeepEqual: (actual, expected, message) => processAssert(() => nodeAssert2.notDeepEqual(actual, expected), { message }), notStrictEqual: (actual, expected, message) => processAssert(() => nodeAssert2.notStrictEqual(actual, expected), { message }), notDeepStrictEqual: (actual, expected, message) => processAssert(() => nodeAssert2.notDeepStrictEqual(actual, expected), { message }), match: (value, regExp, message) => { processAssert(() => nodeAssert2?.match(value, regExp), { message, actual: "Value", expected: "RegExp", defaultMessage: "Value should match regExp" }); }, ifError: (value, message) => processAssert(() => nodeAssert2.ifError(value), { message, defaultMessage: "Expected no error, but received an error", hideDiff: !0, throw: !0 }), fail: (message) => { processAssert(() => nodeAssert2.fail(message), { message, defaultMessage: "Test failed intentionally", hideDiff: !0 }), process.exit(1); }, rejects: (async (block, errorOrMessage, message) => { await processAsyncAssert( async () => { if (isPredicate(errorOrMessage)) await nodeAssert2.rejects(block, errorOrMessage, message); else { const msg = typeof errorOrMessage == "string" ? errorOrMessage : message; await nodeAssert2.rejects(block, msg); } }, { message: typeof errorOrMessage == "string" ? errorOrMessage : message, defaultMessage: "Expected promise to be rejected with specified error", hideDiff: !0, throw: !0 } ); }) } ); }, assert = createAssert(nodeAssert), strict = createAssert(nodeAssert$1), each = { before: { status: !0, cb: void 0 }, after: { status: !0, cb: void 0 } }, getTitle = (input) => typeof input == "string" ? input : void 0, getCallback = (input) => typeof input == "function" ? input : void 0, onlyCall = /(?:^|[^.\w$])(?:it|test|describe)\.only\s*\(/, checkOnly = (cb) => typeof cb != "function" ? !1 : onlyCall.test(String(cb)), checkNoOnly = (cb) => typeof cb == "function" && !checkOnly(cb), todo = (async (messageOrCb, _cb) => { const message = typeof messageOrCb == "string" ? messageOrCb : "Planning"; GLOBAL.reporter.onTodoModifier({ message }); }), skip$1 = (async (messageOrCb, _cb) => { const message = typeof messageOrCb == "string" ? messageOrCb : "Skipping"; GLOBAL.reporter.onSkipModifier({ message }); }), createOnlyDescribe = (describeBase2) => (async (messageOrCb, cb) => { if (hasOnly || (log$1( format("Can't run `describe.only` tests without `--only` flag").fail() ), exit$1(1)), checkNoOnly( typeof messageOrCb == "function" ? messageOrCb : cb ) && (GLOBAL.runAsOnly = !0), typeof messageOrCb == "string" && cb) return describeBase2(messageOrCb, cb); if (typeof messageOrCb == "function") return describeBase2(messageOrCb); }), createOnlyIt = (itBase2) => (async (messageOrCb, cb) => { if (hasOnly || (log$1( format( "Can't run `it.only` and `test.only` tests without `--only` flag" ).fail() ), exit$1(1)), typeof messageOrCb == "string" && cb) return itBase2(messageOrCb, cb); if (typeof messageOrCb == "function") return itBase2(messageOrCb); }), SCOPE_HOOKS_KEY = /* @__PURE__ */ Symbol.for("@pokujs/poku.test-scope-hooks"), getScopeHook = () => globalThis[SCOPE_HOOKS_KEY], itBase = async (titleOrCb, callback) => { try { const title = getTitle(titleOrCb), hasTitle = typeof title == "string", cb = getCallback(hasTitle ? callback : titleOrCb); let success = !0, start, end; if (GLOBAL.reporter.onItStart({ title }), hasTitle && indentation.itDepth++, typeof each.before.cb == "function") { const beforeResult = each.before.cb(); beforeResult instanceof Promise && await beforeResult; } const insideDescribe = errorHoist.depth > 0; let onError; insideDescribe ? errorHoist.failed = !1 : (onError = (error) => { process$1.exitCode = 1, success = !1, error instanceof AssertionError || console.error(error); }, process$1.once("uncaughtException", onError), process$1.once("unhandledRejection", onError)), start = process$1.hrtime(); try { const hooks = getScopeHook(); if (hooks) { const holder = hooks.createHolder(); await hooks.runScoped(holder, (params) => cb(params)); } else { const resultCb = cb(); resultCb instanceof Promise && await resultCb; } } catch (error) { process$1.exitCode = 1, success = !1, error instanceof AssertionError || console.error(error); } finally { end = process$1.hrtime(start), onError ? (process$1.removeListener("uncaughtException", onError), process$1.removeListener("unhandledRejection", onError)) : errorHoist.failed && (success = !1, errorHoist.failed = !1); } if (typeof each.after.cb == "function") { const afterResult = each.after.cb(); afterResult instanceof Promise && await afterResult; } if (!title) return; const duration = end[0] * 1e3 + end[1] / 1e6; indentation.itDepth--, GLOBAL.reporter.onItEnd({ title, duration, success }); } catch (error) { if (indentation.itDepth > 0 && indentation.itDepth--, typeof each.after.cb == "function") { const afterResult = each.after.cb(); afterResult instanceof Promise && await afterResult; } throw error; } }, itCore = (async (titleOrCb, cb) => { if (!(GLOBAL.configs.testNamePattern && typeof titleOrCb == "string" && !GLOBAL.configs.testNamePattern.test(titleOrCb)) && !(GLOBAL.configs.testSkipPattern && typeof titleOrCb == "string" && GLOBAL.configs.testSkipPattern.test(titleOrCb)) && !(hasOnly && !GLOBAL.runAsOnly)) { if (typeof titleOrCb == "string" && cb) return itBase(titleOrCb, cb); if (typeof titleOrCb == "function") return itBase(titleOrCb); } }), it = Object.assign(itCore, { todo, skip: skip$1, only: createOnlyIt(itBase) }), test = it, getOptions = (input) => !input || typeof input != "object" ? void 0 : input, describeBase = async (titleOrCb, callbackOrOptions) => { const { reporter: reporter2 } = GLOBAL, title = getTitle(titleOrCb), hasTitle = typeof title == "string", cb = getCallback(hasTitle ? callbackOrOptions : titleOrCb), hasCB = typeof cb == "function", options = hasCB ? void 0 : getOptions(callbackOrOptions); let success = !0, start, end; if (hasTitle && (hasCB ? (reporter2.onDescribeStart({ title }), indentation.describeDepth++) : reporter2.onDescribeAsTitle(title, options)), !hasCB) return; const onError = (error) => { process$1.exitCode = 1, success = !1, errorHoist.failed = !0, error instanceof AssertionError || console.error(error); }, initialExitCode = process$1.exitCode; errorHoist.depth++, process$1.once("uncaughtException", onError), process$1.once("unhandledRejection", onError), start = process$1.hrtime(); try { const resultCb = cb(); resultCb instanceof Promise && await resultCb; } catch (error) { onError(error); } finally { end = process$1.hrtime(start), process$1.removeListener("uncaughtException", onError), process$1.removeListener("unhandledRejection", onError), errorHoist.depth--, process$1.exitCode !== initialExitCode && (success = !1); } if (!title) return; const duration = end[0] * 1e3 + end[1] / 1e6; indentation.describeDepth--, reporter2.onDescribeEnd({ title, duration, success }), GLOBAL.runAsOnly = !1; }, describeCore = (async (messageOrCb, cbOrOptions) => { if (typeof messageOrCb == "string" && typeof cbOrOptions != "function") return describeBase(messageOrCb, cbOrOptions); if (!(hasOnly && !checkOnly( typeof messageOrCb == "function" ? messageOrCb : cbOrOptions ))) { if (typeof messageOrCb == "string" && typeof cbOrOptions == "function") return describeBase(messageOrCb, cbOrOptions); if (typeof messageOrCb == "function") return describeBase(messageOrCb); } }), describe = Object.assign(describeCore, { todo, skip: skip$1, only: createOnlyDescribe(describeBase) }), removeComments = (input) => { let inQuote = !1, quoteChar = ""; for (let i = 0; i < input.length; i++) { const char = input[i]; if (inQuote) char === quoteChar && input[i - 1] !== "\\" && (inQuote = !1); else if (char === '"' || char === "'") inQuote = !0, quoteChar = char; else if (char === "#") return input.slice(0, i).trim(); } return input.trim(); }, parseEnvLine = (line) => { const index = line.indexOf("="); if (index === -1) return null; const arg = line.substring(0, index).trim(), value = line.substring(index + 1).trim().replace(/^['"]|['"]$/g, ""); return { arg, value }; }, resolveEnvVariables = (str, env2) => { let result = "", rangeStart = 0, i = 0; for (; i < str.length; ) if (str[i] === "$" && str[i + 1] === "{") { result += str.slice(rangeStart, i), i += 2; const varStart = i; for (; i < str.length && str[i] !== "}"; ) i++; result += env2[str.slice(varStart, i)] ?? "", i++, rangeStart = i; } else i++; return rangeStart === 0 ? str : (rangeStart < str.length && (result += str.slice(rangeStart)), result); }, regex$1 = { comment: /^\s*#/ }, envFile = async (filePath = ".env") => { const mapEnv = /* @__PURE__ */ new Map(), lines = (await readFile(sanitizePath(filePath), "utf8")).split(` `).map((line) => removeComments(line.trim())).filter((line) => line.length > 0 && !regex$1.comment.test(line)); for (const line of lines) { const parsedLine = parseEnvLine(line); if (parsedLine) { const { arg, value } = parsedLine; mapEnv.set(arg, value && resolveEnvVariables(value, env)); } } for (const [arg, value] of mapEnv) Object.prototype.hasOwnProperty.call(env, arg) || (env[arg] = value); }, skip = (message = "Skipping") => { message && GLOBAL.reporter.onSkipFile({ message }), exit$1(0); }, beforeEach = (callback, options) => (options?.immediate && callback(), each.before.cb = () => { if (each.before.status) return callback(); }, { pause: () => { each.before.status = !1; }, continue: () => { each.before.status = !0; }, reset: () => { each.before.cb = void 0; } }), afterEach = (callback) => (each.after.cb = () => { if (each.after.status) return callback(); }, { pause: () => { each.after.status = !1; }, continue: () => { each.after.status = !0; }, reset: () => { each.after.cb = void 0; } }), regex = { sequentialSpaces: /\s+/ }, setPortsAndPIDs = (portOrPID) => Array.isArray(portOrPID) ? portOrPID : [portOrPID].map((p) => Number(p)).filter((p) => !Number.isNaN(p)), populateRange = (startsAt, endsAt) => { const first = Number(startsAt), last = Number(endsAt); return Array.from({ length: last - first + 1 }, (_, i) => first + i); }, killPID$1 = { unix: (PID) => new Promise((resolve2) => { spawn("kill", ["-9", String(Number(PID))], { shell: !1 }).on("close", () => resolve2(void 0)); }), windows: (PID) => new Promise((resolve2) => { spawn( "taskkill", ["/F", "/T", "/PID", String(Number(PID))], { shell: !1 } ).on("close", () => resolve2(void 0)); }) }, getPIDs$1 = { unix: (port) => new Promise((resolve2) => { const PIDs = /* @__PURE__ */ new Set(), service = spawn( "lsof", ["-t", "-i", `:${Number(port)}`, "-s", "TCP:LISTEN"], { shell: !1 } ); service.stdout.on("data", (data) => { const output = data.toString().trim().split(` `); for (const pid of output) pid && PIDs.add(Number(pid)); }), service.on("close", () => resolve2(Array.from(PIDs))); }), windows: (port) => new Promise((resolve2) => { const PIDs = /* @__PURE__ */ new Set(), service = spawn("netstat", ["-aon"], { shell: !1 }), portMatch = `:${Number(port)}`; service.stdout.on("data", (data) => { const lines = data.toString().trim().trim().split(` `); for (const line of lines) { if (!line.includes(portMatch)) continue; const tokens = line.trim().split(regex.sequentialSpaces), stateIndex = tokens.indexOf("LISTENING"); if (stateIndex !== -1 && tokens[stateIndex + 1]) { const pid = Number(tokens[stateIndex + 1]); Number.isNaN(pid) || PIDs.add(pid); } } }), service.on("close", () => resolve2(Array.from(PIDs))); }) }, getPIDsByPorts = async (port) => { const ports = setPortsAndPIDs(port), PIDs = []; return await Promise.all( ports.map(async (p) => { PIDs.push( ...await (isWindows ? getPIDs$1.windows(p) : getPIDs$1.unix(p)) ); }) ), PIDs; }, getPIDsByRange = (startsAt, endsAt) => { const ports = populateRange(startsAt, endsAt); return getPIDs(ports); }, getPIDs = Object.assign(getPIDsByPorts, { range: getPIDsByRange }), killPID = async (PID) => { const PIDs = setPortsAndPIDs(PID); await Promise.all( PIDs.map(async (p) => { isWindows ? await killPID$1.windows(p) : await killPID$1.unix(p); }) ); }, killPort = async (port) => { const PIDs = await getPIDs(port); for (const PID of PIDs) PID && await killPID(PID); }, killRange = async (startsAt, endsAt) => { const PIDs = await getPIDs.range(startsAt, endsAt); for (const PID of PIDs) PID && await killPID(PID); }, kill = { pid: killPID, port: killPort, range: killRange }, runningProcesses = /* @__PURE__ */ new Map(), backgroundProcess = (runtime, args, file, options) => new Promise((resolve2, reject) => { try { let isResolved = !1; const service = spawn(runtime, args, { stdio: ["inherit", "pipe", "pipe"], env: process$1.env, timeout: options?.timeout, cwd: options?.cwd ? sanitizePath(normalize(options.cwd)) : void 0, shell: !1, detached: !isWindows, windowsHide: isWindows }), PID = service.pid; service.stdout.setEncoding("utf8"), service.stderr.setEncoding("utf8"); const end = (port) => new Promise((resolve22) => { try { if (runningProcesses.delete(PID), isWindows) { kill.pid(PID); return; } if (["bun", "deno"].includes(runtime) || ["bun", "deno"].includes(String(options?.runner)) ? process$1.kill(PID) : process$1.kill(-PID, "SIGKILL"), port) setTimeout(async () => { await kill.port(port), resolve22(void 0); }); else { resolve22(void 0); return; } } catch { resolve22(void 0); return; } }); runningProcesses.set(PID, end); const onData = (data) => { !isResolved && typeof options?.startAfter != "number" && (typeof options?.startAfter > "u" || typeof options?.startAfter == "string" && String(data).includes(options.startAfter)) && (resolve2({ end }), clearTimeout(timeout), isResolved = !0), options?.verbose && log$1(data); }; service.stdout.on("data", onData), service.stderr.on("data", onData), service.on("error", (err) => { end(), reject(`Service failed to start: ${err}`); }), service.on("close", (code) => { code !== 0 && reject(`Service exited with code ${code}`); }); const timeout = setTimeout(() => { isResolved || (end(), reject(`createService: Timeout File: ${file}`)); }, options?.timeout || 6e4); typeof options?.startAfter == "number" && setTimeout(() => { isResolved || (resolve2({ end }), clearTimeout(timeout), isResolved = !0); }, options.startAfter); } catch { } }), startService = (file, options) => { const runtimeOptions = runner(file), runtime = runtimeOptions.shift(), runtimeArgs = [...runtimeOptions, file]; return backgroundProcess( runtime, runtimeArgs, normalize(sanitizePath(file)), options ); }, startScript = (script, options) => { const runner2 = options?.runner ?? "npm", runtimeOptions = scriptRunner(runner2), runtime = runtimeOptions.shift(), runtimeArgs = [...runtimeOptions, script]; return backgroundProcess(runtime, runtimeArgs, script, { ...options, runner: runner2 }); }; process$1.once("SIGINT", async () => { for (const end of runningProcesses.values()) await end(); }); const checkPort = (port, host) => new Promise((resolve2) => { const client = createConnection(port, host); client.on("connect", () => { client.end(), resolve2(!0); }), client.on("error", () => resolve2(!1)); }), sleep = (milliseconds) => { if (!Number.isInteger(milliseconds)) throw new Error("Milliseconds must be an integer."); return new Promise((resolve2) => setTimeout(resolve2, milliseconds)); }, waitForExpectedResult = async (callback, expectedResult, options) => { const delay = options?.