From ec3764ad85ffc5b21395b56eafb3790dd6b8df19 Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 18 Apr 2026 10:33:49 +0700 Subject: [PATCH] chore(examples): remove merchant-ledger spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No longer referenced anywhere — sample-app replaces it as the in-tree example. --- examples/specs/merchant-ledger.ts | 168 ------------------------------ 1 file changed, 168 deletions(-) delete mode 100644 examples/specs/merchant-ledger.ts diff --git a/examples/specs/merchant-ledger.ts b/examples/specs/merchant-ledger.ts deleted file mode 100644 index d4a88d4..0000000 --- a/examples/specs/merchant-ledger.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { - extract, - always, - actions, - weighted, - Tap, - InputText, - taps, - swipes, -} from "@uatu/spec"; - -// ── Snapshot extractors (fed by UatuExtractors on Android) ───── -const screen = extract((state) => (state.snapshots.screen as string) ?? ""); -const balance = extract( - (state) => (state.snapshots["ledger.balance"] as number) ?? 0, -); -const totalGiven = extract( - (state) => (state.snapshots["ledger.totalGiven"] as number) ?? 0, -); -const totalReceived = extract( - (state) => (state.snapshots["ledger.totalReceived"] as number) ?? 0, -); - -// ── Screen detection via uiautomator hierarchy ───────────────── -const onLanguageSelect = extract((state) => - Boolean(state.ax.find("id:select_language")), -); -const englishTile = extract((state) => - state.ax.find("id:select_language") ? state.ax.find("text:English") : undefined, -); - -const onEnterMobile = extract((state) => - Boolean(state.ax.find("id:etMobileNumber")), -); -const mobileField = extract((state) => state.ax.find("id:etMobileNumber")); -const termsCheckbox = extract((state) => state.ax.find("id:checkBoxTerms")); -const continueButton = extract((state) => state.ax.find("id:buttonLogin")); - -// OTP screen uses six single-digit EditTexts sharing resource-id "otp". -// Typing into the first one auto-fills the rest. -const otpFirstBox = extract((state) => state.ax.findAll("id:otp")[0]); -const onOtp = extract(() => Boolean(otpFirstBox.current)); - -// Multi-device dialog that gates the Home screen when another device is -// signed in. Spec auto-signs-out the other device. -const signOutOthersButton = extract((state) => state.ax.find("text:Sign Out Other Devices")); -const confirmSignOutButton = extract((state) => { - const cancel = state.ax.find("text:Cancel"); - if (!cancel) return undefined; - return state.ax.find("text:Sign Out"); -}); - -// Notification-permission modal on Home. -const skipNotificationsButton = extract((state) => state.ax.find("text:Skip")); - -// Back arrow visible on customer/supplier ledger toolbars; tapping it -// returns to the Home tab list so the spec can pick another counterparty. -const ledgerBackArrow = extract((state) => - onLedger.current ? state.ax.find("desc:Back") : undefined, -); - -// Home screen customer/supplier rows. Compose testTag appears as -// content-desc; rows are suffixed with a stable UUID. -const customerRows = extract((state) => state.ax.findAll("descPrefix:customer_row_")); -const supplierRows = extract((state) => state.ax.findAll("descPrefix:supplier_row_")); -const onHome = extract( - () => customerRows.current.length > 0 || supplierRows.current.length > 0, -); - -const onLedger = extract( - () => screen.current === "customer_ledger" || screen.current === "supplier_ledger", -); - -// ── Properties ───────────────────────────────────────────────── -export const properties = { - // Sign convention discovered empirically against merchant-android: - // customer ledger: balance == received − given (debt customer owes) - // supplier ledger: balance == given − received (debt merchant owes) - // The two screens flip because "given/received" is recorded from the - // merchant's POV in both DAOs, but each summary balance is stored from - // the counterparty's POV. - ledgerBalanceMatchesTxns: always(() => { - if (screen.current === "customer_ledger") { - return balance.current === totalReceived.current - totalGiven.current; - } - if (screen.current === "supplier_ledger") { - return balance.current === totalGiven.current - totalReceived.current; - } - return true; - }), -}; - -// ── Action generators ────────────────────────────────────────── -const selectEnglish = actions(() => { - if (!onLanguageSelect.current) return []; - return englishTile.current ? [Tap({ on: englishTile.current })] : []; -}); - -const enterMobile = actions(() => { - if (!onEnterMobile.current) return []; - const field = mobileField.current; - const terms = termsCheckbox.current; - const button = continueButton.current; - const phone = process.env.UATU_TEST_PHONE ?? ""; - if (!field || !phone) return []; - // Step by screen state so we never tap a disabled button, append to the - // phone field, or toggle the terms checkbox off again. - if (field.text !== phone) { - return [InputText({ into: field, text: phone })]; - } - if (terms && !terms.checked) { - return [Tap({ on: terms })]; - } - if (button && button.enabled) { - return [Tap({ on: button })]; - } - return []; -}); - -const enterOtp = actions(() => { - if (!onOtp.current) return []; - const field = otpFirstBox.current; - const otp = process.env.UATU_TEST_OTP ?? ""; - if (!field || !otp) return []; - // The first box shows the entered digit once filled; stop re-typing then. - if (field.text && field.text.length > 0) return []; - return [InputText({ into: field, text: otp })]; -}); - -const dismissMultiDevice = actions(() => { - if (confirmSignOutButton.current) return [Tap({ on: confirmSignOutButton.current })]; - if (signOutOthersButton.current) return [Tap({ on: signOutOthersButton.current })]; - return []; -}); - -const dismissNotifications = actions(() => { - return skipNotificationsButton.current - ? [Tap({ on: skipNotificationsButton.current })] - : []; -}); - -const openCustomerOrSupplier = actions(() => { - if (!onHome.current) return []; - const rows = [...customerRows.current, ...supplierRows.current]; - if (rows.length === 0) return []; - return rows.map((row) => Tap({ on: row })); -}); - -const leaveLedger = actions(() => { - return ledgerBackArrow.current ? [Tap({ on: ledgerBackArrow.current })] : []; -}); - -export const actionsRoot = weighted( - [100, selectEnglish], - [100, enterMobile], - [100, enterOtp], - [100, dismissMultiDevice], - [100, dismissNotifications], - [80, openCustomerOrSupplier], - // leaveLedger is lighter so the property gets several evaluations on each - // ledger before we navigate away to a new one. - [25, leaveLedger], - [10, taps], - [2, swipes], -); - -(globalThis as { actions?: unknown; properties?: unknown }).actions = actionsRoot; -(globalThis as { properties?: unknown }).properties = properties;