InkkOops

Command patterns

This page focuses on composition. It explains how the command families fit together, when to choose pointer actions over semantic actions, and how to build scripts that produce useful proof instead of brittle noise.

Command families

  • Timing and layout: ResizeWindow, WaitFrames, WaitForIdle
  • Waits: WaitForElement, WaitForVisible, WaitForEnabled, WaitForInViewport, WaitForInteractive
  • Pointer input: Hover, Click, MovePointer, PointerDown, PointerUp, Drag, Wheel
  • Semantic actions: Invoke, Activate, ScrollTo, ScrollBy, ScrollIntoView
  • Assertions and proof: AssertExists, AssertNotExists, AssertProperty, AssertAutomationEvent, CaptureFrame, DumpTelemetry

Pointer versus semantic interaction

Choose pointer commands when

The issue depends on hover state, hit-testing, drag thresholds, pointer capture, action-point choice, or the exact event path produced by mouse input.

Choose semantic commands when

The control intent matters more than the exact mouse route. These commands are usually less brittle for menu activation, provider-driven scroll, or ordinary button activation.

Pointer example

return new InkkOopsScriptBuilder("scroll-thumb-drag")
    .WaitForInteractive("ScrollThumb")
    .Hover("ScrollThumb", InkkOopsPointerAnchor.Center)
    .PointerDown("ScrollThumb", InkkOopsPointerAnchor.Center)
    .Drag("ScrollThumb", 0f, 120f, InkkOopsPointerAnchor.OffsetBy(4f, 4f))
    .PointerUp("ScrollThumb", InkkOopsPointerAnchor.OffsetBy(4f, 124f))
    .WaitForIdle(InkkOopsIdlePolicy.DiagnosticsStable)
    .CaptureFrame("after-drag")
    .Build();

Semantic example

var sidebar = InkkOopsTargetSelector.Name("CatalogSidebarScrollViewer");
var target = InkkOopsTargetSelector.Within(
    sidebar,
    InkkOopsTargetSelector.AutomationName("RichTextBox"));

return new InkkOopsScriptBuilder("semantic-sidebar-nav")
    .ScrollIntoView(sidebar, target)
    .WaitForInteractive(target)
    .Activate(target)
    .AssertExists("PreviewHost")
    .CaptureFrame("preview-loaded")
    .Build();

Proof-oriented script shape

  1. Prepare the runtime state with resize or initial waits only when necessary.
  2. Wait for a concrete condition instead of guessing with long frame sleeps.
  3. Perform the smallest interaction that proves the bug.
  4. Assert the expected control state.
  5. Capture a frame and telemetry near the stable end state.

Reduction pattern

A good reduction usually starts as a replay, then becomes a short script containing only the commands that create and prove the bug. If a script needs fifty unrelated steps before the interesting part happens, the script is probably documenting navigation noise rather than the defect.

Common mistakes

  • Using WaitFrames where WaitForInteractive would be more deterministic.
  • Using pointer clicks when the actual bug is a semantic activation bug.
  • Capturing proof too early, before transitions or rendering settle.
  • Mixing many unrelated assertions into one script, which makes failure diagnosis slower.