extends GdUnitTestSuite ## Checks that every node of the main window is where it was before the window was ## split into scenes. ## ## [code]tests/data/layout_baseline.json[/code] was written by ## [code]tools/take_screenshots.gd[/code] before the split. It holds the position, size ## and visibility of every node in each UiTour state, keyed by the node's old path. This ## test runs the same tour and compares, after moving each old path to where the node ## lives now. const BASELINE_PATH: String = "res://tests/data/layout_baseline.json" ## Nodes that moved from the main window into the Quiz scene, by their old name. const QUIZ_NODES: Array[String] = [ "Open", "FileDialog", "MusicListPanel", "DebugLabel", "SettingsWindow", "NewCharacterSelect", "WinnerWindow", "Log", ] ## Nodes that moved into the Quiz scene under another path: old name to new path in ## the quiz. const RENAMED_QUIZ_NODES: Dictionary = { "Players": "PlayersPanel", "ScrollContainer": "InspirationList", "VBoxContainer": "NowPlaying", "MusicPlayer": "MusicPlayer/PlayerBar", "RepeatSongCheckButton": "MusicPlayer/RepeatSongCheckButton", "ResetPlaylistButton": "QuizToolbar/ResetPlaylistButton", "ResetPointsButton": "QuizToolbar/ResetPointsButton", "SettingsButton": "QuizToolbar/SettingsButton", "SoundTestButton": "QuizToolbar/SoundTestButton", "ShowAnswerButton": "SongControls/ShowAnswerButton", "NextButton": "SongControls/NextButton", } ## Nodes that moved from the main window into the TopBar scene, by their old name. const TOP_BAR_NODES: Array[String] = [ "TopPanelContainer", "Title", "SearchButton", "SyncButton", "StatisticsButton", "ShortcutsButton", "AboutButton", "QRButton", ] ## How far a node may be from its old place, in pixels. const TOLERANCE: float = 0.5 var _snapshot: AutoloadSnapshot var _server: FakeHttpTransport var _main: Control var _layout: Dictionary = {} func before() -> void: _snapshot = AutoloadSnapshot.take([Settings, Playlist]) UiTour.prepare_autoloads() _server = UiTour.make_server().install() # Laid out at the size the baseline was taken at, like the screenshots var viewport: SubViewport = auto_free(SubViewport.new()) viewport.size = Vector2i(1920, 1080) viewport.gui_embed_subwindows = true Engine.get_main_loop().root.add_child(viewport) _main = load("res://MainWindow.tscn").instantiate() viewport.add_child(_main) await UiTour.new(_main).run(func(state: String, popup: Node) -> void: _layout[state] = UiTour.dump_layout(_main, _main if popup == null else popup)) func after() -> void: _main.free() await Engine.get_main_loop().process_frame _server.uninstall() _snapshot.restore() ## Where the node that used to be at [param old_path] in the main window is now. static func new_path(old_path: String) -> String: var first: String = old_path.get_slice("/", 0) if first in QUIZ_NODES: return "Quiz/" + old_path if first in RENAMED_QUIZ_NODES: return "Quiz/" + RENAMED_QUIZ_NODES[first] + old_path.trim_prefix(first) if first in TOP_BAR_NODES: return "TopBar/" + old_path return old_path func _baseline() -> Dictionary: return JSON.parse_string(FileAccess.get_file_as_string(BASELINE_PATH)) func test_tour_has_the_same_states_as_the_baseline() -> void: assert_array(_layout.keys()).contains_exactly_in_any_order(_baseline().keys()) func test_every_node_is_where_it_was() -> void: var problems: Array[String] = [] var baseline: Dictionary = _baseline() for state: String in baseline: var actual: Dictionary = _layout.get(state, {}) for old_path: String in baseline[state]: var path: String = new_path(old_path) var expected: Dictionary = baseline[state][old_path] if !actual.has(path): problems.append("%s: %s is missing (was %s)" % [state, path, old_path]) continue var rect: Array = actual[path].rect for i: int in 4: if absf(rect[i] - expected.rect[i]) > TOLERANCE: problems.append("%s: %s is at %s, was %s" % [state, path, rect, expected.rect]) break if actual[path].visible != expected.visible: problems.append("%s: %s visible is %s, was %s" % [state, path, actual[path].visible, expected.visible]) assert_array(problems).override_failure_message( "%d nodes moved:\n%s" % [problems.size(), "\n".join(problems.slice(0, 30))]) \ .is_empty()