Skip to content

Commit 29c2688

Browse files
committed
Add RN hardcoded buyer identity E2E smoke
1 parent f52bdca commit 29c2688

15 files changed

Lines changed: 174 additions & 47 deletions

e2e/README.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
This directory contains Maestro end-to-end smoke flows for Checkout Kit sample
44
apps.
55

6-
The current runnable suite starts with React Native. It verifies a full guest
7-
checkout from a seeded cart in the sample app, through Shopify checkout, and
8-
back to the app after completion.
6+
The current runnable suite starts with React Native. It verifies full guest and
7+
hardcoded buyer identity checkouts from seeded carts, through Shopify checkout,
8+
and back to the app after completion.
99

1010
## Run locally
1111

@@ -28,20 +28,24 @@ dev rn e2e android
2828

2929
The React Native commands start Metro if needed, build and launch the target
3030
sample app, then run Maestro. They require the standard storefront `.env` setup,
31-
but the E2E flow seeds its own cart through the bootstrap deep link; no manual
32-
sample cart setup is required.
31+
but the E2E flows seed their own carts through the bootstrap deep link. The
32+
React Native bootstrap link accepts `buyerIdentityMode`, so guest and hardcoded
33+
buyer identity scenarios share the same cart setup path. No manual sample cart
34+
setup is required.
3335

3436
## Files
3537

3638
- `config.yaml` configures Maestro for shared platform behavior.
3739
- `flows/` contains reusable Maestro subflows for app setup and checkout steps.
38-
- `tests/react-native/full-guest-checkout.yaml` composes the React Native guest
40+
- `tests/react-native/checkout-guest.yaml` composes the React Native guest
3941
checkout smoke test from those subflows.
42+
- `tests/react-native/checkout-hardcoded-buyer-identity.yaml` verifies checkout
43+
from a bootstrapped cart with hardcoded buyer identity.
4044

4145
## Scope
4246

4347
This smoke flow is intended to catch regressions in the React Native sample app
44-
integration surface: cart bootstrap, checkout presentation, checkout
45-
completion, and return to the sample app. It is not a replacement for
46-
checkout-web's browser-based coverage or for future native Swift and Android
47-
sample-app E2E coverage.
48+
integration surface: cart bootstrap, buyer identity configuration, checkout
49+
presentation, checkout completion, and return to the sample app. It is not a
50+
replacement for checkout-web's browser-based coverage or for future native
51+
Swift and Android sample-app E2E coverage.

