Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions e2e/flows/checkout/assert-native-preload-cache-reuse.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
appId: ${E2E_APP_ID}
---
- runFlow: present.yaml
- runFlow: close.yaml

# Preload completing is not proof that presentation reused it, so each sample republishes the
# SDK's own cache-hit diagnostic as this identifier. Swift installs a Logger and observes the
# message directly; Kotlin reads it from the app's own PID-scoped Logcat. Same assertion on
# both platforms.
- extendedWaitUntil:
visible:
id: preload-cache-hit-observed
timeout: 30000
33 changes: 33 additions & 0 deletions e2e/flows/checkout/assert-native-preload-disabled.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
appId: ${E2E_APP_ID}
---
# Runs after the shared readiness flow, so disabling below acts on a proven Ready preload
# instead of matching a not-ready state the app merely started in.
- tapOn:
id: settings-tab
- waitForAnimationToEnd

- tapOn:
id: checkout-preloading-toggle
enabled: true
- assertVisible:
id: checkout-preloading-toggle
checked: false

- tapOn:
id: cart-tab
- waitForAnimationToEnd

- extendedWaitUntil:
visible:
id: preload-state-not-ready
timeout: 30000

- assertVisible:
id: preload-cache-hit-none

- runFlow: present.yaml
- runFlow: close.yaml

# Disabled preload presents a fresh checkout, so the cache-hit marker must stay none.
- assertVisible:
id: preload-cache-hit-none
14 changes: 1 addition & 13 deletions e2e/flows/checkout/assert-native-preload-ready.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@ appId: ${E2E_APP_ID}
id: preload-state-ready
timeout: 60000

# Pins the starting value, so a marker stuck on "observed" cannot pass the assertion below.
# Pins the starting value, so a marker stuck on "observed" cannot pass later assertions.
- assertVisible:
id: preload-cache-hit-none

- runFlow: present.yaml
- runFlow: close.yaml

# Preload completing is not proof that presentation reused it, so each sample republishes the
# SDK's own cache-hit diagnostic as this identifier. Swift installs a Logger and observes the
# message directly; Kotlin reads it from the app's own PID-scoped Logcat. Same assertion on
# both platforms.
- extendedWaitUntil:
visible:
id: preload-cache-hit-observed
timeout: 30000
14 changes: 14 additions & 0 deletions e2e/tests/shared/native-preload-disabled.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
appId: ${E2E_APP_ID}
name: Native preload disabled avoids reuse
tags:
- preload
- smoke

