Add visual harmonization tests for editor UI components and ground finish chooser

- Implemented `test_editor_visual_harmonization.gd` to validate the Stickman editor and prop editor UI layouts, ensuring proper functionality and visual consistency.
- Created `test_editor_visual_theme.gd` to verify the loading and application of visual themes in the editor, including semantic overrides and default values.
- Introduced `test_phase19_ground_finish_chooser.gd` to test the ground finish chooser's functionality, including layout responsiveness, selection behavior, and interaction with the stage.
- Added new scripts for ground finish preview and chooser UI components to enhance the editor's visual representation of ground finishes.
This commit is contained in:
2026-10-23 15:20:12 -04:00
parent 0a5ef0a61e
commit ddb298f631
40 changed files with 3442 additions and 434 deletions
+72
View File
@@ -0,0 +1,72 @@
extends SceneTree
const EDITOR_VISUAL_THEME := preload("res://scripts/shared/editor_ui/editor_visual_theme.gd")
var _checks: int = 0
var _failures: int = 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var defaults: EditorVisualTheme = EDITOR_VISUAL_THEME.new()
check("committed shared theme loads", defaults.load_from(EDITOR_VISUAL_THEME.DEFAULT_PATH))
check("default body font is 18", defaults.chrome_px(&"body", &"prop") == 18)
check("default touch target is 44 px", defaults.chrome_px(&"button_min_height", &"stickman") == 44)
check("preview role preserves alpha", is_equal_approx(defaults.chrome_color(&"preview").a, 0.4))
var custom_path: String = "user://editor_visual_theme_test.json"
var custom_file: FileAccess = FileAccess.open(custom_path, FileAccess.WRITE)
custom_file.store_string('{"chrome":{"colors":{"edit":"#22C6FF","focus":"#FF00AA"},"targets":{"button_min_height":48}},"editors":{"prop":{"colors":{"edit":"#FF8800"}}}}')
custom_file.close()
var custom: EditorVisualTheme = EDITOR_VISUAL_THEME.new()
check("custom shared theme loads", custom.load_from(custom_path))
check("prop semantic override wins", custom.chrome_color(&"edit", &"prop").is_equal_approx(Color("#FF8800")))
check("stickman uses common semantic default", custom.chrome_color(&"edit", &"stickman").is_equal_approx(Color("#22C6FF")))
check("common touch target override applies", custom.chrome_px(&"button_min_height", &"prop") == 48)
check("local focus token overrides default", custom.chrome_color(&"focus").is_equal_approx(Color("#FF00AA")))
DirAccess.remove_absolute(custom_path)
var invalid_path: String = "user://editor_visual_theme_test_invalid.json"
var invalid_file: FileAccess = FileAccess.open(invalid_path, FileAccess.WRITE)
invalid_file.store_string('{"chrome":{"colors":{"edit":"electric"},"targets":{"button_min_height":"large"}}}')
invalid_file.close()
var invalid: EditorVisualTheme = EDITOR_VISUAL_THEME.new()
invalid.load_from(invalid_path)
check("invalid color falls back to semantic default", invalid.chrome_color(&"edit").is_equal_approx(Color("#22C6FF")))
check("invalid size falls back to semantic default", invalid.chrome_px(&"button_min_height") == 44)
DirAccess.remove_absolute(invalid_path)
var prop_theme: Theme = defaults.control_theme(&"prop")
var stickman_theme: Theme = defaults.control_theme(&"stickman")
var prop_focus: StyleBoxFlat = prop_theme.get_stylebox("focus", "Button") as StyleBoxFlat
var stickman_focus: StyleBoxFlat = stickman_theme.get_stylebox("focus", "Button") as StyleBoxFlat
check("each editor receives a separate local Theme", prop_theme.get_instance_id() != stickman_theme.get_instance_id())
check("each editor receives separate focus styles", prop_focus.get_instance_id() != stickman_focus.get_instance_id())
check("focus outline uses semantic focus token", prop_focus.border_color.is_equal_approx(defaults.chrome_color(&"focus")))
var action: Button = Button.new()
defaults.style_button_role(action, &"primary", &"prop")
var action_box: StyleBoxFlat = action.get_theme_stylebox("normal") as StyleBoxFlat
check("primary action uses semantic action color", action_box.bg_color.is_equal_approx(defaults.chrome_color(&"action_primary", &"prop")))
check("primary action reaches the minimum target size", action.custom_minimum_size.y >= 44.0)
action.free()
print("----------------------------------------")
if _failures == 0:
print("RESULT: ALL PASSED (%d assertions)" % _checks)
quit(0)
else:
print("RESULT: %d FAILURE(S) out of %d assertions" % [_failures, _checks])
quit(1)
func check(label: String, condition: bool) -> void:
_checks += 1
if condition:
print("PASS: %s" % label)
else:
_failures += 1
push_error("FAIL: %s" % label)