diff --git a/README.md b/README.md index 7040bef..6478d5c 100644 --- a/README.md +++ b/README.md @@ -83,10 +83,7 @@ npm run tap-arc.simple # used to create the screen shot above ### Dev Tips -1. `./test/smoke.js` contains the bare minimum usage of `tap-parser` with `process.stdin`. -Helpful for understanding `tap-parser`'s behavior. - -2. To see previous exit code, run: +1. To see previous exit code, run: ```sh echo $? @@ -101,12 +98,12 @@ Testing could be improved by unit testing the printer and diff maker. ## FAQ
-"Expected n assertions, but found < n" +"Expected n tests, but found < n" _What happened?_ ✅ The TAP parser found zero failing tests ✅ The final tally from the raw TAP shows `n` of `n` passed -🤨 But the TAP plan called for more assertions than were found, counted, and parsed. +🤨 But the TAP plan called for more tests than were found, counted, and parsed. 💁‍♀️ Currently, when this case is detected, `tap-arc` will exit with a successful status code. This can be overridden with the `--fail-bad-count` flag. @@ -138,4 +135,3 @@ If you'd like to see different behavior from `tap-arc`, please open an issue or - [tap-spec](https://github.com/scottcorgan/tap-spec) ol' reliable, but a bit stale and vulnerable - [tap-difflet](https://github.com/namuol/tap-difflet) inspired output and diffing, also vulnerable -- [tap-min](https://github.com/derhuerst/tap-min) helpful approaches to streaming and exit codes, used to report `tap-arc`'s TAP diff --git a/package-lock.json b/package-lock.json index 1d53d3d..2c57d30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,20 @@ { "name": "tap-arc", - "version": "1.1.0", + "version": "1.2.0-RC.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tap-arc", - "version": "1.1.0", + "version": "1.2.0-RC.0", "license": "Apache-2.0", "dependencies": { "chalk": "^5.3.0", "diff": "^5.1.0", - "duplexer3": "^1.0.0", "json5": "^2.2.3", "minimist": "^1.2.8", "strip-ansi": "^7.1.0", - "tap-parser": "^15.2.1" + "tap-reader": "^0.0.8" }, "bin": { "tap-arc": "src/index.js" @@ -24,8 +23,7 @@ "@architect/eslint-config": "^2.1.2", "@types/node": "^16.18.55", "eslint": "^8.51.0", - "tap-min": "^3.0.0", - "tape": "5.7.0" + "tape": "^5.7.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -155,10 +153,13 @@ } }, "node_modules/@ljharb/through": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.9.tgz", - "integrity": "sha512-yN599ZBuMPPK4tdoToLlvgJB4CLK8fGl7ntfy0Wn7U6ttNvHYurd81bfUiK/6sMkiIwm65R6ck4L6+Y3DfVbNQ==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", + "integrity": "sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, "engines": { "node": ">= 0.4" } @@ -569,9 +570,9 @@ "dev": true }, "node_modules/define-data-property": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", - "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", "dev": true, "dependencies": { "get-intrinsic": "^1.2.1", @@ -640,17 +641,6 @@ "ignored": "bin/ignored" } }, - "node_modules/duplexer3": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-1.0.0.tgz", - "integrity": "sha512-6O5ndCyJ9CGF9cR2Yi3VFq1OvXXLEgX848InIOl8xUBPYwb8jn/93j10lGaZyLnMRa71IT5OHhURlOiVjH9OVg==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/es-abstract": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", @@ -1098,14 +1088,6 @@ "node": ">=0.10.0" } }, - "node_modules/events-to-array": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-2.0.3.tgz", - "integrity": "sha512-f/qE2gImHRa4Cp2y1stEOSgw8wTFyUdVJX7G//bMwbaV9JqISFxg99NbmVQeP7YLnDUZ2un851jlaDrlpmGehQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1197,10 +1179,13 @@ "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.6", @@ -1440,15 +1425,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hirestime": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/hirestime/-/hirestime-7.0.3.tgz", - "integrity": "sha512-XmjAwwjLJlDjVVljWht/+Pb6vTfs6A0z2ZpaCkVmzEkwiZcO/+lbj1DsxpsDvkVprYHCmNBxTr7tUohdlxG2Hw==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -1951,16 +1927,21 @@ } }, "node_modules/mock-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mock-property/-/mock-property-1.0.0.tgz", - "integrity": "sha512-imC60k5A55GPUU43PqczbubOyyxCudIgneACKzL3PKfsBk08dc1HgNNU8siQbEIAPPjVUhc+gb0v0ypZ/iP9pw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mock-property/-/mock-property-1.0.2.tgz", + "integrity": "sha512-GHVKHd3bFiXtvZtp23+8+EQLMeDJWcEVrSA2pOBs1KB5Uh2ww8Q+9fYDljS67k3GzU4DIDBa6+qRIgfZ2Bp+gQ==", "dev": true, "dependencies": { - "functions-have-names": "^1.2.2", + "define-data-property": "^1.1.0", + "functions-have-names": "^1.2.3", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "isarray": "^2.0.5" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1978,9 +1959,9 @@ "dev": true }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz", + "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2143,18 +2124,6 @@ "node": ">=6" } }, - "node_modules/parse-ms": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", - "integrity": "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2197,21 +2166,6 @@ "node": ">= 0.8.0" } }, - "node_modules/pretty-ms": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-8.0.0.tgz", - "integrity": "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==", - "dev": true, - "dependencies": { - "parse-ms": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -2268,9 +2222,9 @@ } }, "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -2547,86 +2501,22 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tap-min": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tap-min/-/tap-min-3.0.0.tgz", - "integrity": "sha512-oEhFyYCUEmRLYwtlIkRgeVkX538yEQfoSg6BcWXMq05TFsnpsi3vtQZJeEBkXzMWlj1h/rKaRMaWPCvCTmIIXg==", - "dev": true, - "dependencies": { - "chalk": "^5.3.0", - "duplexer3": "^1.0.0", - "hirestime": "^7.0.3", - "pretty-ms": "^8.0.0", - "tap-parser": "^13.0.2-1" - }, - "bin": { - "tap-min": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tap-min/node_modules/tap-parser": { - "version": "13.0.2-1", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-13.0.2-1.tgz", - "integrity": "sha512-A6U6TvfwEUFVivyZFiTth3LVrGw9aa4j4cSU8W6ui3sfrZBRNzE1y5YhBomz0+RIRURdspFJdaJvVgSXI68h0Q==", - "dev": true, - "dependencies": { - "events-to-array": "^2.0.3", - "tap-yaml": "2.1.1-1" - }, - "bin": { - "tap-parser": "bin/cmd.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/tap-min/node_modules/tap-yaml": { - "version": "2.1.1-1", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.1.1-1.tgz", - "integrity": "sha512-acWZWpwstr0YMms30FW2nlFkJ0hSm/o2x32Hq5v10IKqYKwnRXARSx6TKbz/gzcSoODPi9PkFQYGYBgowxKDfA==", - "dev": true, - "dependencies": { - "yaml": "^2.3.0", - "yaml-types": "^0.3.0" - } - }, - "node_modules/tap-parser": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-15.2.1.tgz", - "integrity": "sha512-9163zwEecM7sYJyknuRznN7PGncke6CG5Ybat9xigg7ppTsQc5eO9J69tAG2ISM244hIbqv9H6SQ1jRUa9AvBA==", - "dependencies": { - "events-to-array": "^2.0.3", - "tap-yaml": "2.2.0" - }, + "node_modules/tap-reader": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/tap-reader/-/tap-reader-0.0.8.tgz", + "integrity": "sha512-4nEq3AewWwZZWRhBvbOH+7awP1Mgt6euJC6daAGjLDJy0Jo6pGWRc43VkHPzL9ZqZnhyPCmgwpATwZibS4StPQ==", "bin": { - "tap-parser": "bin/cmd.cjs" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/tap-yaml": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.0.tgz", - "integrity": "sha512-o8I7WDNiGpuF04tGAVaNYY5rX9waCtqw9A7Y0YVSQBGcFwNUJWUPLkr2lbhgLRTxc+Tpnw4xUXlIanZc+ZAGnw==", - "dependencies": { - "yaml": "^2.3.0", - "yaml-types": "^0.3.0" - }, - "engines": { - "node": ">=16" + "tap-reader": "src/index.js" } }, "node_modules/tape": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/tape/-/tape-5.7.0.tgz", - "integrity": "sha512-6EZoHjMDUUhet8+k32w/9onULL1U8idXKvBCnZxuZF2iFe+tMYOsKo4bpCtXbTSngZmYBnkU08TMhJwsKaHhaw==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/tape/-/tape-5.7.1.tgz", + "integrity": "sha512-5U2nU0PbvWXXtJxE0hFv78VSyhJiyEPq1wNtMCWUxt17SZbeBqs9V5zcyDqkyguYN39d8qAjZxfFkjJ1+kB4yA==", "dev": true, "dependencies": { "@ljharb/resumer": "^0.0.1", - "@ljharb/through": "^2.3.9", + "@ljharb/through": "^2.3.11", "array.prototype.every": "^1.1.5", "call-bind": "^1.0.2", "deep-equal": "^2.2.2", @@ -2645,7 +2535,7 @@ "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "resolve": "^2.0.0-next.4", + "resolve": "^2.0.0-next.5", "string.prototype.trim": "^1.2.8" }, "bin": { @@ -2656,12 +2546,12 @@ } }, "node_modules/tape/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -2886,26 +2776,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/yaml": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", - "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/yaml-types": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/yaml-types/-/yaml-types-0.3.0.tgz", - "integrity": "sha512-i9RxAO/LZBiE0NJUy9pbN5jFz5EasYDImzRkj8Y81kkInTi1laia3P3K/wlMKzOxFQutZip8TejvQP/DwgbU7A==", - "engines": { - "node": ">= 16", - "npm": ">= 7" - }, - "peerDependencies": { - "yaml": "^2.3.0" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 8c40f94..e175135 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "tap-arc", "description": "spec-like TAP reporter", "author": "tbeseda", - "version": "1.1.0", + "version": "1.2.0-RC.0", "license": "Apache-2.0", "type": "module", "main": "src/index.js", @@ -47,24 +47,22 @@ "tape.throws": "tape test/mock/create-throws-tap.cjs", "tape.upstream-error": "tape test/mock/create-upstream-error-tap.cjs", "tape.runtime-error": "tape test/mock/create-runtime-error-tap.js", - "tape": "tape test/**/*-test.js | tap-min", + "tape": "tape test/**/*-test.js", "test": "npm run lint && npm run tape" }, "dependencies": { "chalk": "^5.3.0", "diff": "^5.1.0", - "duplexer3": "^1.0.0", "json5": "^2.2.3", "minimist": "^1.2.8", "strip-ansi": "^7.1.0", - "tap-parser": "^15.2.1" + "tap-reader": "^0.0.8" }, "devDependencies": { "@architect/eslint-config": "^2.1.2", "@types/node": "^16.18.55", "eslint": "^8.51.0", - "tap-min": "^3.0.0", - "tape": "5.7.0" + "tape": "^5.7.1" }, "eslintConfig": { "extends": "@architect/eslint-config", diff --git a/src/_printer.js b/src/_printer.js index d661b52..1420b1d 100644 --- a/src/_printer.js +++ b/src/_printer.js @@ -1,23 +1,24 @@ import { Chalk } from 'chalk' -const RIGHT = '↦' +const RIGHT = '⇥' const CHECK = '✓' const CROSS = '✗' +const BOX = '␣' function prettyMs (start) { const ms = Date.now() - start return ms < 1000 ? `${ms} ms` : `${ms / 1000} s` } -export default function (options) { +export default function (output, options) { const { color, debug, verbose } = options const d = debug || verbose const { blue, bold, - cyan, dim, green, + italic, red, yellow, } = new Chalk({ level: color ? 3 : 0 }) @@ -26,26 +27,34 @@ export default function (options) { const actual = blue const passMark = bold.green(CHECK) const failMark = bold.red(CROSS) - const skipMark = RIGHT + const skipMark = bold.cyan(RIGHT) + const todoMark = bold.cyan(BOX) function pad (n = 1, c = ' ') { return dim(c).repeat(n) } + /** + * Print a line to the output stream + * @param {string} str + * @param {number} p padding + * @param {number} n newlines + * @returns void + */ + function print (str, p = 0, n = 1) { + output.write(`${pad(p)}${str}${'\n'.repeat(n)}`) + } + return { - pass ({ id, name }) { - return `${passMark}${d ? ` [${id}]` : ''} ${dim(name)}` - }, - fail ({ id, name, tapError }) { - return `${failMark} ${tapError ? red(`"${tapError}"`) : `[${id}] ${red(name)}`}` - }, - skip ({ id, name }) { - return cyan(`${skipMark}${d ? ` [${id}]` : ''} ${name}`) + pass ({ id, desc, skip, todo, reason }) { + const mark = skip ? skipMark : todo ? todoMark : passMark + return `${mark}${reason ? ` - ${reason}` : ''}${d ? ` [${id}]` : ''} ${dim(desc)}` }, - todo ({ id, name, ok: pass }) { - const method = pass ? dim : red - return method(`${skipMark}${d ? ` [${id}]` : ''} ${name}`) + fail ({ id, desc, skip, todo, reason }) { + const mark = skip ? skipMark : todo ? todoMark : failMark + return `${mark}${reason ? ` - ${reason}` : ''} [${id}] ${red(desc)}` }, + print, pad, prettyMs, actual, @@ -54,6 +63,7 @@ export default function (options) { dim, expected, good: green, + italic, strong: bold, title: bold.underline, } diff --git a/src/index.js b/src/index.js index b08538b..f89b356 100755 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ #!/usr/bin/env node import minimist from 'minimist' import helpText from './_help-text.js' -import tapArc from './tap-arc.js' +import TapArc from './tap-arc.js' const alias = { help: [ 'h', 'help' ], @@ -18,6 +18,7 @@ const defaultOptions = { pessimistic: false, failBadCount: false, verbose: false, + tap: false, debug: false, } const options = { @@ -30,25 +31,14 @@ if (options.help) { process.exit() } -const parser = tapArc(options) -// @ts-ignore - DuplexWrapper is not typed -parser.on('end', () => { - // @ts-ignore - const { results } = parser._writable +const tapArc = TapArc(process.stdin, process.stdout, options) - if (!results.ok) { - if ( - results.badCount && - results.failures.length === 0 && - !options.failBadCount - ) process.exit(0) - else process.exit(1) - } - if ( - results.count === 0 && - results.plan.comment.indexOf('no tests found') >= 0 - ) process.exit(1) +let badCount = false +tapArc.on('badCount', () => { + badCount = true }) -// @ts-ignore -process.stdin.pipe(parser).pipe(process.stdout) +tapArc.on('end', ({ ok }) => { + if (badCount && options.failBadCount) process.exit(1) + else process.exit(ok ? 0 : 1) +}) diff --git a/src/tap-arc.js b/src/tap-arc.js index fce0fa7..65ea3ec 100644 --- a/src/tap-arc.js +++ b/src/tap-arc.js @@ -1,75 +1,53 @@ -import { Parser } from 'tap-parser' -import { PassThrough } from 'stream' -import duplexer from 'duplexer3' // TODO: write a custom, simpler duplexer +import TapReader from 'tap-reader' import JSON5 from 'json5' import stripAnsi from 'strip-ansi' -import differ from './_make-diff.js' +import createDiffer from './_make-diff.js' import createPrinter from './_printer.js' const { parse } = JSON5 -const reservedCommentPrefixes = [ 'tests ', 'pass ', 'skip', 'todo', 'fail ', 'failed ', 'ok', 'test count' ] - -export default function createParser (options) { - const { debug, pessimistic, showDiff, verbose } = options - const output = new PassThrough() - const parser = new Parser({ bail: pessimistic }) - const stream = duplexer(parser, output) - const _ = createPrinter(options) - const { prettyMs, pad } = _ - const { diffArray, diffObject, diffString } = differ(_) - - /** - * Print a line to the output stream - * @param {string} str - * @param {number} p padding - * @param {number} n newlines - * @returns void - */ - function P (str, p = 0, n = 1) { - output.write(`${pad(p)}${str}${'\n'.repeat(n)}`) - } +const tapeCommentPrefixes = [ 'tests ', 'pass ', 'skip', 'todo', 'fail ', 'failed ', 'ok', 'test count' ] + +export default function createParser (input, output, options = {}) { + const { debug, pessimistic, showDiff, tap, verbose } = options + + const _ = createPrinter(output, options) + const { print: P, prettyMs } = _ + const { diffArray, diffObject, diffString } = createDiffer(_) + + const reader = TapReader({ input, bail: pessimistic }) const cwd = process.cwd() const start = Date.now() - const counter = { - pass: 0, - skip: 0, - todo: 0, - fail: 0, - } + const counter = { pass: 0, fail: 0, skip: 0, todo: 0 } - parser.on('comment', (comment) => { - if (!reservedCommentPrefixes.some((c) => comment.startsWith(c, 2))) { + reader.on('comment', ({ comment }) => { + if (!tapeCommentPrefixes.some((c) => comment.startsWith(c))) { // "comment" is generally a test group name - P(`\n${_.title(comment.trimEnd().replace(/^(# )/, ''))}`) + P(`\n${_.title(comment)}`) } }) - parser.on('extra', (extra) => { + reader.on('other', ({ line }) => { // typically `console.log` output from the test or program it tests - const stripped = stripAnsi(extra).trim() - const justAnsi = stripped.length === 0 && extra.length > 0 - if (!justAnsi) P(extra, 0, 0) + const stripped = stripAnsi(line).trim() + const justAnsi = stripped.length === 0 && line.length > 0 + if (!justAnsi) P(_.italic(line), 0) }) - parser.on('pass', (test) => { + reader.on('pass', (test) => { counter.pass++ - P(_.pass(test), 2) - }) - - parser.on('skip', (test) => { - counter.skip++ - P(_.skip(test), 2) - }) + if (test.skip) counter.skip++ + if (test.todo) counter.todo++ - parser.on('todo', (test) => { - counter.todo++ - P(_.todo(test), 2) + P(_.pass(test), 2) }) - parser.on('fail', (test) => { + reader.on('fail', (test) => { counter.fail++ + if (test.skip) counter.skip++ + if (test.todo) counter.todo++ + P(_.fail(test), 2) if (test.diag) { @@ -144,9 +122,9 @@ export default function createParser (options) { case 'throws': if ( actual - && typeof actual !== 'undefined' - && expected - && typeof expected !== 'undefined' + && typeof actual !== 'undefined' + && expected + && typeof expected !== 'undefined' ) // this weird combination is throws with expected/assertion P(`Expected ${_.expected(expected)} to match "${_.actual(actual.message || actual)}"`, indent) else if (actual && typeof actual !== 'undefined') // this combination is usually "doesNotThrow" @@ -175,71 +153,59 @@ export default function createParser (options) { } }) - parser.on('complete', (result) => { - if (!result.ok) { - const tapFailures = result.failures.filter((f) => f.tapError) - for (const tapFailure of tapFailures) { - const { tapError } = tapFailure - - if (tapError.startsWith('incorrect number of tests')) { - // custom failure was created by tap-parser - P(_.realBad(`\nExpected ${result.plan.end || '?'} assertions, parsed ${result.count || '?'}`)) - result.badCount = true // persisted to CLI process handler - result.failures.shift() - result.fail-- - } - else if (tapError.startsWith('no plan')) - P(_.realBad(`\nTAP test plan not found`)) - else - P(_.realBad(`\n${tapError}`)) - } + reader.on('done', ({ summary, plan, passing, failures, ok }) => { + if (summary && plan && summary.total < plan.end) { + P(_.realBad(`\nExpected ${plan.end} tests, parsed ${summary.total}`)) + reader.emit('badCount', { summary, plan }) + } - if (result.failures.length > 0) { - const singular = result.fail === 1 + if (!ok) { + if (summary.fail > 0) { + const singular = summary.fail === 1 let failureSummary = '\n' failureSummary += _.bad('Failed tests:') failureSummary += ` There ${singular ? 'was' : 'were'} ` - failureSummary += _.bad(result.fail) + failureSummary += _.bad(summary.fail) failureSummary += ` failure${singular ? '' : 's'}\n` P(failureSummary) - for (const test of result.failures) P(_.fail(test), 2) + for (const test in failures) P(_.fail(failures[test]), 2) } } - P(`\ntotal: ${result.count}`) - if (result.bailout) P(_.realBad('BAILED!')) - if (result.pass > 0) P(_.good(`passing: ${result.pass}`)) - if (result.fail > 0) P(_.bad(`failing: ${result.fail}`)) - if (result.skip > 0) P(`skipped: ${result.skip}`) - if (result.todo > 0) P(`todo: ${result.todo}`) + P(`\ntotal: ${summary.total}`) + // if (result.bailout) P(_.realBad('BAILED!')) + if (summary.pass > 0) P(_.good(`passing: ${summary.pass}`)) + if (summary.fail > 0) P(_.bad(`failing: ${summary.fail}`)) + if (summary.skip > 0) P(_.dim(`skipped: ${summary.skip}`)) + if (summary.todo > 0) P(_.dim(`todo: ${summary.todo}`)) + + P(`${_.dim.italic(prettyMs(start))}\n`) // maybe output.end()? if (debug) { - P('tap-parser result:') - P(JSON.stringify(result, null, 2)) + P('tap-reader result:') + P(JSON.stringify({ summary, passing, failures, ok }, null, 2)) P('tap-arc internal counters:') P(JSON.stringify(counter, null, 2)) } - - output.end(`${_.dim(prettyMs(start))}\n`) }) if (verbose) { - parser.on('version', (version) => { + reader.on('version', ({ version }) => { P(`${_.strong('TAP version:')} ${version}`) }) - parser.on('plan', (plan) => { - const { start, end, comment } = plan - P(`${_.strong('Plan:')} start=${start} end=${end} ${comment ? `"${comment}"` : ''}`) + reader.on('plan', ({ plan, bad }) => { + const [ start, end ] = plan + P(`${_.strong('Plan:')} start=${start} end=${end} ${bad ? '(BAD)' : ''}`) }) } - if (debug) { - parser.on('line', (line) => { + if (tap) { + reader.on('line', ({ line }) => { P(line.trim()) }) } - return stream + return reader } diff --git a/test/exit-codes-test.js b/test/exit-codes-test.js index 47b9706..d3d3f88 100644 --- a/test/exit-codes-test.js +++ b/test/exit-codes-test.js @@ -1,6 +1,7 @@ import { exec } from 'child_process' import { join } from 'path' import test from 'tape' +import stripAnsi from 'strip-ansi' const mockPath = join('.', 'test', 'mock') @@ -30,7 +31,7 @@ test('streams and exit codes', (t) => { exec( `npx tape ${join(mockPath, filename)} | node src/index.js`, (error, stdout, stderr) => { - t.ok(error, `"${filename}" creates an error`) + t.notOk(error, `"${filename}" doesn't create an error`) t.ok(stderr, 'stderror should not be empty') t.ok(stdout.indexOf('total: 0') > 0, '"total: 0" should occur in output') } @@ -56,41 +57,43 @@ test('streams and exit codes', (t) => { }) } - const badCountPassing = 'missing-assertions-passing.txt' + const badCountPassing = 'missing-assertions-passing.tap' + const badCountFailing = 'missing-assertions-failing.tap' + t.test(`exit(0) "${badCountPassing}" | tap-arc`, (t) => { t.plan(3) exec( - `cat ${join(mockPath, badCountPassing)} | node src/index.js`, + `cat ${join(mockPath, 'tape', badCountPassing)} | node src/index.js`, (error, stdout, stderr) => { t.notOk(error, `"${badCountPassing}" exits without error`) t.notOk(stderr, 'stderror should be empty') t.ok( - stdout.indexOf('Expected 16 assertions, parsed 13') > 0, - '"Expected 16 assertions, parsed 13" should occur in output', + stripAnsi(stdout).indexOf('Expected 16 tests, parsed 13') > 0, + '"Expected 16 tests, parsed 13" should occur in output', ) } ) }) + t.test(`exit(1) "${badCountPassing}" | tap-arc --fail-bad-count`, (t) => { t.plan(3) exec( - `cat ${join(mockPath, badCountPassing)} | node src/index.js --fail-bad-count`, + `cat ${join(mockPath, 'tape', badCountPassing)} | node src/index.js --fail-bad-count`, (error, stdout, stderr) => { - t.ok(error, `"${badCountFailing}" creates an error`) + t.ok(error, `"${badCountPassing}" creates an error`) t.notOk(stderr, 'stderror should be empty') t.ok( - stdout.indexOf('Expected 16 assertions, parsed 13') > 0, - '"Expected 16 assertions, parsed 13" should occur in output', + stdout.indexOf('Expected 16 tests, parsed 13') > 0, + '"Expected 16 tests, parsed 13" should occur in output', ) } ) }) - const badCountFailing = 'missing-assertions-failing.txt' t.test(`exit(1) "${badCountFailing}" | tap-arc`, (t) => { t.plan(3) exec( - `cat ${join(mockPath, badCountFailing)} | node src/index.js`, + `cat ${join(mockPath, 'tape', badCountFailing)} | node src/index.js`, (error, stdout, stderr) => { t.ok(error, `"${badCountFailing}" creates an error`) t.notOk(stderr, 'stderror should be empty') diff --git a/test/formatting-test.js b/test/formatting-test.js index 367c08b..7299d98 100644 --- a/test/formatting-test.js +++ b/test/formatting-test.js @@ -3,55 +3,186 @@ import test from 'tape' import tapArc from '../src/tap-arc.js' const TAP = { - IN: { - comment: '# Comment', - ok: 'ok 1 should be truthy', - notOk: 'not ok 2 should be falsy', - plan: '1..2', - planTests: '# tests 2', - planPass: '# pass 1', - planFail: '# fail 1', - }, + IN: [ + 'TAP version 13', + '# Sample passing tests', + 'ok 1 Regex: match pass', + 'Arbitrary logs supported', + 'ok 2 Regex: doesNotMatch pass', + 'ok 3 A deeply equal array', + 'ok 4 A skipped test # SKIP', + 'ok 5 A deeply equal object', + '# TODO Some tests marked as "todo"', + 'ok 6 A passing TODO # TODO', + 'not ok 7 A failing TODO # TODO', + ' ---', + ' operator: fail', + ' at: Test. (/test/mock/create-simple-tap.cjs:19:7)', + ' ...', + '# Some failing tests', + 'not ok 8 should be strictly equal', + ' ---', + ' operator: equal', + ' expected: 666', + ' actual: 66', + ' at: Test. (/test/mock/create-simple-tap.cjs:27:5)', + ' stack: |-', + ' Error: should be strictly equal', + ' at Test.assert [as _assert] (/node_modules/tape/lib/test.js:479:48)', + ' at Test.strictEqual (/node_modules/tape/lib/test.js:643:7)', + ' at Test. (/test/mock/create-simple-tap.cjs:27:5)', + ' at Test.run (/node_modules/tape/lib/test.js:113:28)', + ' at Immediate.next [as _onImmediate] (/node_modules/tape/lib/results.js:157:7)', + ' at process.processImmediate (node:internal/timers:476:21)', + ' ...', + 'not ok 9 should be strictly equal', + ' ---', + ' operator: equal', + ' expected: \'Good dog\'', + ' actual: \'Bad dog\'', + ' at: Test. (/test/mock/create-simple-tap.cjs:28:5)', + ' stack: |-', + ' Error: should be strictly equal', + ' at Test.assert [as _assert] (/node_modules/tape/lib/test.js:479:48)', + ' at Test.strictEqual (/node_modules/tape/lib/test.js:643:7)', + ' at Test. (/test/mock/create-simple-tap.cjs:28:5)', + ' at Test.run (/node_modules/tape/lib/test.js:113:28)', + ' at Immediate.next [as _onImmediate] (/node_modules/tape/lib/results.js:157:7)', + ' at process.processImmediate (node:internal/timers:476:21)', + ' ...', + 'not ok 10 Regex: match fail', + ' ---', + ' operator: match', + ' expected: /^A/', + ' actual: \'atreides\'', + ' at: Test. (/test/mock/create-simple-tap.cjs:29:5)', + ' stack: |-', + ' Error: Regex: match fail', + ' at Test.assert [as _assert] (/node_modules/tape/lib/test.js:479:48)', + ' at Test.match (/node_modules/tape/lib/test.js:900:8)', + ' at Test. (/test/mock/create-simple-tap.cjs:29:5)', + ' at Test.run (/node_modules/tape/lib/test.js:113:28)', + ' at Immediate.next [as _onImmediate] (/node_modules/tape/lib/results.js:157:7)', + ' at process.processImmediate (node:internal/timers:476:21)', + ' ...', + '# Nested tests', + 'not ok 11 Sub-test partial array failure', + ' ---', + ' operator: deepEqual', + ' expected: [ \'foo\', \'bar\', \'foobar baz\' ]', + ' actual: [ \'foo\', \'bar\', \'baz\' ]', + ' at: Test. (/test/mock/create-simple-tap.cjs:32:8)', + ' stack: |-', + ' Error: Sub-test partial array failure', + ' at Test.assert [as _assert] (/node_modules/tape/lib/test.js:479:48)', + ' at Test.tapeDeepEqual (/node_modules/tape/lib/test.js:720:7)', + ' at Test. (/test/mock/create-simple-tap.cjs:32:8)', + ' at Test.run (/node_modules/tape/lib/test.js:113:28)', + ' at Test._end (/node_modules/tape/lib/test.js:385:5)', + ' at Immediate._onImmediate (/node_modules/tape/lib/test.js:154:9)', + ' at process.processImmediate (node:internal/timers:476:21)', + ' ...', + 'not ok 12 A small object deepEqual failure', + ' ---', + ' operator: deepEqual', + ' expected: |-', + ' { a: \'bar\', b: [ 420 ] }', + ' actual: |-', + ' { a: \'foo\', b: [ 42 ], c: \'baz\' }', + ' at: Test. (/test/mock/create-simple-tap.cjs:37:8)', + ' stack: |-', + ' Error: A small object deepEqual failure', + ' at Test.assert [as _assert] (/node_modules/tape/lib/test.js:479:48)', + ' at Test.tapeDeepEqual (/node_modules/tape/lib/test.js:720:7)', + ' at Test. (/test/mock/create-simple-tap.cjs:37:8)', + ' at Test.run (/node_modules/tape/lib/test.js:113:28)', + ' at Test._end (/node_modules/tape/lib/test.js:385:5)', + ' at Immediate._onImmediate (/node_modules/tape/lib/test.js:154:9)', + ' at process.processImmediate (node:internal/timers:476:21)', + ' ...', + '', + '1..12', + '# tests 12', + '# pass 7', + '# fail 5', + ], OUT: [ - '\x1B[1m\x1B[4mComment\x1B[24m\x1B[22m', - '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[32m✓\x1B[39m\x1B[22m \x1B[2mshould be truthy\x1B[22m', - '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [2] \x1B[31mshould be falsy\x1B[39m', - '\x1B[31mFailed tests:\x1B[39m There was \x1B[31m1\x1B[39m failure', - '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [2] \x1B[31mshould be falsy\x1B[39m', - 'total: 2', - '\x1B[32mpassing: 1\x1B[39m', - '\x1B[31mfailing: 1\x1B[39m' + '\x1B[1m\x1B[4mSample passing tests\x1B[24m\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[32m✓\x1B[39m\x1B[22m \x1B[2mRegex: match pass\x1B[22m', + '\x1B[3mArbitrary logs supported\x1B[23m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[32m✓\x1B[39m\x1B[22m \x1B[2mRegex: doesNotMatch pass\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[32m✓\x1B[39m\x1B[22m \x1B[2mA deeply equal array\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[36m⇥\x1B[39m\x1B[22m \x1B[2mA skipped test\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[32m✓\x1B[39m\x1B[22m \x1B[2mA deeply equal object\x1B[22m', + '\x1B[1m\x1B[4mSome tests marked as "todo"\x1B[24m\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[36m␣\x1B[39m\x1B[22m \x1B[2mA passing TODO\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[36m␣\x1B[39m\x1B[22m [7] \x1B[31mA failing TODO\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mExplicit fail', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2mAt: Test. (/test/mock/create-simple-tap.cjs:19:7)\x1B[22m', + '\x1B[1m\x1B[4mSome failing tests\x1B[24m\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [8] \x1B[31mshould be strictly equal\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mExpected \x1B[33m666\x1B[39m but got \x1B[34m66\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2mAt: Test. (/test/mock/create-simple-tap.cjs:27:5)\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [9] \x1B[31mshould be strictly equal\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mActual: "Bad dog"', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mExpected: "Good dog"', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2mAt: Test. (/test/mock/create-simple-tap.cjs:28:5)\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [10] \x1B[31mRegex: match fail\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mExpected "\x1B[34matreides\x1B[39m" to match \x1B[33m/^A/\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2mAt: Test. (/test/mock/create-simple-tap.cjs:29:5)\x1B[22m', + '\x1B[1m\x1B[4mNested tests\x1B[24m\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [11] \x1B[31mSub-test partial array failure\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mActual: ["foo","bar","baz"]', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mExpected: ["foo","bar","foobar baz"]', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2mAt: Test. (/test/mock/create-simple-tap.cjs:32:8)\x1B[22m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [12] \x1B[31mA small object deepEqual failure\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mActual: {"a":"foo","b":[42],"c":"baz"}', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22mExpected: {"a":"bar","b":[420]}', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[2mAt: Test. (/test/mock/create-simple-tap.cjs:37:8)\x1B[22m', + '\x1B[31mFailed tests:\x1B[39m There were \x1B[31m5\x1B[39m failures', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [8] \x1B[31mshould be strictly equal\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [9] \x1B[31mshould be strictly equal\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [10] \x1B[31mRegex: match fail\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [11] \x1B[31mSub-test partial array failure\x1B[39m', + '\x1B[2m \x1B[22m\x1B[2m \x1B[22m\x1B[1m\x1B[31m✗\x1B[39m\x1B[22m [12] \x1B[31mA small object deepEqual failure\x1B[39m', + 'total: 12', + '\x1B[32mpassing: 7\x1B[39m', + '\x1B[31mfailing: 5\x1B[39m', + '\x1B[2mskipped: 1\x1B[22m', + '\x1B[2mtodo: 2\x1B[22m', ], } test('basic output formatting', (t) => { - const readable = new Readable({ read () { } }) - const parser = tapArc({ - color: true, - help: false, - pessimistic: false, - failBadCount: false, - verbose: false, - debug: false, - }) + const input = new Readable() let chunks = `` - parser.on('data', (chunk) => { - chunks += chunk.toString() - }) + const output = { + write (string) { chunks += string } + } + + const parser = tapArc( + input, + output, + { + color: true, + help: false, + pessimistic: false, + failBadCount: false, + verbose: false, + debug: false, + } + ) + + for (const line of TAP.IN) input.push(`${line}\n`) + input.push(null) parser.on('end', () => { const actual = chunks.trim().split('\n').slice(0, -1).filter(l => l.length > 0) // remove timer - const expected = Object.keys(TAP.OUT).map((key) => TAP.OUT[key]) - t.deepEqual(actual, expected, 'should print expected output') - t.end() - }) - - readable.pipe(parser) - const lines = Object.keys(TAP.IN).map((key) => TAP.IN[key]) - for (const line of lines) readable.push(`${line}\n`) + // console.log({ actual, expected: TAP.OUT }) - readable.push(null) + t.deepEqual(actual, TAP.OUT, 'should print expected output') + t.end() + }) }) - diff --git a/test/mock/create-passing-tap.cjs b/test/mock/create-passing-tap.cjs index 137d15d..fbc8541 100644 --- a/test/mock/create-passing-tap.cjs +++ b/test/mock/create-passing-tap.cjs @@ -4,8 +4,8 @@ const test = require('tape') test('basic arithmetic', (t) => { - t.equal(2 + 3, 5) - t.equal(7 * 8 + 9, 65) + t.equal(5, 5) + t.equal(65, 65) t.end() }) @@ -13,8 +13,8 @@ test('basic arithmetic', (t) => { test('deep equality', (t) => { t.plan(2) - t.deepEqual([ 3, 4, 5 ], [ 3, 4, 2 + 3 ]) - t.deepEqual({ a: 7, b: [ 8, 9 ] }, { a: 3 + 4, b: [ 4 * 2 ].concat(3 * 3) }) + t.deepEqual([ 3, 4, 5 ], [ 3, 4, 5 ]) + t.deepEqual({ a: 7, b: [ 8, 9 ] }, { a: 7, b: [ 8 ].concat(9) }) }) test('comparing booleans', (t) => { @@ -25,7 +25,7 @@ test('comparing booleans', (t) => { test('negatives', (t) => { t.plan(3) - t.notEqual(1 + 2, 5) + t.notEqual(3, 5) t.notDeepEqual([ 1, 2 ], [ 12 ]) t.notOk(false) }) @@ -49,27 +49,27 @@ test('map with elements', (t) => { test('more info', (t) => { t.plan(2) - t.equal(1 + 2, 3, 'basic arithmetic still works') - t.ok(3 + 4 > 5, 'inequalities are as we might expect') + t.equal(3, 3, 'basic arithmetic still works') + t.ok(7 > 5, 'inequalities are as we might expect') }) test('asynchronous results', (t) => { t.plan(2) - t.equal(2 + 3, 5) + t.equal(5, 5) setTimeout(function () { - t.equal(5 + 5, 10) + t.equal(10, 10) }, 500) }) test('nested', (t) => { - t.test((st) => { + t.test('a nested test 1', (st) => { st.plan(1) - st.equal(1 + 2, 3) + st.equal(3, 3) }) - t.test((st) => { + t.test('a nested test 2', (st) => { st.plan(1) setTimeout(function () { st.pass() diff --git a/test/mock/missing-assertions-failing.txt b/test/mock/tape/missing-assertions-failing.tap similarity index 100% rename from test/mock/missing-assertions-failing.txt rename to test/mock/tape/missing-assertions-failing.tap diff --git a/test/mock/missing-assertions-passing.txt b/test/mock/tape/missing-assertions-passing.tap similarity index 100% rename from test/mock/missing-assertions-passing.txt rename to test/mock/tape/missing-assertions-passing.tap diff --git a/test/smoke.js b/test/smoke.js deleted file mode 100644 index 203d54d..0000000 --- a/test/smoke.js +++ /dev/null @@ -1,6 +0,0 @@ -// ℹ️ Smoke test CLI program with bare minimum Parser - -// eslint-disable-next-line import/no-unresolved -import { Parser } from 'tap-parser' -const p = new Parser(console.log) -process.stdin.pipe(p)