nandi/frqpublic Fork 0
0e7cd322e9fe4d04d215501ceb97171001c09cc2
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

smoke.js · 72 lines · 2.8 KBJavaScript Blame HistoryRaw
The core, compiled to JavaScript 5ac0521 nandi 12h ago1// The web core, driven the way a browser drives it.
2//
3// Not a unit test — the Nim suite is that, and it covers the same reducer
4// this runs. What is checked here is the seam: that the JavaScript build
5// loads, that a tree comes out as JSON, that an event goes in, and that a
6// line fed in as if from a socket reaches the screen. Those are the four
7// things that can break without a single Nim test noticing, because the
8// desktop build does them through a different file.
9//
10// node nim/web/test/smoke.js build/web/frq_core.js
11
12const fs = require('fs');
13const path = process.argv[2] || 'build/web/frq_core.js';
14
15// The bits of a browser this build touches. The core asks localStorage for a
16// saved session and asks `location` where to send a reader for sign-in.
17globalThis.window = {
18 localStorage: {
19 _v: {},
20 getItem(k) { return this._v[k] || ""; },
21 setItem(k, v) { this._v[k] = String(v); return true; },
22 removeItem(k) { delete this._v[k]; },
23 },
24 location: { href: "", origin: "http://localhost", pathname: "/" },
25};
26
27// Global scope, not a module's: the core puts `frq` on globalThis, and a
28// `require` would wrap it where nothing could see it.
29(0, eval)(fs.readFileSync(path, 'utf8'));
30
31let failures = 0;
32function check(what, ok) {
33 console.log((ok ? " ok " : " FAIL ") + what);
34 if (!ok) failures++;
35}
36
37frq.init("");
38check("the connect screen renders", JSON.parse(frq.render()).tag === "page");
39
40frq.demo();
41check("the demo room renders", frq.render().includes("hello there"));
42
43const chats = frq.dispatch(JSON.stringify({ id: "screen.chats" }));
44check("an event answers with the tree it produced", chats.includes("#test"));
45
46// Connecting: the core asks to be dialled rather than dialling.
47frq.dispatch(JSON.stringify({ id: "screen.connect" }));
48frq.dispatch(JSON.stringify({ id: "nick.change", value: "webtester" }));
49frq.dispatch(JSON.stringify({ id: "connect" }));
50const wanted = JSON.parse(frq.wanted() || "{}");
51check("it asks the host for a socket", wanted.host === "irc.freeq.at" && wanted.tls === true);
52
53// The host says the socket opened; the core answers with registration.
54frq.socketEvent("open");
55frq.render();
56const out = frq.takeOutbound().split("\n");
57check("registration goes out on open",
58 out[0] === "CAP LS 302" && out[1] === "NICK webtester");
59check("and is taken once", frq.takeOutbound() === "");
60
61// A line arrives.
62frq.feed(":irc.freeq.at 001 webtester :Welcome");
63frq.feed(":alice!a@h PRIVMSG #test :hello from the web");
64const tree = frq.render();
65check("a fed line reaches the screen", tree.includes("hello from the web"));
66
67// What is saved is saved.
68check("the store writes through localStorage",
69 Object.keys(window.localStorage._v).some(k => k.startsWith("frq.")));
70
71console.log(failures === 0 ? "all ok" : failures + " failed");
72process.exit(failures === 0 ? 0 : 1);