-
State one observable behavior contract for the selected flow.
-
Search all smoke packages for an existing helper before adding a local one. Promote a helper to automationdriver or smoke when a second consumer uses the same interaction contract; keep plugin-specific behavior in the leaf package. Avoid page-object layers or table-editor DSLs until repeated cases justify them.
-
Reuse existing automation IDs, actions, smoke.Case, and helpers. Before driving a control, confirm its semantics expose a stable ID, role, label, current value or checked state, selected state when relevant, and the correct action. If that contract is missing, modify the smallest shared owning UI component to add a stable automation ID or semantic action, then add a focused component test for that contract. The semantic action must follow the real user interaction path; do not add a test-only bypass around product behavior.
-
Add the case under a functional path such as wox.core/test/smoke/launcher/query/plugin/calculator/. Settings cases must live under the product-facing Settings section that owns the control, for example wox.core/test/smoke/setting/ui/ for controls in the UI section; do not place them under a generic or backend/controller-derived path just because they share persisted settings code. Use the next unused three-digit number without renumbering existing cases:
- File:
NNN_descriptive_name_test.go
- Function:
TestNNNDescriptiveName
- Build constraint:
//go:build wox_ui_smoke
-
Immediately above every generated TestNNN... function, add a concise English doc comment that states the user-visible intent, the ordered UI flow, and the final evidence that proves the behavior. Mention prerequisites or cleanup only when they are part of the contract. Describe product behavior rather than automation implementation details. Use this shape:
func TestNNNDescriptiveName(t *testing.T) {
-
Drive the UI through automationdriver.Client. Wait for stable semantic state with client.WaitFor; never use fixed sleeps to guess readiness. Use explicit semantic actions and postconditions such as Selected, Checked, Value, status, or disappearance. Do not use node bounds, pointer coordinates, or screenshot pixels when the owning UI can expose a semantic route. Coordinate interaction is allowed only for an unavoidable native or platform surface that cannot expose semantics; document why, resolve coordinates from a current semantic node instead of hard-coding them, and assert the resulting functional state rather than geometry.
-
Treat query and result state as generation-bound. Setting the same query value may be a no-op, and refreshes may replace dynamic result IDs. Force a real query transition when freshness matters, wait for both the input value and launcher.results=complete, and resolve dynamic IDs again after refresh instead of retaining them across generations.
-
Treat every command executed by a smoke case as interpreter- and platform-dependent input. Confirm the interpreter the case actually selects or inherits on Windows, macOS, and Linux. Prefer the simplest syntax shared by all targeted interpreters; do not assume Bash operators such as &&, export, Unix paths, or Unix-only tools work in Windows PowerShell. When no shared command exists, select the command with runtime.GOOS and, when configurable, the chosen interpreter, while keeping output and side effects equivalent. Normalize path separators and line endings in assertions. If the behavior is intentionally platform-specific, skip it explicitly with the reason instead of waiting for an impossible state.
-
Let smoke.Case own before/after reset and the shared client, but do not assume reset restores plugin settings or desktop side effects. Explicitly restore changed settings and clean external state. Reopen settings or inspect persisted data before exercising runtime behavior; a locally updated control does not prove an asynchronous save completed.
-
Keep assertions user-visible and deterministic. Prefer evidence in this order: real runtime artifact or fresh log slice, reloaded persisted value, then live semantic state. Treat relevant snapshot diagnostics as failures. Do not weaken assertions or add retries merely to hide a race.
-
Do not launch another Wox process or create a second data directory inside a case. Use automationdriver.SharedDataDirectoryEnvironment only when the behavior must inspect real persisted output, and poll artifacts independently of UI generation changes.
-
Format every touched Go file with the repository formatter. Run the new case from the repository root: