diff --git a/bin/cli.js b/bin/cli.js index d4e826c..21511eb 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -451,15 +451,15 @@ program .command("run-test") .description("Run Liquid Tests for a reconciliation template from a YAML file") .requiredOption("-f, --firm ", "Specify the firm to be used", firmIdDefault) - .option("-h, --handle ", "Specify the reconciliation to be used (mandatory)") - .option("-at, --account-template ", "Specify the account template to be used (mandatory)") + .option("-h, --handle ", "Specify one or more reconciliations to be used (mandatory)") + .option("-at, --account-template ", "Specify one or more account templates to be used (mandatory)") .option("-t, --test ", "Specify the name of the test to be run (optional)", "") .option("--html-input", "Get a static html of the input-view of the template generated with the Liquid Test data (optional)", false) .option("--html-preview", "Get a static html of the export-view of the template generated with the Liquid Test data (optional)", false) .option("--preview-only", "Skip the checking of the results of the Liquid Test in case you only want to generate a preview template (optional)", false) .option("--status", "Only return the status of the test runs as PASSED/FAILED (optional)", false) - .action((options) => { + .action(async (options) => { if (!options.handle && !options.accountTemplate) { consola.error("You need to specify either a reconciliation handle or an account template"); process.exit(1); @@ -468,15 +468,32 @@ program const templateType = options.handle ? "reconciliationText" : "accountTemplate"; const templateName = options.handle ? options.handle : options.accountTemplate; + if (!templateName || templateName.length === 0) { + consola.error("You need to provide at least one handle or account template name"); + process.exit(1); + } + + // Block multiple handles/templates without --status + if (templateName.length > 1 && !options.status) { + consola.error("Multiple handles/templates are only allowed when used with the --status flag"); + process.exit(1); + } + if (options.status) { - liquidTestRunner.runTestsStatusOnly(options.firm, templateType, templateName, options.test); - } else { - if (options.previewOnly && !options.htmlInput && !options.htmlPreview) { - consola.info(`When using "--preview-only" you need to specify at least one of the following options: "--html-input", "--html-preview"`); - process.exit(1); - } - liquidTestRunner.runTestsWithOutput(options.firm, templateType, templateName, options.test, options.previewOnly, options.htmlInput, options.htmlPreview); + // Status mode: allow multiple, pass array of template names + await liquidTestRunner.runTestsStatusOnly(options.firm, templateType, templateName, options.test); + return; } + + // Non-status mode: always run a single template, pass string handle/name + const singleTemplateName = templateName[0]; + + if (options.previewOnly && !options.htmlInput && !options.htmlPreview) { + consola.info(`When using "--preview-only" you need to specify at least one of the following options: "--html-input", "--html-preview"`); + process.exit(1); + } + + await liquidTestRunner.runTestsWithOutput(options.firm, templateType, singleTemplateName, options.test, options.previewOnly, options.htmlInput, options.htmlPreview); }); // Create Liquid Test diff --git a/lib/liquidTestRunner.js b/lib/liquidTestRunner.js index 9ade06d..f44bfd2 100644 --- a/lib/liquidTestRunner.js +++ b/lib/liquidTestRunner.js @@ -421,33 +421,57 @@ async function runTestsWithOutput(firmId, templateType, handle, testName = "", p // RETURN (AND LOG) ONLY PASSED OR FAILED // CAN BE USED BY GITHUB ACTIONS -async function runTestsStatusOnly(firmId, templateType, handle, testName = "") { +async function runTestsStatusOnly(firmId, templateType, handles, testName = "") { if (templateType !== "reconciliationText" && templateType !== "accountTemplate") { consola.error(`Template type is missing or invalid`); process.exit(1); } - let status = "FAILED"; - const testResult = await runTests(firmId, templateType, handle, testName, false, "none"); + const runSingleHandle = async (singleHandle) => { + let status = "FAILED"; + const failedTestNames = []; + const testResult = await runTests(firmId, templateType, singleHandle, testName, false, "none"); - if (!testResult) { - status = "PASSED"; - consola.success(status); - return status; - } + if (!testResult) { + status = "PASSED"; + } else { + const testRun = testResult?.testRun; - const testRun = testResult?.testRun; + if (testRun && testRun?.status === "completed") { + const errorsPresent = checkAllTestsErrorsPresent(testRun.tests); + if (errorsPresent === false) { + status = "PASSED"; + } else { + // Extract failed test names + const testNames = Object.keys(testRun.tests).sort(); + testNames.forEach((testName) => { + const testErrorsPresent = checkTestErrorsPresent(testName, testRun.tests); + if (testErrorsPresent) { + failedTestNames.push(testName); + } + }); + } + } + } - if (testRun && testRun?.status === "completed") { - const errorsPresent = checkAllTestsErrorsPresent(testRun.tests); - if (errorsPresent === false) { - status = "PASSED"; - consola.success(status); - return status; + if (status === "PASSED") { + consola.log(`${singleHandle}: ${status}`); + } else { + consola.log(`${singleHandle}: ${status}`); + // Display failed test names + failedTestNames.forEach((testName) => { + consola.log(` ${testName}: FAILED`); + }); } - } - consola.error(status); - return status; + + return { handle: singleHandle, status, failedTestNames }; + }; + + const results = await Promise.all(handles.map(runSingleHandle)); + + const overallStatus = results.every((result) => result.status === "PASSED") ? "PASSED" : "FAILED"; + + return overallStatus; } module.exports = { diff --git a/package.json b/package.json index c05da0f..6c39a3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "silverfin-cli", - "version": "1.47.0", + "version": "1.48.0", "description": "Command line tool for Silverfin template development", "main": "index.js", "license": "MIT",