UNPKG

@pact-toolbox/test

Version:
158 lines (154 loc) 5.71 kB
import { getNetworkConfig, getSerializableNetworkConfig, isDevNetworkConfig, isPactServerNetworkConfig, resolveConfig } from "@pact-toolbox/config"; import { PactToolboxNetwork } from "@pact-toolbox/network"; import { PactToolboxClient } from "@pact-toolbox/runtime"; import { execAsync, getRandomNetworkPorts, logger } from "@pact-toolbox/utils"; import { join } from "pathe"; import readdir from "tiny-readdir-glob"; import chalk from "chalk"; import ora from "ora"; import { cpus } from "node:os"; //#region src/utils.ts function getConfigOverrides(configOverrides) { if (typeof configOverrides === "string") return { defaultNetwork: configOverrides }; return configOverrides || {}; } function injectNetworkConfig(config) { const network = getSerializableNetworkConfig(config); globalThis.__PACT_TOOLBOX_NETWORK_CONFIG__ = network; } async function updatePorts(config) { const ports = await getRandomNetworkPorts(); const network = getNetworkConfig(config); if (isPactServerNetworkConfig(network)) { if (network.serverConfig) network.serverConfig.port = ports.service; } if (isDevNetworkConfig(network)) { if (network.containerConfig) network.containerConfig.port = ports.service; } return network; } //#endregion //#region src/createTestEnv.ts async function createPactTestEnv({ network, client, config, configOverrides } = {}) { logger.pauseLogs(); if (!config) config = await resolveConfig(configOverrides); if (network) config.defaultNetwork = network; await updatePorts(config); injectNetworkConfig(config); if (!client) client = new PactToolboxClient(config); const localNetwork = new PactToolboxNetwork(config, { client, isDetached: true, logAccounts: false, isStateless: true }); return { start: async () => localNetwork.start(), stop: async () => localNetwork.stop(), restart: async () => localNetwork.restart(), client, config }; } //#endregion //#region src/repl.ts async function runWithConcurrency(items, iteratorFn, concurrency) { const results = []; const running = []; let index = 0; async function run() { if (index >= items.length) return; const i = index++; const item = items[i]; if (!item) return; const promise = iteratorFn(item).then((result) => { results[i] = result; }); running.push(promise); if (running.length >= concurrency) await Promise.race(running); await promise.finally(() => { const promiseIndex = running.indexOf(promise); if (promiseIndex > -1) running.splice(promiseIndex, 1); }); await run(); } const initialRuns = Array.from({ length: Math.min(concurrency, items.length) }, run); await Promise.all(initialRuns); await Promise.all(running); return results; } async function runReplTests(config) { const startTime = Date.now(); if (!config) config = await resolveConfig(); const spinner = ora("Finding REPL tests").start(); const cwd = join(process.cwd(), config.contractsDir); const aborter = new AbortController(); const result = await readdir(`**/*.repl`, { cwd, depth: 20, limit: 1e6, followSymlinks: true, ignore: ["prelude/**"], signal: aborter.signal }); const testFiles = result.files; if (testFiles.length === 0) { spinner.succeed("No REPL tests found."); return; } spinner.info(`${testFiles.length} tests found.`); spinner.start(`Running REPL tests...`); let completed = 0; const runTest = async (file) => { const testStartTime = Date.now(); const cleanedFile = file.replace(cwd, "").substring(1); try { await execAsync(`pact -t ${file}`); const duration = Date.now() - testStartTime; completed++; spinner.text = `[${completed}/${testFiles.length}] Running REPL tests... (${cleanedFile})`; return { filePath: cleanedFile, status: "passed", duration }; } catch (error) { completed++; spinner.text = `[${completed}/${testFiles.length}] Running REPL tests... (${cleanedFile})`; const duration = Date.now() - testStartTime; return { filePath: cleanedFile, status: "failed", error, duration }; } }; const concurrency = Math.max(1, cpus().length - 1); const allResults = await runWithConcurrency(testFiles, runTest, concurrency); spinner.stop(); const totalDuration = Date.now() - startTime; const passedTests = allResults.filter((r) => r.status === "passed"); const failedTests = allResults.filter((r) => r.status === "failed"); console.log("\n"); for (const result$1 of allResults) if (result$1.status === "passed") console.log(`${chalk.green.bold("PASS")} ${result$1.filePath} ${chalk.gray(`(${result$1.duration}ms)`)}`); else console.log(`${chalk.red.bold("FAIL")} ${result$1.filePath} ${chalk.gray(`(${result$1.duration}ms)`)}`); if (failedTests.length > 0) { console.log(`\n${chalk.red.bold("Failed Tests:")}`); for (const test of failedTests) { console.log(`\n${chalk.red.bold("●")} ${test.filePath}`); const errorMessage = test.error?.message ?? "Unknown error"; const cleanedError = errorMessage.includes("Command failed:") ? errorMessage.split("Command failed:")[1]?.trim() ?? "" : errorMessage; console.log(`${chalk.red(cleanedError)}`); } } console.log("\n"); console.log(chalk.bold("REPL Test-runner Summary")); console.log(` ${chalk.bold("Test Suites:")} ${failedTests.length > 0 ? `${chalk.red.bold(`${failedTests.length} failed`)}, ` : ""}${chalk.green.bold(`${passedTests.length} passed`)}, ${allResults.length} total`); console.log(` ${chalk.bold("Time:")} ${(totalDuration / 1e3).toFixed(2)}s`); console.log("\n"); if (failedTests.length > 0) process.exit(1); } //#endregion export { createPactTestEnv, getConfigOverrides, injectNetworkConfig, runReplTests, updatePorts }; //# sourceMappingURL=index.node.mjs.map