Files
Ignacy Łątka cd4190b80e Full tgz-only E2E harness (scripts/e2e-full) (#495)
Now verified end-to-end on the real Mac:
install/introspection/validation, the android tier (against a booted
emulator), and the chromium tier all pass from a locally packed tgz; the
rn tier auto-skips without `~/dev/bluesky` as designed.

## What this is

A release-gating end-to-end harness under `scripts/e2e-full/` that
starts from **only a `swmansion-argent-*.tgz` bundle** and exercises the
whole product: the install flow, every CLI command, all 70 tools'
argument validation, and a happy-path run of every tool against real
devices. Intended to be run on the real Linux box and the real Mac
before a release.

Everything runs under a throwaway `HOME` + npm prefix, so it never
touches the machine's real `~/.argent`, editor MCP configs, or global
packages (safe on a shared box). It emits a JSONL log + a markdown
coverage report and exits non-zero if any hard assertion fails.

## Phases

| phase | needs | covers |
|---|---|---|
| `install` | npm + network | `npm i -g <tgz>`, bundled binaries, `init`
(global + `--local`), `update`, `uninstall`, telemetry, MCP-config
generation |
| `introspection` | — | `--version/--help`, `tools describe` for **all
70** tools, feature flags, `server start/status/logs/stop`,
`link/unlink` |
| `validation` | — | per tool: missing-required / bad-enum / bad-type
rejection (schema-driven, no hardware) |
| `android` | Android emulator | happy-path of every
touch/gesture/screenshot/app-lifecycle tool |
| `chromium` | Electron (bundled optional dep) + a display | boots a
generated Electron app; drives CDP tools
(scroll/drag/tabs/cookies/storage) |
| `rn` | `~/dev/bluesky` + Android device | debugger + react/native
profiler + network chain against the real Bluesky app |

Tiers auto-skip with a recorded reason when prerequisites are missing.
iOS / tvOS / Vega are intentionally out of scope for now.

## What I actually verified (real runs, Linux)

- **install** 18✓/0✗, **introspection** 85✓/0✗ (all 70 `tools
describe`), **validation** 81✓/0✗, **chromium** 24✓/0✗ (real Electron
app + CDP).
- Holistic run: **190✓ / 0✗ / 34∼, exit 0.** Failure-gate confirmed
(non-zero on fail), `bash -n` clean on all files, all 72 android/rn JSON
arg literals linted.

## What I did NOT verify live (please scrutinize)

- **`android` and `rn` tiers were never run against a live device.** The
Android emulator would not stay up on my box (memory-constrained shared
machine; QEMU threads hung seconds after boot across ~7 attempts). The
code is complete and uses the same machinery the `chromium` tier
exercised live, but it has **not** been proven end-to-end. This is the
main reason for the "not certain how well it works" caveat.
- The RN tier's exact debugger/profiler arg shapes are derived from
`tools describe`, not confirmed against a running Metro.

## Run it

```bash
bash scripts/e2e-full/run-e2e.sh                                   # everything applicable to this OS
bash scripts/e2e-full/run-e2e.sh --skip-install --phase introspection,validation   # fast offline core
bash scripts/e2e-full/run-e2e.sh --phase android --android-serial emulator-5554     # inject a device
```
2026-07-20 16:43:34 +02:00

100 lines
3.8 KiB
Bash

#!/usr/bin/env bash
# Phase 2 — Argument-matrix validation (offline, no device).
#
# For EVERY tool, generates rejection cases straight from its parsed schema:
# - missing-required : omit all required flags -> must reject
# - bad-enum : junk value for each enum flag -> must reject (that path)
# - bad-type : string where a number is required -> must reject (that path)
#
# Valid-typed dummies are filled for the *other* required flags so the single
# intended violation is what trips the rejection. This is deterministic and
# needs no hardware — it's the "every combination of arguments" guarantee at the
# validation layer. Runs against the private tool-server started in phase 1.
# Tools with no required flags that would actually EXECUTE (touch a device /
# network / state) if called empty — excluded from missing-required here and
# covered by the device tiers instead.
_VAL_EXCLUDE_MISSING="list-devices stop-all-simulator-servers stop-metro native-devtools-status update-argent"
# Build a JSON object with valid dummies for every required flag in a model,
# then apply overrides "field=raw-json" pairs. Emits the JSON on stdout.
_build_args() { # model [field:rawjson ...]
local model="$1"; shift
python3 - "$model" "$@" <<'PY'
import json, sys
model = sys.argv[1]
overrides = {}
for a in sys.argv[2:]:
k, v = a.split("=", 1)
overrides[k] = json.loads(v)
obj = {}
with open(model) as fh:
for line in fh:
line = line.rstrip("\n")
if not line:
continue
name, kind, req, enums = (line.split("\t") + ["", "", "", ""])[:4]
if req != "1":
continue
if kind == "number":
obj[name] = 1
elif kind == "boolean":
obj[name] = True
elif kind == "enum":
obj[name] = (enums.split(",")[0] if enums else "x")
elif kind == "array":
obj[name] = []
elif kind == "object":
obj[name] = {}
else:
obj[name] = "x"
obj.update(overrides)
print(json.dumps(obj))
PY
}
run_phase() {
local P=validation
ensure_server || warn "no private server; validation still runs (client-side schema)"
local names t model
names="$(list_tool_names)"
while read -r t; do
[ -z "$t" ] && continue
model="$(parse_tool_model "$t")"
[ -s "$model" ] || { skip "$P" "$t" schema "no flags to validate"; continue; }
local reqs; reqs="$(model_required_flags "$model")"
# --- missing-required ---------------------------------------------------
if [ -n "$reqs" ]; then
local first_req; first_req="$(printf '%s\n' "$reqs" | head -1)"
# omit everything -> the first required flag must be flagged undefined
assert_reject "$P" "$t" missing-required '{}' "$first_req" "invalid_type"
else
case " $_VAL_EXCLUDE_MISSING " in
*" $t "*) : ;; # device/stateful no-arg tool: covered elsewhere
*) skip "$P" "$t" missing-required "no required flags" ;;
esac
fi
# --- bad-enum (one case per enum flag) ---------------------------------
local ef
for ef in $(model_enum_flags "$model"); do
local args; args="$(_build_args "$model" "$ef=\"__not_a_valid_enum__\"")"
assert_reject "$P" "$t" "bad-enum:$ef" "$args" "$ef" "invalid_value"
done
# --- bad-type (first required number flag gets a string) ---------------
local nf
nf="$(model_number_flags "$model" | while read -r f; do
awk -F'\t' -v n="$f" '$1==n && $3==1{print n}' "$model"; done | head -1)"
if [ -z "$nf" ]; then nf="$(model_number_flags "$model" | head -1)"; fi
if [ -n "$nf" ]; then
local targs; targs="$(_build_args "$model" "$nf=\"not_a_number\"")"
assert_reject "$P" "$t" "bad-type:$nf" "$targs" "$nf" "invalid_type"
fi
done <<< "$names"
}