Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 28 additions & 118 deletions .cursor/skills/build-and-test/SKILL.md

Large diffs are not rendered by default.

57 changes: 38 additions & 19 deletions .cursor/skills/build-and-test/maestro/buy-quote-input.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
# Interaction-only companion to buy-quote.yaml: PIN login -> Buy tab -> enter $500.
# Interaction-only companion to buy-quote.yaml: PIN login -> Buy scene -> enter $500.
# The Buy scene opens with one deep link, `edge://exchange/buy?buyAsset=..`.
# PARAMS: PIN_DIGIT, BUY_AMOUNT, BUY_ASSET (deep-link asset: a plugin id or
# `<pluginId>_<tokenId>`, default bitcoin), MANUAL_PATH ("true" taps the Buy
# tab instead of the link and leaves the asset as the app has it: for a task
# whose change is on the tab bar or the Buy entry).
# Captures nothing — capture-buy-quote.sh grabs the proof screenshot externally
# (see that script for why an external burst beats an in-flow screenshot on this build).
appId: ${APP_ID}
env:
APP_ID: co.edgesecure.app
PIN_DIGIT: "1"
BUY_AMOUNT: "500"
BUY_ASSET: ${BUY_ASSET || "bitcoin"}
MANUAL_PATH: ${MANUAL_PATH || ""}
---
- launchApp
- extendedWaitUntil:
visible: "Exit PIN"
timeout: 40000
- assertVisible: "1"
- assertVisible: "0"
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 1500
# YOLO auto-login can finish mid-entry, so the taps go through the gated
# login-if-needed flow instead of four unconditional taps.
- runFlow:
file: common/login-if-needed.yaml
env:
PIN_DIGIT: ${PIN_DIGIT}
- extendedWaitUntil:
visible: "Buy"
timeout: 30000
Expand All @@ -43,9 +42,29 @@ env:
visible: "Claim Your Web3 Handle"
commands:
- tapOn: "Not Now"
- tapOn: "Buy"
- extendedWaitUntil:
visible: "Amount USD"
timeout: 15000
- runFlow:
when:
true: ${MANUAL_PATH != 'true'}
commands:
- openLink: "edge://exchange/buy?buyAsset=${BUY_ASSET}"
- extendedWaitUntil:
visible: "Amount USD"
timeout: 30000
# The tab bar stays hidden for up to ~20s after login while "Buy" is already
# in the hierarchy, so a single tap can land on nothing. Retry until the Buy
# scene shows.
- runFlow:
when:
true: ${MANUAL_PATH == 'true'}
commands:
- retry:
maxRetries: 3
commands:
- tapOn: "Buy"
- extendedWaitUntil:
visible: "Amount USD"
timeout: 10000
- tapOn: "Amount USD"
# The Buy scene remembers the last amount; clear it or inputText appends.
- eraseText: 20
- inputText: ${BUY_AMOUNT}
39 changes: 19 additions & 20 deletions .cursor/skills/build-and-test/maestro/buy-quote.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Target: the iPhone 16 Pro Max / iOS 18 simulator that holds the pre-provisioned
# roster account `qa-b` (see ~/.config/edge-secrets/test-accounts.json: region
# California/USA). The flow quotes into a BTC wallet, so confirm the logged-in account has one. The Edge
# app must already be installed (build + install steps are in build-and-test/SKILL.md).
# app must already be installed (build + install steps are in build-and-test/references/build.md).
#
# Run: maestro test ~/.cursor/skills/build-and-test/maestro/buy-quote.yaml
#
Expand All @@ -28,21 +28,12 @@ env:
- extendedWaitUntil:
visible: "Exit PIN"
timeout: 40000
# make sure the whole keypad is rendered & interactive before tapping
- assertVisible: "1"
- assertVisible: "0"
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 1500
# YOLO auto-login can finish mid-entry, so the taps go through the gated
# login-if-needed flow instead of four unconditional taps.
- runFlow:
file: common/login-if-needed.yaml
env:
PIN_DIGIT: ${PIN_DIGIT}

# --- wait for the main tab bar, then dismiss optional post-login modals ---
- extendedWaitUntil:
Expand All @@ -59,16 +50,24 @@ env:
commands: [{ tapOn: "Not Now" }]

