Files
MusicPlayer/tests/fakes/main_window_test_suite.gd
T
Sansan d77b72159d Sort the scripts and scenes into folders
main/ holds the main window and top bar, quiz/ the quiz and its parts,
player/ the music player, popups/ every popup and what they share, data/ the
songs, players, playlist and settings, server/ the MusicServer client,
common/ the list row and GameLog, and themes/ the themes and style boxes.
2026-10-06 11:57:29 +02:00

135 lines
4.6 KiB
GDScript

class_name MainWindowTestSuite
extends GdUnitTestSuite
## Base for tests that run the real main window against a fake MusicServer.
const SONG_INFO: Array[Dictionary] = [
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
{"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"},
]
var _server: FakeHttpTransport
var _snapshot: AutoloadSnapshot
var _runner: GdUnitSceneRunner
var _window: Control
var _quiz: Quiz
func before_test() -> void:
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
Playlist.reset_playlist()
Playlist.first_song_played = false
Playlist.is_song_downloading = false
Settings.player_array.clear()
Settings.add_to_stats = true
Settings.hide_next_track = true
Settings.use_low_played_mode = false
Settings.winning_score = 20
_server = FakeHttpTransport.new().install()
var mp3: PackedByteArray = FileAccess.get_file_as_bytes("res://tests/data/short.mp3")
_server.respond_json("/music/all", ["Chrono Trigger", "Final Fantasy VI"])
_server.respond_json("/music/all/order", ["Chrono Trigger", "Final Fantasy VI"])
_server.respond_json("/music/list", [])
_server.respond_json("/characters", [])
_server.respond_bytes("/music/rand", mp3)
_server.respond_bytes("/music/addQue", PackedByteArray())
_server.respond_json("/music/info", SONG_INFO[0])
_server.respond_bytes("/music/reset", PackedByteArray())
_server.respond_bytes("/music/played?song=0", PackedByteArray())
_before_window_starts()
_runner = scene_runner("res://main/MainWindow.tscn")
_window = _runner.scene()
_quiz = _window.get_node("Quiz")
# The debug build lowers the winning score on startup; keep it out of reach
Settings.winning_score = 20
## Override to change the fake server before the window starts and sends its first
## requests.
func _before_window_starts() -> void:
pass
func after_test() -> void:
# Let nodes queued for deletion by the window be freed before orphans are counted
await await_idle_frame()
_server.uninstall()
_snapshot.restore()
## Makes the next song the server hands out the one described by [param info].
func _next_song_is(info: Dictionary) -> void:
_server.respond_json("/music/info", info)
## Presses a button in the quiz.
func _press(button_path: String) -> void:
(_quiz.get_node(button_path) as Button).pressed.emit()
## Presses Next and waits until the first song is playing.
func _play_first_song() -> void:
_press("SongControls/NextButton")
await _runner.simulate_frames(2)
## Adds a player through the name field, the same way the user does.
func _add_player(player_name: String) -> PlayerObject:
var name_field: TextEdit = _quiz.get_node(
"PlayersPanel/VBoxContainer/AddPlayerContainer/PlayerNameField")
name_field.text = player_name
_quiz.players_panel.add_player()
return Settings.player_array.back() if !Settings.player_array.is_empty() else null
## Returns the row in the player list that shows [param player_object].
func _player_row(player_object: PlayerObject) -> PlayerRow:
var rows: Node = _quiz.get_node(
"PlayersPanel/VBoxContainer/ScrollContainer/PlayersListVBoxContainer")
for row: PlayerRow in rows.get_children():
if row.player_object == player_object:
return row
return null
## Removes a player with the remove button in its row.
func _remove_player(player_object: PlayerObject) -> void:
(_player_row(player_object).get_node("HBoxContainer/RemovePlayer") as BaseButton) \
.pressed.emit()
await _runner.simulate_frames(1)
## Clicks at [param position], given in the window's 1920x1080 layout coordinates.
func _click_at(position: Vector2) -> void:
# The runner takes window pixels; the headless test window is much smaller than the
# layout, so convert like a real mouse position would be
_runner.set_mouse_position(_window.get_viewport().get_final_transform() * position)
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
await _runner.await_input_processed()
## Presses [param keys] together, e.g. [code][KEY_ALT, KEY_1][/code], then releases them.
func _press_keys(keys: Array[Key]) -> void:
for key: Key in keys:
_runner.simulate_key_press(key)
await _runner.await_input_processed()
keys.reverse()
for key: Key in keys:
_runner.simulate_key_release(key)
await _runner.await_input_processed()
## Gives a point with Alt+<number>.
func _give_point_with_keybind(number: int) -> void:
await _press_keys([KEY_ALT, (KEY_0 + number) as Key])
## Takes a point with Ctrl+Alt+<number>.
func _take_point_with_keybind(number: int) -> void:
await _press_keys([KEY_CTRL, KEY_ALT, (KEY_0 + number) as Key])
func _scores() -> Array:
return Settings.player_array.map(func(p: PlayerObject) -> int: return p.player_score)