From 2f5d6e97bf27c608f7e56e4951d78c13bf73337c Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Thu, 30 Jul 2026 12:19:26 +0100 Subject: [PATCH 1/2] Add sample app test seams and run them in CI The E2E control link parser lands next and needs a test home in each sample. Today the Swift and Android samples have no test target at all, and the React Native sample's jest tests never run in CI, so its nine cart bootstrap parse cases gate nothing. Swift: add a CheckoutKitSwiftDemoTests bundle.unit-test target and a Scripts/test_samples entry point. Android: add app/src/test with junit and assertj, because the sample is a separate Gradle composite that `dev android test` does not reach. React Native: move the E2E-only cart bootstrap files into sample/src/e2e. Merchants read these samples as integration guidance, so E2E code belongs in one folder they can skip. CI runs all three. swift-build-samples chains test_samples onto the macOS runner that already provisions storefront config. android-test runs :app:testDebugUnitTest in the job that already builds the sample. rn-test adds a sample step without --coverage, so the coverage report stays scoped to the published module. Co-Authored-By: Claude Opus 5 (1M context) --- .env.example | 4 ++ .github/workflows/android-test.yml | 10 +++++ .github/workflows/ci.yml | 8 ++-- .github/workflows/rn-test.yml | 5 +++ ...s.yml => swift-build-and-test-samples.yml} | 8 ++-- .github/workflows/swift-update-linters.yml | 2 +- dev.yml | 20 ++++++++-- .../androiddemo/e2e/E2ETestIdsTest.kt | 11 ++++++ platforms/react-native/sample/src/App.tsx | 2 +- .../__tests__/cartBootstrap.test.ts | 0 .../src/{linking => e2e}/cartBootstrap.ts | 0 .../src/{hooks => e2e}/useE2ECartBootstrap.ts | 7 +--- .../E2E/E2ETestIdsTests.swift | 8 ++++ .../Samples/CheckoutKitSwiftDemo/project.yml | 32 +++++++++++++++- platforms/swift/Scripts/test_samples | 28 ++++++++++++++ scripts/setup_storefront_env | 18 +++++++++ scripts/test_setup_storefront_env | 37 +++++++++++++++++++ 17 files changed, 181 insertions(+), 19 deletions(-) rename .github/workflows/{swift-build-samples.yml => swift-build-and-test-samples.yml} (50%) create mode 100644 platforms/android/samples/CheckoutKitAndroidDemo/app/src/test/java/com/shopify/checkoutkit/androiddemo/e2e/E2ETestIdsTest.kt rename platforms/react-native/sample/src/{linking => e2e}/__tests__/cartBootstrap.test.ts (100%) rename platforms/react-native/sample/src/{linking => e2e}/cartBootstrap.ts (100%) rename platforms/react-native/sample/src/{hooks => e2e}/useE2ECartBootstrap.ts (92%) create mode 100644 platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemoTests/E2E/E2ETestIdsTests.swift create mode 100755 platforms/swift/Scripts/test_samples diff --git a/.env.example b/.env.example index 2674c44d4..c0f22f8bc 100644 --- a/.env.example +++ b/.env.example @@ -13,6 +13,10 @@ STOREFRONT_ACCESS_TOKEN=your-public-storefront-access-token # Optional Apple Pay merchant identifier used by accelerated checkout flows. STOREFRONT_MERCHANT_IDENTIFIER= +# Apple team that signs the Swift sample. Leave blank to keep the Shopify team. +# Set your own team id to build the sample on a device. +DEVELOPMENT_TEAM= + # Storefront API version API_VERSION=2026-04 diff --git a/.github/workflows/android-test.yml b/.github/workflows/android-test.yml index a8515775f..878980ab9 100644 --- a/.github/workflows/android-test.yml +++ b/.github/workflows/android-test.yml @@ -122,6 +122,16 @@ jobs: run: ./gradlew assembleDebug working-directory: platforms/android/samples/CheckoutKitAndroidDemo + - name: Upload sample test reports + if: failure() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: android-sample-test-reports + path: | + platforms/android/samples/CheckoutKitAndroidDemo/**/build/reports/tests/ + platforms/android/samples/CheckoutKitAndroidDemo/**/build/test-results/ + if-no-files-found: warn + lint: runs-on: ubuntu-latest timeout-minutes: 20 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75d7232bb..5b360a66f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: - 'Package.swift' - 'Package.resolved' - '.github/workflows/swift-test-package.yml' - - '.github/workflows/swift-build-samples.yml' + - '.github/workflows/swift-build-and-test-samples.yml' - '.github/workflows/swift-test-workflow.yml' - '.github/workflows/swift-lint.yml' - '.github/workflows/breaking-changes.yml' @@ -129,11 +129,11 @@ jobs: if: needs.changes.outputs.swift == 'true' uses: ./.github/workflows/swift-test-package.yml - swift-build-samples: + swift-build-and-test-samples: name: Swift needs: changes if: needs.changes.outputs.swift == 'true' - uses: ./.github/workflows/swift-build-samples.yml + uses: ./.github/workflows/swift-build-and-test-samples.yml swift-lint: name: Swift @@ -250,7 +250,7 @@ jobs: - changes - android-test - swift-test-package - - swift-build-samples + - swift-build-and-test-samples - swift-lint - swift-sample-package-paths - rn-test diff --git a/.github/workflows/rn-test.yml b/.github/workflows/rn-test.yml index 9f957b75d..f8848a566 100644 --- a/.github/workflows/rn-test.yml +++ b/.github/workflows/rn-test.yml @@ -36,3 +36,8 @@ jobs: coverage-summary-path: platforms/react-native/coverage/coverage-summary.json title: 'React Native — Coverage Report' create-new-comment: false + + # Runs without --coverage so the coverage report above stays scoped to the + # published module. + - name: Run sample tests + run: pnpm test --testPathPatterns="sample/src" diff --git a/.github/workflows/swift-build-samples.yml b/.github/workflows/swift-build-and-test-samples.yml similarity index 50% rename from .github/workflows/swift-build-samples.yml rename to .github/workflows/swift-build-and-test-samples.yml index 0821942c4..17042fa6d 100644 --- a/.github/workflows/swift-build-samples.yml +++ b/.github/workflows/swift-build-and-test-samples.yml @@ -1,4 +1,4 @@ -name: Swift — Build Sample Apps +name: Swift — Build & Test Sample Apps on: workflow_call: @@ -8,9 +8,9 @@ permissions: contents: read jobs: - build-samples: + build-and-test-samples: uses: ./.github/workflows/swift-test-workflow.yml with: - test-path: ./Scripts/build_samples - job-name: Build Sample Apps + test-path: ./Scripts/build_samples && ./Scripts/test_samples + job-name: Build & Test Sample Apps setup-storefront-env: true diff --git a/.github/workflows/swift-update-linters.yml b/.github/workflows/swift-update-linters.yml index c87e0caec..5238cd2f9 100644 --- a/.github/workflows/swift-update-linters.yml +++ b/.github/workflows/swift-update-linters.yml @@ -135,7 +135,7 @@ jobs: BODY+="1. **Close and reopen this PR** — this fires a new \`pull_request\` event from your user, which triggers all checks.\n" BODY+="2. **Trigger workflows via CLI:**\n" BODY+="\`\`\`bash\n" - BODY+="gh workflow run swift-build-samples.yml --ref auto/update-linters\n" + BODY+="gh workflow run swift-build-and-test-samples.yml --ref auto/update-linters\n" BODY+="gh workflow run swift-lint.yml --ref auto/update-linters\n" BODY+="gh workflow run swift-test-package.yml --ref auto/update-linters\n" BODY+="\`\`\`\n" diff --git a/dev.yml b/dev.yml index ed91bf30e..9cc230a2a 100644 --- a/dev.yml +++ b/dev.yml @@ -384,10 +384,24 @@ commands: ../Scripts/xcode_run build CheckoutKitSwiftDemo test: desc: | - `dev swift test` - Run all tests for the ShopifyCheckoutKit-Package. - `dev swift test ` - Run only the specified test class. + `dev swift test` - Run all tests for the ShopifyCheckoutKit-Package and the sample apps. + `dev swift test ` - Run only the specified package test class. + `dev swift test sample [test_class_name]` - Run only the sample app test targets. syntax: "[test_class_name]" - run: cd platforms/swift && ./Scripts/xcode_run test ShopifyCheckoutKit-Package "$1" + run: | + set -e + cd platforms/swift + if [ -n "${1:-}" ]; then + ./Scripts/xcode_run test ShopifyCheckoutKit-Package "$1" + else + ./Scripts/xcode_run test ShopifyCheckoutKit-Package + ./Scripts/test_samples + fi + subcommands: + sample: + desc: Run the sample app test targets + syntax: "[test_class_name]" + run: cd platforms/swift && ./Scripts/test_samples "${1:-}" api: desc: Validate or update the public Swift API baseline (platforms/swift/api/*.json) run: | diff --git a/platforms/android/samples/CheckoutKitAndroidDemo/app/src/test/java/com/shopify/checkoutkit/androiddemo/e2e/E2ETestIdsTest.kt b/platforms/android/samples/CheckoutKitAndroidDemo/app/src/test/java/com/shopify/checkoutkit/androiddemo/e2e/E2ETestIdsTest.kt new file mode 100644 index 000000000..a4961f7d9 --- /dev/null +++ b/platforms/android/samples/CheckoutKitAndroidDemo/app/src/test/java/com/shopify/checkoutkit/androiddemo/e2e/E2ETestIdsTest.kt @@ -0,0 +1,11 @@ +package com.shopify.checkoutkit.androiddemo.e2e + +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class E2ETestIdsTest { + @Test + fun `app ready marker matches the maestro flows`() { + assertThat(E2ETestIds.APP_READY).isEqualTo("checkout-kit-sample-ready") + } +} diff --git a/platforms/react-native/sample/src/App.tsx b/platforms/react-native/sample/src/App.tsx index f05730fbd..7088db8c7 100644 --- a/platforms/react-native/sample/src/App.tsx +++ b/platforms/react-native/sample/src/App.tsx @@ -50,7 +50,7 @@ import ErrorBoundary from './ErrorBoundary'; import env from 'react-native-config'; import {createDebugLogger} from './utils'; import {useShopifyEventHandlers} from './hooks/useCheckoutEventHandlers'; -import {useE2ECartBootstrap} from './hooks/useE2ECartBootstrap'; +import {useE2ECartBootstrap} from './e2e/useE2ECartBootstrap'; import {E2ETestIds} from './e2e/testIds'; const log = createDebugLogger('ENV'); diff --git a/platforms/react-native/sample/src/linking/__tests__/cartBootstrap.test.ts b/platforms/react-native/sample/src/e2e/__tests__/cartBootstrap.test.ts similarity index 100% rename from platforms/react-native/sample/src/linking/__tests__/cartBootstrap.test.ts rename to platforms/react-native/sample/src/e2e/__tests__/cartBootstrap.test.ts diff --git a/platforms/react-native/sample/src/linking/cartBootstrap.ts b/platforms/react-native/sample/src/e2e/cartBootstrap.ts similarity index 100% rename from platforms/react-native/sample/src/linking/cartBootstrap.ts rename to platforms/react-native/sample/src/e2e/cartBootstrap.ts diff --git a/platforms/react-native/sample/src/hooks/useE2ECartBootstrap.ts b/platforms/react-native/sample/src/e2e/useE2ECartBootstrap.ts similarity index 92% rename from platforms/react-native/sample/src/hooks/useE2ECartBootstrap.ts rename to platforms/react-native/sample/src/e2e/useE2ECartBootstrap.ts index 35132b745..e75eecd8c 100644 --- a/platforms/react-native/sample/src/hooks/useE2ECartBootstrap.ts +++ b/platforms/react-native/sample/src/e2e/useE2ECartBootstrap.ts @@ -1,11 +1,8 @@ import {useCallback} from 'react'; import {Alert} from 'react-native'; import {useCart} from '../context/Cart'; -import { - parseCartBootstrapLink, - type CartBootstrapLink, -} from '../linking/cartBootstrap'; -import useShopify from './useShopify'; +import useShopify from '../hooks/useShopify'; +import {parseCartBootstrapLink, type CartBootstrapLink} from './cartBootstrap'; type UseE2ECartBootstrapOptions = { onCartReady: () => void; diff --git a/platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemoTests/E2E/E2ETestIdsTests.swift b/platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemoTests/E2E/E2ETestIdsTests.swift new file mode 100644 index 000000000..4ddeb0562 --- /dev/null +++ b/platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemoTests/E2E/E2ETestIdsTests.swift @@ -0,0 +1,8 @@ +@testable import CheckoutKitSwiftDemo +import XCTest + +class E2ETestIdsTests: XCTestCase { + func testAppReadyMarkerMatchesTheMaestroFlows() { + XCTAssertEqual(E2ETestIds.appReady, "checkout-kit-sample-ready") + } +} diff --git a/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml b/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml index 8a5e97cb2..54193e7cf 100644 --- a/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml +++ b/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml @@ -19,10 +19,13 @@ schemes: build: targets: CheckoutKitSwiftDemo: all + CheckoutKitSwiftDemoTests: [test] run: config: Debug test: config: Debug + targets: + - CheckoutKitSwiftDemoTests profile: config: Release analyze: @@ -47,7 +50,7 @@ targets: settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.shopify.checkoutkit.swiftdemo - DEVELOPMENT_TEAM: A7XGC83MZE + DEVELOPMENT_TEAM: $(DEVELOPMENT_TEAM) SWIFT_VERSION: "6.0" SWIFT_STRICT_CONCURRENCY: complete SWIFT_TREAT_WARNINGS_AS_ERRORS: YES @@ -128,3 +131,30 @@ targets: com.apple.developer.associated-domains: - webcredentials:$(STOREFRONT_DOMAIN)?mode=developer - applinks:$(STOREFRONT_DOMAIN)?mode=developer + + CheckoutKitSwiftDemoTests: + type: bundle.unit-test + platform: iOS + sources: + - path: CheckoutKitSwiftDemoTests + dependencies: + - target: CheckoutKitSwiftDemo + configFiles: + Debug: Storefront.xcconfig + Release: Storefront.xcconfig + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: com.shopify.checkoutkit.swiftdemo.tests + DEVELOPMENT_TEAM: $(DEVELOPMENT_TEAM) + SWIFT_VERSION: "6.0" + SWIFT_STRICT_CONCURRENCY: complete + SWIFT_TREAT_WARNINGS_AS_ERRORS: YES + TEST_HOST: $(BUILT_PRODUCTS_DIR)/CheckoutKitSwiftDemo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/CheckoutKitSwiftDemo + BUNDLE_LOADER: $(TEST_HOST) + LD_RUNPATH_SEARCH_PATHS: + - $(inherited) + - "@executable_path/Frameworks" + - "@loader_path/Frameworks" + info: + path: CheckoutKitSwiftDemoTests/Info.plist + properties: {} diff --git a/platforms/swift/Scripts/test_samples b/platforms/swift/Scripts/test_samples new file mode 100755 index 000000000..8ad917cff --- /dev/null +++ b/platforms/swift/Scripts/test_samples @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +SAMPLES_DIR="$SCRIPT_DIR/../Samples" +TEST_FILTER="${1:-}" + +if ! "$REPO_ROOT/scripts/setup_storefront_env" --check; then + echo "Run dev up from the repo root to sync sample app storefront configuration." + exit 1 +fi + +"$SCRIPT_DIR/generate_xcode_projects" + +if [[ ! -f "$SAMPLES_DIR/CheckoutKitSwiftDemo/Storefront.xcconfig" ]]; then + echo "Missing Storefront.xcconfig for CheckoutKitSwiftDemo. Run dev up from the repo root." + exit 1 +fi + +if [[ -n "$TEST_FILTER" && "$TEST_FILTER" != */* ]]; then + TEST_FILTER="CheckoutKitSwiftDemoTests/$TEST_FILTER" +fi + +cd "$SAMPLES_DIR" + +"$SCRIPT_DIR/xcode_run" test CheckoutKitSwiftDemo "$TEST_FILTER" diff --git a/scripts/setup_storefront_env b/scripts/setup_storefront_env index f086f55a6..08ba8b772 100755 --- a/scripts/setup_storefront_env +++ b/scripts/setup_storefront_env @@ -13,6 +13,11 @@ REACT_NATIVE_ENV="${ROOT_DIR}/platforms/react-native/sample/.env" DEFAULT_API_VERSION="2026-04" DEFAULT_CUSTOMER_ACCOUNT_API_VERSION="2026-04" +# The Shopify team that signs the sample. A developer outside it sets DEVELOPMENT_TEAM in +# .env rather than editing project.yml, because that file is tracked and the edit would +# reach every other clone. +DEFAULT_DEVELOPMENT_TEAM="A7XGC83MZE" + usage() { cat <"$output" 2>&1 + + assert_output_is_sanitized "$output" + assert_contains "$xcconfig" "DEVELOPMENT_TEAM = A7XGC83MZE" + # .env has to carry the key as well, or the next normalizing rewrite drops the override. + assert_contains "$fixture/.env" "DEVELOPMENT_TEAM=A7XGC83MZE" + + awk ' + /^DEVELOPMENT_TEAM=/ { print "DEVELOPMENT_TEAM=SYNTHETIC9"; next } + { print } + ' "$fixture/.env" >"$fixture/.env.next" + mv "$fixture/.env.next" "$fixture/.env" + + "$fixture/scripts/setup_storefront_env" --skip-optional-prompts >"$output" 2>&1 + assert_output_is_sanitized "$output" + assert_contains "$xcconfig" "DEVELOPMENT_TEAM = SYNTHETIC9" + assert_contains "$fixture/.env" "DEVELOPMENT_TEAM=SYNTHETIC9" + + # The Accelerated sample still hardcodes the team in its own project.yml, so writing the + # key into its xcconfig would create a second source that nothing reads. + assert_not_contains \ + "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" \ + "DEVELOPMENT_TEAM" +} + test_migration_from_platform_config() { local fixture output android_env fixture="$(make_fixture)" @@ -277,6 +313,7 @@ test_required_values_only test_optional_sync_updates_blank_optional_values_after_required_setup test_normalizes_existing_root_env test_blank_customer_account_api_version_defaults +test_development_team_defaults_then_yields_to_env test_migration_from_platform_config echo "setup_storefront_env synthetic tests passed." From 2b8fadd404e84969a9bce387577085d0f1975c78 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Wed, 5 Aug 2026 19:20:58 +0100 Subject: [PATCH 2/2] test: widen two tight async waits in CheckoutWebViewTests Both waits were outliers against their own neighbours and failed on consecutive CI runs on slow macOS runners. testPreloadKeepAliveFailureInvalidatesCache polled to a 2s deadline and waited 2s, leaving no slack. The neighbouring expiry test already pairs a 2s deadline with a 3s wait. testWindowOpenRequestReturnsInvalidParamsForMalformedBody was the only sendResponse wait at 1.0s; every other one in the file uses 5.0s. Co-Authored-By: Claude Opus 5 (1M context) Assisted-By: devx/5b4b8d5b-690a-4389-841e-039723ade1da --- .env.example | 4 +- .github/workflows/android-test.yml | 10 --- .../swift-build-and-test-samples.yml | 2 +- .../project.yml | 2 +- .../swift/Scripts/build_and_test_samples | 31 +++++++++ .../CheckoutWebViewTests.swift | 4 +- scripts/setup_storefront_env | 18 ++--- scripts/test_setup_storefront_env | 67 ++++++++++++++----- 8 files changed, 96 insertions(+), 42 deletions(-) create mode 100755 platforms/swift/Scripts/build_and_test_samples diff --git a/.env.example b/.env.example index c0f22f8bc..33060cd54 100644 --- a/.env.example +++ b/.env.example @@ -13,8 +13,8 @@ STOREFRONT_ACCESS_TOKEN=your-public-storefront-access-token # Optional Apple Pay merchant identifier used by accelerated checkout flows. STOREFRONT_MERCHANT_IDENTIFIER= -# Apple team that signs the Swift sample. Leave blank to keep the Shopify team. -# Set your own team id to build the sample on a device. +# Apple team that signs the Swift samples. Set your own team id, or the Xcode build +# fails at signing. A blank value stays blank; setup applies no default team. DEVELOPMENT_TEAM= # Storefront API version diff --git a/.github/workflows/android-test.yml b/.github/workflows/android-test.yml index 878980ab9..a8515775f 100644 --- a/.github/workflows/android-test.yml +++ b/.github/workflows/android-test.yml @@ -122,16 +122,6 @@ jobs: run: ./gradlew assembleDebug working-directory: platforms/android/samples/CheckoutKitAndroidDemo - - name: Upload sample test reports - if: failure() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: android-sample-test-reports - path: | - platforms/android/samples/CheckoutKitAndroidDemo/**/build/reports/tests/ - platforms/android/samples/CheckoutKitAndroidDemo/**/build/test-results/ - if-no-files-found: warn - lint: runs-on: ubuntu-latest timeout-minutes: 20 diff --git a/.github/workflows/swift-build-and-test-samples.yml b/.github/workflows/swift-build-and-test-samples.yml index 17042fa6d..0cc601740 100644 --- a/.github/workflows/swift-build-and-test-samples.yml +++ b/.github/workflows/swift-build-and-test-samples.yml @@ -11,6 +11,6 @@ jobs: build-and-test-samples: uses: ./.github/workflows/swift-test-workflow.yml with: - test-path: ./Scripts/build_samples && ./Scripts/test_samples + test-path: ./Scripts/build_and_test_samples job-name: Build & Test Sample Apps setup-storefront-env: true diff --git a/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/project.yml b/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/project.yml index b266522b3..ab203735a 100644 --- a/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/project.yml +++ b/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/project.yml @@ -49,7 +49,7 @@ targets: settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.shopify.example.ShopifyAcceleratedCheckoutsApp - DEVELOPMENT_TEAM: A7XGC83MZE + DEVELOPMENT_TEAM: $(DEVELOPMENT_TEAM) SWIFT_VERSION: "6.0" TARGETED_DEVICE_FAMILY: "1,2" MARKETING_VERSION: "1.0.1" diff --git a/platforms/swift/Scripts/build_and_test_samples b/platforms/swift/Scripts/build_and_test_samples new file mode 100755 index 000000000..e2d29fcb4 --- /dev/null +++ b/platforms/swift/Scripts/build_and_test_samples @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +SAMPLES_DIR="$SCRIPT_DIR/../Samples" + +if ! "$REPO_ROOT/scripts/setup_storefront_env" --check; then + echo "Run dev up from the repo root to sync sample app storefront configuration." + exit 1 +fi + +"$SCRIPT_DIR/generate_xcode_projects" + +cd "$SAMPLES_DIR" + +run_app() { + local app="$1" + local action="$2" + + if [[ ! -f "$app/Storefront.xcconfig" ]]; then + echo "Missing Storefront.xcconfig for $app. Run dev up from the repo root." + exit 1 + fi + + "$SCRIPT_DIR/xcode_run" "$action" "$app" +} + +run_app CheckoutKitSwiftDemo "clean build test" +run_app ShopifyAcceleratedCheckoutsApp "clean build" diff --git a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift index 26294508d..272ce8456 100644 --- a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift +++ b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift @@ -421,7 +421,7 @@ class CheckoutWebViewTests: XCTestCase { pollForInvalidation() - wait(for: [invalidated], timeout: 2) + wait(for: [invalidated], timeout: 3) } func testInvalidateDetachesCachedPreloadedWebView() { @@ -864,7 +864,7 @@ class CheckoutWebViewTests: XCTestCase { view.userContentController(WKUserContentController(), didReceive: message) - await fulfillment(of: [responseSent], timeout: 1.0) + await fulfillment(of: [responseSent], timeout: 5.0) let response = try XCTUnwrap(MockCheckoutBridge.lastResponseBody) let parsed = try XCTUnwrap(try JSONSerialization.jsonObject(with: Data(response.utf8)) as? [String: Any]) XCTAssertEqual(parsed["id"] as? String, "r") diff --git a/scripts/setup_storefront_env b/scripts/setup_storefront_env index 08ba8b772..d0f72088a 100755 --- a/scripts/setup_storefront_env +++ b/scripts/setup_storefront_env @@ -13,11 +13,6 @@ REACT_NATIVE_ENV="${ROOT_DIR}/platforms/react-native/sample/.env" DEFAULT_API_VERSION="2026-04" DEFAULT_CUSTOMER_ACCOUNT_API_VERSION="2026-04" -# The Shopify team that signs the sample. A developer outside it sets DEVELOPMENT_TEAM in -# .env rather than editing project.yml, because that file is tracked and the edit would -# reach every other clone. -DEFAULT_DEVELOPMENT_TEAM="A7XGC83MZE" - usage() { cat <"$output" 2>&1 assert_output_is_sanitized "$output" - assert_contains "$xcconfig" "DEVELOPMENT_TEAM = A7XGC83MZE" + assert_contains "$demo_xcconfig" "DEVELOPMENT_TEAM =" + assert_not_contains "$demo_xcconfig" "DEVELOPMENT_TEAM = A7XGC83MZE" # .env has to carry the key as well, or the next normalizing rewrite drops the override. - assert_contains "$fixture/.env" "DEVELOPMENT_TEAM=A7XGC83MZE" + assert_contains "$fixture/.env" "DEVELOPMENT_TEAM=" awk ' /^DEVELOPMENT_TEAM=/ { print "DEVELOPMENT_TEAM=SYNTHETIC9"; next } @@ -271,14 +274,47 @@ test_development_team_defaults_then_yields_to_env() { "$fixture/scripts/setup_storefront_env" --skip-optional-prompts >"$output" 2>&1 assert_output_is_sanitized "$output" - assert_contains "$xcconfig" "DEVELOPMENT_TEAM = SYNTHETIC9" + assert_contains "$demo_xcconfig" "DEVELOPMENT_TEAM = SYNTHETIC9" + assert_contains "$accelerated_xcconfig" "DEVELOPMENT_TEAM = SYNTHETIC9" assert_contains "$fixture/.env" "DEVELOPMENT_TEAM=SYNTHETIC9" - # The Accelerated sample still hardcodes the team in its own project.yml, so writing the - # key into its xcconfig would create a second source that nothing reads. - assert_not_contains \ - "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" \ - "DEVELOPMENT_TEAM" + awk ' + /^DEVELOPMENT_TEAM=/ { print "DEVELOPMENT_TEAM="; next } + { print } + ' "$fixture/.env" >"$fixture/.env.next" + mv "$fixture/.env.next" "$fixture/.env" + + "$fixture/scripts/setup_storefront_env" --skip-optional-prompts >"$output" 2>&1 + assert_output_is_sanitized "$output" + assert_not_contains "$demo_xcconfig" "SYNTHETIC9" + assert_not_contains "$accelerated_xcconfig" "SYNTHETIC9" +} + +# A clone whose .env predates DEVELOPMENT_TEAM holds every other canonical key, so the +# normalizing rewrite has to notice the one absent key. Otherwise dev up leaves .env alone +# and the developer never sees the key they are meant to override. +test_development_team_is_added_to_an_existing_env() { + local fixture output accelerated_xcconfig + fixture="$(make_fixture)" + output="$fixture/output.log" + accelerated_xcconfig="$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" + + STOREFRONT_DOMAIN=synthetic-store.example.myshopify.com \ + STOREFRONT_ACCESS_TOKEN=synthetic-token \ + "$fixture/scripts/setup_storefront_env" --skip-optional-prompts >"$output" 2>&1 + + grep -v '^DEVELOPMENT_TEAM=' "$fixture/.env" >"$fixture/.env.next" + mv "$fixture/.env.next" "$fixture/.env" + + if "$fixture/scripts/setup_storefront_env" --check >"$output" 2>&1; then + fail "root .env without DEVELOPMENT_TEAM passed --check" + fi + assert_output_is_sanitized "$output" + + "$fixture/scripts/setup_storefront_env" --skip-optional-prompts >"$output" 2>&1 + assert_output_is_sanitized "$output" + assert_contains "$fixture/.env" "DEVELOPMENT_TEAM=" + assert_contains "$accelerated_xcconfig" "DEVELOPMENT_TEAM =" } test_migration_from_platform_config() { @@ -313,7 +349,8 @@ test_required_values_only test_optional_sync_updates_blank_optional_values_after_required_setup test_normalizes_existing_root_env test_blank_customer_account_api_version_defaults -test_development_team_defaults_then_yields_to_env +test_development_team_follows_env_and_clears +test_development_team_is_added_to_an_existing_env test_migration_from_platform_config echo "setup_storefront_env synthetic tests passed."