Skip to content

Commit 2cdc592

Browse files
committed
Add Swift iOS checkout e2e flow
1 parent 0213b05 commit 2cdc592

8 files changed

Lines changed: 294 additions & 9 deletions

File tree

e2e/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ terminal.
5151
| Platform | From | Command |
5252
| ------------------ | ------------------------------- | ------------------ |
5353
| React Native, iOS | `platforms/react-native/` | `pnpm e2e:ios` |
54-
| Swift, iOS | TBD | TBD |
54+
| Swift, iOS | `platforms/swift/` | `./Scripts/e2e_maestro_ios` |
5555
| Android (native) | TBD | TBD |
5656
| RN, Android | `platforms/react-native/` | `pnpm e2e:android` |
5757

e2e/swift/checkout-completion.yaml

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
appId: com.shopify.example.MobileBuyIntegration
2+
name: Checkout submits and shows result
3+
tags:
4+
- swift
5+
- ios
6+
- checkout
7+
8+
env:
9+
PRODUCT_INDEX: "1"
10+
11+
# CI shipping fixture
12+
COUNTRY_LABEL: "United States"
13+
ADDRESS_LINE1: "700 S Flower St"
14+
CITY: "Los Angeles"
15+
STATE_FIELD_LABEL: "State"
16+
STATE_LABEL: "California"
17+
POSTAL_CODE: "90017"
18+
POSTAL_FIELD_LABEL: "ZIP code"
19+
20+
# CI payment fixture
21+
CARD_NUMBER: "4242424242424242"
22+
CARD_EXPIRY: "1230"
23+
CARD_SECURITY_CODE: "123"
24+
25+
# Accepted terminal checkout states for this smoke test.
26+
POST_SUBMIT_RESULT_PATTERN: ".*(Thank you|Your order|Order confirmed|confirmation|Shipping not available|There was a problem|declined|couldn.t process).*"
27+
---
28+
# Timeout tiers:
29+
# 3000 - animation settles
30+
# 5000 - local in-page interactions and optional probes
31+
# 15000 - sample-app checkout transitions
32+
# 60000 - cold starts, first checkout paint, final submit
33+
34+
# Product and cart
35+
- launchApp:
36+
clearState: true
37+
arguments:
38+
AppleLocale: en_US
39+
AppleLanguages: "(en)"
40+
- runFlow:
41+
when:
42+
visible:
43+
id: catalog-tab
44+
commands:
45+
- tapOn:
46+
id: catalog-tab
47+
- extendedWaitUntil:
48+
visible:
49+
id: product-0-grid-item
50+
timeout: 60000
51+
- scrollUntilVisible:
52+
element:
53+
id: product-${PRODUCT_INDEX}-grid-item
54+
direction: DOWN
55+
timeout: 5000
56+
centerElement: true
57+
- tapOn:
58+
id: product-${PRODUCT_INDEX}-grid-item
59+
- extendedWaitUntil:
60+
visible:
61+
id: add-to-cart-button
62+
timeout: 5000
63+
- tapOn:
64+
id: add-to-cart-button
65+
enabled: true
66+
- extendedWaitUntil:
67+
visible: "^Added$"
68+
timeout: 15000
69+
- tapOn:
70+
id: product-sheet-close-button
71+
- waitForAnimationToEnd:
72+
timeout: 3000
73+
- tapOn:
74+
id: cart-tab
75+
- extendedWaitUntil:
76+
visible:
77+
id: checkout-button
78+
timeout: 15000
79+
- tapOn:
80+
id: checkout-button
81+
enabled: true
82+
83+
# Contact
84+
- extendedWaitUntil:
85+
visible:
86+
text: "^Email( or mobile phone number)?$"
87+
timeout: 60000
88+
- tapOn:
89+
text: "^Email( or mobile phone number)?$"
90+
index: -1
91+
- inputText: "maestro.e2e@shopify.com"
92+
- tapOn: "selected"
93+
- tapOn:
94+
text: "^First name( \\(optional\\))?$"
95+
index: -1
96+
- inputText: "Maestro"
97+
- tapOn: "selected"
98+
- tapOn:
99+
text: "^Last name$"
100+
index: -1
101+
- inputText: "Shopify"
102+
- tapOn: "selected"
103+
104+
# Shipping address
105+
- scrollUntilVisible:
106+
element:
107+
text: "Country/Region"
108+
direction: DOWN
109+
timeout: 5000
110+
- tapOn:
111+
text: "Country/Region"
112+
index: 1
113+
- waitForAnimationToEnd:
114+
timeout: 3000
115+
- scrollUntilVisible:
116+
element:
117+
text: "^${COUNTRY_LABEL}$"
118+
direction: UP
119+
timeout: 5000
120+
visibilityPercentage: 10
121+
optional: true
122+
- scrollUntilVisible:
123+
element:
124+
text: "^${COUNTRY_LABEL}$"
125+
direction: DOWN
126+
timeout: 5000
127+
visibilityPercentage: 10
128+
optional: true
129+
- tapOn:
130+
text: "^${COUNTRY_LABEL}$"
131+
- waitForAnimationToEnd:
132+
timeout: 3000
133+
134+
- scrollUntilVisible:
135+
element:
136+
text: "Address"
137+
direction: DOWN
138+
timeout: 5000
139+
- tapOn:
140+
text: "Address"
141+
index: -1
142+
- eraseText: 80
143+
- inputText: "${ADDRESS_LINE1}"
144+
- tapOn: "selected"
145+
- scrollUntilVisible:
146+
element:
147+
text: "^City$"
148+
direction: DOWN
149+
timeout: 5000
150+
centerElement: true
151+
- tapOn:
152+
text: "^City$"
153+
index: -1
154+
- eraseText: 80
155+
- inputText: "${CITY}"
156+
- tapOn: "selected"
157+
- scrollUntilVisible:
158+
element:
159+
text: "^${STATE_FIELD_LABEL}$"
160+
direction: DOWN
161+
timeout: 5000
162+
centerElement: true
163+
- tapOn:
164+
text: "^${STATE_FIELD_LABEL}$"
165+
index: -1
166+
- waitForAnimationToEnd:
167+
timeout: 3000
168+
- scrollUntilVisible:
169+
element:
170+
text: "^${STATE_LABEL}$"
171+
direction: UP
172+
timeout: 5000
173+
visibilityPercentage: 100
174+
optional: true
175+
- scrollUntilVisible:
176+
element:
177+
text: "^${STATE_LABEL}$"
178+
direction: DOWN
179+
timeout: 5000
180+
visibilityPercentage: 100
181+
optional: true
182+
- tapOn:
183+
text: "^${STATE_LABEL}$"
184+
- waitForAnimationToEnd:
185+
timeout: 3000
186+
- extendedWaitUntil:
187+
notVisible: "Select a state"
188+
timeout: 5000
189+
- extendedWaitUntil:
190+
visible: "^${STATE_LABEL}$"
191+
timeout: 5000
192+
- scrollUntilVisible:
193+
element:
194+
text: "^${POSTAL_FIELD_LABEL}$"
195+
direction: DOWN
196+
timeout: 5000
197+
centerElement: true
198+
- tapOn:
199+
text: "^${POSTAL_FIELD_LABEL}$"
200+
index: -1
201+
- eraseText: 80
202+
- inputText: "${POSTAL_CODE}"
203+
- tapOn: "selected"
204+
- extendedWaitUntil:
205+
visible: "^${POSTAL_CODE}$"
206+
timeout: 5000
207+
- waitForAnimationToEnd:
208+
timeout: 3000
209+
210+
# Payment
211+
- scrollUntilVisible:
212+
element:
213+
text: "^Complete order$"
214+
direction: DOWN
215+
timeout: 5000
216+
centerElement: true
217+
optional: true
218+
- runFlow:
219+
when:
220+
notVisible: "^Complete order$"
221+
commands:
222+
- scrollUntilVisible:
223+
element:
224+
text: "^Field container for: Card number$"
225+
direction: DOWN
226+
timeout: 5000
227+
centerElement: true
228+
optional: true
229+
- runFlow:
230+
when:
231+
visible: "^Field container for: Card number$"
232+
commands:
233+
- tapOn:
234+
text: "^Field container for: Card number$"
235+
- inputText: "${CARD_NUMBER}"
236+
- tapOn: "selected"
237+
- tapOn: "Expiration date (MM / YY)"
238+
- inputText: "${CARD_EXPIRY}"
239+
- tapOn: "selected"
240+
- tapOn: "Field container for: Security code"
241+
- inputText: "${CARD_SECURITY_CODE}"
242+
- tapOn: "selected"
243+
- scrollUntilVisible:
244+
element:
245+
text: "^Field container for: Name on card$"
246+
direction: DOWN
247+
timeout: 5000
248+
centerElement: true
249+
- scrollUntilVisible:
250+
element:
251+
text: "^Pay now$"
252+
direction: DOWN
253+
timeout: 5000
254+
centerElement: true
255+
optional: true
256+
- runFlow:
257+
when:
258+
visible: "^Pay now$"
259+
commands:
260+
- tapOn:
261+
text: "^Pay now$"
262+
enabled: true
263+
- runFlow:
264+
when:
265+
visible: "^Complete order$"
266+
commands:
267+
- tapOn:
268+
text: "^Complete order$"
269+
enabled: true
270+
- extendedWaitUntil:
271+
visible: "${POST_SUBMIT_RESULT_PATTERN}"
272+
timeout: 60000

platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration.xcodeproj/project.pbxproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
mainGroup = 4EBBA75E2A5F0CE200193E19;
160160
packageReferences = (
161161
CB00000012345678 /* XCRemoteSwiftPackageReference "apollo-ios" */,
162-
CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../../../checkout-kit" */,
162+
CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../.." */,
163163
);
164164
productRefGroup = 4EBBA7682A5F0CE200193E19 /* Products */;
165165
projectDirPath = "";
@@ -443,9 +443,9 @@
443443
/* End XCConfigurationList section */
444444

445445
/* Begin XCLocalSwiftPackageReference section */
446-
CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../../../checkout-kit" */ = {
446+
CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../.." */ = {
447447
isa = XCLocalSwiftPackageReference;
448-
relativePath = "../../../../../checkout-kit";
448+
relativePath = "../../../..";
449449
};
450450
/* End XCLocalSwiftPackageReference section */
451451

@@ -473,17 +473,17 @@
473473
};
474474
CB001E302F3CDA0300286F69 /* ShopifyCheckoutProtocol */ = {
475475
isa = XCSwiftPackageProductDependency;
476-
package = CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../../../checkout-kit" */;
476+
package = CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../.." */;
477477
productName = ShopifyCheckoutProtocol;
478478
};
479479
CB1B10B42E4CDDB0001713F8 /* ShopifyCheckoutKit */ = {
480480
isa = XCSwiftPackageProductDependency;
481-
package = CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../../../checkout-kit" */;
481+
package = CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../.." */;
482482
productName = ShopifyCheckoutKit;
483483
};
484484
CBED2D4E2F3F5D1B00EC866A /* ShopifyAcceleratedCheckouts */ = {
485485
isa = XCSwiftPackageProductDependency;
486-
package = CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../../../checkout-kit" */;
486+
package = CB2370002FB21BF100F0D914 /* XCLocalSwiftPackageReference "../../../.." */;
487487
productName = ShopifyAcceleratedCheckouts;
488488
};
489489
/* End XCSwiftPackageProductDependency section */

platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration/Sources/App/SceneDelegate.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,30 +85,35 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
8585
// Catalog grid view
8686
productGridController.tabBarItem.image = UIImage(systemName: "square.grid.2x2")
8787
productGridController.tabBarItem.title = "Catalog"
88+
productGridController.tabBarItem.accessibilityIdentifier = "catalog-tab"
8889
productGridController.navigationItem.titleView = logoImageView
8990
catalogCartButton = createCartButtonWithBadge()
9091
productGridController.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: catalogCartButton!)
9192

9293
// Product Gallery
9394
productGalleryController.tabBarItem.image = UIImage(systemName: "appwindow.swipe.rectangle")
9495
productGalleryController.tabBarItem.title = "Products"
96+
productGalleryController.tabBarItem.accessibilityIdentifier = "products-tab"
9597
productGalleryController.navigationItem.titleView = logoImageView
9698
galleryCartButton = createCartButtonWithBadge()
9799
productGalleryController.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: galleryCartButton!)
98100

99101
// Cart (UI Kit)
100102
swiftUICartController.tabBarItem.image = UIImage(systemName: "cart")
101103
swiftUICartController.tabBarItem.title = "Cart"
104+
swiftUICartController.tabBarItem.accessibilityIdentifier = "cart-tab"
102105
swiftUICartController.navigationItem.title = "Cart (SwiftUI)"
103106

104107
// Account
105108
accountController.tabBarItem.image = UIImage(systemName: "person.circle")
106109
accountController.tabBarItem.title = "Log in"
110+
accountController.tabBarItem.accessibilityIdentifier = "account-tab"
107111
subscribeToAuthStateChanges()
108112

109113
// Settings
110114
settingsController.tabBarItem.image = UIImage(systemName: "gearshape.2")
111115
settingsController.tabBarItem.title = "Settings"
116+
settingsController.tabBarItem.accessibilityIdentifier = "settings-tab"
112117
}
113118

114119
private func subscribeToAuthStateChanges() {

platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration/Sources/Scenes/Cart/CartView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ struct CartView: View {
8080
)
8181
.disabled(isBusy)
8282
.foregroundColor(.white)
83-
.accessibilityIdentifier("checkoutSheetButton")
83+
.accessibilityIdentifier("checkout-button")
8484
}
8585
.padding(.horizontal, 20)
8686
.padding(.bottom, 20)

platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration/Sources/Scenes/ProductGridView.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ struct ProductGridView: View {
1515
ScrollView {
1616
LazyVGrid(columns: columns, spacing: 2) {
1717
if let products = productCache.collection, !products.isEmpty {
18-
ForEach(products, id: \.id) { product in
18+
ForEach(Array(products.enumerated()), id: \.element.id) { index, product in
1919
ProductGridItem(product: product)
20+
.accessibilityIdentifier("product-\(index)-grid-item")
2021
.onTapGesture {
2122
selectProductAndShowSheet(for: product)
2223
}
@@ -65,6 +66,7 @@ struct ProductSheetView: View {
6566
.padding()
6667
.foregroundStyle(.white)
6768
}
69+
.accessibilityIdentifier("product-sheet-close-button")
6870
.padding([.top, .trailing], 16)
6971
}
7072
.edgesIgnoringSafeArea(.top)

platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration/Sources/Scenes/ProductView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ struct ProductView: View {
111111
.foregroundStyle(.white)
112112
.cornerRadius(DesignSystem.cornerRadius)
113113
.disabled(!variant.availableForSale || loading)
114+
.accessibilityIdentifier("add-to-cart-button")
114115

115116
if variant.availableForSale {
116117
AcceleratedCheckoutButtons(variantID: variant.id, quantity: 1)

0 commit comments

Comments
 (0)