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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
from __future__ import annotations
from pygitweb.static_tests.js_runtime import JsPage
from pygitweb.static_tests.pages import board_shell, requested
def _routes(js: JsPage) -> None:
js.route("board/list", body=[{"name": "Tasks", "task_count": 1}, {"name": "Sprint-2", "task_count": 0}])
js.route("tasks/list", body=[])
js.route("board-ref-manifest", body={"commits": [], "refs": []})
js.route("/auth/status", body={"auth_enabled": False})
def test_init_waits_for_dom_content_loaded(js: JsPage) -> None:
_routes(js)
js.set_html(board_shell())
js.run("document.readyState = 'loading';")
js.load("board.js")
assert js.value("__preloaded") == []
js.run("document.readyState = 'complete';")
js.run("document.dispatchEvent(new Event('DOMContentLoaded'))")
assert len(js.value("__preloaded")) == 6
def test_selector_lists_boards_and_navigates(js: JsPage) -> None:
_routes(js)
js.set_html(board_shell())
js.load("board.js")
labels = js.value(
"Array.from(document.querySelectorAll('#board-board-select option')).map(function(el){return el.textContent;})"
)
assert labels == ["Tasks (1)", "Sprint-2 (0)"]
assert js.prop("#board-board-select", "value") == "Tasks"
js.dispatch("#board-board-select", "change")
assert js.value("__assigned") is None
js.set_prop("#board-board-select", "value", "Sprint-2")
js.dispatch("#board-board-select", "change")
assert js.value("__assigned") == "/project/demo/board/?b=Sprint-2"
def test_unknown_current_board_is_inserted(js: JsPage) -> None:
_routes(js)
js.set_html(board_shell(board="Other"))
js.load("board.js")
assert js.prop("#board-board-select", "value") == "Other"
assert js.text("#board-board-select option") == "Other"
def test_empty_or_failed_board_list_leaves_the_select(js: JsPage) -> None:
js.route("board/list", body=[])
js.route("tasks/list", body=[])
js.route("board-ref-manifest", body={"commits": [], "refs": []})
js.route("/auth/status", body={"auth_enabled": False})
js.set_html(board_shell())
js.load("board.js")
assert js.count("#board-board-select option") == 0
def test_failed_board_list_leaves_the_select(js: JsPage) -> None:
js.route("board/list", error="offline")
js.route("tasks/list", body=[])
js.route("board-ref-manifest", body={"commits": [], "refs": []})
js.route("/auth/status", body={"auth_enabled": False})
js.set_html(board_shell())
js.load("board.js")
assert js.count("#board-board-select option") == 0
def test_sprint_name_increments_and_the_form_can_be_cancelled(js: JsPage) -> None:
_routes(js)
js.route("board/list", body=[{"name": "Sprint-2"}, {"name": "notes"}, {"name": "Sprint-9"}])
js.set_html(board_shell())
js.load("board.js")
js.click("#board-new-sprint-btn")
assert "d-none" not in js.classes("#board-new-form")
assert js.prop("#board-new-name", "value") == "Sprint-10"
js.click("#board-new-cancel")
assert "d-none" in js.classes("#board-new-form")
js.click("#board-new-board-btn")
assert js.prop("#board-new-name", "value") == ""
def test_create_board_navigates_or_shows_the_error(js: JsPage) -> None:
_routes(js)
js.route("board/create", status=200)
js.set_html(board_shell())
js.load("board.js")
js.click("#board-new-board-btn")
js.set_prop("#board-new-name", "value", " ")
js.dispatch("#board-new-form", "submit")
assert requested(js, "board/create") is False
js.set_prop("#board-new-name", "value", "My Board")
js.dispatch("#board-new-form", "submit")
assert js.value("__assigned") == "/project/demo/board/?b=My-Board"
js.route("board/create", status=400, body={"detail": "taken"})
js.set_prop("#board-new-name", "value", "Tasks")
js.dispatch("#board-new-form", "submit")
assert js.text("#board-new-error") == "taken"
assert "d-none" not in js.classes("#board-new-error")
js.route("board/create", status=400, json_error=True)
js.dispatch("#board-new-form", "submit")
assert js.text("#board-new-error") == "Could not create board."
js.route("board/create", error="offline")
js.dispatch("#board-new-form", "submit")
assert js.text("#board-new-error") == "Could not create board."
def test_open_task_from_the_query_string(js: JsPage) -> None:
_routes(js)
js.route(
"tasks/list",
body=[{"ref": "refs/tags/tasks/task_abcd", "title": "Ship", "status": "TODO"}],
)
js.set_location("http://127.0.0.1/project/demo/board/?task=refs/tags/tasks/task_abcd")
js.set_html(board_shell())
js.load("board.js")
assert js.count(".board-card-popout") == 0
js.tick()
assert "board-card-popout" in js.classes(".board-card")
def test_open_task_skips_a_card_that_is_already_open(js: JsPage) -> None:
_routes(js)
js.route("tasks/list", body=[{"ref": "t1", "title": "Ship", "status": "TODO"}])
js.set_location("http://127.0.0.1/project/demo/board/?task=t1")
js.set_html(board_shell())
js.load("board.js")
js.run("document.querySelector('.board-card').classList.add('board-card-popout')")
js.tick()
assert js.count(".board-card-popout-overlay") == 0
def test_missing_query_task_does_not_open_a_card(js: JsPage) -> None:
_routes(js)
js.set_html(board_shell())
js.load("board.js")
js.tick()
assert js.count(".board-card-popout-overlay") == 0
def test_init_without_a_project_skips_the_network(js: JsPage) -> None:
js.set_html('<div class="board-columns"></div><select id="board-board-select"></select>')
js.set_location("http://127.0.0.1/")
js.load("board.js")
assert requested(js, "board/list") is False
assert requested(js, "tasks/list") is False
def test_sprint_suggestion_starts_at_one_before_the_list_loads(js: JsPage) -> None:
js.route("tasks/list", body=[])
js.route("board-ref-manifest", body={"commits": [], "refs": []})
js.route("/auth/status", body={"auth_enabled": False})
js.set_html(board_shell())
js.load("board.js")
js.click("#board-new-sprint-btn")
assert js.prop("#board-new-name", "value") == "Sprint-1"