|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
| 5 | +import shutil |
5 | 6 | from typing import TYPE_CHECKING |
6 | 7 |
|
| 8 | +from paths import GAME_DIRNAME |
7 | 9 | from scenarios.geometry import ( |
| 10 | + DIALOG, |
8 | 11 | EDITORS, |
9 | 12 | TAB_X, |
10 | 13 | TAB_Y, |
11 | 14 | TOOLBAR, |
| 15 | + dialog_point, |
12 | 16 | editor_point, |
13 | 17 | panel_left, |
14 | 18 | panel_point, |
@@ -82,54 +86,69 @@ def panel_tabs_are_choices(run_state: E2ERun) -> None: |
82 | 86 |
|
83 | 87 |
|
84 | 88 | @scenario() |
85 | | -def toolbar_actions(run_state: E2ERun) -> None: |
86 | | - """Every Rust shell-toolbar icon invokes its own action. |
| 89 | +def import_action(run_state: E2ERun) -> None: |
| 90 | + """The Import toolbar icon picks an image and dispatches its command. |
87 | 91 |
|
88 | | - Project actions are opened and cancelled rather than accepted: the point is |
89 | | - the action-to-dialog wiring, not creating files in an isolated e2e run. |
90 | | - Clipboard actions use a selected tree and then compare the map, so a button |
91 | | - that merely receives a click cannot pass. |
| 92 | + Import is the one toolbar action no other scenario drives (New/Load/Save |
| 93 | + As/Export are covered by gallery and map). Diffuse is the default type, so |
| 94 | + picking a file is the full path: icon -> dialog -> pick -> ImportDiffuseCommand. |
92 | 95 | """ |
93 | 96 | run_state.focus() |
94 | 97 | left = panel_left(run_state) |
95 | 98 |
|
96 | | - # New Project has its own dialog. Load, Import, Save (without a project |
97 | | - # path), Save As, and Export all use the file dialog, with distinct visible |
98 | | - # headings/configuration. Capturing each gives the review a concise audit |
99 | | - # trail of the icon row without mutating project state. |
100 | | - run_state.click(*panel_point(left, TOOLBAR["new_project"]), delay=0.7) |
101 | | - run_state.screenshot("new-project") |
102 | | - run_state.key("Escape", delay=0.35) |
| 99 | + # Import browses springboard/projects/; drop an image there for it to pick. |
| 100 | + assert run_state.write_dir is not None |
| 101 | + projects = run_state.write_dir / "springboard" / "projects" |
| 102 | + projects.mkdir(parents=True, exist_ok=True) |
| 103 | + game_image = ( |
| 104 | + run_state.write_dir |
| 105 | + / "games" |
| 106 | + / GAME_DIRNAME |
| 107 | + / "LuaUI" |
| 108 | + / "images" |
| 109 | + / "scenedit" |
| 110 | + / "area-add.png" |
| 111 | + ) |
| 112 | + shutil.copyfile(game_image, projects / "import_test.png") |
| 113 | + |
| 114 | + run_state.click(*panel_point(left, TOOLBAR["import"]), delay=0.7) |
| 115 | + run_state.screenshot("import-dialog") |
| 116 | + run_state.click(*dialog_point(run_state, DIALOG["asset_first_cell"]), delay=0.4) |
| 117 | + run_state.click(*dialog_point(run_state, DIALOG["file_ok_name"]), delay=0.6) |
| 118 | + run_state.assert_any_command("ImportDiffuseCommand") |
103 | 119 |
|
104 | | - for action in ("load", "import", "save", "save_as", "export"): |
105 | | - before = run_state.screenshot(f"before-{action}") |
106 | | - run_state.click(*panel_point(left, TOOLBAR[action]), delay=0.65) |
107 | | - opened = run_state.screenshot(f"{action}-dialog") |
108 | | - run_state.assert_screenshot_pixels(before, opened, min_changed=2_000) |
109 | | - run_state.key("Escape", delay=0.35) |
110 | 120 |
|
111 | | - # Exact toolbar clicks, not their keyboard shortcuts. Paste needs the |
112 | | - # cursor ground hit; move it to a distinct map point before clicking the |
113 | | - # icon so the second tree's placement is observable. |
| 121 | +@scenario() |
| 122 | +def clipboard_actions(run_state: E2ERun) -> None: |
| 123 | + """The Copy/Cut/Paste toolbar icons round-trip a selected object. |
| 124 | +
|
| 125 | + Exact toolbar clicks, not their keyboard shortcuts. Clicking the Paste icon |
| 126 | + leaves the cursor over the panel, so the paste must land at the map centre — |
| 127 | + in view — rather than off-screen behind the panel; the golden checks that |
| 128 | + centre region changed. Cut is then undone with Ctrl+Z. Each step asserts its |
| 129 | + grouped native command and a real change to the map. |
| 130 | + """ |
| 131 | + run_state.focus() |
114 | 132 | left = _open(run_state, "features") |
115 | 133 | _arm_tree(run_state, left) |
116 | 134 | width, height = window_size(run_state) |
117 | 135 | source = (width // 3 - 130, height // 2) |
118 | | - target = (width // 3 + 220, height // 2 + 120) |
119 | 136 | run_state.wheel(*source, clicks=8, up=True) |
120 | 137 | run_state.click(*source, delay=0.8) |
121 | 138 | run_state.key("Escape", delay=0.35) |
122 | 139 | run_state.click(*source, delay=0.5) |
123 | 140 |
|
124 | 141 | run_state.click(*panel_point(left, TOOLBAR["copy"]), delay=0.4) |
125 | 142 | before_paste = run_state.screenshot("copied") |
126 | | - run_state.move(*target, delay=0.25) |
127 | 143 | mark = len(run_state.commands()) |
128 | 144 | run_state.click(*panel_point(left, TOOLBAR["paste"]), delay=0.8) |
129 | 145 | pasted = run_state.screenshot("pasted") |
130 | 146 | if not any(entry["data"].get("className") == "CompoundCommand" for entry in run_state.commands()[mark:]): |
131 | 147 | raise AssertionError("toolbar Paste did not dispatch a grouped native command") |
132 | | - run_state.assert_screenshot_pixels(before_paste, pasted, min_changed=400) |
| 148 | + # The paste must appear near the centre of the map view (left of the panel), |
| 149 | + # not at the off-screen cursor over the Paste icon. |
| 150 | + centre = (left // 2 - 220, height // 2 - 220, 440, 440) |
| 151 | + run_state.assert_region_pixels(before_paste, pasted, centre, min_changed=200) |
133 | 152 |
|
134 | 153 | mark = len(run_state.commands()) |
135 | 154 | run_state.click(*panel_point(left, TOOLBAR["cut"]), delay=0.8) |
|
0 commit comments