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
from __future__ import annotations
from pygitweb.static_tests.js_runtime import JsPage
from pygitweb.static_tests.pages import board_shell, card_html, requested
def _bind(js: JsPage, html: str | None = None) -> None:
js.set_html(html if html is not None else board_shell(cards_todo=card_html(ref="t1", title="A", points="1")))
js.load("board-dnd.js")
js.call("board-dnd.js", "bindBoardInteractions")
def test_binding_without_a_board_does_nothing(js: JsPage) -> None:
js.set_html("<div></div>")
js.load("board-dnd.js")
js.call("board-dnd.js", "bindBoardInteractions")
assert requested(js, "tasks/update") is False
def test_drop_on_another_column_saves_and_reorders(js: JsPage) -> None:
js.route("tasks/update", status=200)
js.route("tasks/list", body=[{"ref": "t1", "status": "IN_PROGRESS", "title": "A"}])
_bind(js)
js.dispatch(".board-card", "dragstart")
assert "opacity-50" in js.classes(".board-card")
js.dispatch('.board-column[data-status="IN_PROGRESS"]', "dragover")
assert "border-primary" in js.classes('.board-column[data-status="IN_PROGRESS"]')
js.dispatch('.board-column[data-status="IN_PROGRESS"]', "drop")
assert js.count('.board-column[data-status="IN_PROGRESS"] .board-card') == 1
assert js.attr(".board-card", "data-task-status") == "IN_PROGRESS"
assert requested(js, "tasks/update") is True
js.dispatch(".board-card", "dragend")
assert "opacity-50" not in js.classes(".board-card")
assert "border-primary" not in js.classes(".board-column")
def test_same_column_drop_does_not_save(js: JsPage) -> None:
_bind(js)
js.dispatch(".board-card", "dragstart")
js.dispatch('.board-column[data-status="TODO"]', "drop")
assert js.count('.board-column[data-status="TODO"] .board-card') == 1
assert requested(js, "tasks/update") is False
def test_a_forbidden_move_puts_the_card_back(js: JsPage) -> None:
js.route("tasks/update", status=403)
html = board_shell(
cards_todo=card_html(ref="t1", title="A") + card_html(ref="t2", title="B"),
)
_bind(js, html)
js.dispatch('.board-card[data-task-ref="t1"]', "dragstart")
js.dispatch('.board-column[data-status="IN_PROGRESS"]', "drop")
assert js.count('.board-column[data-status="TODO"] .board-card') == 2
assert "Not authorized" in js.text(".board-task-error-hint")
js.route("tasks/update", status=500)
js.dispatch('.board-card[data-task-ref="t1"]', "dragstart")
js.dispatch('.board-column[data-status="IN_PROGRESS"]', "drop")
assert "Could not save" in js.text(".board-task-error-hint")
assert js.attr('.board-card[data-task-ref="t1"]', "data-task-status") == "TODO"
def test_a_card_without_a_ref_is_moved_back(js: JsPage) -> None:
_bind(js, board_shell(cards_todo=card_html(title="A")))
js.dispatch(".board-card", "dragstart")
js.dispatch('.board-column[data-status="IN_PROGRESS"]', "drop")
assert js.count('.board-column[data-status="TODO"] .board-card') == 1
assert "Could not save" in js.text(".board-task-error-hint")
def test_drag_data_failures_still_move_the_dragged_card(js: JsPage) -> None:
js.route("tasks/update", status=200)
js.route("tasks/list", body=[{"ref": "t1", "status": "IN_PROGRESS"}])
_bind(js)
js.run("__failSetData = true;")
js.dispatch(".board-card", "dragstart")
assert "opacity-50" in js.classes(".board-card")
js.run("__failGetData = true;")
js.dispatch('.board-column[data-status="IN_PROGRESS"]', "drop")
assert js.attr(".board-card", "data-task-status") == "IN_PROGRESS"
def test_click_opens_the_popout_unless_the_gesture_was_a_drag(js: JsPage) -> None:
_bind(js)
js.dispatch(".board-card", "dragstart")
js.click(".board-card")
assert js.count(".board-card-popout-overlay") == 0
js.dispatch(".board-card", "dragend")
js.tick()
js.click(".board-card")
assert js.count(".board-card-popout-overlay") == 1
js.set_html(board_shell(cards_todo=card_html(ref="t1", title="A")))
js.call("board-dnd.js", "bindBoardInteractions")
js.run("document.querySelector('.board-card').classList.add('board-card-popout')")
js.click(".board-card")
assert js.count(".board-card-popout-overlay") == 0
def test_drop_without_a_card_or_a_list_is_ignored(js: JsPage) -> None:
html = (
'<div class="board-columns" data-project="demo" data-board="Tasks">'
'<div class="board-column dropzone" data-status="TODO"></div>'
'<div class="board-column dropzone" data-status="IN_PROGRESS"><div class="board-column-cards"></div></div>'
"</div>"
)
_bind(js, html)
js.dispatch('.board-column[data-status="IN_PROGRESS"]', "drop")
js.dispatch('.board-column[data-status="TODO"]', "dragstart")
js.dispatch('.board-column[data-status="TODO"]', "drop")
assert requested(js, "tasks/update") is False
def test_dragover_outside_a_column_does_not_highlight(js: JsPage) -> None:
_bind(js)
js.dispatch(".board-column-cards", "dragover")
assert "border-primary" not in js.classes(".board-column")