agentsclimarketplace

Native macos test

Skill Myra-Agents/skills/skills/native-macos-test

Agent Skills by Myra Agents — install with: npx skills add https://github.com/Myra-Agents/skills --skill <name>

Install
npx -y skills add Myra-Agents/skills --skill native-macos-test

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Author and run reusable component UI tests for a NATIVE macOS app (Tauri, Electron, or any WKWebView/AppKit app) by driving the macOS accessibility (AX) tree — match elements by AXRole + name/label, act with AXPress, type with real key events. YOU (the agent) run everything; the user just converses. The harness is vendored into the app repo (default tests/native/) so the test library is versioned WITH the app and self-locating across sessions. USE THIS when asked to: "test the desktop/Tauri app", "write a UI test for the native app", "add an AX/accessibility test", "automate clicking through the app", "add this flow to the test library", "component test for the macOS app", "regression test the app UI". Triggers: "test the app", "UI test", "AX test", "automate the desktop app", "drive the app", "macOS app test". Pixel-coordinate clicking is banned — everything targets stable AX anchors.

SKILL.md

8.9 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it

native-macos-test — AX-driven component tests for native macOS apps

Drive a running native app through its accessibility (AX) tree (the macos_automator technique) and accumulate the flows into a reusable, versioned test library that lives in the app's own repo.

You run everything. The user invokes this skill and converses; you execute all bun/osascript work via Bash and report results + proof. Never hand the user a command to run — run it yourself.

Locate/init the AX home → inspect AX tree → write a flow → run → assert on read-back → index

0. Locate (or initialize) the AX test home

The harness is vendored into the app repo and marked by a .native-macos.json file. On every invocation, first find it:

REPO=$(git rev-parse --show-toplevel)
HOME_DIR=$(find "$REPO" -name .native-macos.json -not -path '*/node_modules/*' -print -quit)
HOME_DIR=${HOME_DIR:+$(dirname "$HOME_DIR")}
echo "AX home: ${HOME_DIR:-<not initialized>}"
  • Found → that directory is the home; cd there for all commands below.
  • Not found → initialize it (next step). Default location tests/native/, unless the user names another.

Initialize (first time only)

  1. Find this skill's bundled harness (the vendor payload):
    HARNESS=$(find "$HOME" "$REPO/.claude" /root/.claude ~/.claude -type d \
      -path '*/native-macos-test/harness' -not -path '*/node_modules/*' -print -quit 2>/dev/null)
    echo "harness source: $HARNESS"
    
    (It sits next to this SKILL.md, in harness/.)
  2. Vendor it into the app repo and confirm the marker travels:
    mkdir -p "$REPO/tests/native"
    cp -R "$HARNESS"/. "$REPO/tests/native/"
    test -f "$REPO/tests/native/.native-macos.json" && echo "vendored OK"
    
  3. Register the app (asks you nothing if you already know the window title; otherwise determine it — see step 1):
    cd "$REPO/tests/native"
    bun scripts/scaffold.ts <slug> "<Window Title>" ["Display Name"]
    
  4. Record the home so humans and future agents see it: add a one-line pointer to the app repo's CLAUDE.md (e.g. "Native AX UI tests live in tests/native/ — driven by the native-macos-test skill"). The .native-macos.json marker is the machine anchor; this is the human one.

1. Identify the app (window title)

