enh
This commit is contained in:
parent
b5274e0c2b
commit
31085bdf32
5 changed files with 147 additions and 64 deletions
|
|
@ -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`}
|
||||||
|
|
|
||||||
|
|
@ -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
17
e2e/.env
Normal 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
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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 }}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue