Files
MusicPlayer/tests/integration/test_layout_unchanged.gd
Sansan 13fdb3f68c
Build / test (push) Successful in 38s
Build / build (push) Successful in 1m13s
Show the server's version history in the About popup
The About popup is twice as wide and shows the player's and the server's
version history side by side, each in its own scrolling column. The
server's comes from GET /api/v1/version/history every time the popup
opens. The description, which is about both, is centred above the
columns, and each history starts right under its version.
2026-10-07 14:32:31 +02:00

86 lines
3.2 KiB
GDScript

extends GdUnitTestSuite
## Checks that every node of the main window is where it was when the baseline was taken.
##
## [code]tests/data/layout_baseline.json[/code] is written by
## [code]tools/take_screenshots.gd[/code] (run it with --headless and copy its layout.json).
## It holds the position, size and visibility of every node in each UiTour state, keyed
## by the node's path from the main window. Take a new baseline when the layout is
## meant to change, e.g. after moving a button.
const BASELINE_PATH: String = "res://tests/data/layout_baseline.json"
## Nodes whose height follows text that changes between versions, such as the changelog.
## Their position and width are still checked.
const HEIGHT_FOLLOWS_TEXT: Array[String] = [
"AboutPopup/AboutPanel/Columns/ScrollContainer/ContentVBox",
"AboutPopup/AboutPanel/Columns/ServerScrollContainer/ServerContentVBox",
]
## 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://main/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()
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 path: String in baseline[state]:
var expected: Dictionary = baseline[state][path]
if !actual.has(path):
problems.append("%s: %s is missing" % [state, path])
continue
var rect: Array = actual[path].rect
var sides: int = 3 if _height_follows_text(path) else 4
for i: int in sides:
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()
static func _height_follows_text(path: String) -> bool:
return HEIGHT_FOLLOWS_TEXT.any(func(node_path: String) -> bool:
return path == node_path || path.begins_with(node_path + "/"))