Skip to content

Commit c34d151

Browse files
committed
CLI: Show help when missing argument (i.e. plain/default invocation)
1 parent 91aa490 commit c34d151

File tree

6 files changed

+31
-17
lines changed

6 files changed

+31
-17
lines changed

ARCHITECTURE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Examples:
2020

2121
This argument relates directly to a concept we know the user naturally knows and is most concerned about (their test file). There are no other unnamed arguments. There are no required options or flags. The default browser is selected automatically. No awareness of test framework is required (in most cases).
2222

23+
When invoking `qtap` without arguments out of curiosity, we generate not just an error message but also the `--help` usage documentation.
24+
2325
* We favour a single way of doing something that works everywhere, over marginal gains that would introduce layers of indirection, abstraction, conditional branches, or additional dependencies.
2426

2527
* We favour an explicit and efficient inline implementation (e.g. in the form of a single well-documented function with a clear purpose, which may be relatively long, but is readable and linear), over many local functions that are weaved together.

bin/qtap.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ program
4242
.option('-v, --verbose', 'Enable verbose debug logging.')
4343
.option('-V, --version', 'Display version number.')
4444
.helpOption('-h, --help', 'Display this usage information.')
45+
.showHelpAfterError()
4546
.parse(process.argv);
4647

4748
const opts = program.opts();

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
"test": "node bin/qtap.js -v test/pass.html && npm run -s lint"
2424
},
2525
"dependencies": {
26-
"@tapjs/tap-finished": "^0.0.3",
26+
"@tapjs/tap-finished": "0.0.3",
2727
"commander": "12.1.0",
28-
"kleur": "^4.1.5",
29-
"tap-parser": "^5.4.0",
30-
"which": "^5.0.0"
28+
"kleur": "4.1.5",
29+
"tap-parser": "18.0.0",
30+
"which": "5.0.0"
3131
},
3232
"devDependencies": {
3333
"eslint": "^8.13.0",

src/browsers.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ function createFirefoxPrefsJs (prefs) {
132132
function * getFirefoxCandidates () {
133133
if (process.env.FIREFOX_BIN) yield process.env.FIREFOX_BIN;
134134

135-
// Find /usr/bin/firefox on platforms like linux (including WSL), freebsd, openbsd.
135+
// Handle unix-like platforms such as linux (incl WSL), darwin (macOS), freebsd, openbsd.
136+
// Example: /usr/bin/firefox
136137
yield which.sync('firefox', { nothrow: true });
137138

138139
if (process.platform === 'darwin') {

src/server.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import http from 'node:http';
66
import path from 'node:path';
77
import stream from 'node:stream';
88

9-
import TapParser from 'tap-parser';
9+
import { Parser as TapParser } from 'tap-parser';
1010
import tapFinished from '@tapjs/tap-finished';
1111

1212
const MIME_TYPES = {
@@ -111,6 +111,7 @@ class ControlServer {
111111
const logger = this.logger.channel(`qtap_browser_${browserName}_${clientId}`);
112112

113113
const controller = new AbortController();
114+
const summary = { ok: true };
114115

115116
let readableController;
116117
const readable = new ReadableStream({
@@ -120,11 +121,10 @@ class ControlServer {
120121
});
121122

122123
this.browsers.set(clientId, {
123-
readableController
124+
logger,
125+
readableController,
124126
});
125127

126-
const [readableForFinished, readeableForParser] = readable.tee();
127-
128128
const tapFinishFinder = tapFinished({ wait: 0 }, () => {
129129
logger.debug('browser_tap_finished', 'Requesting browser stop');
130130
// Check in case browser already gone (race condition)
@@ -133,23 +133,32 @@ class ControlServer {
133133
controller.abort('QTap: browser_tap_finished');
134134
}
135135
});
136-
readableForFinished.pipeTo(stream.Writable.toWeb(tapFinishFinder));
137136

138-
const tapParser = new TapParser();
139-
readeableForParser.pipeTo(stream.Writable.toWeb(tapParser));
140137
// Also stop on bailout (tap-finished doesn't handle this)
138+
const tapParser = new TapParser();
141139
tapParser.on('bailout', (reason) => {
140+
summary.ok = false;
142141
logger.debug('browser_tap_bailout', reason);
142+
143143
// Check in case browser already gone (race condition)
144144
if (this.browsers.get(clientId)) {
145145
this.browsers.delete(clientId);
146146
controller.abort('QTap: browser_tap_bailout');
147147
}
148148
});
149+
tapParser.once('fail', () => {
150+
summary.ok = false;
151+
logger.debug('browser_tap_fail', 'One or more tests failed');
152+
});
153+
149154
// Debugging
150155
// tapParser.on('assert', logger.debug.bind(logger, 'browser_tap_assert'));
151156
// tapParser.on('plan', logger.debug.bind(logger, 'browser_tap_plan'));
152157

158+
const [readeableForParser, readableForFinished] = readable.tee();
159+
readeableForParser.pipeTo(stream.Writable.toWeb(tapParser));
160+
readableForFinished.pipeTo(stream.Writable.toWeb(tapFinishFinder));
161+
153162
// TODO: Implement timeout if stream is quiet for too long
154163
// --timeout=3000s
155164
// use in getTestFile() as QTAP_TIMEOUT for qunit_config_testtimeout
@@ -317,10 +326,12 @@ class ControlServer {
317326
// eslint-disable-next-line no-control-regex
318327
body = body.replace(/\x1b\[[0-9]+m/g, '');
319328
const clientId = url.searchParams.get('qtap_clientId');
320-
this.logger.debug('browser_tap', clientId, JSON.stringify(body.slice(0, 30) + '…'));
321329
const browser = this.browsers.get(clientId);
322330
if (browser) {
323331
browser.readableController.enqueue(body);
332+
browser.logger.debug('browser_tap_received', JSON.stringify(body.slice(0, 30) + '…'));
333+
} else {
334+
this.logger.debug('browser_tap_unhandled', clientId, JSON.stringify(body.slice(0, 30) + '…'));
324335
}
325336
});
326337
resp.writeHead(204);

test/fail.html

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
<script>
44
console.log('TAP version 13');
55
console.log('ok 1 Foo bar');
6-
console.log('ok 2 Baz > this thing');
7-
console.log("not ok 3 \u001b[31mexample > hello fail\u001b[39m");
6+
console.log("not ok 2 \u001b[31mexample > hello fail\u001b[39m");
87
console.log(" ---\n message: \"y\"\n severity: failed\n actual : {\n \"foo\": \"50\",\n \"quux\": \"62\"\n}\n expected: {\n \"foo\": \"50\",\n \"quux\": \"70\"\n}\n stack: |\n @https://demo.localhost:4000/test/fail.html:21:12\n ...");
9-
console.log('ok 4 Quux');
10-
console.log('1..4');
8+
console.log('ok 3 Quux');
9+
console.log('1..3');
1110
</script>

0 commit comments

Comments
 (0)