themes/main_theme.tres is the project theme. It holds Godot's default look for every control type the game uses, plus named styles for the game's own look (popups, the background, spacers, list rows, title and text sizes, highlights) and a palette for the popup dimming. Scenes and scripts name these styles instead of setting colours, sizes or style boxes, and the five old theme files are gone. themes/README.md explains the styles and how to make a new theme. The screenshot tour now uses the real character pictures, so the layout baseline is taken again. Screenshots are pixel-identical to before, and test_theme.gd checks that the look stays in the theme.
85 lines
3.1 KiB
GDScript
85 lines
3.1 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/ScrollContainer/ContentVBox",
|
|
]
|
|
|
|
## 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 + "/"))
|