extends MainWindowTestSuite ## The Statistics tab: switching between it and the quiz, the soundtrack cards, 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}, ]}, {"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: 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"]) assert_array(_visible_texts(card.least_played_list)).contains_exactly( ["0 × To Far Away Times", "0 × Wind Scene", "1 × Corridors of Time"]) func test_card_of_never_played_soundtrack() -> 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_array(_visible_texts(card.most_played_list)).contains_exactly(["0 × Underworld"]) assert_bool(card.least_played_header.visible).is_false() 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") # 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 · 7 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", "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)