1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
from __future__ import annotations
import json
from pygitweb.static_tests.js_runtime import JsPage
from pygitweb.static_tests.pages import MANIFEST
_ROOT = (
'<div id="root"><p>see #abcd and #abc and @main and @1234 and @missing and (#eeee)</p>'
"<pre><code>skip #abcd</code></pre><a href='/z'>keep @main</a></div>"
'<textarea id="note"></textarea>'
)
def _load(js: JsPage) -> None:
js.set_html(_ROOT)
js.run("__manifest = " + json.dumps(MANIFEST))
js.load("board-refs.js")
def test_linkify_resolves_commits_refs_and_skips_code(js: JsPage) -> None:
_load(js)
js.run("__loaded['board-refs.js'].linkifyElement(null, __manifest, 'demo')")
js.run("__loaded['board-refs.js'].linkifyElement(document.getElementById('root'), __manifest, '')")
assert js.count(".board-ref-link") == 0
js.run("__loaded['board-refs.js'].linkifyElement(document.getElementById('root'), __manifest, 'group/demo')")
assert js.attr(".board-ref-commit", "href") == "/c/abcd"
assert js.attr(".board-ref-commit", "title") == "subject"
assert js.count(".board-ref-commit") >= 2
assert js.attr(".board-ref-tag", "href") == "/r/main"
assert js.text(".board-ref-unresolved") == "@missing"
assert js.attr(".board-ref-unresolved", "title") == "Unresolved reference"
assert "#abcd" in js.text("pre")
assert js.count("a[href='/z'] .board-ref-link") == 0
def test_unresolved_commit_links_to_the_project(js: JsPage) -> None:
js.set_html("<div id='root'>#ffff</div>")
js.run("__manifest = " + json.dumps(MANIFEST))
js.load("board-refs.js")
js.run("__loaded['board-refs.js'].linkifyElement(document.getElementById('root'), __manifest, 'group/demo')")
href = js.attr(".board-ref-commit", "href") or ""
assert "/project/group/demo" in href
assert "h=ffff" in href
assert js.attr(".board-ref-commit", "title") is None
def test_load_manifest_normalizes_payloads(js: JsPage) -> None:
js.load("board-refs.js")
js.route("board-ref-manifest", body=MANIFEST)
got = js.settle("__loaded['board-refs.js'].loadManifest('group/demo', 'Sprint')")
assert got["commits"][0]["insert"] == "abcd"
assert any("b=Sprint" in str(item["url"]) and "/project/group/demo/" in str(item["url"]) for item in js.requests())
js.route("board-ref-manifest", status=500, body={"commits": "nope", "refs": None})
assert js.settle("__loaded['board-refs.js'].loadManifest('demo', '')") == {"commits": [], "refs": []}
js.route("board-ref-manifest", body={"commits": "nope", "refs": {}})
normalized = js.settle("__loaded['board-refs.js'].loadManifest('demo', 'Tasks')")
assert normalized == {"commits": [], "refs": []}
js.route("board-ref-manifest", error="offline")
assert js.settle("__loaded['board-refs.js'].loadManifest('demo', 'Tasks')") == {"commits": [], "refs": []}
def test_autocomplete_inserts_a_suggestion(js: JsPage) -> None:
_load(js)
js.run("__loaded['board-refs.js'].attachAutocomplete(null, __manifest)")
js.run("__loaded['board-refs.js'].attachAutocomplete(document.getElementById('note'), __manifest)")
js.run("__loaded['board-refs.js'].attachAutocomplete(document.getElementById('note'), __manifest)")
js.set_prop("#note", "value", "see @ma")
js.set_prop("#note", "selectionStart", 7)
js.dispatch("#note", "input")
assert "d-none" not in js.classes(".board-ref-suggest")
assert js.text(".board-ref-suggest-title") == "main"
js.dispatch(".board-ref-suggest-item", "mousedown")
assert js.prop("#note", "value") == "see @main"
assert "d-none" in js.classes(".board-ref-suggest")
def test_autocomplete_filters_commits_and_caps_the_list(js: JsPage) -> None:
commits = [
{"insert": f"{index:04x}", "name": f"name-{index}", "url": "/c", "tags": "t", "snippet": "s"}
for index in range(14)
]
js.set_html("<textarea id='note'></textarea>")
js.run("__manifest = " + json.dumps({"commits": commits, "refs": MANIFEST["refs"]}))
js.load("board-refs.js")
js.run("__loaded['board-refs.js'].attachAutocomplete(document.getElementById('note'), __manifest)")
js.set_prop("#note", "value", "#")
js.set_prop("#note", "selectionStart", 1)
js.dispatch("#note", "keyup")
assert js.count(".board-ref-suggest-item") == 12
js.set_prop("#note", "value", "#1")
js.set_prop("#note", "selectionStart", 2)
js.dispatch("#note", "input")
assert js.count(".board-ref-suggest-item") >= 1
js.dispatch("#note", "keydown", key="Escape")
assert "d-none" in js.classes(".board-ref-suggest")
def test_autocomplete_hides_on_blur_and_outside_click(js: JsPage) -> None:
_load(js)
js.run("__loaded['board-refs.js'].attachAutocomplete(document.getElementById('note'), __manifest)")
js.set_prop("#note", "value", "@")
js.set_prop("#note", "selectionStart", 1)
js.dispatch("#note", "input")
assert js.count(".board-ref-suggest-item") == 2
js.dispatch("#note", "blur")
assert "d-none" not in js.classes(".board-ref-suggest")
js.tick()
assert "d-none" in js.classes(".board-ref-suggest")
js.set_prop("#note", "value", "@ma")
js.set_prop("#note", "selectionStart", 3)
js.dispatch("#note", "input")
js.dispatch("#root", "mousedown")
assert "d-none" in js.classes(".board-ref-suggest")
def test_autocomplete_ignores_text_without_a_token(js: JsPage) -> None:
_load(js)
js.run("__loaded['board-refs.js'].attachAutocomplete(document.getElementById('note'), __manifest)")
js.set_prop("#note", "value", "hello")
js.set_prop("#note", "selectionStart", 5)
js.dispatch("#note", "input")
assert js.count(".board-ref-suggest-item") == 0
def test_suggestion_dates_and_snippets_are_escaped(js: JsPage) -> None:
manifest = {
"commits": [],
"refs": [{"insert": "main", "name": "<b>", "url": "/r", "tags": "main", "snippet": "<i>", "created": "<d>"}],
}
js.set_html("<textarea id='note'></textarea>")
js.run("__manifest = " + json.dumps(manifest))
js.load("board-refs.js")
js.run("__loaded['board-refs.js'].attachAutocomplete(document.getElementById('note'), __manifest)")
js.set_prop("#note", "value", "@")
js.set_prop("#note", "selectionStart", 1)
js.dispatch("#note", "input")
html = js.prop(".board-ref-suggest-item", "innerHTML")
assert "<b>" in html
assert "<i>" in html
assert "<d>" in html
assert "<b>" not in html