The driver finds the app by exact window title (robust — a dev build's AX process name often differs from the display name). To discover it from the running app:

osascript -l JavaScript -e 'Application("System Events").processes.whose({backgroundOnly:false})().flatMap(p=>{try{return p.windows().map(w=>w.name())}catch(e){return[]}}).filter(Boolean).join("\n")'

Pick the title, set it in apps/<slug>/app.config.ts (scaffold writes it). If ambiguous, ask the user which window.

2. Inspect the live AX tree (authoring)

cd "$HOME_DIR"
bun scripts/inspect.ts "<Window Title>"        # interesting nodes
bun scripts/inspect.ts "<Window Title>" --all  # everything + geometry

(Or, if the macos_automator MCP is connected, dump the tree via execute_script — same data.) Pick stable anchors: AXRole+AXName for buttons/links/tabs, and the input's preceding label for fields. Labels marked * (required) start with the label text, so "Schedule Name" matches "Schedule Name *".

3. Write the flow

Create apps/<slug>/components/<feature>.test.ts with the app() builder:

import { test, expect, describe } from "bun:test";
import { app, assertFlowOk } from "@ax";   // tsconfig path alias -> scripts/ax.ts
import { APP } from "../app.config";

describe("Schedules", () => {
  test("New Schedule modal accepts input", async () => {
    const r = await app(APP.windowTitle)
      .click("AXLink", "Schedules")
      .waitFor("AXHeading", "Schedules")
      .click("AXButton", "New Schedule")
      .waitFor("AXHeading", "New Schedule")
      .fillByLabel("Schedule Name", "AXTextField", "My test")  // focus + keystroke
      .readByLabel("Schedule Name", "AXTextField", "name")     // value -> reads.name
      .assertExists({ role: "AXButton", name: "Create" })
      .click("AXButton", "Cancel")          // non-destructive cleanup
      .run();
    assertFlowOk(r);
    expect(r.reads.name).toBe("My test");
  });
});

Selector fields: role (required), name, desc, valuePrefix, nth (index among position-deduped matches — virtualized lists render twice), settle.

4. Run and report

cd "$HOME_DIR"
bun test                       # every app, non-destructive
bun test apps/<slug>           # one app's suite
bun test <feature>             # one file by name fragment
DESTRUCTIVE=1 bun test         # include persisting tests (writes real data)

Iterate on anchors until green, then regenerate the index and report to the user (pass/fail counts + what's covered):

bun scripts/index.ts           # refresh apps.index.json
bun scripts/index.ts --check   # CI: fail if stale

Hard rules

  1. You run it, not the user. Execute every command via Bash; report results.
  2. No pixel coordinates. Match by role + name/label. No stable name ⇒ prefer label (field-after-its-label) over nth.
  3. One scenario = one flow = one osascript pass. Modals/menus re-render or close between separate invocations, so open → fill → read → assert → cleanup must all be in a single Flow.run().
  4. Read back, don't assume. Every fill is followed by a read; assert on the returned value.
  5. Non-destructive by default. Inspect/fill flows end on Cancel/Close. Anything that persists (Create/Send/Delete) is gated behind DESTRUCTIVE=1 and test.if(!!process.env.DESTRUCTIVE), and you confirm with the user before running it.
  6. React/controlled inputs need real keys — handled by fill/fillByLabel (focus + keystroke); setting AXValue alone won't fire onChange.

Prerequisites

  • macOS + Bun; osascript is built in.
  • Accessibility permission for whatever launches the tests (your terminal or bun): System Settings → Privacy & Security → Accessibility. Without it, System Events calls hang and the driver returns no output.
  • The app under test must be running.
  • macos_automator MCP — optional, authoring only (interactive AX exploration). Not needed to run tests (scripts/inspect.ts covers it). To install the Myra fork (needs Node ≥24 — pin a Homebrew node so Claude Code's Node 18 runtime doesn't crash it):
    claude mcp add macos-automator -- /opt/homebrew/opt/node@26/bin/node \
      /opt/homebrew/lib/node_modules/npm/bin/npx-cli.js -y \
      --package @steipete/macos-automator-mcp macos-automator-mcp
    
    Tools surface only after a Claude Code session restart.

Files (in this skill)

PathRole
harness/The vendor payload — copied into the app repo's AX home
harness/scripts/ax-driver.jsJXA core — runs a whole flow in one osascript pass, returns a JSON transcript
harness/scripts/ax.tsTyped Flow builder (imported as @ax)
harness/scripts/inspect.ts · scaffold.ts · index.tsauthor / register / index
harness/apps/_template/scaffold source (.tmpl)
harness/.native-macos.jsondiscovery marker that travels with the vendored home
references/ax-techniques.mdAX gotchas cookbook
references/writing-tests.mdstep-by-step for adding a new component test

Gotchas (see references/ax-techniques.md)

  • Dev build's AX process name ≠ display name → resolve by window title.
  • Modal closes/re-renders between osascript calls → one flow per pass.
  • Virtualized lists render the AX tree twice → driver position-dedups; use nth.
  • AXValue set alone won't update Reactfill uses focus + keystroke.
  • First AX call is slow (TCC handshake + tree size) → budget seconds/step; the bundled scripts set a 60s test timeout.

Gives 0 of the 12 instructions most test skills give in ~2.2k tokens

Counted across 964 of the 1,571 authors here whose files we hold, read 2026-08-06

  • close the browser when donein 55 of 964, across 12 files
  • wait for network idle statein 51 of 964, across 6 files
  • launch chromium in headless modein 49 of 964, across 6 files
  • use descriptive selectors for elementsin 49 of 964, across 6 files
  • run provided scripts with help flag firstin 49 of 964, across 6 files
  • add appropriate explicit waitsin 48 of 964, across 5 files
  • use bundled scripts as black boxesin 46 of 964, across 3 files
  • do not read script source codein 46 of 964, across 3 files
  • use sync playwright for scriptsin 46 of 964, across 3 files
  • inspect dom before executing actionsin 46 of 964, across 3 files
  • run the full test suitein 36 of 964, across 34 files
  • write the failing test firstin 25 of 964, across 18 files

Said here and by no other author read

  • find the accessibility test home directory
  • use accessibility role and name as stable anchors
  • write each scenario as a single flow pass
  • read values back after filling inputs
  • run every command yourself via Bash
  • end non-destructive test flows by cancelling

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.