extends MainWindowTestSuite ## The Statistics tab: switching between it and the quiz, the soundtrack cards, the list ## of songs, sorting, searching, the show filter and the popup with all songs of a ## soundtrack. const STATISTICS: Array[Dictionary] = [ {"soundtrack_uuid": "st-1", "soundtrack_name": "Chrono Trigger", "soundtrack_played": 5, "soundtrack_last_played": "2026-09-30T20:00:00+02:00", "songs": [ {"song_name": "Corridors of Time", "times_played": 1}, {"song_name": "Frog's Theme", "times_played": 3}, {"song_name": "Wind Scene", "times_played": 0}, {"song_name": "Battle with Magus", "times_played": 2}, {"song_name": "To Far Away Times", "times_played": 0}, {"song_name": "Schala's Theme", "times_played": 4}, {"song_name": "Peaceful Days", "times_played": 1}, {"song_name": "Zeal Palace", "times_played": 1}, ]}, {"soundtrack_uuid": "st-2", "soundtrack_name": "Terranigma", "soundtrack_played": 0, "songs": [{"song_name": "Underworld", "times_played": 0}]}, {"soundtrack_uuid": "st-3", "soundtrack_name": "earthbound", "soundtrack_played": 9, "soundtrack_last_played": "2026-10-01T10:00:00Z", "songs": []}, {"soundtrack_uuid": "st-4", "soundtrack_name": "Final Fantasy VI", "soundtrack_played": 1, "soundtrack_last_played": "2026-08-01T10:00:00Z", "songs": [ {"song_name": "Dancing Mad", "times_played": 1}, ]}, ] var _view: StatisticsView func _before_window_starts() -> void: _server.respond_json("/statistics/soundtracks", STATISTICS) func before_test() -> void: await super() _view = _window.get_node("StatisticsView") func _open_statistics() -> void: await _click_at(_center(_window.get_node("TopBar/%StatisticsTab"))) await _runner.simulate_frames(2) func _center(control: Control) -> Vector2: return control.get_global_rect().get_center() func _shown_names() -> Array[String]: var names: Array[String] = [] for card: SoundtrackCard in _view.cards: if card.visible: names.append(card.soundtrack.soundtrack_name) return names func _card(soundtrack_name: String) -> SoundtrackCard: for card: SoundtrackCard in _view.cards: if card.soundtrack.soundtrack_name == soundtrack_name: return card return null func _visible_texts(list: VBoxContainer) -> Array[String]: var texts: Array[String] = [] for label: Label in list.get_children(): if label.visible: texts.append(label.text) return texts # Tabs func test_quiz_tab_is_chosen_at_startup() -> void: assert_bool(_view.visible).is_false() assert_bool((_window.get_node("TopBar/%QuizTab") as Button).button_pressed).is_true() assert_int(_server.count("/statistics/soundtracks")).is_equal(0) func test_clicking_statistics_tab_shows_statistics_instead_of_the_quiz() -> void: await _open_statistics() assert_bool(_view.visible).is_true() assert_bool(_quiz.visible).is_false() assert_bool((_window.get_node("TopBar/%StatisticsTab") as Button).button_pressed).is_true() assert_bool((_window.get_node("TopBar/%QuizTab") as Button).button_pressed).is_false() assert_vector(_view.get_global_rect().position).is_equal(Vector2(0, 56)) assert_vector(_view.get_global_rect().size).is_equal(Vector2(1920, 1024)) func test_clicking_quiz_tab_goes_back_to_the_quiz() -> void: await _open_statistics() await _click_at(_center(_window.get_node("TopBar/%QuizTab"))) assert_bool(_view.visible).is_false() assert_bool(_quiz.visible).is_true() assert_bool((_window.get_node("TopBar/%QuizTab") as Button).button_pressed).is_true() func test_clicks_on_statistics_do_not_reach_the_quiz_behind() -> void: await _open_statistics() var next_button: Button = _quiz.get_node("SongControls/NextButton") await _click_at(_center(next_button)) assert_int(Playlist.currently_playing_song).is_equal(-1) func test_song_keeps_playing_behind_statistics() -> void: await _play_first_song() await _open_statistics() assert_int(Playlist.currently_playing_song).is_equal(0) assert_bool((_quiz.get_node("MusicPlayer") as MusicPlayer).audio_player.stream_paused) \ .is_false() func test_statistics_are_loaded_again_each_time_the_tab_opens() -> void: await _open_statistics() await _click_at(_center(_window.get_node("TopBar/%QuizTab"))) await _open_statistics() assert_int(_server.count("/statistics/soundtracks")).is_equal(2) assert_int(_view.cards.size()).is_equal(STATISTICS.size()) func test_statistics_are_loaded_again_after_a_sync() -> void: await _open_statistics() _window.get_node("SyncPopup").sync_finished.emit() assert_int(_server.count("/statistics/soundtracks")).is_equal(2) # Cards func test_one_card_per_soundtrack_sorted_a_to_z() -> void: await _open_statistics() assert_array(_shown_names()).contains_exactly( ["Chrono Trigger", "earthbound", "Final Fantasy VI", "Terranigma"]) assert_str(_view.count_label.text).is_equal("4 soundtracks") func test_card_shows_plays_last_played_and_most_and_least_played_songs() -> void: await _open_statistics() var card: SoundtrackCard = _card("Chrono Trigger") assert_str(card.name_label.text).is_equal("Chrono Trigger") assert_str(card.played_label.text).is_equal("Played 5 times") assert_str(card.last_played_label.text).is_equal("Last played 2026-09-30") assert_array(_visible_texts(card.most_played_list)).contains_exactly( ["4 × Schala's Theme", "3 × Frog's Theme", "2 × Battle with Magus"]) # Songs never played are left out, so the least played are the least played of those assert_array(_visible_texts(card.least_played_list)).contains_exactly( ["1 × Corridors of Time", "1 × Peaceful Days", "1 × Zeal Palace"]) assert_bool(card.least_played_header.visible).is_true() func test_card_of_never_played_soundtrack_lists_no_songs() -> void: await _open_statistics() var card: SoundtrackCard = _card("Terranigma") assert_str(card.played_label.text).is_equal("Never played") assert_bool(card.last_played_label.visible).is_false() assert_str(card.most_played_header.text).is_equal("No songs played yet") assert_array(_visible_texts(card.most_played_list)).is_empty() assert_bool(card.least_played_header.visible).is_false() func test_card_with_one_played_song_lists_only_it() -> void: await _open_statistics() var card: SoundtrackCard = _card("Final Fantasy VI") assert_str(card.most_played_header.text).is_equal("Most played") assert_array(_visible_texts(card.most_played_list)).contains_exactly(["1 × Dancing Mad"]) assert_bool(card.least_played_header.visible).is_false() assert_array(_visible_texts(card.least_played_list)).is_empty() func test_card_with_fewer_than_six_played_songs_lists_them_all_as_most_played() -> void: var songs: Array[Dictionary] = [{"song_name": "Never", "times_played": 0}] for i: int in 5: songs.append({"song_name": "Song %d" % (i + 1), "times_played": i + 1}) _server.respond_json("/statistics/soundtracks", [ {"soundtrack_name": "Lufia II", "soundtrack_played": 15, "songs": songs}]) await _open_statistics() var card: SoundtrackCard = _card("Lufia II") assert_array(_visible_texts(card.most_played_list)).contains_exactly( ["5 × Song 5", "4 × Song 4", "3 × Song 3", "2 × Song 2", "1 × Song 1"]) assert_bool(card.least_played_header.visible).is_false() assert_array(_visible_texts(card.least_played_list)).is_empty() func test_card_without_songs() -> void: await _open_statistics() var card: SoundtrackCard = _card("earthbound") assert_str(card.most_played_header.text).is_equal("No songs") assert_array(_visible_texts(card.most_played_list)).is_empty() assert_bool(card.least_played_header.visible).is_false() # Sorting, searching and filtering func test_sort_orders() -> void: await _open_statistics() var expected: Dictionary = { StatisticsView.SortOrder.Z_TO_A: ["Terranigma", "Final Fantasy VI", "earthbound", "Chrono Trigger"], StatisticsView.SortOrder.MOST_PLAYED: ["earthbound", "Chrono Trigger", "Final Fantasy VI", "Terranigma"], StatisticsView.SortOrder.LEAST_PLAYED: ["Terranigma", "Final Fantasy VI", "Chrono Trigger", "earthbound"], StatisticsView.SortOrder.A_TO_Z: ["Chrono Trigger", "earthbound", "Final Fantasy VI", "Terranigma"], } for order: StatisticsView.SortOrder in expected: _view.sort_option.select(order) _view.sort_option.item_selected.emit(order) assert_array(_shown_names()).contains_exactly(expected[order]) # The grid shows the cards in the same order for i: int in _view.cards.size(): assert_int(_view.cards[i].get_index()).is_equal(i) func test_sort_by_plays_breaks_ties_by_name() -> void: var tied: Array[Dictionary] = [ {"soundtrack_name": "Lufia II", "soundtrack_played": 2}, {"soundtrack_name": "Earthbound", "soundtrack_played": 2}, ] _server.respond_json("/statistics/soundtracks", tied) await _open_statistics() _view.sort_option.select(StatisticsView.SortOrder.MOST_PLAYED) _view.apply_sort() assert_array(_shown_names()).contains_exactly(["Earthbound", "Lufia II"]) func test_typing_in_search_filters_cards_and_keeps_the_sort() -> void: await _open_statistics() _view.sort_option.select(StatisticsView.SortOrder.Z_TO_A) _view.apply_sort() # What typing does; the test runner's key presses type every letter twice _view.search_field.text = "tri" _view.search_field.text_changed.emit("tri") assert_str(_view.search_field.text).is_equal("tri") # "Chrono Trigger" contains it, "Terranigma" has the letters in order assert_array(_shown_names()).contains_exactly(["Terranigma", "Chrono Trigger"]) assert_str(_view.count_label.text).is_equal("2 of 4 soundtracks") func test_search_uses_the_search_popup_matching() -> void: await _open_statistics() _view.search_field.text = "finalfantasy" _view.apply_filter() assert_array(_shown_names()).contains_exactly(["Final Fantasy VI"]) func test_clear_button_shows_all_cards() -> void: await _open_statistics() _view.search_field.text = "chrono" _view.apply_filter() await _click_at(_center(_view.clear_button)) assert_str(_view.search_field.text).is_empty() assert_int(_shown_names().size()).is_equal(4) func test_show_played_and_never_played() -> void: await _open_statistics() _view.show_option.select(StatisticsView.ShowFilter.PLAYED) _view.show_option.item_selected.emit(StatisticsView.ShowFilter.PLAYED) assert_array(_shown_names()).contains_exactly( ["Chrono Trigger", "earthbound", "Final Fantasy VI"]) assert_str(_view.count_label.text).is_equal("3 of 4 soundtracks") _view.show_option.select(StatisticsView.ShowFilter.NEVER_PLAYED) _view.show_option.item_selected.emit(StatisticsView.ShowFilter.NEVER_PLAYED) assert_array(_shown_names()).contains_exactly(["Terranigma"]) assert_str(_view.count_label.text).is_equal("1 of 4 soundtracks") _view.show_option.select(StatisticsView.ShowFilter.ALL) _view.show_option.item_selected.emit(StatisticsView.ShowFilter.ALL) assert_int(_shown_names().size()).is_equal(4) assert_str(_view.count_label.text).is_equal("4 soundtracks") func test_show_filter_and_search_together() -> void: await _open_statistics() _view.show_option.select(StatisticsView.ShowFilter.PLAYED) _view.search_field.text = "t" _view.apply_filter() # Terranigma matches the search but has never been played assert_array(_shown_names()).contains_exactly( ["Chrono Trigger", "earthbound", "Final Fantasy VI"]) func test_filters_stay_when_statistics_are_loaded_again() -> void: await _open_statistics() _view.show_option.select(StatisticsView.ShowFilter.NEVER_PLAYED) _view.sort_option.select(StatisticsView.SortOrder.Z_TO_A) _view.refresh() assert_array(_shown_names()).contains_exactly(["Terranigma"]) assert_str(_view.cards[0].soundtrack.soundtrack_name).is_equal("Terranigma") # Songs func _show_songs_mode() -> void: await _open_statistics() await _click_at(_center(_view.songs_mode_button)) await _runner.simulate_frames(1) func _listed_songs() -> Array[String]: var listed: Array[String] = [] for song: SongInfoForStats in _view.song_list.songs: listed.append(song.song_name) return listed func _search(text: String) -> void: _view.search_field.text = text _view.apply_filter() func test_songs_button_shows_every_played_song_a_to_z_instead_of_the_cards() -> void: await _show_songs_mode() assert_bool(_view.song_list.visible).is_true() assert_bool(_view.card_scroll.visible).is_false() assert_bool(_view.songs_mode_button.button_pressed).is_true() assert_bool(_view.soundtracks_mode_button.button_pressed).is_false() # Songs never played are left out assert_array(_listed_songs()).contains_exactly([ "Battle with Magus", "Corridors of Time", "Dancing Mad", "Frog's Theme", "Peaceful Days", "Schala's Theme", "Zeal Palace", ]) assert_str(_view.count_label.text).is_equal("7 played songs") assert_str(_view.search_field.placeholder_text).is_equal("Search songs and soundtracks") func test_song_rows_show_the_song_its_soundtrack_and_plays() -> void: await _show_songs_mode() var row: SongStatsRow = _view.song_list.shown_rows()[0] assert_str(row.song_label.get_parsed_text()).is_equal("Battle with Magus") assert_str(row.soundtrack_label.get_parsed_text()).is_equal("Chrono Trigger") assert_str(row.played_label.text).is_equal("2") assert_int(_view.song_list.shown_rows().size()).is_equal(7) func test_soundtracks_button_shows_the_cards_again() -> void: await _show_songs_mode() await _click_at(_center(_view.soundtracks_mode_button)) assert_bool(_view.card_scroll.visible).is_true() assert_bool(_view.song_list.visible).is_false() assert_str(_view.count_label.text).is_equal("4 soundtracks") assert_bool(_view.show_option.visible).is_true() func test_song_search_finds_song_names_and_soundtrack_names() -> void: await _show_songs_mode() _search("magus") assert_array(_listed_songs()).contains_exactly(["Battle with Magus"]) assert_str(_view.count_label.text).is_equal("1 of 7 played songs") # Every song of a soundtrack whose name matches _search("final fantasy") assert_array(_listed_songs()).contains_exactly(["Dancing Mad"]) func test_song_search_highlights_what_matched() -> void: await _show_songs_mode() _search("magus") var row: SongStatsRow = _view.song_list.shown_rows()[0] assert_str(row.song_label.text).contains("[color=") assert_str(row.song_label.get_parsed_text()).is_equal("Battle with Magus") assert_str(row.soundtrack_label.text).not_contains("[color=") func test_typing_a_song_search_waits_for_a_pause() -> void: await _show_songs_mode() _view.search_field.text = "magus" _view.search_field.text_changed.emit("magus") assert_int(_view.song_list.songs.size()).is_equal(7) await await_millis(300) assert_array(_listed_songs()).contains_exactly(["Battle with Magus"]) func test_show_menu_is_hidden_for_songs() -> void: await _show_songs_mode() assert_bool(_view.show_option.visible).is_false() assert_bool(_view.get_node("Toolbar/ShowLabel").visible).is_false() func test_song_sort_orders() -> void: await _show_songs_mode() var expected: Dictionary = { StatisticsView.SortOrder.MOST_PLAYED: ["Schala's Theme", "Frog's Theme", "Battle with Magus", "Corridors of Time", "Dancing Mad", "Peaceful Days", "Zeal Palace"], StatisticsView.SortOrder.LEAST_PLAYED: ["Corridors of Time", "Dancing Mad", "Peaceful Days", "Zeal Palace", "Battle with Magus", "Frog's Theme", "Schala's Theme"], StatisticsView.SortOrder.Z_TO_A: ["Zeal Palace", "Schala's Theme", "Peaceful Days", "Frog's Theme", "Dancing Mad", "Corridors of Time", "Battle with Magus"], } for order: StatisticsView.SortOrder in expected: _view.sort_option.select(order) _view.sort_option.item_selected.emit(order) assert_array(_listed_songs()).contains_exactly(expected[order]) func test_songs_with_the_same_name_are_sorted_by_soundtrack() -> void: _server.respond_json("/statistics/soundtracks", [ {"soundtrack_name": "Lufia II", "songs": [{"song_name": "Main Theme", "times_played": 1}]}, {"soundtrack_name": "Earthbound", "songs": [{"song_name": "Main Theme", "times_played": 1}]}, ]) await _show_songs_mode() var soundtracks: Array[String] = [] for song: SongInfoForStats in _view.song_list.songs: soundtracks.append(song.soundtrack_name) assert_array(soundtracks).contains_exactly(["Earthbound", "Lufia II"]) func test_clicking_a_song_shows_its_soundtrack() -> void: await _show_songs_mode() var popup: SoundtrackStatsPopup = _window.get_node("SoundtrackStatsPopup") _search("dancing") await _click_at(_center(_view.song_list.shown_rows()[0])) assert_bool(popup.visible).is_true() assert_str(popup.title_label.text).is_equal("Final Fantasy VI") func test_songs_stay_shown_when_statistics_are_loaded_again() -> void: await _show_songs_mode() _server.respond_json("/statistics/soundtracks", STATISTICS.slice(3, 4)) _view.refresh() assert_bool(_view.song_list.visible).is_true() assert_array(_listed_songs()).contains_exactly(["Dancing Mad"]) func test_only_the_rows_on_screen_are_made_for_many_songs() -> void: var songs: Array[Dictionary] = [] for i: int in 5000: songs.append({"song_name": "Song %04d" % i, "times_played": i % 7 + 1}) _server.respond_json("/statistics/soundtracks", [{"soundtrack_name": "Big", "songs": songs}]) await _show_songs_mode() var rows: int = _view.song_list.rows_area.get_child_count() assert_int(rows).is_less(60) assert_str(_view.count_label.text).is_equal("5000 played songs") _view.song_list.scroll_to(2500) await _runner.simulate_frames(1) assert_str(_view.song_list.shown_rows()[0].song.song_name).is_equal("Song 2500") assert_int(_view.song_list.rows_area.get_child_count()).is_equal(rows) func test_mouse_wheel_scrolls_the_songs() -> void: var songs: Array[Dictionary] = [] for i: int in 200: songs.append({"song_name": "Song %03d" % i, "times_played": 1}) _server.respond_json("/statistics/soundtracks", [{"soundtrack_name": "Big", "songs": songs}]) await _show_songs_mode() var transform: Transform2D = _window.get_viewport().get_final_transform() _runner.set_mouse_position(transform * _center(_view.song_list.rows_area)) await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_WHEEL_DOWN) await _runner.await_input_processed() assert_str(_view.song_list.shown_rows()[0].song.song_name).is_equal("Song 003") # Popup func test_clicking_a_card_shows_all_its_songs_most_played_first() -> void: await _open_statistics() var popup: SoundtrackStatsPopup = _window.get_node("SoundtrackStatsPopup") await _click_at(_center(_card("Chrono Trigger"))) assert_bool(popup.visible).is_true() assert_str(popup.title_label.text).is_equal("Chrono Trigger") assert_str(popup.summary_label.text) \ .is_equal("Played 5 times · Last played 2026-09-30 · 8 songs") var rows: Array[String] = [] for row: ListRow in popup.song_list.get_children(): rows.append(row.text) assert_array(rows).contains_exactly([ "4 × Schala's Theme", "3 × Frog's Theme", "2 × Battle with Magus", "1 × Corridors of Time", "1 × Peaceful Days", "1 × Zeal Palace", "0 × To Far Away Times", "0 × Wind Scene", ]) func test_clicking_outside_the_popup_closes_it() -> void: await _open_statistics() var popup: SoundtrackStatsPopup = _window.get_node("SoundtrackStatsPopup") await _click_at(_center(_card("Chrono Trigger"))) await _runner.simulate_frames(1) await _click_at(Vector2(100, 1000)) assert_bool(popup.visible).is_false() assert_bool(_view.visible).is_true() # Loading func test_failed_load_shows_error_and_retry_loads() -> void: _server.respond_json("/statistics/soundtracks", {"error": "Internal Server Error"}, 500) await _open_statistics() assert_str(_view.status_label.text).is_equal("Could not load statistics") assert_bool(_view.retry_button.visible).is_true() assert_array(_view.cards).is_empty() _server.respond_json("/statistics/soundtracks", STATISTICS) await _click_at(_center(_view.retry_button)) assert_str(_view.status_label.text).is_empty() assert_bool(_view.retry_button.visible).is_false() assert_int(_view.cards.size()).is_equal(4) func test_shows_loading_until_the_server_answers() -> void: _server.hold("/statistics/soundtracks") await _open_statistics() assert_str(_view.status_label.text).is_equal("Loading statistics…") _server.release("/statistics/soundtracks") assert_str(_view.status_label.text).is_empty() assert_int(_view.cards.size()).is_equal(4) func test_failed_reload_keeps_the_cards() -> void: await _open_statistics() _server.respond_json("/statistics/soundtracks", [], 500) _view.refresh() assert_int(_view.cards.size()).is_equal(4) assert_bool(_view.retry_button.visible).is_false() func test_fewer_soundtracks_after_reload_removes_cards() -> void: await _open_statistics() _server.respond_json("/statistics/soundtracks", STATISTICS.slice(0, 2)) _view.refresh() assert_int(_view.cards.size()).is_equal(2) assert_int(_view.card_grid.get_child_count()).is_equal(2)