Drive WeChat Mini Program DevTools through miniprogram-automator instead of ad hoc UI clicking. Prefer the bundled runner for stable, JSON-driven harness workflows.
Before running any workflow, verify all of the following:
command -v node >/dev/null 2>&1
test -x /Applications/wechatwebdevtools.app/Contents/MacOS/cli || true
node -p "require.resolve('miniprogram-automator')"
If require.resolve fails, install the package in the working directory:
npm install miniprogram-automator
If connecting to an already-open DevTools window, ensure the target project is open with automation enabled. The package reports connection failures as "check if target project window is opened with automation enabled".
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
export WXA_RUNNER="$CODEX_HOME/skills/wechat-miniprogram-automator/scripts/run_automator.cjs"
export WXA_RESOLVER="$CODEX_HOME/skills/wechat-miniprogram-automator/scripts/resolve_wechat_project.cjs"
export WXA_BOOTSTRAP="$CODEX_HOME/skills/wechat-miniprogram-automator/scripts/ensure_devtools_session.cjs"
export WXA_FLOW="$CODEX_HOME/skills/wechat-miniprogram-automator/scripts/run_wechat_flow.cjs"
export WXA_BATCH="$CODEX_HOME/skills/wechat-miniprogram-automator/scripts/run_wechat_batch.cjs"
cli auto bootstrapping plus connect, even when you know the project path.launch only as a fallback for clean, disposable sessions where the project is not already open in DevTools.output/wechat-miniprogram-automator/ when the repo already has an output area. Otherwise use /tmp.run_wechat_batch.cjs so the batch leaves one top-level report.json plus one subreport per case.root or inspectDataTree when you need structure-level snapshots. Business hook state such as loading or houseData may resolve to undefined from page.data(path).Readiness selector guidance:
container selector: the page shell, root node, list wrapper, or layout block that can appear before real content is readybusiness selector: the first selector that only appears after real data has rendered, such as the first card, the real title text block, an image inside a swiper, or an enabled submit buttonbusiness selector over container selectorUse the resolver before picking launch or connect:
node "$WXA_RESOLVER" --cwd "$PWD"
The resolver returns one of these shapes:
standalone-miniprogram: the current repo is itself the Mini Program root. Use projectPath directly.hosted-subpackage: the current repo builds into one or more host Mini Programs. Use selectedTarget.devtoolsProjectPath as the DevTools project path, not the current repo path.unknown: the skill could not find either shape and needs manual input.For hosted subpackages, the resolver inspects package.json, .mps.config.js, and config/index.js, then returns structured target metadata such as:
weappType: internal build target such as tongcheng or wubascriptSuffix: script-facing short name such as wbfc or ajkpublishKey: script-facing target such as weapp-wbfcdevScript: watch command to keep the subpackage output synced into the hosthostProjectPath: runtime Mini Program root that contains app.jsondevtoolsProjectPath: DevTools project root that contains project.config.jsonsubpackageRoot: relative path from the host root to the mounted subpackage outputisActiveCandidate: whether the resolver found a matching running watch processselectionReason: why the target was marked active or recommended--target accepts any of weappType, scriptSuffix, publishKey, or full script names such as dev:weapp-wbfc.
This split matters because some hosts keep project.config.json one level above the runtime miniprogram/ directory. Opening the runtime root in DevTools can start a broken or partial session even though the files exist.
When the resolver returns more than one hosted target, do not silently pick one and continue.
Instead:
weappTypedevScriptdevtoolsProjectPathsubpackageRootUse the resolver default only when there is exactly one hosted target.
When the resolver can uniquely match a running dev:weapp-* or taro build --watch process, it also returns recommendedTarget. Use that recommendation to prefill or highlight the likely host, but still ask the user to confirm when multiple hosts exist.
Prefer this over automator.launch():
node "$WXA_BOOTSTRAP" --project-path /abs/path/to/devtools-project
Internally this runs cli auto --project ... --auto-port . If you call bootstrap directly, you can still manage a fixed port yourself. If you use the higher-level flow or batch entrypoints, they now derive a stable per-project port from devtoolsProjectPath so different projects do not accidentally reuse the same old session. That flow is idempotent enough for day-to-day use:
After bootstrapping, connect to the matching websocket port. Low-level scripts can target a manual endpoint such as ws://127.0.0.1:9420; high-level entrypoints choose the project-specific port automatically.
When the current repo is a subpackage business repo instead of a standalone Mini Program:
tongcheng or weapp-wbfc.selectedTarget.devScript so the host-mounted output stays fresh.selectedTarget.devtoolsProjectPath.reLaunch, tap, data, and screenshot after the host app is open.Example:
node "$WXA_RESOLVER" --cwd "$PWD" --target tongcheng
npm run dev:weapp-tongcheng
node "$WXA_BOOTSTRAP" \
--project-path /abs/path/to/devtools-project
node "$WXA_RUNNER" \
--mode connect \
--ws-endpoint ws://127.0.0.1:9420 \
--actions-file /tmp/wxa-actions.json
Important: for hosted subpackages, --project-path in the bootstrap step must point at the DevTools project root, not blindly at the nearest app.json directory. Those can differ.
In Codex-like sandboxed environments, local websocket ports may be unreachable even when DevTools is correctly configured. If lsof shows the target port listening but plain node or curl still cannot connect, re-run the port probe and the automator command before changing the Mini Program workflow.
There is a second sandbox failure mode worth treating separately: cli auto succeeds, lsof shows the port listening, and curl -i http://127.0.0.1: returns 426 Upgrade Required, but Node-based scripts still fail with messages such as "check if target project window is opened with automation enabled" or a bootstrap false negative. Treat that as a sandbox transport issue rather than a DevTools configuration issue. In that case:
cli auto --project ... --auto-port 9420lsof -nP -iTCP:9420 -sTCP:LISTENcurl -i http://127.0.0.1:9420Launch DevTools for a local project and run a route smoke flow:
cat >/tmp/wxa-actions.json <<'EOF'
[
{ "type": "reLaunch", "url": "/pages/home/index" },
{ "type": "wait", "ms": 800 },
{ "type": "tap", "selector": ".primary-cta" },
{ "type": "wait", "ms": 300 },
{ "type": "data", "path": "ready" },
{ "type": "screenshot", "path": "/tmp/wxa-home.png" }
]
EOF
node "$WXA_BOOTSTRAP" \
--project-path /abs/path/to/devtools-project
node "$WXA_RUNNER" \
--mode connect \
--ws-endpoint ws://127.0.0.1:9420 \
--actions-file /tmp/wxa-actions.json
Connect to an existing DevTools instance:
node "$WXA_RUNNER" \
--mode connect \
--ws-endpoint ws://127.0.0.1:9420 \
--actions-file /tmp/wxa-actions.json
If DevTools is already open but 9420 is not listening yet, turn on the DevTools port/automation setting and bootstrap the project first:
node "$WXA_BOOTSTRAP" \
--project-path /abs/path/to/devtools-project
High-level single-flow entrypoint:
node "$WXA_FLOW" \
--cwd "$PWD" \
--target anxinchathost \
--actions-file /tmp/wxa-actions.json
If you do not pass --port here, the flow script chooses a stable port for the current DevTools project. That prevents cross-project collisions when you switch between repos such as anxinwechat and anjuke_weapp.
Or use a built-in template:
node "$WXA_FLOW" \
--cwd "$PWD" \
--target anxinchathost \
--template route-screenshot \
--template-vars-json '{"ROUTE_URL":"/pages/home/index?id=1","ROUTE_PATH":"pages/home/index","ROUTE_QUERY":{"id":"1"},"ROUTE_TIMEOUT_MS":5000,"READY_SELECTOR":".page-root","READY_TIMEOUT_MS":5000,"SCREENSHOT_PATH":"/tmp/home.png"}'
Batch entrypoint:
node "$WXA_BATCH" \
--cwd "$PWD" \
--target anxinchathost \
--cases-file /tmp/wxa-cases.json
Optional preflight before the main flow or batch:
node "$WXA_FLOW" \
--cwd "$PWD" \
--target anxinchathost \
--preflight-actions-file /tmp/wxa-preflight.json \
--actions-file /tmp/wxa-actions.json
node "$WXA_BATCH" \
--cwd "$PWD" \
--target anxinchathost \
--preflight-actions-file /tmp/wxa-preflight.json \
--cases-file /tmp/wxa-cases.json
Or use the reusable built-in preflight template:
node "$WXA_FLOW" \
--cwd "$PWD" \
--target anxinchathost \
--preflight-template preflight-route-ready \
--template route-screenshot \
--template-vars-json '{"ROUTE_URL":"/pages/home/index?id=1","ROUTE_PATH":"pages/home/index","ROUTE_QUERY":{"id":"1"},"ROUTE_TIMEOUT_MS":5000,"READY_SELECTOR":".page-root","READY_TIMEOUT_MS":5000,"SCREENSHOT_PATH":"/tmp/home-ready.png"}'
node "$WXA_BATCH" \
--cwd "$PWD" \
--target anxinchathost \
--preflight-template preflight-route-ready \
--template-var ROUTE_URL='"/pages/home/index?id=1"' \
--template-var ROUTE_PATH='"pages/home/index"' \
--template-var ROUTE_QUERY='{"id":"1"}' \
--template-var ROUTE_TIMEOUT_MS=5000 \
--template-var READY_SELECTOR='".page-root"' \
--template-var READY_TIMEOUT_MS=5000 \
--template-var SCREENSHOT_PATH='"/tmp/home-ready.png"' \
--cases-file /tmp/wxa-cases.json
Keep preflight generic and short:
reLaunch the target routeIf preflight fails, treat that as an environment or readiness blocker first. Do not immediately interpret a full batch of selector timeouts as twelve independent product regressions.
Or use a built-in batch template:
node "$WXA_BATCH" \
--cwd "$PWD" \
--target anxinchathost \
--template batch-route-cases \
--template-vars-json '{"ROUTE_URL":"/pages/home/index?id=1","ROUTE_PATH":"pages/home/index","ROUTE_QUERY":{"id":"1"},"ROUTE_TIMEOUT_MS":5000,"READY_SELECTOR":".page-root","READY_TIMEOUT_MS":5000,"SNAPSHOT_DATA_PATHS":["loading"],"SNAPSHOT_PATH":"/tmp/home-snapshot.json","SCREENSHOT_PATH":"/tmp/home.png"}'
Reusable templates:
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/route-screenshot.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/route-smoke.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/preflight-route-ready.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/route-ready-screenshot.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/page-not-skeleton.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/open-preview-then-close.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/image-preview-open-close.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/list-to-detail.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/webview-navigation.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/blank-page-diagnose.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/skeleton-stuck-diagnose.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/request-fail-diagnose.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/route-request-mock.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/storage-fixture.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/globaldata-fixture.actions.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/batch-route-cases.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/batch-smoke-cases.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/page-smoke-suite.cases.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/list-interaction-suite.cases.json
$CODEX_HOME/skills/wechat-miniprogram-automator/templates/detail-interaction-suite.cases.json
Use scripts/run_automator.cjs as the default entry point. It supports a constrained action set that maps to stable miniprogram-automator APIs:
reLaunch, navigateTo, redirectTo, switchTab, navigateBackwait, scrollTo, waitForRoute, waitForData, waitForSelector, waitForRequestinspectElements, findByText, inspectDataTree, findInDataTree, suggestSelectorstap, input, text, attributedata, setData, callMethodsetGlobalData, getGlobalData, callAppMethod, callWxMethod, setStorage, getStorage, clearStorage, mockWxMethod, restoreWxMethodscreenshotThe script prints one JSON object to stdout so harness code can parse the result without scraping logs.
data-testid-style classes or ids, use those instead of brittle layout selectors.cli auto plus connect over launch, because opening the same DevTools project twice is unreliable and can fail with opaque automator errors.data() or a screenshot before changing the action file so the failure remains diagnosable.connect mode, disconnect from the websocket when finished; do not close the user-owned DevTools instance. Closing DevTools from a shared session breaks subsequent routes and batch captures.connect mode. Do not tear down the underlying DevTools window between pages.Open only what is needed:
references/workflow.mdscripts/run_automator.cjsscripts/run_wechat_flow.cjsscripts/run_wechat_batch.cjstemplates/route-screenshot.actions.json, templates/route-smoke.actions.json, templates/batch-route-cases.json, templates/batch-smoke-cases.jsontemplates/preflight-route-ready.actions.json, templates/route-ready-screenshot.actions.json, templates/page-not-skeleton.actions.jsontemplates/open-preview-then-close.actions.json, templates/image-preview-open-close.actions.jsontemplates/list-to-detail.actions.json, templates/webview-navigation.actions.jsontemplates/blank-page-diagnose.actions.json, templates/skeleton-stuck-diagnose.actions.json, templates/request-fail-diagnose.actions.jsontemplates/route-request-mock.actions.jsontemplates/page-smoke-suite.cases.json, templates/list-interaction-suite.cases.json, templates/detail-interaction-suite.cases.jsontemplates/storage-fixture.actions.json, templates/globaldata-fixture.actions.jsonscripts/resolve_wechat_project.cjsscripts/ensure_devtools_session.cjs共 1 个版本