# --- navigate to the Buy (Buy Crypto) scene ---
- tapOn: "Buy"
- extendedWaitUntil:
visible: "Amount USD"
timeout: 15000
# The tab bar stays hidden for up to ~20s after login while "Buy" is already
# in the hierarchy, so a single tap can land on nothing. Retry until the Buy
# scene shows.
- retry:
maxRetries: 3
commands:
- tapOn: "Buy"
- extendedWaitUntil:
visible: "Amount USD"
timeout: 10000

# --- enter the $500 fiat amount ---
# NOTE: do NOT call `hideKeyboard` here — on this debug build it forces a re-layout
# that reliably triggers the RN Fabric text-measure SIGABRT. The USD + converted-BTC
# fields and the exchange-rate line are all above the keyboard, so leave it up.
- tapOn: "Amount USD"
# The Buy scene remembers the last amount; clear it or inputText appends.
- eraseText: 20
- inputText: ${BUY_AMOUNT}

# --- let the live quote resolve, then capture ---
Expand Down
2 changes: 2 additions & 0 deletions .cursor/skills/build-and-test/maestro/common/find-wallet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ env:
visible: "Search Wallets"
timeout: 20000
- tapOn: "Search Wallets"
# The search text survives navigation; clear it or inputText appends.
- eraseText: 40
- inputText: ${SEARCH_TERM}
- runFlow:
when:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
# ~/.config/edge-secrets/test-accounts.json).
# GOTCHA: taps MUST stay spaced (waitToSettleTimeoutMs) — fast taps drop digits →
# wrong PIN → exponential lockout. Never tighten these.
# YOLO auto-login can finish mid-entry and leave the PIN screen, so each tap
# is gated on the PIN screen still showing.
appId: ${APP_ID}
env:
APP_ID: co.edgesecure.app
PIN_DIGIT: "0"
# `${KEY || default}` so a caller's runFlow env wins over the default.
PIN_DIGIT: ${PIN_DIGIT || "0"}
---
- runFlow:
when:
Expand All @@ -18,12 +21,24 @@ env:
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- runFlow:
when:
visible: "Exit PIN"
commands:
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- runFlow:
when:
visible: "Exit PIN"
commands:
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 900
- runFlow:
when:
visible: "Exit PIN"
commands:
- tapOn:
text: ${PIN_DIGIT}
waitToSettleTimeoutMs: 1500
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ env:
FIAT_SEARCH: "USD"
FIAT_ROW: "USD United States Dollar"
---
- tapOn:
text: ".*(Select your region|USA|Germany|United Kingdom|Canada|Australia).*"
- extendedWaitUntil:
visible: "Search region"
timeout: 10000
# With the amount keyboard up, the first tap only dismisses the keyboard.
- retry:
maxRetries: 2
commands:
- tapOn:
text: ".*(Select your region|USA|Germany|United Kingdom|Canada|Australia).*"
- extendedWaitUntil:
visible: "Search region"
timeout: 5000
- tapOn: "Search region"
- inputText: ${COUNTRY_SEARCH}
- waitForAnimationToEnd:
Expand Down
85 changes: 68 additions & 17 deletions .cursor/skills/build-and-test/maestro/common/select-swap-pair.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
# common/select-swap-pair.yaml — Exchange tab → pick source/receiving wallets →
# common/select-swap-pair.yaml: open the Exchange scene with the pair selected →
# enter fiat amount → Next → wait for a quote → optionally force a provider.
# Assumes logged-in app (compose login-if-needed + dismiss-startup-modals first).
# The pair is set with one deep link, `edge://exchange/swap?sellAsset=..&buyAsset=..`,
# which works from any scene. The wallet pickers below it run only for a side
# the link did not settle.
# PARAMS:
# SRC_WALLET / DST_WALLET — text typed into "Search Wallets" AND the regex
# matched against the filtered result (e.g. ".*Bitcoin.*")
# SRC_ASSET / DST_ASSET: deep-link asset: a plugin id (`bitcoin`) or
# `<pluginId>_<tokenId>` (`ethereum_0xa0b8..`).
# Default bitcoin / ethereum. A side named only by
# SRC_WALLET / DST_WALLET is left out of the link
# and picked by name instead.
# MANUAL_PATH: "true" skips the link: Exchange tab, then both
# wallet pickers. For a task whose change is on the
# tab bar, the Exchange entry or the wallet picker.
# SRC_WALLET / DST_WALLET — plain text typed into "Search Wallets" (e.g.
# "My Bitcoin"); the first filtered row is picked.
# Used on the manual path, for a side with no asset
# param, and when the link raises the app's picker
# (the account holds several wallets for the asset)
# FIAT_AMOUNT — fiat number typed into the amount field
# PROVIDER — exact provider name to force (e.g. "Maya Protocol").
# Forcing works by SELECTING it in the provider sheet;
Expand All @@ -23,15 +37,44 @@
appId: ${APP_ID}
env:
APP_ID: co.edgesecure.app
SRC_WALLET: ".*Bitcoin.*"
DST_WALLET: ".*Ethereum.*"
FIAT_AMOUNT: "16"
PROVIDER: ""
# `${KEY || default}` so a caller's runFlow env wins over the default.
# The asset lines come first: they read whether the caller named a wallet
# (`typeof`, because an unset name is not declared yet at that point).
SRC_ASSET: '${SRC_ASSET || (typeof SRC_WALLET === "string" && SRC_WALLET ? "" : "bitcoin")}'
DST_ASSET: '${DST_ASSET || (typeof DST_WALLET === "string" && DST_WALLET ? "" : "ethereum")}'
MANUAL_PATH: ${MANUAL_PATH || ""}
SRC_WALLET: ${SRC_WALLET || "Bitcoin"}
DST_WALLET: ${DST_WALLET || "Ethereum"}
FIAT_AMOUNT: ${FIAT_AMOUNT || "16"}
PROVIDER: ${PROVIDER || ""}
---
- extendedWaitUntil:
visible: "Exchange"
timeout: 30000
- tapOn: "Exchange"
- runFlow:
when:
true: ${MANUAL_PATH != 'true'}
commands:
- openLink: "edge://exchange/swap?sellAsset=${SRC_ASSET}&buyAsset=${DST_ASSET}"
- extendedWaitUntil:
visible: "Select Source Wallet|Select Receiving Wallet|I have"
timeout: 30000
# The link returns before the scene settles on the linked pair.
- waitForAnimationToEnd:
timeout: 5000
- runFlow:
when:
true: ${MANUAL_PATH == 'true'}
commands:
- extendedWaitUntil:
visible: "Exchange"
timeout: 30000
# The tab bar stays hidden for up to ~20s after login while "Exchange" is
# already in the hierarchy, so retry the tap until the Exchange scene shows.
- retry:
maxRetries: 3
commands:
- tapOn: "Exchange"
- extendedWaitUntil:
visible: "Select Source Wallet|I have"
timeout: 10000
- runFlow:
when:
visible: "Select Source Wallet"
Expand All @@ -44,12 +87,16 @@ env:
visible: "Not Now"
commands:
- tapOn: "Not Now"
# The search field holds the typed text, so it is always match 0; the
# rows' labels contain the wallet name, so match 1 is the first row.
- extendedWaitUntil:
visible: ${SRC_WALLET}
visible:
text: ".*${SRC_WALLET}.*"
index: 1
timeout: 15000
- tapOn:
text: ${SRC_WALLET}
index: 0
text: ".*${SRC_WALLET}.*"
index: 1
- runFlow:
when:
visible: "Select Receiving Wallet"
Expand All @@ -62,12 +109,16 @@ env:
visible: "Not Now"
commands:
- tapOn: "Not Now"
# The search field holds the typed text, so it is always match 0; the
# rows' labels contain the wallet name, so match 1 is the first row.
- extendedWaitUntil:
visible: ${DST_WALLET}
visible:
text: ".*${DST_WALLET}.*"
index: 1
timeout: 15000
- tapOn:
text: ${DST_WALLET}
index: 0
text: ".*${DST_WALLET}.*"
index: 1
- extendedWaitUntil:
visible: "Tap to edit"
timeout: 15000
Expand Down
Loading