MusicListPanel, PlayersPanel (was Players) and InspirationList (was ScrollContainer) each get their own scene and script. They report what happens through signals, and the quiz wires them to the playlist, the music player, the log and the popups. Every node keeps its place on screen. Screenshots of every UI state are pixel-identical to before, the layout test still matches the original baseline, and each part is tested on its own as well as through the quiz.
107 lines
4.2 KiB
GDScript
107 lines
4.2 KiB
GDScript
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", "VBoxContainer",
|
|
"MusicPlayer", "ResetPlaylistButton", "ResetPointsButton", "SettingsButton",
|
|
"SoundTestButton", "ShowAnswerButton", "NextButton", "RepeatSongCheckButton",
|
|
"DebugLabel", "SettingsWindow", "NewCharacterSelect", "WinnerWindow", "Log",
|
|
]
|
|
|
|
## Nodes that moved into the Quiz scene and were renamed there: old name to new name.
|
|
const RENAMED_QUIZ_NODES: Dictionary = {
|
|
"Players": "PlayersPanel",
|
|
"ScrollContainer": "InspirationList",
|
|
}
|
|
|
|
## 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()
|