e2e/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
flows:
2-
- tests/**/*.yaml
2+
- tests/react-native/*.yaml
33

44
platform:
55
ios:

e2e/flows/app/bootstrap-cart-from-link.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ appId: ${APP_ID}
99
# Reset app data before testing the deep-link cold-start path. The app is
1010
# stopped so openLink is the launch that seeds the cart.
1111
- stopApp
12-
- openLink: "${CART_BOOTSTRAP_LINK}"
12+
- openLink: "${CART_BOOTSTRAP_BASE_LINK}&buyerIdentityMode=${BUYER_IDENTITY_MODE}"
1313
- waitForAnimationToEnd
1414
- extendedWaitUntil:
1515
visible:
1616
id: checkout-button
17-
timeout: 30000
17+
timeout: 10000
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
appId: ${APP_ID}
2+
---
3+
- runFlow:
4+
when:
5+
visible: "Open debugger to view warnings."
6+
commands:
7+
- tapOn:
8+
point: "92%,92%"
9+
- waitForAnimationToEnd

e2e/flows/app/launch.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ appId: ${APP_ID}
1010
visible:
1111
id: checkout-kit-sample-ready
1212
timeout: 10000
13+
- runFlow: dismiss-dev-warning.yaml
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
appId: ${APP_ID}
2+
---
3+
- tapOn:
4+
id: settings-tab
5+
- waitForAnimationToEnd
6+
- runFlow:
7+
when:
8+
notVisible:
9+
id: settings-section-authentication
10+
commands:
11+
- tapOn:
12+
id: settings-tab
13+
- waitForAnimationToEnd
14+
- extendedWaitUntil:
15+
visible:
16+
id: settings-section-authentication
17+
timeout: 10000
18+
- tapOn:
19+
id: "settings-buyer-identity-option-${BUYER_IDENTITY_MODE}"
20+
- waitForAnimationToEnd

e2e/flows/checkout/present.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ appId: ${APP_ID}
55
enabled: true
66
- extendedWaitUntil:
77
visible:
8-
text: "^Email( or mobile phone number)?$"
8+
text: "^(Email( or mobile phone number)?|Delivery|Card number)$"
99
timeout: 10000

e2e/tests/react-native/full-guest-checkout.yaml renamed to e2e/tests/react-native/checkout-guest.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
appId: ${APP_ID}
2-
name: React Native full guest checkout
2+
name: React Native checkout - guest
33

44
env:
5+
# Sample app buyer identity configuration
6+
BUYER_IDENTITY_MODE: "guest"
7+
58
# Checkout contact fixture
69
EMAIL: "maestro.e2e@shopify.com"
710
FIRST_NAME: "Maestro"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
appId: ${APP_ID}
2+
name: React Native checkout - hardcoded buyer identity
3+
4+
env:
5+
# Sample app buyer identity configuration
6+
BUYER_IDENTITY_MODE: "hardcoded"
7+
8+
# Checkout payment fixture
9+
CARD_NUMBER: "1"
10+
CARD_SECURITY_CODE: "123"
11+
12+
# Accepted successful checkout states for this smoke test.
13+
POST_SUBMIT_RESULT_PATTERN: ".*(Thank you|Your order|Order confirmed|confirmation).*"
14+
---
15+
- runFlow: ../../flows/app/bootstrap-cart-from-link.yaml
16+
- runFlow: ../../flows/checkout/present.yaml
17+
- runFlow: ../../flows/checkout/fill-payment-card.yaml
18+
- runFlow: ../../flows/checkout/submit.yaml
19+
- runFlow: ../../flows/checkout/assert-complete.yaml
20+
- runFlow: ../../flows/checkout/assert-returned-to-empty-cart.yaml

platforms/react-native/sample/src/context/Cart.tsx

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,19 @@ interface Context {
2222
addingToCart: Set<string>;
2323
clearCart: () => void;
2424
addToCart: (variantId: string, quantity?: number) => Promise<void>;
25-
seedCart: (variantId: string, quantity?: number) => Promise<void>;
25+
seedCart: (
26+
variantId: string,
27+
quantity?: number,
28+
buyerIdentityMode?: BuyerIdentityMode,
29+
) => Promise<void>;
2630
removeFromCart: (variantId: string) => Promise<void>;
2731
}
2832

33+
type AddToCartOptions = {
34+
forceNewCart?: boolean;
35+
buyerIdentityMode?: BuyerIdentityMode;
36+
};
37+
2938
const defaultCartId = undefined;
3039
const defaultCheckoutURL = undefined;
3140
const defaultTotalQuantity = 0;
@@ -114,19 +123,30 @@ export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
114123
}, [cartId, fetchCart, setTotalQuantity]);
115124

116125
const addToCart = useCallback(
117-
async (variantId: string, quantity = 1, forceNewCart = false) => {
126+
async (
127+
variantId: string,
128+
quantity = 1,
129+
{
130+
forceNewCart = false,
131+
buyerIdentityMode = appConfig.buyerIdentityMode,
132+
}: AddToCartOptions = {},
133+
) => {
118134
if (!Number.isInteger(quantity) || quantity < 1) {
119135
throw new Error('Cart quantity must be a positive integer');
120136
}
121137

122138
let id = forceNewCart ? undefined : cartId;
139+
const cartAppConfig = {
140+
...appConfig,
141+
buyerIdentityMode,
142+
};
123143

124144
dispatch({type: 'add', variantId});
125145

126146
try {
127147
if (
128148
!id &&
129-
appConfig.buyerIdentityMode === BuyerIdentityMode.CustomerAccount &&
149+
buyerIdentityMode === BuyerIdentityMode.CustomerAccount &&
130150
!isAuthenticated
131151
) {
132152
const signInRequiredMessage =
@@ -144,14 +164,11 @@ export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
144164

145165
if (!id) {
146166
let customerAccessToken: string | undefined;
147-
if (
148-
appConfig.buyerIdentityMode === BuyerIdentityMode.CustomerAccount
149-
) {
150-
customerAccessToken =
151-
(await getValidAccessToken()) ?? undefined;
167+
if (buyerIdentityMode === BuyerIdentityMode.CustomerAccount) {
168+
customerAccessToken = (await getValidAccessToken()) ?? undefined;
152169
}
153170
const cartInput = createBuyerIdentityCartInput(
154-
appConfig,
171+
cartAppConfig,
155172
customerAccessToken,
156173
);
157174
const cart = await createCart({variables: {input: cartInput}});
@@ -198,8 +215,15 @@ export const CartProvider: React.FC<PropsWithChildren> = ({children}) => {
198215
);
199216

200217
const seedCart = useCallback(
201-
async (variantId: string, quantity = 1) => {
202-
await addToCart(variantId, quantity, true);
218+
async (
219+
variantId: string,
220+
quantity = 1,
221+
buyerIdentityMode?: BuyerIdentityMode,
222+
) => {
223+
await addToCart(variantId, quantity, {
224+
forceNewCart: true,
225+
buyerIdentityMode,
226+
});
203227
},
204228
[addToCart],
205229
);

0 commit comments

Comments
 (0)