Files
MusicPlayer/tests/integration/test_animations.gd
T
SansanandClaude Opus 5.5 06421bb63e
Build / test (push) Successful in 1m50s
Build / build (push) Successful in 1m14s
Change soundtrack covers from the app and show the cover with the answer
Cover menu in the soundtrack popup ("Change cover"):
- Choose picture uploads a JPEG, PNG or WebP picture (up to 10 MB).
- Pick by ID uses a game's cover on SteamGridDB or an anime's on AniList.
- Remove cover deletes it, so the server searches for a new one.
- The server's reason is shown when it refuses a change.
After a change the new cover time is fetched, and the popup, the
statistics card and the quiz show the new cover.

Quiz: once the answer is shown, the soundtrack's cover shows to the left of
the titles. Cover and titles are centered together, left and right and up
and down, and each title keeps to two lines. Cover times come from the
soundtrack list, and songs keep their soundtrack's UUID, also in saves.

Requests can now send any body with its content type, and every 2xx answer
counts as success. Cover frames are 2:3 like the server's covers. Small
copies of real covers are used by the tests and screenshots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:32:09 +02:00

216 lines
6.8 KiB
GDScript

extends MainWindowTestSuite
## The animations, with Reduce animations off: popups, points, songs starting, the
## winner, filtering, the tabs and the buttons. The other tests run with animations off.
var _settings: SettingsPopup
func before_test() -> void:
await super()
Settings.reduce_animations = false
_settings = _window.get_node("SettingsPopup")
func _wait(seconds: float) -> void:
await await_millis(int(seconds * 1000) + 60)
func _layers(container: Node) -> Array[Node]:
return container.get_children().filter(func(node: Node) -> bool: return node is ColorRect)
func test_popup_fades_in_while_growing() -> void:
_settings.open()
assert_float(_settings.settings_panel.modulate.a).is_less(1.0)
assert_float(_settings.settings_panel.scale.x).is_less(1.0)
await _wait(Anim.NORMAL)
assert_float(_settings.settings_panel.modulate.a).is_equal(1.0)
assert_vector(_settings.settings_panel.scale).is_equal(Vector2.ONE)
func test_closing_popup_hides_after_fading_out() -> void:
_settings.open()
await _wait(Anim.NORMAL)
_settings.close()
assert_bool(_settings.visible).is_true()
assert_bool(_settings.is_closing).is_true()
await _wait(Anim.FAST)
assert_bool(_settings.visible).is_false()
assert_bool((_window.get_node("PopupBackdrop") as Control).visible).is_false()
# Ready to open again at full size
assert_float(_settings.settings_panel.modulate.a).is_equal(1.0)
func test_popup_opened_again_while_closing_stays_open() -> void:
_settings.open()
await _wait(Anim.NORMAL)
_settings.close()
_settings.open()
await _wait(Anim.NORMAL)
assert_bool(_settings.visible).is_true()
var backdrop: Control = _window.get_node("PopupBackdrop")
assert_bool(backdrop.visible).is_true()
assert_float(backdrop.modulate.a).is_equal(1.0)
func test_reduce_animations_opens_and_closes_at_once() -> void:
Settings.reduce_animations = true
_settings.open()
assert_float(_settings.settings_panel.modulate.a).is_equal(1.0)
_settings.close()
assert_bool(_settings.visible).is_false()
func test_reduce_animations_switch_is_saved() -> void:
# The switch shows the setting the window started with, which the tests turn on
assert_bool(_settings.reduce_animations_button.button_pressed).is_true()
_settings.reduce_animations_button.button_pressed = false
assert_bool(Settings.reduce_animations).is_false()
_settings.reduce_animations_button.button_pressed = true
assert_bool(Settings.reduce_animations).is_true()
var saved: ConfigFile = ConfigFile.new()
assert_int(saved.load(Settings.saved_settings_path())).is_equal(OK)
assert_bool(saved.get_value("app", "reduce_animations")).is_true()
func test_first_point_flashes_the_row_and_pops_the_score() -> void:
var crono: PlayerObject = _add_player("Crono")
await _play_first_song()
var row: PlayerRow = _player_row(crono)
row.add_point()
assert_array(_layers(row)).has_size(1)
assert_float(row.score_label.scale.x).is_greater(1.0)
await _wait(Anim.SLOW * 2)
assert_array(_layers(row)).is_empty()
assert_vector(row.score_label.scale).is_equal(Vector2.ONE)
func test_later_points_only_pop_the_score() -> void:
var crono: PlayerObject = _add_player("Crono")
await _play_first_song()
var row: PlayerRow = _player_row(crono)
row.add_point()
await _wait(Anim.SLOW * 2)
row.add_point()
assert_array(_layers(row)).is_empty()
assert_float(row.score_label.scale.x).is_greater(1.0)
func test_match_point_glows_and_says_so_until_it_changes() -> void:
Settings.winning_score = 3
var crono: PlayerObject = _add_player("Crono")
await _play_first_song()
var row: PlayerRow = _player_row(crono)
row.add_point()
row.add_point()
assert_bool(row.match_point_tag.visible).is_true()
assert_object(row.get_node_or_null("Pulse")).is_not_null()
row.minus_point()
assert_bool(row.match_point_tag.visible).is_false()
assert_object(row.get_node_or_null("Pulse")).is_null()
func test_match_point_glows_still_with_reduced_animations() -> void:
Settings.reduce_animations = true
Settings.winning_score = 2
var crono: PlayerObject = _add_player("Crono")
await _play_first_song()
_player_row(crono).add_point()
assert_object(_player_row(crono).get_node_or_null("Pulse")).is_not_null()
func test_song_start_fades_in_the_title_and_flashes_its_row() -> void:
Settings.hide_next_track = false
# The next song is downloaded while the first plays
_next_song_is({"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"})
await _play_first_song()
await _wait(Anim.SLOW)
_press("SongControls/NextButton")
await _wait(0.55)
var now_playing: Control = _quiz.get_node("NowPlaying")
assert_float(now_playing.modulate.a).is_less(1.0)
var rows: Array[Node] = _quiz.music_list_panel.get_node("%MusicList").get_children()
var flashing: Array = rows.filter(func(row: Node) -> bool: return !_layers(row).is_empty())
assert_array(flashing).is_not_empty()
func test_winner_gets_confetti_and_a_graph_drawn_from_the_left() -> void:
Settings.winning_score = 1
var crono: PlayerObject = _add_player("Crono")
await _play_first_song()
_player_row(crono).add_point()
await _runner.simulate_frames(1)
var winner: WinnerPopup = _quiz.winner_popup
assert_bool(winner.visible).is_true()
assert_object(winner.winner_panel.get_node_or_null("Confetti")).is_not_null()
assert_float(winner.score_graph.progress).is_less(1.0)
await _wait(1.3)
assert_float(winner.score_graph.progress).is_equal(1.0)
func test_graph_lines_are_cut_where_the_drawing_has_reached() -> void:
var points: PackedVector2Array = [Vector2(0, 0), Vector2(10, 0), Vector2(10, 10),
Vector2(30, 10)]
assert_array(Array(ScoreGraph.clip_line(points, 20))) \
.contains_exactly([Vector2(0, 0), Vector2(10, 0), Vector2(10, 10), Vector2(20, 10)])
assert_array(Array(ScoreGraph.clip_line(points, 100))).has_size(4)
assert_array(Array(ScoreGraph.clip_line(points, 5))) \
.contains_exactly([Vector2(0, 0), Vector2(5, 0)])
func test_statistics_tab_slides_in_and_ends_in_place() -> void:
var statistics: Control = _window.get_node("StatisticsView")
var home: Vector2 = statistics.position
_window.show_tab(&"statistics")
assert_float(statistics.position.x).is_greater(home.x)
await _wait(Anim.NORMAL)
assert_vector(statistics.position).is_equal(home)
assert_float(statistics.modulate.a).is_equal(1.0)
func test_every_button_bounces() -> void:
var sync: Button = _window.get_node("TopBar/%SyncButton")
var reset: Button = _quiz.get_node("QuizToolbar/ResetPointsButton")
var crono: PlayerObject = _add_player("Crono")
for button: BaseButton in [sync, reset, _player_row(crono).add_button]:
assert_bool(button.has_meta(&"button_bounce_added")).override_failure_message(
button.name).is_true()
func test_helpers_do_nothing_with_reduced_animations() -> void:
Settings.reduce_animations = true
var label: Label = _quiz.get_node("NowPlaying/Titles/SongLabel")
Anim.pop(label)
Anim.fade_in(label)
assert_vector(label.scale).is_equal(Vector2.ONE)
assert_float(label.modulate.a).is_equal(1.0)