2.1 KiB
2.1 KiB
Automated Testing Framework
The designer-test (designer-test/) provides automated UI testing.
Test Architecture
- WindowController: Finds designer window, sends mouse/keyboard events via Windows SendInput API
- HierarchyReader: Parses UI hierarchy JSON to find elements by ID/class (with retry logic and exponential backoff)
- LogParser: Monitors log file for navigation events
- TestRunner: Orchestrates test execution, reports results
- UIInspector: Dumps UI hierarchy with atomic writes (temp file + rename pattern)
Key Implementation Details
- Path Normalization: RmlUi uses
|instead of:in Windows paths (e.g.,D|\Dev\...). The UIInspector normalizes paths for correct document matching. - Atomic File Writes: Hierarchy files are written to
.tmpthen renamed to prevent partial reads. - Retry with Backoff: HierarchyReader retries up to 10 times with exponential backoff (30ms base) and validates JSON completeness.
- Dynamic Back Button:
GoHome()finds back buttons from hierarchy by class (app-bar-navorbrowser-nav-btn) instead of fixed coordinates.
Writing Tests
// Find element by ID and click it
bool ClickById(TestContext& ctx, const std::string& id) {
ctx.hierarchy.Reload();
auto element = ctx.hierarchy.FindById(id);
if (!element) return false;
int x = element->bounds.centerX();
int y = element->bounds.centerY();
ScaleToPhysical(ctx, x, y); // Convert logical to physical coords
ctx.window.SendClick(x, y);
return true;
}
// Test example
bool TestNavigateToDialer(TestContext& ctx) {
GoHome(ctx);
ctx.log.Clear();
if (!ClickById(ctx, "dock-phone")) return false;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
ctx.log.Reload();
return ctx.log.Contains("Loaded screen: apps/dialer/dialer.rml");
}
Test Output
Tests produce JSON results at test_results.json:
{
"name": "Mosis Designer UI Tests",
"summary": {"passed": 5, "failed": 0, "total": 5},
"tests": [
{"name": "Navigate to Dialer", "status": "passed", "duration_ms": 3500}
]
}