nandi/frqpublic Fork 0
43a02c2ddd7ebb7cdcd7d46f8c9a20b5b1b55b5e
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.

tui.nim · 105 lines · 3.8 KBNim Blame HistoryRaw
Nim owns the screen, Dart owns the pixels 43a02c2 nandi 20h ago1## The screen as a pure function of the app, and the reducer that moves it.
2import std/sequtils
3##
4## These are the tests the Clojure screens never had and could not easily
5## have: a screen there is hiccup over cells a host installs, so exercising
6## one means standing up a host. Here it is a function from a record to a
7## tree, and a test is a call.
8
9import std/[json, strutils]
10import std/unittest
11import frq/[ui, state]
12import frq/screens/connect as cs
13
14proc find(node: Node, tag: string): seq[Node] =
15 ## Every node with this tag, depth first.
16 if node.isNil: return
17 if node.tag == tag: result.add node
18 for c in node.children:
19 result.add c.find(tag)
20
21proc texts(node: Node, tag: string): seq[string] =
22 for n in node.find(tag):
23 result.add n.props{"label"}.getStr()
24
25suite "the connect screen":
26 setup:
27 app = initState()
28
29 test "renders a page with the title and the server fields":
30 let t = cs.connectScreen(app)
31 check t.tag == "page"
32 check "frq" in t.texts("title")
33 check "Server" in t.texts("label")
34 check t.find("checkbutton").len == 1
35
36 test "is pure — twice with no dispatch is the same tree":
37 check $cs.connectScreen(app).toJson == $cs.connectScreen(app).toJson
38
39 test "guest is the default mode and shows a nickname field":
40 let keys = cs.connectScreen(app).find("entry").mapIt(it.props{"key"}.getStr())
41 check "nick" in keys
42 check "handle" notin keys
43
44 test "the selected mode is the primary button, and only it":
45 let t = cs.connectScreen(app)
46 var primary: seq[string]
47 for b in t.find("button"):
48 if b.props{"kind"}.getStr() == "primary":
49 primary.add b.props{"label"}.getStr()
50 # Guest is selected; Connect is primary because it is the action.
51 check "Guest" in primary
52 check "Bluesky" notin primary
53
54suite "dispatch":
55 setup:
56 app = initState()
57
58 test "switching mode changes which fields are shown":
59 dispatch(%*{"id": "mode.bluesky"})
60 let keys = cs.connectScreen(app).find("entry").mapIt(it.props{"key"}.getStr())
61 check "handle" in keys
62 check "nick" notin keys
63
64 test "typing into the host field lands in the tree":
65 dispatch(%*{"id": "host.change", "value": "localhost"})
66 let host = cs.connectScreen(app).find("entry").filterIt(
67 it.props{"key"}.getStr() == "host")[0]
68 check host.props{"text"}.getStr() == "localhost"
69
70 test "the TLS tick carries the port with it":
71 check app.formPort == "6697"
72 dispatch(%*{"id": "tls.toggle"})
73 check not app.formTls
74 check app.formPort == "6667"
75 dispatch(%*{"id": "tls.toggle"})
76 check app.formPort == "6697"
77
78 test "connecting swaps the button for a spinner":
79 check cs.connectScreen(app).find("spinner").len == 0
80 dispatch(%*{"id": "connect"})
81 let t = cs.connectScreen(app)
82 check t.find("spinner").len == 1
83 check "Connect" notin t.texts("button")
84
85 test "an empty host is refused, and the error is dismissable":
86 dispatch(%*{"id": "host.change", "value": " "})
87 dispatch(%*{"id": "connect"})
88 check app.hasError
89 check "Dismiss" in cs.connectScreen(app).texts("button")
90 dispatch(%*{"id": "error.dismiss"})
91 check not app.hasError
92 check "Dismiss" notin cs.connectScreen(app).texts("button")
93
94 test "the error note keeps its place in the tree either way":
95 # The bug the stable wrapper exists for: a renderer matching children by
96 # position would patch the header into a card when the error appeared.
97 let before = cs.connectScreen(app).children.mapIt(it.tag)
98 dispatch(%*{"id": "host.change", "value": ""})
99 dispatch(%*{"id": "connect"})
100 check cs.connectScreen(app).children.mapIt(it.tag) == before
101
102 test "an unknown event is ignored rather than fatal":
103 let before = $cs.connectScreen(app).toJson
104 dispatch(%*{"id": "no.such.event"})
105 check $cs.connectScreen(app).toJson == before