diff --git a/.env.example b/.env.example index 33060cd54..a909903d8 100644 --- a/.env.example +++ b/.env.example @@ -10,8 +10,10 @@ # Storefront details STOREFRONT_DOMAIN=your-store.myshopify.com STOREFRONT_ACCESS_TOKEN=your-public-storefront-access-token -# Optional Apple Pay merchant identifier used by accelerated checkout flows. -STOREFRONT_MERCHANT_IDENTIFIER= +# Optional Apple Pay merchant identifiers used by accelerated checkout flows. +# Will be read in sample apps as APPLE_PAY_MERCHANT_IDENTIFIER +REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER= +SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER= # 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. diff --git a/config/secrets/demo.ejson b/config/secrets/demo.ejson index d7cb44edd..1c9bc5375 100644 --- a/config/secrets/demo.ejson +++ b/config/secrets/demo.ejson @@ -18,6 +18,8 @@ "LAST_NAME": "EJ[1:COcqDoNiIoRpNVpn5RtY+/98SiWXneivqVxsvjS2j1M=:Y6D/bjRLXox1Ev2x1wzwYkCcnSzyRqQr:Jy1SP2wB1gcl3EejYjG+BN7qguQeyEM=]", "PROVINCE": "EJ[1:COcqDoNiIoRpNVpn5RtY+/98SiWXneivqVxsvjS2j1M=:0TOrvPZDSNScmprg0GXGTCll0xiNg+sl:Y5zUNb4NN+0nUWUC/J1D0jjR]", "ZIP": "EJ[1:COcqDoNiIoRpNVpn5RtY+/98SiWXneivqVxsvjS2j1M=:i2R2JMndnE4CNZyGFxRrHQb9XJoHvGSP:wdAactHwHtDOTAhjdJ+wR3T2LRQ6IkI=]", - "PHONE": "EJ[1:COcqDoNiIoRpNVpn5RtY+/98SiWXneivqVxsvjS2j1M=:03PvHIo8P/rTDTomdb8wS+PH651lcbWY:j1idH9SHYOeh9iocqGY/wE689kiBKoRpATLD]" + "PHONE": "EJ[1:COcqDoNiIoRpNVpn5RtY+/98SiWXneivqVxsvjS2j1M=:03PvHIo8P/rTDTomdb8wS+PH651lcbWY:j1idH9SHYOeh9iocqGY/wE689kiBKoRpATLD]", + "REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER": "EJ[1:bhiOcRbAtZO6Hx3yvpCxPekCoORmQ1SLbS6EzjpoYEc=:tlKW/3ULel0N4o/SNSZJyE2IQ/FNZBfj:PmjIjdGhazyKgikizSAgKapRApjF13mhnTiV9emAmDYVj6qwQEuWIVYTtdxUAyYOwWnyXshLfNUHrDp829R46A==]", + "SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER": "EJ[1:bhiOcRbAtZO6Hx3yvpCxPekCoORmQ1SLbS6EzjpoYEc=:qvUsEPq8EDTo9jo0SHAZODzj+PIQ52WT:Q1lUWz8YLQj7Um9twGTRlzb78c+LCgzPnsTEFW0CKlGxEGtm1yGXnB5+bzD6EWlxjVAMvZdLsGZG2A==]" } } diff --git a/platforms/react-native/sample/@types/env.d.ts b/platforms/react-native/sample/@types/env.d.ts index aa80478fd..9bccafdf8 100644 --- a/platforms/react-native/sample/@types/env.d.ts +++ b/platforms/react-native/sample/@types/env.d.ts @@ -3,7 +3,7 @@ declare module '@env' { export const STOREFRONT_ACCESS_TOKEN: string; export const API_VERSION: string | undefined; export const STOREFRONT_VERSION: string | undefined; - export const STOREFRONT_MERCHANT_IDENTIFIER: string | undefined; + export const APPLE_PAY_MERCHANT_IDENTIFIER: string | undefined; export const EMAIL: string; export const ADDRESS_1: string; diff --git a/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo.xcodeproj/project.pbxproj b/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo.xcodeproj/project.pbxproj index 67d5a6fd9..5998b5f14 100644 --- a/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo.xcodeproj/project.pbxproj +++ b/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 6AF2B3762B0BCA6600C6CE4F /* CheckoutKitReactNativeDemo-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CheckoutKitReactNativeDemo-Bridging-Header.h"; sourceTree = ""; }; 6AFAD2D12BA9DEF8001F9644 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = Localizable.xcstrings; path = CheckoutKitReactNativeDemo/Localizable.xcstrings; sourceTree = ""; }; 6AFC2CB62B0D5814003B5A63 /* libShopifyCheckoutKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libShopifyCheckoutKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 7A4F0E4A2E4B123400000001 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = CheckoutKitReactNativeDemo/LaunchScreen.storyboard; sourceTree = ""; }; 9E0AC43398437CA0E3D05DDF /* libPods-CheckoutKitReactNativeDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CheckoutKitReactNativeDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ED728EF8BB9B5E9BA9D50EBE /* Pods-CheckoutKitReactNativeDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CheckoutKitReactNativeDemo.debug.xcconfig"; path = "Target Support Files/Pods-CheckoutKitReactNativeDemo/Pods-CheckoutKitReactNativeDemo.debug.xcconfig"; sourceTree = ""; }; @@ -88,6 +89,7 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 7A4F0E4A2E4B123400000001 /* Config.xcconfig */, 6AB7C68F2AF197BE000DB11B /* Packages */, 13B07FAE1A68108700A75B9A /* CheckoutKitReactNativeDemo */, 832341AE1AAA6A7D00B99B32 /* Libraries */, @@ -456,6 +458,7 @@ }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 7A4F0E4A2E4B123400000001 /* Config.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CC = ""; @@ -539,6 +542,7 @@ }; 83CBBA211A601CBA00E9B192 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 7A4F0E4A2E4B123400000001 /* Config.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CC = ""; diff --git a/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo/CheckoutKitReactNativeDemo.entitlements b/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo/CheckoutKitReactNativeDemo.entitlements index 9d2a9244e..a92816a9d 100644 --- a/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo/CheckoutKitReactNativeDemo.entitlements +++ b/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo/CheckoutKitReactNativeDemo.entitlements @@ -9,7 +9,7 @@ com.apple.developer.in-app-payments - merchant.com.shopify.checkoutkit.reactnativedemo + $(APPLE_PAY_MERCHANT_IDENTIFIER) diff --git a/platforms/react-native/sample/ios/Config.xcconfig b/platforms/react-native/sample/ios/Config.xcconfig new file mode 100644 index 000000000..8cd6af16a --- /dev/null +++ b/platforms/react-native/sample/ios/Config.xcconfig @@ -0,0 +1,2 @@ +APPLE_PAY_MERCHANT_IDENTIFIER = +#include? "Storefront.xcconfig" diff --git a/platforms/react-native/sample/src/App.tsx b/platforms/react-native/sample/src/App.tsx index 7088db8c7..bf5fe84f6 100644 --- a/platforms/react-native/sample/src/App.tsx +++ b/platforms/react-native/sample/src/App.tsx @@ -66,8 +66,8 @@ log('STOREFRONT_DOMAIN:', configured(env.STOREFRONT_DOMAIN)); log('STOREFRONT_ACCESS_TOKEN:', configured(env.STOREFRONT_ACCESS_TOKEN)); log('API_VERSION:', configured(storefrontApiVersion)); log( - 'STOREFRONT_MERCHANT_IDENTIFIER:', - configured(env.STOREFRONT_MERCHANT_IDENTIFIER), + 'APPLE_PAY_MERCHANT_IDENTIFIER:', + configured(env.APPLE_PAY_MERCHANT_IDENTIFIER), ); log('EMAIL:', configured(env.EMAIL)); log('PHONE:', configured(env.PHONE)); @@ -399,7 +399,7 @@ function AppWithCheckoutKit({children}: PropsWithChildren) { ApplePayContactField.email, ApplePayContactField.phone, ], - merchantIdentifier: env.STOREFRONT_MERCHANT_IDENTIFIER!, + merchantIdentifier: env.APPLE_PAY_MERCHANT_IDENTIFIER!, }, }, }, diff --git a/platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemo/Sources/Lib/InfoDictionary.swift b/platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemo/Sources/Lib/InfoDictionary.swift index 23b542334..548a0e608 100644 --- a/platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemo/Sources/Lib/InfoDictionary.swift +++ b/platforms/swift/Samples/CheckoutKitSwiftDemo/CheckoutKitSwiftDemo/Sources/Lib/InfoDictionary.swift @@ -35,7 +35,7 @@ final class InfoDictionary: Sendable { let phone = infoPlist["Phone"] as? String, let domain = infoPlist["StorefrontDomain"] as? String, let accessToken = infoPlist["StorefrontAccessToken"] as? String, - let merchantIdentifier = infoPlist["StorefrontMerchantIdentifier"] as? String, + let merchantIdentifier = infoPlist["ApplePayMerchantIdentifier"] as? String, let version = infoPlist["CFBundleShortVersionString"] as? String, let buildNumber = infoPlist["CFBundleVersion"] as? String else { diff --git a/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml b/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml index 8a2b08ef9..e517f5b98 100644 --- a/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml +++ b/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml @@ -84,7 +84,7 @@ targets: info: path: CheckoutKitSwiftDemo/Info.plist properties: - StorefrontMerchantIdentifier: $(STOREFRONT_MERCHANT_IDENTIFIER) + ApplePayMerchantIdentifier: $(APPLE_PAY_MERCHANT_IDENTIFIER) StorefrontDomain: $(STOREFRONT_DOMAIN) StorefrontAccessToken: $(STOREFRONT_ACCESS_TOKEN) CustomerAccountApiClientId: $(CUSTOMER_ACCOUNT_API_CLIENT_ID) @@ -132,7 +132,7 @@ targets: path: CheckoutKitSwiftDemo/CheckoutKitSwiftDemo.entitlements properties: com.apple.developer.in-app-payments: - - merchant.com.shopify.checkoutkit.swiftdemo + - $(APPLE_PAY_MERCHANT_IDENTIFIER) com.apple.developer.associated-domains: - webcredentials:$(STOREFRONT_DOMAIN)?mode=developer - applinks:$(STOREFRONT_DOMAIN)?mode=developer diff --git a/scripts/setup_storefront_env b/scripts/setup_storefront_env index d0f72088a..0e9461a93 100755 --- a/scripts/setup_storefront_env +++ b/scripts/setup_storefront_env @@ -9,6 +9,7 @@ ANDROID_ENV="${ROOT_DIR}/platforms/android/samples/CheckoutKitAndroidDemo/.env" SWIFT_DEMO_XCCONFIG="${ROOT_DIR}/platforms/swift/Samples/CheckoutKitSwiftDemo/Storefront.xcconfig" SWIFT_ACCELERATED_XCCONFIG="${ROOT_DIR}/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" REACT_NATIVE_ENV="${ROOT_DIR}/platforms/react-native/sample/.env" +REACT_NATIVE_XCCONFIG="${ROOT_DIR}/platforms/react-native/sample/ios/Storefront.xcconfig" DEFAULT_API_VERSION="2026-04" DEFAULT_CUSTOMER_ACCOUNT_API_VERSION="2026-04" @@ -225,7 +226,8 @@ root_has_canonical_keys() { for key in \ STOREFRONT_DOMAIN \ STOREFRONT_ACCESS_TOKEN \ - STOREFRONT_MERCHANT_IDENTIFIER \ + REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER \ + SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER \ DEVELOPMENT_TEAM \ API_VERSION \ CUSTOMER_ACCOUNT_API_CLIENT_ID \ @@ -257,7 +259,8 @@ optional_values_need_prompt() { [[ "$prompt_optional_values" == "true" ]] && [[ -t 0 ]] && ( - [[ -z "$STOREFRONT_MERCHANT_IDENTIFIER_VALUE" ]] || + [[ -z "$REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" ]] || + [[ -z "$SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" ]] || [[ -z "$CUSTOMER_ACCOUNT_API_CLIENT_ID_VALUE" ]] || [[ -z "$CUSTOMER_ACCOUNT_API_SHOP_ID_VALUE" ]] ) @@ -267,10 +270,18 @@ fill_optional_values_from_environment() { local value local updated="false" - if [[ -z "$STOREFRONT_MERCHANT_IDENTIFIER_VALUE" ]]; then - value="$(env_fallback STOREFRONT_MERCHANT_IDENTIFIER)" + if [[ -z "$REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" ]]; then + value="$(env_fallback REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER)" if [[ -n "$value" ]] && ! is_placeholder_value "$value"; then - STOREFRONT_MERCHANT_IDENTIFIER_VALUE="$value" + REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE="$value" + updated="true" + fi + fi + + if [[ -z "$SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" ]]; then + value="$(env_fallback SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER)" + if [[ -n "$value" ]] && ! is_placeholder_value "$value"; then + SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE="$value" updated="true" fi fi @@ -418,10 +429,19 @@ load_values() { "$(read_env_value API_VERSION "$SWIFT_ACCELERATED_XCCONFIG")" \ "$DEFAULT_API_VERSION")" - STOREFRONT_MERCHANT_IDENTIFIER_VALUE="$(root_or_source_value STOREFRONT_MERCHANT_IDENTIFIER \ + REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE="$(root_or_source_value REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER \ + "$(env_fallback REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER)" \ + "$(read_env_value STOREFRONT_MERCHANT_IDENTIFIER "$ROOT_ENV")" \ "$(env_fallback STOREFRONT_MERCHANT_IDENTIFIER)" \ - "$(read_env_value STOREFRONT_MERCHANT_IDENTIFIER "$ANDROID_ENV")" \ + "$(read_env_value APPLE_PAY_MERCHANT_IDENTIFIER "$REACT_NATIVE_ENV")" \ "$(read_env_value STOREFRONT_MERCHANT_IDENTIFIER "$REACT_NATIVE_ENV")" \ + "$(read_env_value APPLE_PAY_MERCHANT_IDENTIFIER "$REACT_NATIVE_XCCONFIG")")" + + SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE="$(root_or_source_value SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER \ + "$(env_fallback SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER)" \ + "$(read_env_value STOREFRONT_MERCHANT_IDENTIFIER "$ROOT_ENV")" \ + "$(env_fallback STOREFRONT_MERCHANT_IDENTIFIER)" \ + "$(read_env_value APPLE_PAY_MERCHANT_IDENTIFIER "$SWIFT_DEMO_XCCONFIG")" \ "$(read_env_value STOREFRONT_MERCHANT_IDENTIFIER "$SWIFT_DEMO_XCCONFIG")")" CUSTOMER_ACCOUNT_API_CLIENT_ID_VALUE="$(root_or_source_value CUSTOMER_ACCOUNT_API_CLIENT_ID \ @@ -473,8 +493,12 @@ collect_missing_values() { STOREFRONT_ACCESS_TOKEN_VALUE="$(prompt_required "Storefront access token")" fi - if [[ "$prompt_optional_values" == "true" && -z "$STOREFRONT_MERCHANT_IDENTIFIER_VALUE" ]]; then - STOREFRONT_MERCHANT_IDENTIFIER_VALUE="$(prompt_optional "Apple Pay merchant identifier")" + if [[ "$prompt_optional_values" == "true" && -z "$REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" ]]; then + REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE="$(prompt_optional "React Native Apple Pay merchant identifier")" + fi + + if [[ "$prompt_optional_values" == "true" && -z "$SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" ]]; then + SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE="$(prompt_optional "Swift Apple Pay merchant identifier")" fi if [[ "$prompt_optional_values" == "true" && -z "$CUSTOMER_ACCOUNT_API_CLIENT_ID_VALUE" ]]; then @@ -509,8 +533,9 @@ generate_root_env() { EOF write_env_assignment STOREFRONT_DOMAIN "$STOREFRONT_DOMAIN_VALUE" write_env_assignment STOREFRONT_ACCESS_TOKEN "$STOREFRONT_ACCESS_TOKEN_VALUE" - echo "# Optional Apple Pay merchant identifier used by accelerated checkout flows." - write_env_assignment STOREFRONT_MERCHANT_IDENTIFIER "$STOREFRONT_MERCHANT_IDENTIFIER_VALUE" + echo "# Optional Apple Pay merchant identifiers used by accelerated checkout flows." + write_env_assignment REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER "$REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" + write_env_assignment SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER "$SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER_VALUE" cat <"$SWIFT_DEMO_XCCONFIG" generate_swift_accelerated_xcconfig >"$SWIFT_ACCELERATED_XCCONFIG" generate_react_native_env >"$REACT_NATIVE_ENV" + generate_react_native_xcconfig >"$REACT_NATIVE_XCCONFIG" echo "Synced sample app storefront configuration files." } @@ -754,6 +785,7 @@ check_generated_files() { check_generated_file "$SWIFT_DEMO_XCCONFIG" generate_swift_demo_xcconfig || failed="true" check_generated_file "$SWIFT_ACCELERATED_XCCONFIG" generate_swift_accelerated_xcconfig || failed="true" check_generated_file "$REACT_NATIVE_ENV" generate_react_native_env || failed="true" + check_generated_file "$REACT_NATIVE_XCCONFIG" generate_react_native_xcconfig || failed="true" if [[ "$failed" == "true" ]]; then exit 1 diff --git a/scripts/test_setup_storefront_env b/scripts/test_setup_storefront_env index 50ced5973..c7c16a2e7 100755 --- a/scripts/test_setup_storefront_env +++ b/scripts/test_setup_storefront_env @@ -32,7 +32,7 @@ make_fixture() { mkdir -p \ "$fixture/scripts" \ "$fixture/platforms/android/samples/CheckoutKitAndroidDemo" \ - "$fixture/platforms/react-native/sample" \ + "$fixture/platforms/react-native/sample/ios" \ "$fixture/platforms/swift/Samples/CheckoutKitSwiftDemo" \ "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp" @@ -50,14 +50,14 @@ assert_contains() { local path="$1" local pattern="$2" - grep -Fq "$pattern" "$path" || fail "expected generated file content was not found: $path: $pattern" + grep -Fq -- "$pattern" "$path" || fail "expected generated file content was not found: $path: $pattern" } assert_not_contains() { local path="$1" local pattern="$2" - if grep -Fq "$pattern" "$path"; then + if grep -Fq -- "$pattern" "$path"; then fail "unexpected generated file content was found" fi } @@ -70,6 +70,8 @@ assert_output_is_sanitized() { synthetic-store.example.myshopify.com \ synthetic-token \ synthetic-merchant \ + synthetic-react-native-merchant \ + synthetic-swift-merchant \ synthetic-client \ synthetic-shop \ migrated-store.example.myshopify.com \ @@ -82,6 +84,63 @@ assert_output_is_sanitized() { done } +test_merchant_identifier_propagates_to_sample_apps() { + local fixture output react_native_xcconfig swift_xcconfig + fixture="$(make_fixture)" + output="$fixture/output.log" + react_native_xcconfig="$fixture/platforms/react-native/sample/ios/Storefront.xcconfig" + swift_xcconfig="$fixture/platforms/swift/Samples/CheckoutKitSwiftDemo/Storefront.xcconfig" + + STOREFRONT_DOMAIN=synthetic-store.example.myshopify.com \ + STOREFRONT_ACCESS_TOKEN=synthetic-token \ + REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-react-native-merchant \ + SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-swift-merchant \ + "$fixture/scripts/setup_storefront_env" >"$output" 2>&1 + + assert_output_is_sanitized "$output" + assert_contains "$fixture/.env" \ + "REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-react-native-merchant" + assert_contains "$fixture/.env" \ + "SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-swift-merchant" + assert_contains "$fixture/platforms/react-native/sample/.env" \ + 'APPLE_PAY_MERCHANT_IDENTIFIER="synthetic-react-native-merchant"' + assert_contains "$react_native_xcconfig" \ + "APPLE_PAY_MERCHANT_IDENTIFIER = synthetic-react-native-merchant" + assert_contains "$swift_xcconfig" \ + "APPLE_PAY_MERCHANT_IDENTIFIER = synthetic-swift-merchant" +} + +test_sample_projects_read_generated_merchant_identifier() { + local demo_ejson react_native_app react_native_config react_native_entitlements react_native_project swift_project + demo_ejson="$REPO_ROOT/config/secrets/demo.ejson" + react_native_app="$REPO_ROOT/platforms/react-native/sample/src/App.tsx" + react_native_config="$REPO_ROOT/platforms/react-native/sample/ios/Config.xcconfig" + react_native_entitlements="$REPO_ROOT/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo/CheckoutKitReactNativeDemo.entitlements" + react_native_project="$REPO_ROOT/platforms/react-native/sample/ios/CheckoutKitReactNativeDemo.xcodeproj/project.pbxproj" + swift_project="$REPO_ROOT/platforms/swift/Samples/CheckoutKitSwiftDemo/project.yml" + + jq -e '.environment | has("REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER")' \ + "$demo_ejson" >/dev/null || fail "demo.ejson is missing the React Native Apple Pay merchant identifier" + jq -e '.environment | has("SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER")' \ + "$demo_ejson" >/dev/null || fail "demo.ejson is missing the Swift Apple Pay merchant identifier" + assert_contains "$react_native_app" \ + "merchantIdentifier: env.APPLE_PAY_MERCHANT_IDENTIFIER!" + assert_not_contains "$react_native_app" \ + "merchant.com.shopify.checkoutkit.reactnativedemo" + assert_contains "$react_native_entitlements" \ + '$(APPLE_PAY_MERCHANT_IDENTIFIER)' + assert_not_contains "$react_native_entitlements" \ + "merchant.com.shopify.checkoutkit.reactnativedemo" + assert_contains "$react_native_config" "APPLE_PAY_MERCHANT_IDENTIFIER =" + assert_contains "$react_native_config" '#include? "Storefront.xcconfig"' + assert_contains "$react_native_project" "Config.xcconfig" + assert_contains "$swift_project" \ + 'ApplePayMerchantIdentifier: $(APPLE_PAY_MERCHANT_IDENTIFIER)' + assert_contains "$swift_project" \ + '- $(APPLE_PAY_MERCHANT_IDENTIFIER)' + assert_not_contains "$swift_project" "STOREFRONT_MERCHANT_IDENTIFIER" +} + test_sync_and_check() { local fixture output fixture="$(make_fixture)" @@ -89,7 +148,8 @@ test_sync_and_check() { STOREFRONT_DOMAIN=synthetic-store.example.myshopify.com \ STOREFRONT_ACCESS_TOKEN=synthetic-token \ - STOREFRONT_MERCHANT_IDENTIFIER=synthetic-merchant \ + REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-react-native-merchant \ + SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-swift-merchant \ CUSTOMER_ACCOUNT_API_CLIENT_ID=synthetic-client \ CUSTOMER_ACCOUNT_API_SHOP_ID=synthetic-shop \ "$fixture/scripts/setup_storefront_env" >"$output" 2>&1 @@ -100,10 +160,10 @@ test_sync_and_check() { assert_file_exists "$fixture/platforms/react-native/sample/.env" assert_file_exists "$fixture/platforms/swift/Samples/CheckoutKitSwiftDemo/Storefront.xcconfig" assert_file_exists "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" - assert_not_contains "$fixture/platforms/android/samples/CheckoutKitAndroidDemo/.env" "STOREFRONT_MERCHANT_IDENTIFIER" + assert_not_contains "$fixture/platforms/android/samples/CheckoutKitAndroidDemo/.env" "APPLE_PAY_MERCHANT_IDENTIFIER" assert_not_contains "$fixture/platforms/react-native/sample/.env" "CUSTOMER_ACCOUNT_API_VERSION" assert_not_contains "$fixture/platforms/swift/Samples/CheckoutKitSwiftDemo/Storefront.xcconfig" "CUSTOMER_ACCOUNT_API_VERSION" - assert_not_contains "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" "STOREFRONT_MERCHANT_IDENTIFIER" + assert_not_contains "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" "APPLE_PAY_MERCHANT_IDENTIFIER" assert_not_contains "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" "CUSTOMER_ACCOUNT_API_CLIENT_ID" assert_not_contains "$fixture/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig" "EMAIL" @@ -145,7 +205,8 @@ test_required_values_only() { assert_contains "$fixture/platforms/android/samples/CheckoutKitAndroidDemo/.env" "STOREFRONT_DOMAIN=synthetic-store.example.myshopify.com" assert_contains "$fixture/platforms/react-native/sample/.env" "STOREFRONT_DOMAIN=\"synthetic-store.example.myshopify.com\"" assert_contains "$fixture/platforms/swift/Samples/CheckoutKitSwiftDemo/Storefront.xcconfig" "STOREFRONT_DOMAIN = synthetic-store.example.myshopify.com" - assert_contains "$fixture/.env" "STOREFRONT_MERCHANT_IDENTIFIER=" + assert_contains "$fixture/.env" "REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=" + assert_contains "$fixture/.env" "SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=" assert_contains "$fixture/.env" "CUSTOMER_ACCOUNT_API_CLIENT_ID=" assert_contains "$fixture/.env" "CUSTOMER_ACCOUNT_API_SHOP_ID=" assert_contains "$fixture/.env" "CUSTOMER_ACCOUNT_API_VERSION=2026-04" @@ -168,24 +229,52 @@ test_optional_sync_updates_blank_optional_values_after_required_setup() { "$fixture/scripts/setup_storefront_env" --skip-optional-prompts >"$output" 2>&1 assert_output_is_sanitized "$output" - assert_contains "$fixture/.env" "STOREFRONT_MERCHANT_IDENTIFIER=" + assert_contains "$fixture/.env" "REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=" + assert_contains "$fixture/.env" "SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=" assert_contains "$fixture/.env" "CUSTOMER_ACCOUNT_API_CLIENT_ID=" assert_contains "$fixture/.env" "CUSTOMER_ACCOUNT_API_SHOP_ID=" - STOREFRONT_MERCHANT_IDENTIFIER=synthetic-merchant \ + REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-react-native-merchant \ + SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-swift-merchant \ CUSTOMER_ACCOUNT_API_CLIENT_ID=synthetic-client \ CUSTOMER_ACCOUNT_API_SHOP_ID=synthetic-shop \ "$fixture/scripts/setup_storefront_env" >"$output" 2>&1 assert_output_is_sanitized "$output" - assert_contains "$fixture/.env" "STOREFRONT_MERCHANT_IDENTIFIER=synthetic-merchant" + assert_contains "$fixture/.env" "REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-react-native-merchant" + assert_contains "$fixture/.env" "SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-swift-merchant" assert_contains "$fixture/.env" "CUSTOMER_ACCOUNT_API_CLIENT_ID=synthetic-client" assert_contains "$fixture/.env" "CUSTOMER_ACCOUNT_API_SHOP_ID=synthetic-shop" - assert_contains "$fixture/platforms/react-native/sample/.env" "STOREFRONT_MERCHANT_IDENTIFIER=\"synthetic-merchant\"" + assert_contains "$fixture/platforms/react-native/sample/.env" "APPLE_PAY_MERCHANT_IDENTIFIER=\"synthetic-react-native-merchant\"" assert_contains "$fixture/platforms/swift/Samples/CheckoutKitSwiftDemo/Storefront.xcconfig" "CUSTOMER_ACCOUNT_API_CLIENT_ID = synthetic-client" assert_contains "$fixture/platforms/android/samples/CheckoutKitAndroidDemo/.env" "CUSTOMER_ACCOUNT_API_REDIRECT_URI=shop.synthetic-shop.app://callback" } +test_shared_merchant_identifier_migrates_to_app_specific_keys() { + local fixture output + fixture="$(make_fixture)" + output="$fixture/output.log" + + cat >"$fixture/.env" <<'EOF' +STOREFRONT_DOMAIN=synthetic-store.example.myshopify.com +STOREFRONT_ACCESS_TOKEN=synthetic-token +STOREFRONT_MERCHANT_IDENTIFIER=synthetic-merchant +EOF + + "$fixture/scripts/setup_storefront_env" --skip-optional-prompts >"$output" 2>&1 + assert_output_is_sanitized "$output" + + assert_not_contains "$fixture/.env" "STOREFRONT_MERCHANT_IDENTIFIER=" + assert_contains "$fixture/.env" \ + "REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-merchant" + assert_contains "$fixture/.env" \ + "SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER=synthetic-merchant" + assert_contains "$fixture/platforms/react-native/sample/.env" \ + 'APPLE_PAY_MERCHANT_IDENTIFIER="synthetic-merchant"' + assert_contains "$fixture/platforms/swift/Samples/CheckoutKitSwiftDemo/Storefront.xcconfig" \ + "APPLE_PAY_MERCHANT_IDENTIFIER = synthetic-merchant" +} + test_normalizes_existing_root_env() { local fixture output fixture="$(make_fixture)" @@ -219,7 +308,8 @@ test_blank_customer_account_api_version_defaults() { cat >"$fixture/.env" <<'EOF' STOREFRONT_DOMAIN=synthetic-store.example.myshopify.com STOREFRONT_ACCESS_TOKEN=synthetic-token -STOREFRONT_MERCHANT_IDENTIFIER= +REACT_NATIVE_APPLE_PAY_MERCHANT_IDENTIFIER= +SWIFT_APPLE_PAY_MERCHANT_IDENTIFIER= API_VERSION=2026-04 CUSTOMER_ACCOUNT_API_CLIENT_ID=synthetic-client CUSTOMER_ACCOUNT_API_SHOP_ID=synthetic-shop @@ -344,9 +434,12 @@ EOF assert_output_is_sanitized "$output" } +test_merchant_identifier_propagates_to_sample_apps +test_sample_projects_read_generated_merchant_identifier test_sync_and_check test_required_values_only test_optional_sync_updates_blank_optional_values_after_required_setup +test_shared_merchant_identifier_migrates_to_app_specific_keys test_normalizes_existing_root_env test_blank_customer_account_api_version_defaults test_development_team_follows_env_and_clears