From 7229be677747f527c3a9778fb28b7697bec50cd9 Mon Sep 17 00:00:00 2001 From: Delphine Demeulenaere Date: Mon, 27 Oct 2025 15:14:12 +0100 Subject: [PATCH 1/2] adjust version number --- package-lock.json | 178 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 90 insertions(+), 90 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e09d55..75b4d4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "silverfin-cli", - "version": "1.47.0", + "version": "1.48.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "silverfin-cli", - "version": "1.47.0", + "version": "1.48.0", "license": "MIT", "dependencies": { "axios": "^1.6.2", @@ -47,9 +47,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "dev": true, "license": "MIT", "engines": { @@ -57,21 +57,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -88,14 +88,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -184,9 +184,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -218,13 +218,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -488,18 +488,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -507,14 +507,14 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -547,9 +547,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -610,9 +610,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", - "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", + "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", "dev": true, "license": "MIT", "engines": { @@ -1267,13 +1267,13 @@ } }, "node_modules/@types/node": { - "version": "24.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz", - "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==", + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.12.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/stack-utils": { @@ -1284,9 +1284,9 @@ "license": "MIT" }, "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "version": "17.0.34", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.34.tgz", + "integrity": "sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==", "dev": true, "license": "MIT", "dependencies": { @@ -1563,9 +1563,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz", - "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==", + "version": "2.8.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz", + "integrity": "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1608,9 +1608,9 @@ } }, "node_modules/browserslist": { - "version": "4.26.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz", - "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", "dev": true, "funding": [ { @@ -1628,11 +1628,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.3", - "caniuse-lite": "^1.0.30001741", - "electron-to-chromium": "^1.5.218", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" @@ -1692,9 +1692,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001743", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz", - "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==", + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", "dev": true, "funding": [ { @@ -1812,9 +1812,9 @@ } }, "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, "license": "MIT" }, @@ -2039,9 +2039,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.222", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz", - "integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==", + "version": "1.5.240", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.240.tgz", + "integrity": "sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==", "dev": true, "license": "ISC" }, @@ -3069,9 +3069,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -3608,9 +3608,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -3896,9 +3896,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -4014,9 +4014,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", - "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", "dev": true, "license": "MIT" }, @@ -4478,13 +4478,13 @@ } }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4879,16 +4879,16 @@ } }, "node_modules/undici-types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", - "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", "dev": true, "funding": [ { 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", From df0d7278f97678a60c7238cb90e25d5da646a9c4 Mon Sep 17 00:00:00 2001 From: Delphine Demeulenaere Date: Mon, 27 Oct 2025 15:14:33 +0100 Subject: [PATCH 2/2] implement batch testing --- README.md | 32 ++++++ bin/cli.js | 20 +++- lib/cli/devMode.js | 7 +- lib/liquidTestRunner.js | 161 +++++++++++++++++++++++++---- package-lock.json | 48 ++++----- resources/liquidTests/README.md | 29 ++++++ tests/lib/liquidTestRunner.test.js | 93 +++++++++++++++++ 7 files changed, 339 insertions(+), 51 deletions(-) create mode 100644 tests/lib/liquidTestRunner.test.js diff --git a/README.md b/README.md index 3d6ca9e..fa39822 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,32 @@ You can run the Liquid Tests of a reconciliation using the following command: silverfin run-test --handle ``` +#### Run a specific test + +To run a specific test by name: + +```bash +silverfin run-test --handle --test +``` + +#### Run batch tests (pattern matching) + +To run all tests that contain a specific batch identifier, use the `--batch` option. This is useful when you want to test a group of related tests without running all tests: + +```bash +silverfin run-test --handle --batch +``` + +For example, if you have tests named `unit_3_test_1`, `unit_3_test_2`, `unit_3_test_3`, `unit_4_test_1`, etc., you can run only the tests for unit 3: + +```bash +silverfin run-test --handle --batch "unit_3_" +``` + +This will run all tests that contain the string "unit_3_" in their name (i.e., `unit_3_test_1`, `unit_3_test_2`, and `unit_3_test_3`). + +**Note:** You cannot use both `--test` and `--batch` options at the same time. + ### Updating the CLI Whenever a new version of the CLI is available, you should see a message in your terminal informing it, so you can keep it always up to date. To update the CLI to the latest version, you can run the following command: @@ -259,6 +285,12 @@ There are two different ways to use the `development-mode`: silverfin development-mode --handle ``` +You can also use the `--batch` option with development mode to run only tests matching a specific batch identifier: + +```bash +silverfin development-mode --handle --batch "unit_3_" +``` + - Using the `--update-templates` flag. This will listen for changes in liquid files. Every time a change is saved to a liquid file of a reconciliation or shared part, it will be updated in Silverfin. **Note that this will not run any liquid test, and it will replace the liquid code of your template in Silverfin.** (equivalent to use: `silverfin update-reconciliation --handle ` or `silverfin update-shared-part --shared-part `) ```bash diff --git a/bin/cli.js b/bin/cli.js index d4e826c..c9c2965 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -454,6 +454,7 @@ program .option("-h, --handle ", "Specify the reconciliation to be used (mandatory)") .option("-at, --account-template ", "Specify the account template to be used (mandatory)") .option("-t, --test ", "Specify the name of the test to be run (optional)", "") + .option("-b, --batch ", "Run all tests that contain this batch identifier (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) @@ -465,17 +466,22 @@ program process.exit(1); } + if (options.test && options.batch) { + consola.error("You cannot use both --test and --batch options at the same time"); + process.exit(1); + } + const templateType = options.handle ? "reconciliationText" : "accountTemplate"; const templateName = options.handle ? options.handle : options.accountTemplate; if (options.status) { - liquidTestRunner.runTestsStatusOnly(options.firm, templateType, templateName, options.test); + liquidTestRunner.runTestsStatusOnly(options.firm, templateType, templateName, options.test, options.batch); } 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); + liquidTestRunner.runTestsWithOutput(options.firm, templateType, templateName, options.test, options.previewOnly, options.htmlInput, options.htmlPreview, options.batch); } }); @@ -675,22 +681,28 @@ program .option("-at, --account-template ", "Watch for changes in liquid and yaml files related to the account template mentioned. Run a new Liquid Test on each save") .option("-u, --update-templates", "Watch for changes in any liquid file. Publish the new code of the template into the Platform on each save") .option("-t, --test ", `Specify the name of the test to be run (optional). It has to be used together with "--handle"`, "") + .option("-b, --batch ", `Run all tests that contain this batch identifier (optional). It has to be used together with "--handle" or "--account-template"`, "") .option("--html", `Get a html file of the template's input-view generated with the Liquid Test information (optional). It has to be used together with "--handle"`, false) .option("--yes", "Skip the prompt confirmation (optional)") .action((options) => { cliUtils.checkDefaultFirm(options.firm, firmIdDefault); cliUtils.checkUniqueOption(["handle", "updateTemplates", "accountTemplate"], options); + if (options.test && options.batch) { + consola.error("You cannot use both --test and --batch options at the same time"); + process.exit(1); + } + if (options.updateTemplates && !options.yes) { cliUtils.promptConfirmation(); } if (options.accountTemplate) { - devMode.watchLiquidTest(options.firm, options.accountTemplate, options.test, options.html, "accountTemplate"); + devMode.watchLiquidTest(options.firm, options.accountTemplate, options.test, options.html, "accountTemplate", options.batch); } if (options.handle) { - devMode.watchLiquidTest(options.firm, options.handle, options.test, options.html, "reconciliationText"); + devMode.watchLiquidTest(options.firm, options.handle, options.test, options.html, "reconciliationText", options.batch); } if (options.updateTemplates) { devMode.watchLiquidFiles(options.firm); diff --git a/lib/cli/devMode.js b/lib/cli/devMode.js index 2a5dc3a..6648226 100644 --- a/lib/cli/devMode.js +++ b/lib/cli/devMode.js @@ -13,8 +13,9 @@ const chokidar = require("chokidar"); * @param {String} testName - Test name (empty string to run all tests) * @param {boolean} renderInput - Open browser and show the HTML from input view * @param {String} templateType - Template type (reconciliationText, accountTemplate) + * @param {String} batch - Batch identifier to filter tests (empty string to run all tests) */ -async function watchLiquidTest(firmId, handle, testName, renderInput, templateType) { +async function watchLiquidTest(firmId, handle, testName, renderInput, templateType, batch = "") { if (templateType !== "reconciliationText" && templateType !== "accountTemplate") { consola.error(`Template type is missing or invalid`); process.exit(1); @@ -33,7 +34,7 @@ async function watchLiquidTest(firmId, handle, testName, renderInput, templateTy // Watch YAML chokidar.watch(filePath).on("change", async () => { // Run test - await liquidTestRunner.runTestsWithOutput(firmId, templateType, handle, testName, false, renderInput); + await liquidTestRunner.runTestsWithOutput(firmId, templateType, handle, testName, false, renderInput, false, batch); }); // Watch liquid files @@ -41,7 +42,7 @@ async function watchLiquidTest(firmId, handle, testName, renderInput, templateTy for (const filePath of liquidFiles) { chokidar.watch(filePath).on("change", async () => { // Run test - await liquidTestRunner.runTestsWithOutput(firmId, templateType, handle, testName, false, renderInput); + await liquidTestRunner.runTestsWithOutput(firmId, templateType, handle, testName, false, renderInput, false, batch); }); } } diff --git a/lib/liquidTestRunner.js b/lib/liquidTestRunner.js index 9ade06d..b976507 100644 --- a/lib/liquidTestRunner.js +++ b/lib/liquidTestRunner.js @@ -31,13 +31,58 @@ function findTestRows(testContent) { return indexes; } -function buildTestParams(firmId, templateType, handle, testName = "", renderMode) { - let relativePath = `./reconciliation_texts/${handle}`; - - if (templateType === "accountTemplate") { - relativePath = `./account_templates/${handle}`; +/** + * Filters test YAML content to include only specified test names, preserving formatting + * @param {string} testContent - The full test YAML content + * @param {string[]} testNamesToInclude - Array of test names to include in the filtered result + * @returns {string} - Filtered YAML content containing only the specified tests + */ +function filterTestsByNames(testContent, testNamesToInclude) { + const options = { maxAliasCount: 10000 }; + const testYAML = yaml.parse(testContent, options); + const allTestNames = Object.keys(testYAML); + + const testRows = testContent.split("\n"); + const indexes = findTestRows(testContent); + const filteredLines = []; + + for (let i = 0; i < testNamesToInclude.length; i++) { + const testName = testNamesToInclude[i]; + if (!allTestNames.includes(testName)) { + continue; + } + + const startIndex = indexes[testName]; + + // Find where this test ends (next test starts or end of file) + let endIndex = testRows.length; + for (let j = startIndex + 1; j < testRows.length; j++) { + // Check if we've hit the next test by looking for top-level keys + if (testRows[j] && testRows[j].match(/^[a-zA-Z0-9_-]+:\s*$/)) { + // Make sure this is a test name we know about + const potentialTestName = testRows[j].split(":")[0]; + if (allTestNames.includes(potentialTestName)) { + endIndex = j; + break; + } + } + } + + // Add lines for this test + for (let j = startIndex; j < endIndex; j++) { + filteredLines.push(testRows[j]); + } + + // Add blank line after each test (except the last one) + if (i < testNamesToInclude.length - 1) { + filteredLines.push(""); + } } + + return filteredLines.join("\n"); +} +function buildTestParams(firmId, templateType, handle, testName = "", renderMode, batch = "") { const configPresent = fsUtils.configExists(templateType, handle); if (!configPresent) { @@ -47,7 +92,7 @@ function buildTestParams(firmId, templateType, handle, testName = "", renderMode } const config = fsUtils.readConfig(templateType, handle); - const testPath = `${relativePath}/${config.test}`; + const testPath = path.join(process.cwd(), fsUtils.FOLDERS[templateType], handle, config.test); if (!fs.existsSync(testPath)) { consola.error(`Test file for "${handle}" not found`); @@ -101,6 +146,26 @@ function buildTestParams(firmId, templateType, handle, testName = "", renderMode } testParams.test_line = indexes[testName] + 1; } + + // Filter tests by batch identifier if provided + if (batch) { + const options = { maxAliasCount: 10000 }; + const testYAML = yaml.parse(testContent, options); + const testNames = Object.keys(testYAML); + const matchingTests = testNames.filter((name) => name.includes(batch)); + + if (matchingTests.length === 0) { + consola.error(`No tests found matching batch "${batch}" in template "${handle}"`); + process.exit(1); + } + + consola.info(`Running ${matchingTests.length} test${matchingTests.length > 1 ? "s" : ""} matching batch "${batch}" in template "${handle}"`); + + testParams.tests = filterTestsByNames(testContent, matchingTests); + + consola.debug(`Filtered YAML contains ${matchingTests.length} tests: ${matchingTests.join(", ")}`); + } + return testParams; } @@ -129,12 +194,54 @@ async function fetchResult(firmId, testRunId, templateType) { return testRun; } -function listErrors(items, type) { +function mapFilteredLineToOriginal(testName, filteredLineNumber, originalTestContent, batch) { + // Find where this test starts in the original content + const testIndexes = findTestRows(originalTestContent); + + if (!testIndexes[testName]) { + return filteredLineNumber; // Fallback if test not found + } + + // Recreate the filtered content to find where this test appears in it + const options = { maxAliasCount: 10000 }; + const testYAML = yaml.parse(originalTestContent, options); + const allTestNames = Object.keys(testYAML); + const matchingTests = allTestNames.filter((name) => name.includes(batch)); + + // Get the filtered content with all matching tests + const filteredContent = filterTestsByNames(originalTestContent, matchingTests); + const filteredLines = filteredContent.split("\n"); + + // Find where this specific test starts in the filtered content + let testStartInFiltered = -1; + for (let i = 0; i < filteredLines.length; i++) { + if (filteredLines[i] && filteredLines[i].includes(testName + ":")) { + testStartInFiltered = i + 1; // Convert to 1-based + break; + } + } + + if (testStartInFiltered === -1) { + return testIndexes[testName] + 1; // Fallback to test start in original + } + + // Calculate offset: filtered line number relative to test start in filtered content + const offsetFromTestStart = filteredLineNumber - testStartInFiltered; + + // Return corresponding line in original file + return testIndexes[testName] + 1 + offsetFromTestStart; +} + +function listErrors(items, type, originalTestContent = null, testName = null, batch = null) { const itemsKeys = Object.keys(items); consola.log(chalk.red(`${itemsKeys.length} ${type} expectation${itemsKeys.length > 1 ? "s" : ""} failed`)); itemsKeys.forEach((itemName) => { const itemDetails = items[itemName]; - consola.log(`At line number ${itemDetails.line_number}`); + let lineNumber = itemDetails.line_number; + if (originalTestContent && testName && batch) { + lineNumber = mapFilteredLineToOriginal(testName, lineNumber, originalTestContent, batch); + } + consola.log(`At line number ${lineNumber}`); let gotDataType = typeof itemDetails.got; let expectedDataType = typeof itemDetails.expected; let displayedGot = itemDetails.got; @@ -215,7 +322,7 @@ function checkTestErrorsPresent(testName, testsFeedback) { return errorsPresent; } -function processTestRunResponse(testRun, previewOnly) { +function processTestRunResponse(testRun, previewOnly, originalTestContent = null, batch = null) { // Possible status: started, completed, test_error, internal_error let errorsPresent; switch (testRun.status) { @@ -268,19 +375,23 @@ function processTestRunResponse(testRun, previewOnly) { // Reconciled if (testElements.reconciled !== null) { consola.log(chalk.red("Reconciliation expectation failed")); - consola.log(`At line number ${testElements.reconciled.line_number}`); + let lineNumber = testElements.reconciled.line_number; + if (originalTestContent && batch) { + lineNumber = mapFilteredLineToOriginal(testName, lineNumber, originalTestContent, batch); + } + consola.log(`At line number ${lineNumber}`); consola.log(`got ${chalk.blue.bold(testElements.reconciled.got)} but expected ${chalk.blue.bold(testElements.reconciled.expected)}`); consola.log(""); } // Results if (Object.keys(testElements.results).length > 0) { - listErrors(testElements.results, "result"); + listErrors(testElements.results, "result", originalTestContent, testName, batch); } // Rollforwards if (Object.keys(testElements.rollforwards).length > 0) { - listErrors(testElements.rollforwards, "rollforward"); + listErrors(testElements.rollforwards, "rollforward", originalTestContent, testName, batch); } }); break; @@ -365,17 +476,27 @@ async function handleHTMLfiles(testName = "", testRun, renderMode) { } // Used by VSCode Extension -async function runTests(firmId, templateType, handle, testName = "", previewOnly = false, renderMode = "none") { +async function runTests(firmId, templateType, handle, testName = "", previewOnly = false, renderMode = "none", batch = "") { try { if (templateType !== "reconciliationText" && templateType !== "accountTemplate") { consola.error(`Template type is missing or invalid`); process.exit(1); } - const testParams = buildTestParams(firmId, templateType, handle, testName, renderMode); + const testParams = buildTestParams(firmId, templateType, handle, testName, renderMode, batch); if (!testParams) return; + // Store original test content and batch identifier if batch was used (for line number mapping) + let originalTestContent = null; + if (batch) { + const config = fsUtils.readConfig(templateType, handle); + const testPath = path.join(process.cwd(), fsUtils.FOLDERS[templateType], handle, config.test); + if (fs.existsSync(testPath)) { + originalTestContent = fs.readFileSync(testPath, "utf-8").trim(); + } + } + let testRun = null; let previewRun = null; @@ -392,13 +513,13 @@ async function runTests(firmId, templateType, handle, testName = "", previewOnly testRun = await fetchResult(firmId, testRunId, templateType); } - return { testRun, previewRun }; + return { testRun, previewRun, originalTestContent, batch }; } catch (error) { errorUtils.errorHandler(error); } } -async function runTestsWithOutput(firmId, templateType, handle, testName = "", previewOnly = false, htmlInput = false, htmlPreview = false) { +async function runTestsWithOutput(firmId, templateType, handle, testName = "", previewOnly = false, htmlInput = false, htmlPreview = false, batch = "") { try { if (templateType !== "reconciliationText" && templateType !== "accountTemplate") { consola.error(`Template type is missing or invalid`); @@ -406,10 +527,10 @@ async function runTestsWithOutput(firmId, templateType, handle, testName = "", p } const renderMode = runTestUtils.checkRenderMode(htmlInput, htmlPreview); - const testsRun = await runTests(firmId, templateType, handle, testName, previewOnly, renderMode); + const testsRun = await runTests(firmId, templateType, handle, testName, previewOnly, renderMode, batch); if (!testsRun) return; - processTestRunResponse(testsRun?.testRun || testsRun?.previewRun, previewOnly); + processTestRunResponse(testsRun?.testRun || testsRun?.previewRun, previewOnly, testsRun.originalTestContent, testsRun.batch); if (testsRun.previewRun && testsRun.previewRun.status !== "test_error" && renderMode !== "none") { handleHTMLfiles(testName, testsRun.previewRun, renderMode); @@ -421,14 +542,14 @@ 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, handle, testName = "", batch = "") { 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 testResult = await runTests(firmId, templateType, handle, testName, false, "none", batch); if (!testResult) { status = "PASSED"; diff --git a/package-lock.json b/package-lock.json index 75b4d4c..63481a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -610,9 +610,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.38.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", - "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { @@ -1267,9 +1267,9 @@ } }, "node_modules/@types/node": { - "version": "24.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", - "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "dev": true, "license": "MIT", "dependencies": { @@ -1415,9 +1415,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz", + "integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -1563,9 +1563,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.20", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz", - "integrity": "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==", + "version": "2.8.23", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.23.tgz", + "integrity": "sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1692,9 +1692,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001751", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", - "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "version": "1.0.30001753", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001753.tgz", + "integrity": "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw==", "dev": true, "funding": [ { @@ -2039,9 +2039,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.240", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.240.tgz", - "integrity": "sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==", + "version": "1.5.244", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.244.tgz", + "integrity": "sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==", "dev": true, "license": "ISC" }, @@ -2696,9 +2696,9 @@ } }, "node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", "engines": { @@ -4014,9 +4014,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.26", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", - "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, diff --git a/resources/liquidTests/README.md b/resources/liquidTests/README.md index aa1b06e..19847b5 100644 --- a/resources/liquidTests/README.md +++ b/resources/liquidTests/README.md @@ -1,5 +1,34 @@ # Liquid Testing +## Pattern Matching Example + +The `example_pattern_test.yml` file demonstrates how to use pattern matching to run batches of related tests. + +### Example Usage + +If you have tests organized with naming conventions like: +- `unit_3_test_1`, `unit_3_test_2`, `unit_3_test_3` +- `unit_4_test_1`, `unit_4_test_2` +- `table_test_1`, `table_test_2` + +You can run specific groups of tests using the `--string-pattern` option: + +```bash +# Run all unit 3 tests +silverfin run-test --handle --string-pattern "unit_3_" + +# Run all unit 4 tests +silverfin run-test --handle --string-pattern "unit_4_" + +# Run all table tests +silverfin run-test --handle --string-pattern "table_" +``` + +This feature is useful when: +- You want to test specific functionality (e.g., all table-related tests) +- You're developing a specific unit and want to run only those tests +- You want to run a subset of tests without running the entire test suite + ## [Template name] > Use this Readme file to add extra information about the Liquid Tests that can be performed diff --git a/tests/lib/liquidTestRunner.test.js b/tests/lib/liquidTestRunner.test.js new file mode 100644 index 0000000..830905c --- /dev/null +++ b/tests/lib/liquidTestRunner.test.js @@ -0,0 +1,93 @@ +const yaml = require("yaml"); +const { consola } = require("consola"); + +// Mock consola before requiring the module +jest.mock("consola"); + +describe("liquidTestRunner", () => { + describe("filterTestsByBatch", () => { + // We need to test the filterTestsByBatch function + // Since it's not exported, we'll test it indirectly through buildTestParams + + const sampleYAML = `unit_3_test_1: + context: + period: '2023' + expectation: + reconciled: true + +unit_3_test_2: + context: + period: '2023' + expectation: + reconciled: true + +unit_4_test_1: + context: + period: '2023' + expectation: + reconciled: true + +table_test_1: + context: + period: '2023' + expectation: + reconciled: true`; + + it("should filter tests by batch identifier correctly", () => { + const options = { maxAliasCount: 10000 }; + const testYAML = yaml.parse(sampleYAML, options); + const testNames = Object.keys(testYAML); + + // Test filtering for "unit_3_" + const unit3Tests = testNames.filter((name) => name.includes("unit_3_")); + expect(unit3Tests).toEqual(["unit_3_test_1", "unit_3_test_2"]); + expect(unit3Tests.length).toBe(2); + + // Test filtering for "unit_4_" + const unit4Tests = testNames.filter((name) => name.includes("unit_4_")); + expect(unit4Tests).toEqual(["unit_4_test_1"]); + expect(unit4Tests.length).toBe(1); + + // Test filtering for "table_" + const tableTests = testNames.filter((name) => name.includes("table_")); + expect(tableTests).toEqual(["table_test_1"]); + expect(tableTests.length).toBe(1); + + // Test filtering for "test_1" + const test1Tests = testNames.filter((name) => name.includes("test_1")); + expect(test1Tests).toEqual(["unit_3_test_1", "unit_4_test_1", "table_test_1"]); + expect(test1Tests.length).toBe(3); + }); + + it("should create filtered YAML with only matching tests", () => { + const options = { maxAliasCount: 10000 }; + const testYAML = yaml.parse(sampleYAML, options); + const testNames = Object.keys(testYAML); + + // Filter for "unit_3_" + const matchingTestNames = testNames.filter((name) => name.includes("unit_3_")); + const filteredTests = {}; + matchingTestNames.forEach((testName) => { + filteredTests[testName] = testYAML[testName]; + }); + + const filteredYAML = yaml.stringify(filteredTests, options); + const reparsed = yaml.parse(filteredYAML, options); + + expect(Object.keys(reparsed)).toEqual(["unit_3_test_1", "unit_3_test_2"]); + expect(Object.keys(reparsed).length).toBe(2); + }); + + it("should return empty array when no tests match the batch identifier", () => { + const options = { maxAliasCount: 10000 }; + const testYAML = yaml.parse(sampleYAML, options); + const testNames = Object.keys(testYAML); + + const noMatch = testNames.filter((name) => name.includes("nonexistent_")); + expect(noMatch).toEqual([]); + expect(noMatch.length).toBe(0); + }); + }); +}); + +