Split now playing, the quiz buttons and song loading out of the quiz

NowPlaying, QuizToolbar and SongControls become their own scenes, the auto
repeat switch moves into the music player scene, and downloading songs moves
into a SongLoader node. The quiz only wires the parts together. Every node
keeps its place on screen.

Screenshots of every UI state are pixel-identical to before, the layout test
still matches the original baseline, and each new part has its own tests.
This commit is contained in:
Sansan committed 2026-10-06 11:11:18 +02:00
1 parent bad4b3ad8b
commit e94c75e84d
32 files changed
+822 -300

No files matched your search

+44 -10
View File
@@ -51,11 +51,21 @@ func test_top_bar_is_drawn_below_the_quiz() -> void:
func test_quiz_parts_are_their_own_scenes() -> void:
for node_name: String in ["MusicListPanel", "PlayersPanel", "InspirationList"]:
for node_name: String in ["MusicListPanel", "PlayersPanel", "InspirationList",
"NowPlaying", "QuizToolbar", "SongControls", "MusicPlayer"]:
assert_str(_quiz.get_node(node_name).scene_file_path) \
.is_equal("res://%s.tscn" % node_name)
func test_quiz_downloads_songs_with_a_song_loader() -> void:
assert_object(_quiz.song_loader).is_instanceof(SongLoader)
func test_auto_repeat_is_part_of_the_music_player() -> void:
assert_object(_quiz.get_node("MusicPlayer/RepeatSongCheckButton")).is_instanceof(CheckButton)
assert_object(_quiz.get_node_or_null("RepeatSongCheckButton")).is_null()
func test_top_bar_holds_only_title_and_buttons() -> void:
assert_array(_children(_window.get_node("TopBar"))) \
.contains_exactly_in_any_order(TOP_BAR_CHILDREN)
@@ -83,22 +93,22 @@ func test_clicking_each_top_bar_button_opens_its_popup() -> void:
func test_clicking_quiz_buttons_plays_and_shows_answer() -> void:
await _click_at(_center(_quiz.get_node("NextButton")))
await _click_at(_center(_quiz.get_node("SongControls/NextButton")))
await _runner.simulate_frames(2)
assert_int(Playlist.currently_playing_song).is_equal(0)
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
assert_str((_quiz.get_node("NowPlaying/SoundtrackLabel") as Label).text) \
.is_not_equal("Chrono Trigger")
await _click_at(_center(_quiz.get_node("ShowAnswerButton")))
await _click_at(_center(_quiz.get_node("SongControls/ShowAnswerButton")))
assert_str((_quiz.get_node("VBoxContainer/SoundtrackLabel") as Label).text) \
assert_str((_quiz.get_node("NowPlaying/SoundtrackLabel") as Label).text) \
.is_equal("Chrono Trigger")
func test_clicking_a_song_in_the_music_list_plays_it() -> void:
_next_song_is(SONG_INFO[1])
await _play_first_song()
_press("NextButton")
_press("SongControls/NextButton")
# Changing song waits a moment for the old one to stop
await get_tree().create_timer(0.7).timeout
assert_int(Playlist.currently_playing_song).is_equal(1)
@@ -137,6 +147,30 @@ func test_character_button_in_the_player_list_picks_a_new_character() -> void:
assert_object(crono.character).is_same(texture)
func test_sound_test_button_fetches_the_sound_test_song() -> void:
_server.respond_bytes("/music/soundTest", FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
await _click_at(_center(_quiz.get_node("QuizToolbar/SoundTestButton")))
assert_int(_server.count("/music/soundTest")).is_equal(1)
func test_loaded_song_list_shows_in_the_music_list() -> void:
# No new song finishes downloading, so only loading the list can show the songs
_server.hold("/music/rand")
_server.respond_json("/music/list", [
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
{"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"},
])
Playlist.is_song_downloading = false
_quiz.song_loader.load_song_list()
var rows: Array[Node] = _quiz.get_node("MusicListPanel/ScrollContainer/MusicList").get_children()
assert_array(rows.map(func(row: SongListObject) -> int: return row.song_object.song_number)) \
.contains_exactly([0, 1])
func test_quiz_popup_backdrop_covers_the_top_bar() -> void:
var settings: PopupWindow = _quiz.get_node("SettingsWindow")
settings.open()
@@ -169,8 +203,8 @@ func test_sync_disables_quiz_buttons_until_finished() -> void:
_top_bar_button("SyncButton").pressed.emit()
sync_window.sync_timer.stop()
for button_name: String in ["SoundTestButton", "ResetPlaylistButton", "ShowAnswerButton",
"NextButton"]:
for button_name: String in ["QuizToolbar/SoundTestButton", "QuizToolbar/ResetPlaylistButton", "SongControls/ShowAnswerButton",
"SongControls/NextButton"]:
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
.override_failure_message(button_name + " not disabled").is_true()
assert_bool(_top_bar_button("SyncButton").disabled).is_false()
@@ -180,8 +214,8 @@ func test_sync_disables_quiz_buttons_until_finished() -> void:
sync_window._on_sync_timeout()
await _runner.simulate_frames(2)
for button_name: String in ["SoundTestButton", "ResetPlaylistButton", "ShowAnswerButton",
"NextButton"]:
for button_name: String in ["QuizToolbar/SoundTestButton", "QuizToolbar/ResetPlaylistButton", "SongControls/ShowAnswerButton",
"SongControls/NextButton"]:
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
.override_failure_message(button_name + " still disabled").is_false()
# The search list in the main window and the quiz playlist are both reloaded