From 192126cf9e8b24cf816e24799c04f9eb8301f6a0 Mon Sep 17 00:00:00 2001 From: shafi54 <108669266+shafi-aviz@users.noreply.github.com> Date: Wed, 16 Sep 2026 21:48:06 +0530 Subject: [PATCH] enh --- apps/admin-ui/app/_layout.tsx | 8 + apps/user-ui/app/(auth)/login.tsx | 5 + .../app/(drawer)/(tabs)/home/index.tsx | 1 + .../(tabs)/home/search-results/index.tsx | 1 + apps/user-ui/app/_layout.tsx | 9 +- .../components/CheckoutAddressSelector.tsx | 3 +- .../components/PaymentAndOrderComponent.tsx | 4 +- .../src/components/AddToCartDialog.tsx | 2 +- change-log.txt | 149 ++++++++++++++++++ opencode.jsonc | 4 + .../ui/src/components/ImageUploaderNeo.tsx | 1 + packages/ui/src/components/search-bar.tsx | 5 + tests/e2e/.env.example | 20 +-- tests/e2e/README.md | 4 +- tests/e2e/add-product.yaml | 15 +- tests/e2e/add-slot-with-product.yaml | 32 ++-- tests/e2e/config.yaml | 5 +- tests/e2e/dev/add-empty-slot.yaml | 14 +- tests/e2e/run.sh | 32 ++-- tests/e2e/subflows/login-user.yaml | 17 ++ tests/e2e/subflows/login.yaml | 5 - tests/e2e/subflows/pick-image.yaml | 77 ++------- tests/e2e/subflows/set-slot-times.yaml | 19 +-- tests/e2e/user-order.yaml | 119 ++++++++++++++ 24 files changed, 385 insertions(+), 166 deletions(-) create mode 100644 opencode.jsonc create mode 100644 tests/e2e/subflows/login-user.yaml create mode 100644 tests/e2e/user-order.yaml diff --git a/apps/admin-ui/app/_layout.tsx b/apps/admin-ui/app/_layout.tsx index cc5a54d..8d23919 100644 --- a/apps/admin-ui/app/_layout.tsx +++ b/apps/admin-ui/app/_layout.tsx @@ -1,11 +1,19 @@ import { QueryClientProvider } from "@tanstack/react-query"; import queryClient from "../utils/queryClient"; import { Stack } from "expo-router"; +import { LogBox } from "react-native"; import { StaffAuthProvider } from "@/components/context/staff-auth-context"; import { trpc, trpcClient } from "@/src/trpc-client"; import { SafeAreaView } from "react-native-safe-area-context"; import { RefreshProvider } from '../../../packages/ui/src/lib/refresh-context'; +// Silence dev warnings/errors in LogBox. The "Open debugger to view warnings" +// toast overlays the bottom of the UI and intercepts taps (e.g. the Add Slot +// FAB), which breaks E2E flows. +if (__DEV__) { + LogBox.ignoreAllLogs(true); +} + export default function Layout() { return ( diff --git a/apps/user-ui/app/(auth)/login.tsx b/apps/user-ui/app/(auth)/login.tsx index ad0c3c5..ec855a1 100644 --- a/apps/user-ui/app/(auth)/login.tsx +++ b/apps/user-ui/app/(auth)/login.tsx @@ -290,6 +290,7 @@ function Login() { render={({ field: { onChange, onBlur, value } }) => ( ( ( { setPasswordBackTo('mobile'); setValue('identifier', watch('mobile') || ''); diff --git a/apps/user-ui/app/(drawer)/(tabs)/home/index.tsx b/apps/user-ui/app/(drawer)/(tabs)/home/index.tsx index 986629e..d25274c 100755 --- a/apps/user-ui/app/(drawer)/(tabs)/home/index.tsx +++ b/apps/user-ui/app/(drawer)/(tabs)/home/index.tsx @@ -696,6 +696,7 @@ export default function Dashboard() { style={searchBarContainerStyle} > { }} onPress={handleSearchPress} diff --git a/apps/user-ui/app/(drawer)/(tabs)/home/search-results/index.tsx b/apps/user-ui/app/(drawer)/(tabs)/home/search-results/index.tsx index b54b74c..943637b 100644 --- a/apps/user-ui/app/(drawer)/(tabs)/home/search-results/index.tsx +++ b/apps/user-ui/app/(drawer)/(tabs)/home/search-results/index.tsx @@ -128,6 +128,7 @@ export default function SearchResults() { = ({ decelerationRate="fast" snapToInterval={CARD_WIDTH} > - {sortedAddresses.map((address) => ( + {sortedAddresses.map((address, index) => ( { onAddressSelect(address.id); resetScrollToLeft(); diff --git a/apps/user-ui/components/PaymentAndOrderComponent.tsx b/apps/user-ui/components/PaymentAndOrderComponent.tsx index db0e045..654ed16 100644 --- a/apps/user-ui/components/PaymentAndOrderComponent.tsx +++ b/apps/user-ui/components/PaymentAndOrderComponent.tsx @@ -328,8 +328,8 @@ const PaymentAndOrderComponent: React.FC = ({ {/* Bottom Action Bar */} - {!selectedAddress && ( - + {!selectedAddress && ( + Please select a delivery address to place order diff --git a/apps/user-ui/src/components/AddToCartDialog.tsx b/apps/user-ui/src/components/AddToCartDialog.tsx index b56e212..6157c9f 100644 --- a/apps/user-ui/src/components/AddToCartDialog.tsx +++ b/apps/user-ui/src/components/AddToCartDialog.tsx @@ -162,7 +162,7 @@ export default function AddToCartDialog() { {availableSlots.map((slot: any) => ( { diff --git a/change-log.txt b/change-log.txt index 4049f6e..46e5568 100644 --- a/change-log.txt +++ b/change-log.txt @@ -2382,6 +2382,155 @@ again; callers invoke it only when the login screen is showing. commands: - runFlow: +[2026-09-16 19:41:02] Disable LogBox in dev builds (admin-ui + user-ui). + +The dev LogBox toast ("Open debugger to view warnings.") overlays the bottom of +the UI and intercepts taps (e.g. the Add Slot FAB), which breaks E2E flows. + +=== apps/admin-ui/app/_layout.tsx === +- import: + LogBox from 'react-native' +- module top: `if (__DEV__) { LogBox.ignoreAllLogs(true) }` + +=== apps/user-ui/app/_layout.tsx === +- import: + LogBox from 'react-native' +- module top: `if (__DEV__) { LogBox.ignoreAllLogs(true) }` + +[2026-09-16 19:46:50] Add a standalone image-upload dev flow + image remove testID. + +Standalone flow to iterate on the image picker without running the whole product flow. + +=== packages/ui/src/components/ImageUploaderNeo.tsx === +- per-image remove button: + testID={testID ? `${testID}-remove` : undefined} + +=== tests/e2e/dev/upload-image.yaml (NEW) === +- addMedia -> launchApp -> conditional login -> add-product-menu-item -> + scroll to variant-0-image-add -> tap -> runFlow subflows/pick-image.yaml -> + assert variant-0-image-add-remove visible +- lives in dev/ so the root suite glob does not pick it up + +Run with: bash tests/e2e/run.sh dev/upload-image.yaml + +[2026-09-16 19:50:12] Speed up the image-picker subflow. + +`pick-image.yaml` was a chain of ~7 `optional: true` taps; each miss waited the +full element timeout, so a single image took ~35-45s. + +=== tests/e2e/subflows/pick-image.yaml === +- now: extendedWaitUntil for the thumbnail, tap it, extendedWaitUntil for + button_add, tap it, then assert app-root +- ids use a regex matching either MediaProvider package: + `com\.(google\.)?android\.providers\.media\.module:id/(icon_thumbnail|button_add)` +- dropped the DocumentsUI / permission-dialog optional fallbacks and the final + guarded fallback block (no longer needed; keeps it fast) +- if the picker doesn't open, it now fails at the first wait instead of timing + out ~7 times + +[2026-09-16 19:53:11] Remove the temporary image-upload dev flow. + +=== tests/e2e/dev/upload-image.yaml === +- deleted (served its purpose; picker flow is now fast and verified) + +[2026-09-16 20:04:01] Re-add the user-app order flow (rebuilt). + +Runs after add-product + add-slot-with-product: opens the user app, logs in, +search the created product, adds it to the cart in the created slot, checks out +and places a COD order. + +=== tests/e2e/user-order.yaml (NEW) === +- launchApp(in.freshyo.app) clearState -> optional FirstUser "Next" +- openLink freshyo://login (x2) -> wait user-login-mobile -> conditional + runFlow subflows/login-user.yaml +- wait home-search -> tap home-search -> search-input-input -> inputText + ${PRODUCT_NAME} -> pressKey enter -> tap "Add to Cart" +- wait slot-option -> tap slot-option -> tap add-to-cart-confirm +- openLink freshyo://home/cart -> scrollUntilVisible checkout-button -> tap +- extendedWaitUntil notVisible "Please select a delivery address" (address + auto-select) -> scrollUntilVisible place-order-button -> tap +- assertVisible "Order Placed Successfully!" + +=== tests/e2e/subflows/login-user.yaml (NEW) === +- mobile -> "other ways to login" -> password -> Login + +=== tests/e2e/config.yaml === +- executionOrder.flowsOrder += user-order + +=== tests/e2e/run.sh === +- + -e USER_APP_ID / USER_MOBILE / USER_PASSWORD + +[2026-09-16 20:09:14] user-order.yaml: login only if checkout demands it. + +No more `openLink freshyo://login`: launchApp (clearState) -> optional FirstUser +"Next" -> home-search -> search product -> "Add to Cart" -> slot-option -> +confirm -> deep link freshyo://home/cart -> checkout-button. Then wait for +`user-login-mobile|place-order-button`; run subflows/login-user.yaml only when +the login screen is showing (auth gate). Address auto-select wait and Place +Order unchanged. + +[2026-09-16 20:15:02] user-order.yaml: post-login lands on cart, re-enter checkout. + +Login returns to the cart page (not checkout), so after the conditional +subflows/login-user.yaml there is now a second conditional runFlow: when +`checkout-button` is visible (cart page), scroll to it and tap it to return to +checkout. No-op when already on checkout. YAML validates (2 docs). + +[2026-09-16 20:21:33] user-order.yaml: fix post-login recovery (button below fold). + +The separate `when: visible: checkout-button` conditional never fired because +Maestro visibility needs the element on-screen. Folded the recovery into the +login branch instead: after subflows/login-user.yaml, wait for +`${PRODUCT_NAME}` (cart loaded), then scrollUntilVisible checkout-button DOWN +and tap it. No visibility gate on the button itself. YAML validates (2 docs). + +[2026-09-16 20:28:44] user-order: tap first address card when none auto-selected. + +Checkout auto-select only picks the address flagged isDefault +(CheckoutAddressSelector.tsx:65-72); with none marked default the "Please +select a delivery address" banner persisted and Place Order stayed disabled. +Added testID `address-option-{index}` to the address cards and a conditional +step in user-order.yaml: when the banner is visible, wait for address-option-0 +and tap it, then continue to Place Order. + +[2026-09-16 20:35:10] user-order: read the address error at the bottom first. + +The "select address" banner sits at the bottom next to Place Order, so a +`when: visible:` check from the top of the page never fires. Reordered: +wait for address-option-0 (cards loaded at top) -> scroll DOWN to +place-order-button -> only then check the banner; if visible, scroll back UP +to address-option-0, tap it, and scroll back DOWN before Place Order. + +[2026-09-16 20:41:02] user-order: testID for the select-address error banner. + +Added testID `select-address-error` to the "Please select a delivery address" +banner in PaymentAndOrderComponent.tsx; user-order.yaml now matches on that id +instead of text for both the `when: visible:` check and the `notVisible` wait. + +[2026-09-16 20:56:12] E2E: deterministic slot via SLOT_DATE/HOUR/MIN + go-to-cart nav. + +.env (+ .env.example) gains SLOT_DATE (today, YYYY-MM-DD), SLOT_HOUR, SLOT_MIN +(delivery wall-time, 24h zero-padded, device-local); run.sh requires them, +forwards them, and computes SLOT_FREEZE_HOUR/MIN = delivery - 10 min in bash. +set-slot-times.yaml rewritten to absolute times (date pickers just confirm +today; time pickers use text-input mode with env values; no evalScript). +AddToCartDialog slot options get testID `slot-YYYY-MM-DD-HH-mm` (replaces +generic `slot-option`). user-order.yaml taps `slot-${SLOT_DATE}-${SLOT_HOUR}- +${SLOT_MIN}` and reaches the cart via the floating `go-to-cart` bar instead of +the `freshyo://home/cart` deep link. README layout lines updated. + +[2026-09-16 21:02:33] user-order: normalize post-login landing via relaunch. + +Login may land on the cart page or the home page, so detecting the landing is +fragile. After subflows/login-user.yaml the flow now relaunches the app +without clearState (session + cart persist; initial route is always home), +then goes home -> go-to-cart -> cart -> checkout-button like the main path. + +[2026-09-16 21:06:12] user-order: handle home landing inline, no relaunch. + +Reverted the post-login relaunch. After subflows/login-user.yaml the flow now +assumes the home landing: wait for home-search, tap the floating go-to-cart +bar, then scroll to checkout-button and re-enter checkout. + +[2026-09-16 21:12:40] E2E: stripped narration comments from flows, run.sh, .env. + diff --git a/opencode.jsonc b/opencode.jsonc new file mode 100644 index 0000000..47e2655 --- /dev/null +++ b/opencode.jsonc @@ -0,0 +1,4 @@ +// { +// "$schema": "https://opencode.ai/config.json", +// "permission": "allow" +// } diff --git a/packages/ui/src/components/ImageUploaderNeo.tsx b/packages/ui/src/components/ImageUploaderNeo.tsx index 37201f9..312f9e4 100644 --- a/packages/ui/src/components/ImageUploaderNeo.tsx +++ b/packages/ui/src/components/ImageUploaderNeo.tsx @@ -48,6 +48,7 @@ const ImageUploaderNeo: React.FC = style={tw`w-full aspect-square rounded`} /> onImageRemove({ url: image.imgUrl, diff --git a/packages/ui/src/components/search-bar.tsx b/packages/ui/src/components/search-bar.tsx index f56b2e9..3b54434 100755 --- a/packages/ui/src/components/search-bar.tsx +++ b/packages/ui/src/components/search-bar.tsx @@ -16,6 +16,7 @@ interface SearchBarProps { containerStyle?: ViewStyle; onPress?: () => void; activeOpacity?: number; + testID?: string; } const SearchBar = forwardRef(({ @@ -28,6 +29,7 @@ const SearchBar = forwardRef(({ containerStyle, onPress, activeOpacity = 0.8, + testID, }, ref) => { const Wrapper = onPress ? MyTouchableOpacity : View; @@ -35,8 +37,10 @@ const SearchBar = forwardRef(({ style: [tw`flex-row items-center bg-white rounded-2xl px-4 h-12 mb-6 shadow-md`, { overflow: 'visible' }, containerStyle], onPress, activeOpacity, + testID, } : { style: [tw`flex-row items-center bg-white rounded-2xl px-4 h-12 mb-6 shadow-md`, { overflow: 'visible' }, containerStyle], + testID, }; return ( @@ -44,6 +48,7 @@ const SearchBar = forwardRef(({