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
158
159
160
161
162
163
164
165
166
167
168
from __future__ import annotations
from pygitweb.static_tests.js_runtime import JsPage
from pygitweb.static_tests.pages import requested
_FORM = (
'<input id="project_name">'
'<input type="radio" name="project_source_type" value="empty" checked>'
'<input type="radio" name="project_source_type" value="zip">'
'<div id="tab-empty-repo"></div>'
'<div id="tab-upload-zip" class="d-none"></div>'
'<input id="pull_from_remote" value="git://example">'
'<input id="repo_zip" value="old.zip">'
'<div id="dropzone">'
"<span data-dropzone-placeholder>drop</span>"
'<span data-dropzone-filename class="d-none"></span>'
"</div>"
)
def test_empty_document_skips_every_widget(js: JsPage) -> None:
js.set_html("<div></div>")
js.load("addproject.js")
assert js.count("#project_name") == 0
def test_blank_name_clears_the_border(js: JsPage) -> None:
js.set_html(_FORM)
js.load("addproject.js")
js.dispatch("#project_name", "blur")
assert "border" not in js.classes("#project_name")
assert requested(js, "projectnamevalid") is False
def test_blur_marks_an_accepted_name(js: JsPage) -> None:
js.route("projectnamevalid", status=200)
js.set_html(_FORM)
js.load("addproject.js")
js.set_prop("#project_name", "value", " demo ")
js.dispatch("#project_name", "blur")
assert "border-success" in js.classes("#project_name")
assert any("name=demo" in str(item["url"]) for item in js.requests())
def test_blur_marks_a_rejected_name(js: JsPage) -> None:
js.route("projectnamevalid", status=404)
js.set_html(_FORM)
js.load("addproject.js")
js.set_prop("#project_name", "value", "taken")
js.dispatch("#project_name", "blur")
assert "border-danger" in js.classes("#project_name")
def test_name_check_clears_the_border_when_fetch_fails(js: JsPage) -> None:
js.route("projectnamevalid", error="offline")
js.set_html(_FORM)
js.load("addproject.js")
js.set_prop("#project_name", "value", "demo")
js.dispatch("#project_name", "blur")
assert "border" not in js.classes("#project_name")
def test_input_checks_the_name_after_the_debounce(js: JsPage) -> None:
js.route("projectnamevalid", status=200)
js.set_html(_FORM)
js.load("addproject.js")
js.set_prop("#project_name", "value", "demo")
js.dispatch("#project_name", "input")
assert requested(js, "projectnamevalid") is False
js.tick()
assert requested(js, "projectnamevalid") is True
def test_clearing_the_name_cancels_the_debounce(js: JsPage) -> None:
js.route("projectnamevalid", status=200)
js.set_html(_FORM)
js.load("addproject.js")
js.set_prop("#project_name", "value", "demo")
js.dispatch("#project_name", "input")
js.set_prop("#project_name", "value", " ")
js.dispatch("#project_name", "input")
js.tick()
assert requested(js, "projectnamevalid") is False
assert "border" not in js.classes("#project_name")
def test_zip_source_hides_the_empty_tab_and_clears_the_remote(js: JsPage) -> None:
js.set_html(_FORM)
js.load("addproject.js")
assert "d-none" not in js.classes("#tab-empty-repo")
js.set_prop('input[value="empty"]', "checked", False)
js.set_prop('input[value="zip"]', "checked", True)
js.dispatch('input[value="zip"]', "change")
assert "d-none" in js.classes("#tab-empty-repo")
assert "d-none" not in js.classes("#tab-upload-zip")
assert js.prop("#pull_from_remote", "value") == ""
def test_empty_source_clears_the_zip_input(js: JsPage) -> None:
js.set_html(_FORM)
js.load("addproject.js")
js.set_prop('input[value="empty"]', "checked", False)
js.set_prop('input[value="zip"]', "checked", True)
js.dispatch('input[value="zip"]', "change")
js.set_prop('input[value="zip"]', "checked", False)
js.set_prop('input[value="empty"]', "checked", True)
js.dispatch('input[value="empty"]', "change")
assert js.prop("#repo_zip", "value") == ""
assert "d-none" in js.classes("#tab-upload-zip")
def test_unchecked_radios_default_to_the_empty_source(js: JsPage) -> None:
html = _FORM.replace(" checked", "", 1)
js.set_html(html)
js.load("addproject.js")
assert "d-none" in js.classes("#tab-upload-zip")
def test_dropzone_click_clicks_the_file_input(js: JsPage) -> None:
js.set_html(_FORM)
js.load("addproject.js")
js.run(
"globalThis.__zipClicks = 0;"
" document.getElementById('repo_zip').addEventListener('click', function() { __zipClicks++; });"
)
js.click("#dropzone")
assert js.value("__zipClicks") == 1
def test_drag_highlights_the_dropzone_until_leave_or_drop(js: JsPage) -> None:
js.set_html(_FORM)
js.load("addproject.js")
js.dispatch("#dropzone", "dragover")
assert "border-primary" in js.classes("#dropzone")
js.dispatch("#dropzone", "dragleave")
assert "border-primary" not in js.classes("#dropzone")
def test_drop_accepts_only_a_zip_file(js: JsPage) -> None:
js.set_html(_FORM)
js.load("addproject.js")
js.run(
"var ev = new Event('drop', {bubbles:true, cancelable:true});"
"ev.dataTransfer.files = [{name: 'notes.txt'}];"
"document.getElementById('dropzone').dispatchEvent(ev);"
)
assert "Selected:" not in js.text("[data-dropzone-filename]")
js.run(
"var ev = new Event('drop', {bubbles:true, cancelable:true});"
"ev.dataTransfer.files = [{name: 'Pkg.ZIP'}];"
"document.getElementById('dropzone').dispatchEvent(ev);"
)
assert js.text("[data-dropzone-filename]") == "Selected: Pkg.ZIP"
assert "d-none" in js.classes("[data-dropzone-placeholder]")
assert "border-primary" not in js.classes("#dropzone")
def test_file_input_change_shows_and_clears_the_name(js: JsPage) -> None:
js.set_html(_FORM)
js.load("addproject.js")
js.run("document.getElementById('repo_zip').files = [{name: 'a.zip'}];")
js.dispatch("#repo_zip", "change")
assert js.text("[data-dropzone-filename]") == "Selected: a.zip"
js.run("document.getElementById('repo_zip').files = [];")
js.dispatch("#repo_zip", "change")
assert js.text("[data-dropzone-filename]") == ""
assert "d-none" not in js.classes("[data-dropzone-placeholder]")