env:
# Preload caches a checkout per buyer, so the identity is pinned rather than left to
# whatever the sample was last configured with.
E2E_CART_PARAMS: "productIndex=0&quantity=1&buyerIdentityMode=guest"
---
- runFlow: ../../flows/app/bootstrap-cart-from-link.yaml
- runFlow: ../../flows/checkout/assert-native-preload-ready.yaml
- runFlow: ../../flows/checkout/assert-native-preload-disabled.yaml
1 change: 1 addition & 0 deletions e2e/tests/shared/native-preload-ready.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ env:
---
- runFlow: ../../flows/app/bootstrap-cart-from-link.yaml
- runFlow: ../../flows/checkout/assert-native-preload-ready.yaml
- runFlow: ../../flows/checkout/assert-native-preload-cache-reuse.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ object AccessibilityIdentifiers {

object Tabs {
const val CART = "cart-tab"
const val SETTINGS = "settings-tab"
}

object Settings {
const val CHECKOUT_PRELOADING_TOGGLE = "checkout-preloading-toggle"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.shopify.checkoutkit.androiddemo.R
import com.shopify.checkoutkit.androiddemo.accessibility.AccessibilityIdentifiers
import com.shopify.checkoutkit.androiddemo.common.components.BodySmall

@Composable
Expand Down Expand Up @@ -54,6 +56,7 @@ fun BottomAppBarWithNavigation(
ImageVector.vectorResource(R.drawable.profile),
stringResource(id = R.string.navigation_log_in),
currentScreen,
modifier = Modifier.testTag(AccessibilityIdentifiers.Tabs.SETTINGS),
)
}
}
Expand All @@ -66,6 +69,7 @@ fun NavigationItem(
icon: ImageVector,
label: String,
currentScreen: Screen,
modifier: Modifier = Modifier,
) {
val isActiveScreen = currentScreen == screen
val color = if (isActiveScreen) {
Expand All @@ -77,7 +81,7 @@ fun NavigationItem(
Column {
IconButton(
onClick = { navController.navigate(screen.route) },
modifier = Modifier.semantics {
modifier = modifier.semantics {
this.contentDescription = "$label icon"
}
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import com.shopify.checkoutkit.androiddemo.common.components.BodyMedium

@Composable
Expand All @@ -28,6 +29,7 @@ fun SettingsSwitch(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier,
testTag: String? = null,
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
Expand All @@ -37,7 +39,8 @@ fun SettingsSwitch(
BodyMedium(label)
Switch(
checked = checked,
onCheckedChange = onCheckedChange
onCheckedChange = onCheckedChange,
modifier = if (testTag == null) Modifier else Modifier.testTag(testTag),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.shopify.checkoutkit.androiddemo.R
import com.shopify.checkoutkit.androiddemo.accessibility.AccessibilityIdentifiers
import com.shopify.checkoutkit.androiddemo.common.components.BodyMedium
import com.shopify.checkoutkit.androiddemo.common.components.Header2
import com.shopify.checkoutkit.androiddemo.common.components.ProgressIndicator
Expand Down Expand Up @@ -101,7 +102,8 @@ fun SettingsView(
onCheckedChange = settingsViewModel::setCheckoutPreloadingEnabled,
modifier = Modifier
.background(color = MaterialTheme.colorScheme.background)
.fillMaxWidth()
.fillMaxWidth(),
testTag = AccessibilityIdentifiers.Settings.CHECKOUT_PRELOADING_TOGGLE,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,12 @@ class AccessibilityIdentifiersTest {
@Test
fun `tab markers match the maestro flows`() {
assertThat(AccessibilityIdentifiers.Tabs.CART).isEqualTo("cart-tab")
assertThat(AccessibilityIdentifiers.Tabs.SETTINGS).isEqualTo("settings-tab")
}

@Test
fun `settings markers match the maestro flows`() {
assertThat(AccessibilityIdentifiers.Settings.CHECKOUT_PRELOADING_TOGGLE)
.isEqualTo("checkout-preloading-toggle")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@ enum AccessibilityIdentifiers {

enum Tabs {
static let cart = "cart-tab"
static let settings = "settings-tab"
}

enum Settings {
static let checkoutPreloadingToggle = "checkout-preloading-toggle"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// Settings
settingsController.tabBarItem.image = UIImage(systemName: "gearshape.2")
settingsController.tabBarItem.title = "Settings"
settingsController.tabBarItem.accessibilityIdentifier = AccessibilityIdentifiers.Tabs.settings
}

private func subscribeToAuthStateChanges() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,22 @@ struct SettingsView: View {
NavigationView {
List {
Section(header: Text("Features")) {
Toggle("Checkout preloading", isOn: $checkoutPreloadingEnabled)
.onChange(of: checkoutPreloadingEnabled) { _ in
ShopifyCheckoutKit.configure {
$0.preloading.enabled = checkoutPreloadingEnabled
// A whole-row Toggle exposes one full-width element whose center tap misses
// the switch, so the label sits outside and the identifier tags the control.
HStack {
Text("Checkout preloading")
Spacer()
Toggle("Checkout preloading", isOn: $checkoutPreloadingEnabled)
.labelsHidden()
.accessibilityIdentifier(
AccessibilityIdentifiers.Settings.checkoutPreloadingToggle
)
.onChange(of: checkoutPreloadingEnabled) { _ in
ShopifyCheckoutKit.configure {
$0.preloading.enabled = checkoutPreloadingEnabled
}
}
}
}

Picker("Window open handler", selection: $windowOpenHandler) {
ForEach(WindowOpenHandlerOption.allCases, id: \.self) { option in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@ class AccessibilityIdentifiersTests: XCTestCase {

func testTabMarkersMatchTheMaestroFlows() {
XCTAssertEqual(AccessibilityIdentifiers.Tabs.cart, "cart-tab")
XCTAssertEqual(AccessibilityIdentifiers.Tabs.settings, "settings-tab")
}

func testSettingsMarkersMatchTheMaestroFlows() {
XCTAssertEqual(AccessibilityIdentifiers.Settings.checkoutPreloadingToggle, "checkout-preloading-toggle")
}
}
Loading