This commit is contained in:
shafi54 2026-09-15 18:35:54 +05:30
parent b5274e0c2b
commit 31085bdf32
5 changed files with 147 additions and 64 deletions

View file

@ -442,6 +442,7 @@ const ProductForm = forwardRef<ProductFormRef, ProductFormProps>(({
<View style={tw`flex-1`}> <View style={tw`flex-1`}>
<MyTextInput <MyTextInput
topLabel="Our Price" topLabel="Our Price"
testID={`variant-${vIndex}-price`}
placeholder="Selling price" placeholder="Selling price"
keyboardType="numeric" keyboardType="numeric"
value={variant.price?.toString() ?? ''} value={variant.price?.toString() ?? ''}
@ -452,6 +453,7 @@ const ProductForm = forwardRef<ProductFormRef, ProductFormProps>(({
<View style={tw`flex-row items-center mb-3`}> <View style={tw`flex-row items-center mb-3`}>
<Checkbox <Checkbox
testID={`variant-${vIndex}-flash`}
checked={variant.isFlashAvailable} checked={variant.isFlashAvailable}
onPress={() => { onPress={() => {
setFieldValue(`variants.${vIndex}.isFlashAvailable`, !variant.isFlashAvailable) setFieldValue(`variants.${vIndex}.isFlashAvailable`, !variant.isFlashAvailable)
@ -485,6 +487,7 @@ const ProductForm = forwardRef<ProductFormRef, ProductFormProps>(({
{mode === 'edit' && ( {mode === 'edit' && (
<View style={tw`flex-row items-center mb-3`}> <View style={tw`flex-row items-center mb-3`}>
<Checkbox <Checkbox
testID={`variant-${vIndex}-suspend`}
checked={variant.isSuspended} checked={variant.isSuspended}
onPress={() => setFieldValue(`variants.${vIndex}.isSuspended`, !variant.isSuspended)} onPress={() => setFieldValue(`variants.${vIndex}.isSuspended`, !variant.isSuspended)}
style={tw`mr-3`} style={tw`mr-3`}

View file

@ -2030,3 +2030,27 @@ placeholder text:
+ id: "slot-products-selector" + id: "slot-products-selector"
e2e/flows/admin-product-full.yaml — same change for the attach leg. e2e/flows/admin-product-full.yaml — same change for the attach leg.
[2026-09-14 22:55:00] Fix: the second variant's Our Price had no stable selector.
Symptom: saving the product edit failed validation with "price is required" —
variant 2's Our Price never received the typed value. The flow tapped the
"Selling price" PLACEHOLDER, which only exists while the field is empty; that tap
works for variant 1 (filled during create) but does not focus the lower card's
input, so inputText went nowhere and the new variant stayed priceless.
apps/admin-ui/src/components/ProductForm.tsx — give each variant's price field a
per-index testID:
<MyTextInput
topLabel="Our Price"
+ testID={`variant-${vIndex}-price`}
placeholder="Selling price"
e2e/flows/admin-product-full.yaml — target it by id (0-indexed: the new variant is
index 1) instead of by placeholder:
- - tapOn: "Selling price"
+- tapOn:
+- id: "variant-1-price"
- inputText: "999"

17
e2e/.env Normal file
View file

@ -0,0 +1,17 @@
# Copy this file to e2e/.env (gitignored). `run.sh` / `bun run e2e` loads it
# automatically, so you don't need -e flags on the command line.
#
# Login uses the username + password path ("other ways to login"), because the
# OTP flow needs a real SMS/OTP that can't be automated.
TEST_IDENTIFIER=9676651496
TEST_PASSWORD=meatfarmer@123
# Optional: the address vars already have non-secret defaults in config.yaml.
# Set them here only if you want to override those.
# ADDRESS_NAME=
# ADDRESS_PHONE=
# ADDRESS_LINE1=
ADMIN_NAME=shafi
ADMIN_PASSWORD=shafI123

View file

@ -22,37 +22,40 @@ appId: in.freshyo.adminui
--- ---
# --- 1. Admin: create the product and attach it to the slot ------------------ # --- 1. Admin: create the product and attach it to the slot ------------------
# Reuses the standalone flows so the selectors live in one place. # Reuses the standalone flows so the selectors live in one place.
# Slot update disabled for now — only product create + update.
- runFlow: admin-product.yaml - runFlow: admin-product.yaml
- runFlow: admin-attach-product.yaml # - runFlow: admin-attach-product.yaml
# --- 2. User: the new product is searchable --------------------------------- # --- 2. User: the new product is searchable ---------------------------------
- launchApp: # DISABLED while iterating on the admin side — re-enable to verify in the user
appId: in.freshyo.app # app (it is a long leg: app switch + CDN refresh + search).
clearState: false # - launchApp:
- tapOn: # appId: in.freshyo.app
text: "^Home$" # clearState: false
optional: true # - tapOn:
- extendedWaitUntil: # text: "^Home$"
visible: # optional: true
id: "add-to-cart-icon" # - extendedWaitUntil:
timeout: 90000 # visible:
# The catalog is a versioned CDN file, so refresh to pick up the new product. # id: "add-to-cart-icon"
- swipe: # timeout: 90000
start: "50%,30%" # # The catalog is a versioned CDN file, so refresh to pick up the new product.
end: "50%,80%" # - swipe:
- waitForAnimationToEnd: # start: "50%,30%"
timeout: 10000 # end: "50%,80%"
- tapOn: "Search fresh meat..." # - waitForAnimationToEnd:
- extendedWaitUntil: # timeout: 10000
visible: "All Products" # - tapOn: "Search fresh meat..."
timeout: 30000 # - extendedWaitUntil:
- inputText: ${PRODUCT_NAME} # visible: "All Products"
- hideKeyboard # timeout: 30000
- extendedWaitUntil: # - inputText: ${PRODUCT_NAME}
visible: "${PRODUCT_NAME}.*" # - hideKeyboard
timeout: 120000 # - extendedWaitUntil:
# The card carries the unit notation and the price from the admin form. # visible: "${PRODUCT_NAME}.*"
- assertVisible: "Quantity: 0.5 kg" # timeout: 120000
# # The card carries the unit notation and the price from the admin form.
# - assertVisible: "Quantity: 0.5 kg"
# --- 3. Admin: suspend the SKU, change its units, add a variant ------------- # --- 3. Admin: suspend the SKU, change its units, add a variant -------------
- launchApp: - launchApp:
@ -97,8 +100,23 @@ appId: in.freshyo.adminui
centerElement: true centerElement: true
timeout: 30000 timeout: 30000
- tapOn: ".*Add Variant" - tapOn: ".*Add Variant"
# Reveal the new card — it is added below the fold, and extendedWaitUntil never
# scrolls. Only retry the button if the card is still absent AFTER scrolling (a
# bare notVisible would be true while the card is merely off-screen and would
# double-tap, adding a third variant).
- scrollUntilVisible:
element:
text: "Variant 2"
direction: DOWN
centerElement: true
timeout: 30000
- runFlow:
when:
notVisible: "Variant 2"
commands:
- waitForAnimationToEnd: - waitForAnimationToEnd:
timeout: 5000 timeout: 3000
- tapOn: ".*Add Variant"
- scrollUntilVisible: - scrollUntilVisible:
element: element:
text: "Variant 2" text: "Variant 2"
@ -117,7 +135,19 @@ appId: in.freshyo.adminui
# nothing, which is why this field stayed empty before. # nothing, which is why this field stayed empty before.
- waitForAnimationToEnd: - waitForAnimationToEnd:
timeout: 5000 timeout: 5000
- tapOn: "Selling price" # Scroll to the price field — the second variant (index 1, shown as "Variant 2")
# sits below the first, so this reveals it. Tapping an off-screen field does
# nothing, hence the scroll first.
- scrollUntilVisible:
element:
id: "variant-1-price"
direction: DOWN
centerElement: true
timeout: 30000
- waitForAnimationToEnd:
timeout: 5000
- tapOn:
id: "variant-1-price"
- inputText: "999" - inputText: "999"
- hideKeyboard - hideKeyboard
- scrollUntilVisible: - scrollUntilVisible:
@ -134,14 +164,16 @@ appId: in.freshyo.adminui
- inputText: "2 kg" - inputText: "2 kg"
- hideKeyboard - hideKeyboard
# Flash: turn it on, fill the flash price, then turn it back off. # Flash: turn it on, fill the flash price, then turn it back off. Tap the actual
# checkbox (id), not the label text — the label is a plain Text that ignores taps.
- scrollUntilVisible: - scrollUntilVisible:
element: element:
text: "Flash Available" id: "variant-0-flash"
direction: DOWN direction: DOWN
centerElement: true centerElement: true
timeout: 30000 timeout: 30000
- tapOn: "Flash Available" - tapOn:
id: "variant-0-flash"
- waitForAnimationToEnd: - waitForAnimationToEnd:
timeout: 3000 timeout: 3000
- runFlow: - runFlow:
@ -151,12 +183,14 @@ appId: in.freshyo.adminui
- tapOn: "Enter flash price" - tapOn: "Enter flash price"
- inputText: "399" - inputText: "399"
- hideKeyboard - hideKeyboard
- tapOn: "Flash Available" - tapOn:
id: "variant-0-flash"
- waitForAnimationToEnd: - waitForAnimationToEnd:
timeout: 3000 timeout: 3000
# Suspend the SKU (the whole product effectively goes unavailable to users). # Suspend the SKU (the whole product effectively goes unavailable to users).
- tapOn: "Suspend SKU" - tapOn:
id: "variant-0-suspend"
# Replace the image: the add tile sits just below the checkboxes, and this is the # Replace the image: the add tile sits just below the checkboxes, and this is the
# only path (expo-image-picker -> Android Photo Picker). # only path (expo-image-picker -> Android Photo Picker).
@ -213,31 +247,33 @@ appId: in.freshyo.adminui
- tapOn: "OK" - tapOn: "OK"
# --- 4. User: the changes are visible --------------------------------------- # --- 4. User: the changes are visible ---------------------------------------
- launchApp: # DISABLED while iterating on the admin side — re-enable to assert the effects
appId: in.freshyo.app # (suspended -> Out of Stock / UNAVAILABLE, new unit, no 1 hr row).
clearState: false # - launchApp:
- tapOn: # appId: in.freshyo.app
text: "^Home$" # clearState: false
optional: true # - tapOn:
- extendedWaitUntil: # text: "^Home$"
visible: # optional: true
id: "add-to-cart-icon" # - extendedWaitUntil:
timeout: 90000 # visible:
- swipe: # id: "add-to-cart-icon"
start: "50%,30%" # timeout: 90000
end: "50%,80%" # - swipe:
- waitForAnimationToEnd: # start: "50%,30%"
timeout: 10000 # end: "50%,80%"
- tapOn: "Search fresh meat..." # - waitForAnimationToEnd:
- extendedWaitUntil: # timeout: 10000
visible: "All Products" # - tapOn: "Search fresh meat..."
timeout: 30000 # - extendedWaitUntil:
- inputText: ${PRODUCT_NAME} # visible: "All Products"
- hideKeyboard # timeout: 30000
# - inputText: ${PRODUCT_NAME}
# Suspended SKU -> the card is marked out of stock and cannot be added. # - hideKeyboard
- extendedWaitUntil: #
visible: "${PRODUCT_NAME}.*" # # Suspended SKU -> the card is marked out of stock and cannot be added.
timeout: 120000 # - extendedWaitUntil:
- assertVisible: "Out of Stock" # visible: "${PRODUCT_NAME}.*"
- assertVisible: "UNAVAILABLE" # timeout: 120000
# - assertVisible: "Out of Stock"
# - assertVisible: "UNAVAILABLE"

View file

@ -14,6 +14,7 @@ interface CheckboxProps {
checkedColor?: string; // deprecated, use checkColor checkedColor?: string; // deprecated, use checkColor
fillColor?: string; // new prop for box/circle fill fillColor?: string; // new prop for box/circle fill
checkColor?: string; // new prop for check/tick color checkColor?: string; // new prop for check/tick color
testID?: string;
} }
const Checkbox: React.FC<CheckboxProps> = ({ const Checkbox: React.FC<CheckboxProps> = ({
@ -25,6 +26,7 @@ const Checkbox: React.FC<CheckboxProps> = ({
checkedColor, // deprecated checkedColor, // deprecated
fillColor, fillColor,
checkColor, checkColor,
testID,
}) => { }) => {
const { colors } = useTheme().theme; const { colors } = useTheme().theme;
const fill = fillColor || colors.brand500; const fill = fillColor || colors.brand500;
@ -39,6 +41,7 @@ const Checkbox: React.FC<CheckboxProps> = ({
style={style} style={style}
activeOpacity={0.7} activeOpacity={0.7}
disabled={disabled} disabled={disabled}
testID={testID}
accessibilityRole="checkbox" accessibilityRole="checkbox"
accessibilityState={{ checked, disabled }} accessibilityState={{ checked, disabled }}
> >