diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 852c3e028..7fb9fd45c 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -5,6 +5,67 @@ All notable changes to this project will be documented in this file. #### 4.x Releases +## [4.3.8](https://github.com/checkout/frames-ios/releases/tag/4.3.8) + +Released on 2025-06-03 + +Updates: + +- Update minimum version to iOS 13+ +- Update Risk SDK from min version 3.0.2 +- Update PhoneNumberKit from min version 4.0+ +- Fixed issues + +## [4.3.7](https://github.com/checkout/frames-ios/releases/tag/4.3.7) + +Released on 2024-08-06 + +Updates: + +- Removing the need to await for Risk SDK completion + +## [4.3.6](https://github.com/checkout/frames-ios/releases/tag/4.3.6) + +Released on 2024-05-30 + +Updates: + +- Fixing a crash within the Risk SDK implementation. + +## [4.3.5](https://github.com/checkout/frames-ios/releases/tag/4.3.5) + +Released on 2024-05-01 + +Updates: + +- Fixing a crash within the Risk SDK implementation. + +## [Deprecated - 4.3.4](https://github.com/checkout/frames-ios/releases/tag/4.3.4) + +Released on 2024-04-17 + +Updates: + +- Small internal logging data structure alteration. No public or breaking changes. + + +## [Deprecated - 4.3.3](https://github.com/checkout/frames-ios/releases/tag/4.3.3) + +Released on 2024-04-04 + +Updates: + +- Included a Correlation ID enhancement in our logging. + + +## [4.3.2](https://github.com/checkout/frames-ios/releases/tag/4.3.2) + +Released on 2024-03-01 + +Updates: + +- Send risk data via Risk SDK for the opted-in customers. No public changes. + ## [4.3.1](https://github.com/checkout/frames-ios/releases/tag/4.3.1) Released on 2024-01-19 diff --git a/.github/workflows/check-pr.yml b/.github/workflows/check-pr.yml index 4d2426f1c..0b02b59cf 100644 --- a/.github/workflows/check-pr.yml +++ b/.github/workflows/check-pr.yml @@ -9,11 +9,11 @@ on: - 'release/*' env: - destination: "platform=iOS Simulator,name=iPhone 14 Pro,OS=latest" + destination: "platform=iOS Simulator,name=iPhone 17 Pro,OS=26.1" configuration: "Debug" noIndex: "COMPILER_INDEX_STORE_ENABLE=NO" noSigning: "CODE_SIGNING_ALLOWED=NO" - versionXcode: "14.3.1" + versionXcode: "26.2" concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -22,23 +22,23 @@ concurrency: jobs: lint: name: SwiftLint - runs-on: macos-latest + runs-on: macos-15-large steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Lint Edited Files run: bash .github/scripts/lintEditedFiles.sh checkout: name: Checkout Verification - runs-on: macos-13-xl + runs-on: macos-15-xlarge needs: lint steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Select Xcode run: | @@ -75,12 +75,12 @@ jobs: frames: name: Frames Verification - runs-on: macos-13-xl + runs-on: macos-15-xlarge needs: lint steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Select Xcode run: | @@ -117,16 +117,16 @@ jobs: run-ui-tests: name: Run UI Tests - runs-on: macos-12-xl + runs-on: macos-15-xlarge needs: lint steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Select Xcode run: | - sudo xcode-select -switch /Applications/Xcode_14.2.app + sudo xcode-select -switch /Applications/Xcode_26.2.app - name: Log xcodebuild Version run: | diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 56a4bcdec..d50b41169 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -19,10 +19,17 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +env: + destination: "platform=iOS Simulator,name=iPhone 17 Pro,OS=latest" + configuration: "Debug" + noIndex: "COMPILER_INDEX_STORE_ENABLE=NO" + noSigning: "CODE_SIGNING_ALLOWED=NO" + versionXcode: "26.2" + jobs: analyze: name: Analyze - runs-on: [ macos-latest ] + runs-on: [ macos-15-xlarge ] permissions: actions: read contents: read @@ -35,20 +42,48 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: submodules: recursive # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@bc02a25f6449997c5e9d5a368879b28f56ae19a1 with: languages: ${{ matrix.language }} queries: security-and-quality - - name: Build + - name: Select Xcode + run: | + sudo xcode-select -switch /Applications/Xcode_${versionXcode}.app + + - name: Log xcodebuild Version + run: | + xcodebuild -version + + + - name: Build Frames + run: | + xcodebuild -scheme Frames -destination "${destination}" "${noIndex}" "${noSigning}" | xcpretty + + - name: Build CheckoutTests + run: | + xcodebuild build -scheme CheckoutTests -destination "${destination}" "${noIndex}" "${noSigning}" | xcpretty + + - name: Build FramesTests + run: | + xcodebuild build -scheme FramesTests -destination "${destination}" "${noIndex}" "${noSigning}" | xcpretty + + - name: Build iOS Example Frame SPM + run: | + cd iOS\ Example\ Frame\ SPM + xcodebuild build -scheme iOS\ Example\ Frame -destination "${destination}" "${noIndex}" "${noSigning}" | xcpretty + + - name: Build UITest run: | - xcodebuild -scheme Frames -destination "platform=iOS Simulator,name=iPhone 14 Pro,OS=latest" + cd iOS\ Example\ Frame\ SPM + xcodebuild -scheme UITest -destination "${destination}" "${noIndex}" "${noSigning}" | xcpretty - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + # Perform analysis on the code + - name: Analyze code with CodeQL + uses: github/codeql-action/analyze@bc02a25f6449997c5e9d5a368879b28f56ae19a1 diff --git a/.github/workflows/deploy-github-pages.yml b/.github/workflows/deploy-github-pages.yml index e1512107f..2eb417894 100644 --- a/.github/workflows/deploy-github-pages.yml +++ b/.github/workflows/deploy-github-pages.yml @@ -27,16 +27,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Setup Pages - uses: actions/configure-pages@v3 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 + uses: actions/jekyll-build-pages@44a6e6beabd48582f863aeeb6cb2151cc1716697 with: source: ./.github/docs destination: ./_site - name: Upload artifact - uses: actions/upload-pages-artifact@v2 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # Deployment job deploy: @@ -48,4 +48,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e diff --git a/.github/workflows/generate-jazzy-docs.yml b/.github/workflows/generate-jazzy-docs.yml index 7f91f6cde..66cc6b1d5 100644 --- a/.github/workflows/generate-jazzy-docs.yml +++ b/.github/workflows/generate-jazzy-docs.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Setup Ruby uses: ruby/setup-ruby@5311f05890856149502132d25c4a24985a00d426 @@ -45,7 +45,7 @@ jobs: run: sh .github/scripts/buildDocs.sh - name: Upload Generated Jazzy Docs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: Jazzy Docs path: ".github/docs" diff --git a/.github/workflows/publish-Checkout.podspec.yml b/.github/workflows/publish-Checkout.podspec.yml index cbf58e609..506676303 100644 --- a/.github/workflows/publish-Checkout.podspec.yml +++ b/.github/workflows/publish-Checkout.podspec.yml @@ -5,13 +5,21 @@ on: workflow_dispatch jobs: publish: environment: CocoaPodsRelease - runs-on: macos-12-xl + runs-on: macos-15-xlarge steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + +# - name: Check current branch +# run: | +# if [[ "${GITHUB_REF#refs/heads/}" != "main" && "${GITHUB_REF#refs/heads/}" != release/* ]]; then +# echo "This workflow is expected to run on the main or release branch only." +# exit 1 +# fi - name: Publish Checkout.podspec run: | gem install cocoapods - pod trunk push Checkout.podspec --allow-warnings + pod trunk register mobilesdkteam@checkout.com + pod trunk push Checkout.podspec --allow-warnings --verbose env: COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} diff --git a/.github/workflows/publish-Frames.podspec.yml b/.github/workflows/publish-Frames.podspec.yml index ee398a9f0..3c555a6c6 100644 --- a/.github/workflows/publish-Frames.podspec.yml +++ b/.github/workflows/publish-Frames.podspec.yml @@ -5,13 +5,21 @@ on: workflow_dispatch jobs: publish: environment: CocoaPodsRelease - runs-on: macos-12-xl + runs-on: macos-15-xlarge steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + +# - name: Check current branch +# run: | +# if [[ "${GITHUB_REF#refs/heads/}" != "main" && "${GITHUB_REF#refs/heads/}" != release/* ]]; then +# echo "This workflow is expected to run on the main or release branch only." +# exit 1 +# fi - name: Publish Frames.podspec run: | gem install cocoapods - pod trunk push Frames.podspec --allow-warnings + pod trunk register mobilesdkteam@checkout.com + pod trunk push --synchronous Frames.podspec --allow-warnings --verbose env: COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} diff --git a/.github/workflows/run-regression-tests.yml b/.github/workflows/run-regression-tests.yml index 86cb7c4fa..fb55b84c8 100644 --- a/.github/workflows/run-regression-tests.yml +++ b/.github/workflows/run-regression-tests.yml @@ -1,28 +1,24 @@ name: Run Regression Tests on: - pull_request: - types: [ labeled ] - workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: run-regression-tests: - if: contains(github.event.pull_request.labels.*.name, 'Run Regression Tests') name: Run Regression Tests - runs-on: macos-12-xl + runs-on: macos-15-xlarge steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Select Xcode run: | - sudo xcode-select -switch /Applications/Xcode_14.2.app + sudo xcode-select -switch /Applications/Xcode_26.2.app - name: Log xcodebuild Version run: | @@ -30,7 +26,7 @@ jobs: - name: Run Regression Tests run: | - set -o pipefail && xcodebuild "test" "-project" "iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj" "-scheme" "Regression Tests" "-configuration" "Debug" "-destination" "platform=iOS Simulator,name=iPhone 14 Pro,OS=latest" | xcpretty + set -o pipefail && xcodebuild "test" "-project" "iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj" "-scheme" "Regression Tests" "-configuration" "Debug" "-destination" "platform=iOS Simulator,name=iPhone 17 Pro,OS=latest" | xcpretty # # Comment out below only when needed, to avoid overhead. @@ -38,14 +34,14 @@ jobs: # - name: Upload Artifacts # if: always() -# uses: actions/upload-artifact@v3 +# uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # with: # name: Test Results and Logs # path: "~/Library/Developer/Xcode/DerivedData/*/Logs/Test/" # - name: Upload Generated Screenshots # if: always() -# uses: actions/upload-artifact@v3 +# uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # with: # name: Test Results and Logs # path: "iOS\ Example\ Frame\ SPM/iOS\ Example\ Frame\ Regression\ Tests/__Snapshots__" diff --git a/.github/workflows/validate-for-app-store.yml b/.github/workflows/validate-for-app-store.yml index 88ec5b49e..cb9601d67 100644 --- a/.github/workflows/validate-for-app-store.yml +++ b/.github/workflows/validate-for-app-store.yml @@ -12,14 +12,14 @@ concurrency: jobs: validate_for_app_store: - if: contains(github.event.pull_request.labels.*.name, 'Validate For App Store') + if: (github.event_name == 'workflow_dispatch') || contains(github.event.pull_request.labels.*.name, 'Validate For App Store') name: Validate For App Store environment: AppStoreValidation - runs-on: macos-12-xl + runs-on: macos-15-xlarge steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Install the Apple certificate and provisioning profile env: BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} diff --git a/.gitignore b/.gitignore index 6bd835fe1..e9b2edc33 100644 --- a/.gitignore +++ b/.gitignore @@ -132,8 +132,7 @@ iOSInjectionProject/ ### SwiftPM ### Packages xcuserdata -Package.resolved -*/Package.resolved +## */Package.resolved IDEWorkspaceChecks.plist @@ -148,11 +147,14 @@ contents.xcworkspacedata /*.gcno ### Xcode Patch ### -*.xcodeproj/project.workspace/xcshareddata/swiftpm/Package.resolved +## *.xcodeproj/project.workspace/xcshareddata/swiftpm/Package.resolved *.xcodeproj/* !*.xcodeproj/project.pbxproj */IDEWorkspaceChecks.plist !*.xcworkspace/contents.xcworkspacedata **/xcshareddata/WorkspaceSettings.xcsettings -# End of https://www.toptal.com/developers/gitignore/api/macos,swift,xcode,carthage,cocoapods,swiftpm \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/macos,swift,xcode,carthage,cocoapods,swiftpm + +*.build +Package.resolved \ No newline at end of file diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/CheckoutTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/CheckoutTests.xcscheme index 0b5f0da47..e94d9d260 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/CheckoutTests.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/CheckoutTests.xcscheme @@ -8,7 +8,7 @@ @@ -53,6 +53,15 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/FramesTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/FramesTests.xcscheme index 7401b5223..52abafc31 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/FramesTests.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/FramesTests.xcscheme @@ -5,6 +5,22 @@ + + + + + + + + + + diff --git a/Checkout.podspec b/Checkout.podspec index 1dddd6899..2c235f0f7 100644 --- a/Checkout.podspec +++ b/Checkout.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Checkout' - s.version = '4.3.0' + s.version = '4.5.0' s.summary = 'Checkout SDK for iOS' s.description = <<-DESC @@ -13,12 +13,13 @@ Pod::Spec.new do |s| s.author = { "Checkout.com Integration" => "integration@checkout.com" } s.source = { :git => "https://github.com/checkout/frames-ios.git", :tag => s.version } - s.ios.deployment_target = '11.0' + s.ios.deployment_target = '13.0' s.swift_version = "5.7" s.source_files = 'Checkout/Source/**/*.swift' s.exclude_files = "Checkout/Samples/**" s.dependency 'CheckoutEventLoggerKit', '~> 1.2.4' + s.dependency 'Risk', '~> 6.0.1' end diff --git a/Checkout/Samples/CocoapodsSample/CheckoutCocoapodsSample.xcodeproj/project.pbxproj b/Checkout/Samples/CocoapodsSample/CheckoutCocoapodsSample.xcodeproj/project.pbxproj index 3d1fcde59..744d59e54 100644 --- a/Checkout/Samples/CocoapodsSample/CheckoutCocoapodsSample.xcodeproj/project.pbxproj +++ b/Checkout/Samples/CocoapodsSample/CheckoutCocoapodsSample.xcodeproj/project.pbxproj @@ -472,7 +472,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -527,7 +527,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -554,7 +554,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -586,7 +586,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -608,7 +608,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = E32XBQK4Q5; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -632,7 +632,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = E32XBQK4Q5; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/Checkout/Samples/CocoapodsSample/Podfile b/Checkout/Samples/CocoapodsSample/Podfile index 663560fad..656daec7b 100644 --- a/Checkout/Samples/CocoapodsSample/Podfile +++ b/Checkout/Samples/CocoapodsSample/Podfile @@ -1,10 +1,9 @@ -platform :ios, '12.0' +platform :ios, '13.0' install! 'cocoapods', :share_schemes_for_development_pods => true target 'CheckoutCocoapodsSample' do use_frameworks! # Pods for CheckoutSDKCocoapodsSample - pod 'Checkout', '4.2.1' - + pod 'Checkout', :path => '../../../' end diff --git a/Checkout/Samples/CocoapodsSample/Podfile.lock b/Checkout/Samples/CocoapodsSample/Podfile.lock index bd1a547cc..8d722a8c4 100644 --- a/Checkout/Samples/CocoapodsSample/Podfile.lock +++ b/Checkout/Samples/CocoapodsSample/Podfile.lock @@ -1,20 +1,40 @@ PODS: - - Checkout (4.2.0): + - Checkout (4.5.0): - CheckoutEventLoggerKit (~> 1.2.4) + - Risk (~> 6.0.1) - CheckoutEventLoggerKit (1.2.4) + - FingerprintJS (1.7.0): + - FingerprintJS/Core (= 1.7.0) + - FingerprintJS/Core (1.7.0): + - FingerprintJS/SystemControl + - FingerprintJS/SystemControl (1.7.0) + - FingerprintPro (2.17.2) + - Risk (6.0.1): + - CheckoutEventLoggerKit (~> 1.2.4) + - FingerprintJS (< 2.0.0, >= 1.7.0) + - FingerprintPro (< 3.0.0, >= 2.12.0) DEPENDENCIES: - - Checkout (~> 4.0) + - Checkout (from `../../../`) SPEC REPOS: trunk: - - Checkout - CheckoutEventLoggerKit + - FingerprintJS + - FingerprintPro + - Risk + +EXTERNAL SOURCES: + Checkout: + :path: "../../../" SPEC CHECKSUMS: - Checkout: 7015595d6318c822cd81c3d73bf780507f99f60c + Checkout: e209a32fdbc31fc2e30dc70baf54ca73aaa70f27 CheckoutEventLoggerKit: b780dec46295a34942780ea6230d0d5fd08aa05a + FingerprintJS: afb6185cf6951b60adc334f41d63e2e0a520bcf4 + FingerprintPro: 9a703bc7fb00413ffe5624bcbb07b62129f00ab6 + Risk: 9fc0f6688a284ab40d41b1c5ac8301b62c4dc53c -PODFILE CHECKSUM: 4ba1f8758ad74e15c9805de325a88bc4f977165e +PODFILE CHECKSUM: 36c08580c11dc09229142a4df18cbb3b7682087d -COCOAPODS: 1.12.1 +COCOAPODS: 1.17.0 diff --git a/Checkout/Samples/SPMSample/CheckoutSPMSample.xcodeproj/project.pbxproj b/Checkout/Samples/SPMSample/CheckoutSPMSample.xcodeproj/project.pbxproj index af3c43145..0da4cb5ef 100644 --- a/Checkout/Samples/SPMSample/CheckoutSPMSample.xcodeproj/project.pbxproj +++ b/Checkout/Samples/SPMSample/CheckoutSPMSample.xcodeproj/project.pbxproj @@ -511,8 +511,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/checkout/frames-ios"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.0.0; + kind = exactVersion; + version = 4.3.6; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/Checkout/Source/Logging/CheckoutLogEvent.swift b/Checkout/Source/Logging/CheckoutLogEvent.swift index ccb2313aa..01dae8118 100644 --- a/Checkout/Source/Logging/CheckoutLogEvent.swift +++ b/Checkout/Source/Logging/CheckoutLogEvent.swift @@ -18,6 +18,8 @@ enum CheckoutLogEvent: Equatable { case validateCVV case cvvRequested(SecurityCodeTokenRequestData) case cvvResponse(SecurityCodeTokenRequestData, TokenResponseData) + case riskSDKCompletion + case riskSDKTimeOut func event(date: Date) -> Event { Event( @@ -55,6 +57,10 @@ enum CheckoutLogEvent: Equatable { return "card_validator_expiry_integer" case .validateCVV: return "card_validator_cvv" + case .riskSDKCompletion: + return "risk_sdk_completion" + case .riskSDKTimeOut: + return "risk_sdk_time_out" } } @@ -66,9 +72,12 @@ enum CheckoutLogEvent: Equatable { .validateExpiryString, .validateExpiryInteger, .validateCVV, - .cvvRequested: + .cvvRequested, + .riskSDKCompletion, + .riskSDKTimeOut: return .info - case .tokenResponse(_, let tokenResponseData), .cvvResponse(_, let tokenResponseData): + case .tokenResponse(_, let tokenResponseData), + .cvvResponse(_, let tokenResponseData): return level(from: tokenResponseData.httpStatusCode) } } @@ -87,7 +96,9 @@ enum CheckoutLogEvent: Equatable { .validateCardNumber, .validateExpiryString, .validateExpiryInteger, - .validateCVV: + .validateCVV, + .riskSDKCompletion, + .riskSDKTimeOut: return [:] case let .tokenRequested(tokenRequestData): return [ diff --git a/Checkout/Source/Logging/LogManager.swift b/Checkout/Source/Logging/LogManager.swift index a87b43083..5c7e1bfb1 100644 --- a/Checkout/Source/Logging/LogManager.swift +++ b/Checkout/Source/Logging/LogManager.swift @@ -106,6 +106,13 @@ enum LogManager: LogManaging { } } + /// Synchronously waits for all previously enqueued log work to finish. + /// Uses `loggingQueue.sync {}` so it is safe to call from any thread except the logging queue's own thread. + /// For test use only — not part of the public API. + static func _drainLoggingQueueForTesting() { + loggingQueue.sync { } + } + private static func log(_ event: CheckoutLogEvent, date: Date) { let logEvent = event.event(date: date) diff --git a/Checkout/Source/Model/Environment.swift b/Checkout/Source/Model/Environment.swift index 924004707..971820b0b 100644 --- a/Checkout/Source/Model/Environment.swift +++ b/Checkout/Source/Model/Environment.swift @@ -8,7 +8,21 @@ import Foundation protocol BaseURLProviding { - var baseURL: URL { get } + var baseURL: URL? { get } +} + +private enum APIHost { + static let production = "api.checkout.com" + static let sandbox = "api.sandbox.checkout.com" + + static func prefixed(_ prefix: String, environment: Environment) -> String { + switch environment { + case .production: + return "\(prefix).\(production)" + case .sandbox: + return "\(prefix).\(sandbox)" + } + } } /// Environment Enum for Production and Sandbox end points. @@ -16,12 +30,30 @@ public enum Environment: String, BaseURLProviding { case production case sandbox - var baseURL: URL { + var baseURL: URL? { + let host: String switch self { case .production: - return URL(string: "https://api.checkout.com/") + host = APIHost.production case .sandbox: - return URL(string: "https://api.sandbox.checkout.com/") + host = APIHost.sandbox + } + return URL(string: "https://\(host)/") + } +} + +/// Provides a base URL for a given environment, optionally prefixed with a subdomain. +/// When `baseURLPrefix` is set (after trimming), URLs follow the pattern `{prefix}.api[.sandbox].checkout.com`. +struct EnvironmentURLProvider: BaseURLProviding { + let environment: Environment + let baseURLPrefix: String? + + var baseURL: URL? { + let trimmed = baseURLPrefix?.trimmingCharacters(in: .whitespacesAndNewlines) + guard let prefix = trimmed, !prefix.isEmpty else { + return environment.baseURL } + let host = APIHost.prefixed(prefix, environment: environment) + return URL(string: "https://\(host)/") } } diff --git a/Checkout/Source/Network/RequestFactory.swift b/Checkout/Source/Network/RequestFactory.swift index eead6c641..860337e70 100644 --- a/Checkout/Source/Network/RequestFactory.swift +++ b/Checkout/Source/Network/RequestFactory.swift @@ -74,7 +74,9 @@ final class RequestFactory: RequestProviding { } func url(baseURLProvider: BaseURLProviding) -> Result { - guard var urlComponents = URLComponents(url: baseURLProvider.baseURL, resolvingAgainstBaseURL: false) else { + guard let baseURL = baseURLProvider.baseURL, + var urlComponents = URLComponents(url:baseURL, + resolvingAgainstBaseURL: false) else { return .failure(.baseURLCouldNotBeConvertedToComponents) } diff --git a/Checkout/Source/Tokenisation/CheckoutAPIService.swift b/Checkout/Source/Tokenisation/CheckoutAPIService.swift index 10ac0fc00..eb1b4d141 100644 --- a/Checkout/Source/Tokenisation/CheckoutAPIService.swift +++ b/Checkout/Source/Tokenisation/CheckoutAPIService.swift @@ -1,6 +1,6 @@ // // CheckoutAPIService.swift -// +// // // Created by Harry Brown on 23/11/2021. // @@ -8,6 +8,11 @@ import Foundation import UIKit import CheckoutEventLoggerKit +#if canImport(RiskSDK) +import RiskSDK +#elseif canImport(Risk) +import Risk +#endif public protocol CheckoutAPIProtocol { func createToken(_ paymentSource: PaymentSource, completion: @escaping (Result) -> Void) @@ -15,19 +20,27 @@ public protocol CheckoutAPIProtocol { var correlationID: String { get } } +protocol RiskProtocol: AnyObject { + func configure(completion: @escaping (Result) -> Void) + func publishData (cardToken: String?, completion: @escaping (Result) -> Void) +} + +extension Risk: RiskProtocol {} + final public class CheckoutAPIService: CheckoutAPIProtocol { private let requestExecutor: RequestExecuting private let requestFactory: RequestProviding private let tokenRequestFactory: TokenRequestProviding private let tokenDetailsFactory: TokenDetailsProviding private let logManager: LogManaging.Type + private var riskSDK: RiskProtocol private let publicKey: String private let environment: BaseURLProviding /// Initializes a CheckoutAPIService object with public key and Environment. /// CheckoutAPIService holds the core tokenisation logic methods to tokenise a user’s card details - public convenience init(publicKey: String, environment: Environment) { + public convenience init(publicKey: String, environment: Environment, baseURLPrefix: String? = nil) { let snakeCaseJSONEncoder = JSONEncoder() let snakeCaseJSONDecoder = JSONDecoder() @@ -37,11 +50,20 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { let cardValidator = CardValidator(environment: environment) let networkManager = NetworkManager(decoder: snakeCaseJSONDecoder, session: .shared) - let requestFactory = RequestFactory(encoder: snakeCaseJSONEncoder, baseURLProvider: environment) + let baseURLProvider = EnvironmentURLProvider(environment: environment, baseURLPrefix: baseURLPrefix) + let requestFactory = RequestFactory(encoder: snakeCaseJSONEncoder, baseURLProvider: baseURLProvider) let tokenRequestFactory = TokenRequestFactory(cardValidator: cardValidator, decoder: snakeCaseJSONDecoder) let tokenDetailsFactory = TokenDetailsFactory() let logManager = LogManager.self - + + var riskEnvironment: RiskEnvironment + switch environment { + case .production: + riskEnvironment = .production + case .sandbox: + riskEnvironment = .sandbox + } + logManager.setup( environment: environment, logger: CheckoutEventLogger(productName: Constants.Product.name), @@ -49,6 +71,10 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { dateProvider: DateProvider(), anyCodable: AnyCodable() ) + + let framesOptions = FramesOptions(productIdentifier: Constants.Product.name, version: Constants.Product.version) + let riskConfig = RiskConfig(publicKey: publicKey, environment: riskEnvironment, framesOptions: framesOptions) + let riskSDK = Risk.init(config: riskConfig) self.init( publicKey: publicKey, @@ -57,7 +83,8 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { requestFactory: requestFactory, tokenRequestFactory: tokenRequestFactory, tokenDetailsFactory: tokenDetailsFactory, - logManager: logManager) + logManager: logManager, + riskSDK: riskSDK) } init( @@ -67,7 +94,8 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { requestFactory: RequestProviding, tokenRequestFactory: TokenRequestProviding, tokenDetailsFactory: TokenDetailsProviding, - logManager: LogManaging.Type + logManager: LogManaging.Type, + riskSDK: RiskProtocol ) { self.publicKey = publicKey self.environment = environment @@ -76,6 +104,7 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { self.tokenRequestFactory = tokenRequestFactory self.tokenDetailsFactory = tokenDetailsFactory self.logManager = logManager + self.riskSDK = riskSDK } /// The create token method tokenises the user’s card details. @@ -112,7 +141,7 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { tokenType: tokenRequest.type, publicKey: publicKey ))) - createToken(requestParameters: requestParameters, completion: completion) + createToken(requestParameters: requestParameters, paymentType: tokenRequest.type, completion: completion) case .failure(let error): switch error { case .baseURLCouldNotBeConvertedToComponents, .couldNotBuildURL: @@ -121,32 +150,91 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { } } - private func createToken(requestParameters: NetworkManager.RequestParameters, completion: @escaping (Result) -> Void) { + let timeoutInterval: TimeInterval = 5.0 + private let taskCompletionQueue = DispatchQueue(label: "taskCompletionQueue", qos: .userInitiated) + private var isTaskCompleted = false + + private func createToken(requestParameters: NetworkManager.RequestParameters, + paymentType: TokenRequest.TokenType, + completion: @escaping (Result) -> Void) { requestExecutor.execute( requestParameters, responseType: TokenResponse.self, responseErrorType: TokenisationError.ServerError.self - ) { [tokenDetailsFactory, logManager, logTokenResponse] tokenResponseResult, httpURLResponse in - logTokenResponse(tokenResponseResult, httpURLResponse) + ) { [weak self, tokenDetailsFactory, logManager, logTokenResponse] tokenResponseResult, httpURLResponse in + logTokenResponse(tokenResponseResult, paymentType, httpURLResponse) switch tokenResponseResult { case .response(let tokenResponse): let tokenDetails = tokenDetailsFactory.create(tokenResponse: tokenResponse) - completion(.success(tokenDetails)) + + guard let self else { + logManager.resetCorrelationID() + return + } + + self.callRiskSDK(tokenDetails: tokenDetails) { + completion(.success(tokenDetails)) + } + case .errorResponse(let errorResponse): completion(.failure(.serverError(errorResponse))) + logManager.resetCorrelationID() case .networkError(let networkError): completion(.failure(.networkError(networkError))) + logManager.resetCorrelationID() + } + } + } + + private func callRiskSDK(tokenDetails: TokenDetails, + completion: @escaping () -> Void) { + + /* Risk SDK calls can be finalised in 3 different ways + 1. When Risk SDK's configure(...) function completed successfully and publishData(...) completed successfully or not + 2. When Risk SDK's configure(...) function completed with failure + 3. When Risk SDK's configure(...) or publishData(...) functions hang and don't call their completion blocks. + In this case, we wait for `self.timeoutInterval` amount of time and call the completion block anyway. + + All these operations are done synchronously to avoid the completion closure getting called multiple times. + */ + + let finaliseRiskSDKCalls = { + self.taskCompletionQueue.sync { + if !self.isTaskCompleted { + self.isTaskCompleted = true + completion() + } } + } - logManager.resetCorrelationID() + DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + timeoutInterval) { + finaliseRiskSDKCalls() + self.logManager.queue(event: .riskSDKTimeOut) + } + + self.riskSDK.configure { [weak self] configurationResult in + guard let self else { return } + switch configurationResult { + case .failure: + finaliseRiskSDKCalls() + self.logManager.resetCorrelationID() + case .success(): + self.riskSDK.publishData(cardToken: tokenDetails.token) { _ in + self.logManager.queue(event: .riskSDKCompletion) + finaliseRiskSDKCalls() + self.logManager.resetCorrelationID() + } + } } } - private func logTokenResponse(tokenResponseResult: NetworkRequestResult, httpURLResponse: HTTPURLResponse?) { + private func logTokenResponse(tokenResponseResult: NetworkRequestResult, + paymentType: TokenRequest.TokenType, + httpURLResponse: HTTPURLResponse?) { switch tokenResponseResult { case .response(let tokenResponse): - let tokenRequestData = CheckoutLogEvent.TokenRequestData(tokenType: tokenResponse.type, publicKey: publicKey) + let tokenRequestData = CheckoutLogEvent.TokenRequestData(tokenType: paymentType, publicKey: publicKey) let tokenResponseData = CheckoutLogEvent.TokenResponseData( tokenID: tokenResponse.token, scheme: tokenResponse.scheme, @@ -156,7 +244,7 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { logManager.queue(event: .tokenResponse(tokenRequestData, tokenResponseData)) case .errorResponse(let errorResponse): - let tokenRequestData = CheckoutLogEvent.TokenRequestData(tokenType: nil, publicKey: publicKey) + let tokenRequestData = CheckoutLogEvent.TokenRequestData(tokenType: paymentType, publicKey: publicKey) let tokenResponseData = CheckoutLogEvent.TokenResponseData( tokenID: nil, scheme: nil, diff --git a/Checkout/Source/Validation/Constants.swift b/Checkout/Source/Validation/Constants.swift index a855affe9..825d2544f 100644 --- a/Checkout/Source/Validation/Constants.swift +++ b/Checkout/Source/Validation/Constants.swift @@ -25,7 +25,7 @@ public enum Constants { } enum Product { - static let version = "4.3.0" + static let version = "4.5.0" static let name = "checkout-ios-sdk" static let userAgent = "checkout-sdk-ios/\(version)" } diff --git a/CheckoutTests/Integration/CheckoutAPIServiceIntegrationTests.swift b/CheckoutTests/Integration/CheckoutAPIServiceIntegrationTests.swift index dbc820a6e..f03f3264d 100644 --- a/CheckoutTests/Integration/CheckoutAPIServiceIntegrationTests.swift +++ b/CheckoutTests/Integration/CheckoutAPIServiceIntegrationTests.swift @@ -61,38 +61,39 @@ final class CheckoutAPIServiceIntegrationTests: XCTestCase { } } - func test_createApplePayToken() { - let applePay = StubProvider.createApplePay() - - // details associated with default apple pay token - let expectedApplePayDetails = ApplePayDetails( - expiryDate: try! CardValidator(environment: .sandbox).validate(expiryMonth: 3, expiryYear: 24).get(), - bin: "537426", - last4: "7789" - ) - - let expectation = XCTestExpectation(description: "Waiting for token creation") - var tokenDetailsResult: Result? - - subject.createToken(.applePay(applePay)) { - tokenDetailsResult = $0 - expectation.fulfill() - } - - wait(for: [expectation], timeout: 35) - - guard let tokenDetailsResult = tokenDetailsResult else { - XCTFail("expected tokenDetailsResult") - return - } - - switch tokenDetailsResult { - case .success(let tokenDetails): - verifyApplePayToken(applePayDetails: expectedApplePayDetails, tokenDetails: tokenDetails) - case .failure(let tokenisationError): - XCTFail("expected success, received error, code: \(tokenisationError.code)") - } - } + #warning("Commented out until we get a new dummy Apple Pay token for stubbing purposes") +// func test_createApplePayToken() { +// let applePay = StubProvider.createApplePay() +// +// // details associated with default apple pay token +// let expectedApplePayDetails = ApplePayDetails( +// expiryDate: .init(month: 3, year: 2024), +// bin: "537426", +// last4: "7789" +// ) +// +// let expectation = XCTestExpectation(description: "Waiting for token creation") +// var tokenDetailsResult: Result? +// +// subject.createToken(.applePay(applePay)) { +// tokenDetailsResult = $0 +// expectation.fulfill() +// } +// +// wait(for: [expectation], timeout: 35) +// +// guard let tokenDetailsResult = tokenDetailsResult else { +// XCTFail("expected tokenDetailsResult") +// return +// } +// +// switch tokenDetailsResult { +// case .success(let tokenDetails): +// verifyApplePayToken(applePayDetails: expectedApplePayDetails, tokenDetails: tokenDetails) +// case .failure(let tokenisationError): +// XCTFail("expected success, received error, code: \(tokenisationError.code)") +// } +// } private func verifyCardToken( card: Card, diff --git a/CheckoutTests/Logging/LogManagerTests.swift b/CheckoutTests/Logging/LogManagerTests.swift index d43649795..3e8cf5459 100644 --- a/CheckoutTests/Logging/LogManagerTests.swift +++ b/CheckoutTests/Logging/LogManagerTests.swift @@ -21,9 +21,19 @@ final class LogManagerTests: XCTestCase { override func setUp() { super.setUp() - let logQueueFlushExpectation = XCTestExpectation() - subject.queue(event: .cardValidator) { logQueueFlushExpectation.fulfill() } - wait(for: [logQueueFlushExpectation], timeout: 5) + // Configure LogManager with stubs, then drain the serial logging queue synchronously. + // Using _drainLoggingQueueForTesting (loggingQueue.sync {}) avoids depending on the run loop + // to schedule .background QoS work, which is unreliable in CI. + subject.setup( + environment: .sandbox, + logger: stubCheckoutEventLogger, + uiDevice: stubDeviceInformationProvider, + dateProvider: stubDateProvider, + anyCodable: stubAnyCodable + ) + subject.queue(event: .cardValidator) { } + LogManager._drainLoggingQueueForTesting() + stubCheckoutEventLogger.resetLogCalledWith() } override func tearDown() { @@ -89,9 +99,6 @@ final class LogManagerTests: XCTestCase { } func test_setup_production() { - let correlationIDExpectation = XCTestExpectation() - stubCheckoutEventLogger.addMetadateExpectations.append(correlationIDExpectation) - subject.setup( environment: .production, logger: stubCheckoutEventLogger, @@ -99,6 +106,7 @@ final class LogManagerTests: XCTestCase { dateProvider: stubDateProvider, anyCodable: stubAnyCodable ) + LogManager._drainLoggingQueueForTesting() #if DEBUG XCTAssertEqual(stubCheckoutEventLogger.enableLocalProcessorCalledWith, .debug) @@ -142,8 +150,6 @@ final class LogManagerTests: XCTestCase { #endif #if !SWIFT_PACKAGE - wait(for: [correlationIDExpectation], timeout: 5) - XCTAssertEqual( stubCheckoutEventLogger.addMetadataCalledWith.first?.metadata, CheckoutEventLogger.MetadataKey.correlationID.rawValue @@ -154,8 +160,6 @@ final class LogManagerTests: XCTestCase { } func test_queue() { - let initialCorrelationIDExpectation = XCTestExpectation() - stubCheckoutEventLogger.addMetadateExpectations.append(initialCorrelationIDExpectation) subject.setup( environment: .sandbox, logger: stubCheckoutEventLogger, @@ -163,13 +167,10 @@ final class LogManagerTests: XCTestCase { dateProvider: stubDateProvider, anyCodable: stubAnyCodable ) - wait(for: [initialCorrelationIDExpectation], timeout: 3) + LogManager._drainLoggingQueueForTesting() - let expectation = XCTestExpectation(description: "Waiting for token creation") - stubCheckoutEventLogger.logExpectation = expectation subject.queue(event: .tokenRequested(CheckoutLogEvent.TokenRequestData(tokenType: .card, publicKey: "publicKey"))) - - wait(for: [expectation], timeout: 3) + LogManager._drainLoggingQueueForTesting() XCTAssertEqual( stubCheckoutEventLogger.logCalledWith, @@ -193,11 +194,8 @@ final class LogManagerTests: XCTestCase { anyCodable: stubAnyCodable ) - let expectation = XCTestExpectation(description: "Waiting for token creation") - stubCheckoutEventLogger.logExpectation = expectation subject.queue(event: .cardValidator) - - wait(for: [expectation], timeout: 10) + LogManager._drainLoggingQueueForTesting() XCTAssertEqual( stubCheckoutEventLogger.logCalledWith, @@ -211,16 +209,14 @@ final class LogManagerTests: XCTestCase { ] ) + // Queue cardValidator a second time — it should not log again (one-time event). subject.queue(event: .cardValidator) - // queueing another event here to flush the log queue - let expectation2 = XCTestExpectation(description: "Waiting for token creation") - stubCheckoutEventLogger.logExpectation = expectation2 + // Queue tokenRequested to ensure the second cardValidator has been processed. subject.queue(event: .tokenRequested(CheckoutLogEvent.TokenRequestData(tokenType: .card, publicKey: "publicKey"))) + LogManager._drainLoggingQueueForTesting() - wait(for: [expectation2], timeout: 10) - - // checking that card_validator only got logged once + // card_validator should appear only once. XCTAssertEqual( stubCheckoutEventLogger.logCalledWith, [ @@ -241,10 +237,8 @@ final class LogManagerTests: XCTestCase { } func test_resetCorrelationID() { - let initialCorrelationIDExpectation = XCTestExpectation() - let resetCorrelationIDExpectation = XCTestExpectation() - - stubCheckoutEventLogger.addMetadateExpectations.append(initialCorrelationIDExpectation) + // setUp's setup() call = add() #1. + // This test's setup() call = add() #2. subject.setup( environment: .sandbox, logger: stubCheckoutEventLogger, @@ -252,13 +246,13 @@ final class LogManagerTests: XCTestCase { dateProvider: stubDateProvider, anyCodable: stubAnyCodable ) + LogManager._drainLoggingQueueForTesting() - wait(for: [initialCorrelationIDExpectation], timeout: 3) - stubCheckoutEventLogger.addMetadateExpectations.append(resetCorrelationIDExpectation) + // Explicit reset = add() #3. subject.resetCorrelationID() - wait(for: [resetCorrelationIDExpectation], timeout: 3) + LogManager._drainLoggingQueueForTesting() - XCTAssertEqual(stubCheckoutEventLogger.addMetadataCalledWith.count, 2) + XCTAssertEqual(stubCheckoutEventLogger.addMetadataCalledWith.count, 3) XCTAssertTrue(stubCheckoutEventLogger.addMetadataCalledWith.allSatisfy { $0.metadata == CheckoutEventLogger.MetadataKey.correlationID.rawValue }) @@ -267,11 +261,11 @@ final class LogManagerTests: XCTestCase { // MARK: correlationID func test_correlationID() { + // setUp's setup() already set a new correlationID — capture it as the baseline. let initialCorrelationID = subject.correlationID XCTAssertNotNil(UUID(uuidString: initialCorrelationID), "failed to verify initialCorrelationID was a UUID") - let resetCorrelationIDExpectation = XCTestExpectation() - stubCheckoutEventLogger.addMetadateExpectations.append(resetCorrelationIDExpectation) + // A second setup() triggers resetCorrelationID() which generates a new UUID. subject.setup( environment: .sandbox, logger: stubCheckoutEventLogger, @@ -279,21 +273,16 @@ final class LogManagerTests: XCTestCase { dateProvider: stubDateProvider, anyCodable: stubAnyCodable ) - - wait(for: [resetCorrelationIDExpectation], timeout: 3) + LogManager._drainLoggingQueueForTesting() let newCorrelationID = subject.correlationID XCTAssertNotNil(UUID(uuidString: newCorrelationID), "failed to verify newCorrelationID was a UUID") - XCTAssertNotEqual(initialCorrelationID, newCorrelationID, "expected correlationIDs to change") } // MARK: registerTypes func test_registerTypes_TokenisationError_ServerError() { - let addCorrelationIDExpectation = XCTestExpectation() - stubCheckoutEventLogger.addMetadateExpectations.append(addCorrelationIDExpectation) - subject.setup( environment: .sandbox, logger: stubCheckoutEventLogger, @@ -301,6 +290,7 @@ final class LogManagerTests: XCTestCase { dateProvider: stubDateProvider, anyCodable: stubAnyCodable ) + LogManager._drainLoggingQueueForTesting() let serverError = TokenisationError.ServerError( requestID: "requestID", @@ -322,7 +312,5 @@ final class LogManagerTests: XCTestCase { let encodeCalledWith = stubSingleValueEncodingContainer.encodeCalledWith as? TokenisationError.ServerError XCTAssertEqual(encodeCalledWith, serverError) - - wait(for: [addCorrelationIDExpectation], timeout: 3) } } diff --git a/CheckoutTests/Model/EnvironmentTests.swift b/CheckoutTests/Model/EnvironmentTests.swift index ed9caad5f..59dd1f459 100644 --- a/CheckoutTests/Model/EnvironmentTests.swift +++ b/CheckoutTests/Model/EnvironmentTests.swift @@ -21,3 +21,67 @@ final class EnvironmentTests: XCTestCase { XCTAssertEqual(subject.baseURL, URL(string: "https://api.sandbox.checkout.com/")) } } + +final class EnvironmentURLProviderTests: XCTestCase { + + // MARK: - No prefix (falls back to default environment URLs) + + func test_baseURL_production_noPrefix() { + let subject = EnvironmentURLProvider(environment: .production, baseURLPrefix: nil) + XCTAssertEqual(subject.baseURL, URL(string: "https://api.checkout.com/")) + } + + func test_baseURL_sandbox_noPrefix() { + let subject = EnvironmentURLProvider(environment: .sandbox, baseURLPrefix: nil) + XCTAssertEqual(subject.baseURL, URL(string: "https://api.sandbox.checkout.com/")) + } + + func test_baseURL_production_emptyPrefix_fallsBackToDefault() { + let subject = EnvironmentURLProvider(environment: .production, baseURLPrefix: "") + XCTAssertEqual(subject.baseURL, URL(string: "https://api.checkout.com/")) + } + + func test_baseURL_sandbox_emptyPrefix_fallsBackToDefault() { + let subject = EnvironmentURLProvider(environment: .sandbox, baseURLPrefix: "") + XCTAssertEqual(subject.baseURL, URL(string: "https://api.sandbox.checkout.com/")) + } + + // MARK: - With prefix + + func test_baseURL_production_withPrefix() { + let subject = EnvironmentURLProvider(environment: .production, baseURLPrefix: "msdd") + XCTAssertEqual(subject.baseURL, URL(string: "https://msdd.api.checkout.com/")) + } + + func test_baseURL_sandbox_withPrefix() { + let subject = EnvironmentURLProvider(environment: .sandbox, baseURLPrefix: "msdd") + XCTAssertEqual(subject.baseURL, URL(string: "https://msdd.api.sandbox.checkout.com/")) + } + + func test_baseURL_production_withDifferentPrefix() { + let subject = EnvironmentURLProvider(environment: .production, baseURLPrefix: "custom-subdomain") + XCTAssertEqual(subject.baseURL, URL(string: "https://custom-subdomain.api.checkout.com/")) + } + + func test_baseURL_sandbox_withDifferentPrefix() { + let subject = EnvironmentURLProvider(environment: .sandbox, baseURLPrefix: "custom-subdomain") + XCTAssertEqual(subject.baseURL, URL(string: "https://custom-subdomain.api.sandbox.checkout.com/")) + } + + // MARK: - Trimmed prefix + + func test_baseURL_production_trimmedPrefix() { + let subject = EnvironmentURLProvider(environment: .production, baseURLPrefix: " msdd ") + XCTAssertEqual(subject.baseURL, URL(string: "https://msdd.api.checkout.com/")) + } + + func test_baseURL_sandbox_trimmedPrefix() { + let subject = EnvironmentURLProvider(environment: .sandbox, baseURLPrefix: "\tmsdd\n") + XCTAssertEqual(subject.baseURL, URL(string: "https://msdd.api.sandbox.checkout.com/")) + } + + func test_baseURL_production_whitespaceOnlyPrefix_fallsBackToDefault() { + let subject = EnvironmentURLProvider(environment: .production, baseURLPrefix: " ") + XCTAssertEqual(subject.baseURL, URL(string: "https://api.checkout.com/")) + } +} diff --git a/CheckoutTests/Stubs/StubBaseURLProvider.swift b/CheckoutTests/Stubs/StubBaseURLProvider.swift index 45ae0f905..e47229940 100644 --- a/CheckoutTests/Stubs/StubBaseURLProvider.swift +++ b/CheckoutTests/Stubs/StubBaseURLProvider.swift @@ -10,10 +10,10 @@ import Foundation // swiftlint:disable force_unwrapping final class StubBaseURLProvider: BaseURLProviding { - var baseURLToReturn = URL(string: "https://www.checkout.com/")! + var baseURLToReturn: URL? = URL(string: "https://www.checkout.com/")! private(set) var baseURLCalled = false - var baseURL: URL { + var baseURL: URL? { baseURLCalled = true return baseURLToReturn } diff --git a/CheckoutTests/Stubs/StubCheckoutEventLogger.swift b/CheckoutTests/Stubs/StubCheckoutEventLogger.swift index b439fe92d..dbc843b36 100644 --- a/CheckoutTests/Stubs/StubCheckoutEventLogger.swift +++ b/CheckoutTests/Stubs/StubCheckoutEventLogger.swift @@ -11,6 +11,12 @@ import XCTest class StubCheckoutEventLogger: CheckoutEventLogging { private(set) var logCalledWith: [Event] = [] var logExpectation: XCTestExpectation? + + /// Reset accumulated log events so tests can assert on a clean slate. Call after flushing the queue in setUp. + func resetLogCalledWith() { + logCalledWith = [] + } + func log(event: Event) { logCalledWith.append(event) logExpectation?.fulfill() diff --git a/CheckoutTests/Stubs/StubRisk.swift b/CheckoutTests/Stubs/StubRisk.swift new file mode 100644 index 000000000..38058a017 --- /dev/null +++ b/CheckoutTests/Stubs/StubRisk.swift @@ -0,0 +1,41 @@ +// +// StubRisk.swift +// +// +// Created by Precious Ossai on 20/02/2024. +// + +import Foundation +#if canImport(RiskSDK) +@testable import RiskSDK +#elseif canImport(Risk) +@testable import Risk +#endif +@testable import Checkout + +// swiftlint:disable large_tuple +class StubRisk: RiskProtocol { + + var configureCalledCount = 0 + var publishDataCalledCount = 0 + + // If set to false, Risk SDK will hang and not call the completion block for that specific function. + // It will mimic the behaviour of a bug we have. We need to call Frames's completion block after the defined timeout period in that case. + var shouldConfigureFunctionCallCompletion: Bool = true + var shouldPublishFunctionCallCompletion: Bool = true + + func configure(completion: @escaping (Result) -> Void) { + configureCalledCount += 1 + if shouldConfigureFunctionCallCompletion { + completion(.success(())) + } + } + + func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { + publishDataCalledCount += 1 + if shouldPublishFunctionCallCompletion { + completion(.success(PublishRiskData(deviceSessionId: "dsid_testDeviceSessionId"))) + } + } +} + diff --git a/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift b/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift index 076c28d47..a33ec53d8 100644 --- a/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift +++ b/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift @@ -24,6 +24,7 @@ final class CheckoutAPIServiceTests: XCTestCase { private var stubRequestFactory: StubRequestFactory! = StubRequestFactory() private var stubTokenRequestFactory: StubTokenRequestFactory! = StubTokenRequestFactory() private var stubTokenDetailsFactory: StubTokenDetailsFactory! = StubTokenDetailsFactory() + private var stubRisk: StubRisk! = .init() override func setUp() { @@ -36,7 +37,8 @@ final class CheckoutAPIServiceTests: XCTestCase { requestFactory: stubRequestFactory, tokenRequestFactory: stubTokenRequestFactory, tokenDetailsFactory: stubTokenDetailsFactory, - logManager: StubLogManager.self + logManager: StubLogManager.self, + riskSDK: stubRisk ) } @@ -49,6 +51,7 @@ final class CheckoutAPIServiceTests: XCTestCase { stubTokenRequestFactory = nil stubSecurityCodeRequestExecutor = nil stubTokenDetailsFactory = nil + stubRisk = nil super.tearDown() } @@ -85,11 +88,13 @@ final class CheckoutAPIServiceTests: XCTestCase { XCTAssertEqual(stubTokenDetailsFactory.createCalledWith, tokenResponse) - XCTAssertEqual(StubLogManager.queueCalledWith.last, .tokenResponse( + XCTAssertEqual(StubLogManager.queueCalledWith.dropLast().last, .tokenResponse( .init(tokenType: .card, publicKey: "publicKey"), .init(tokenID: "token", scheme: "visa", httpStatusCode: 200, serverError: nil) )) + XCTAssertEqual(stubRisk.configureCalledCount, 1) + XCTAssertEqual(stubRisk.publishDataCalledCount, 1) XCTAssertEqual(result, .success(tokenDetails)) } @@ -119,7 +124,7 @@ final class CheckoutAPIServiceTests: XCTestCase { XCTAssertEqual(result, .failure(.couldNotBuildURLForRequest)) } - func test_createToken_failure_serverError() { + func test_createToken_failure_card_payment_serverError() { let card = StubProvider.createCard() let tokenRequest = StubProvider.createTokenRequest() let requestParameters = StubProvider.createRequestParameters() @@ -143,7 +148,7 @@ final class CheckoutAPIServiceTests: XCTestCase { stubRequestExecutor.executeCalledWithCompletion?(.errorResponse(serverError), HTTPURLResponse()) XCTAssertEqual(StubLogManager.queueCalledWith.last, .tokenResponse( - .init(tokenType: nil, publicKey: "publicKey"), + .init(tokenType: .card, publicKey: "publicKey"), .init( tokenID: nil, scheme: nil, @@ -213,7 +218,8 @@ extension CheckoutAPIServiceTests { requestFactory: stubRequestFactory, tokenRequestFactory: stubTokenRequestFactory, tokenDetailsFactory: stubTokenDetailsFactory, - logManager: StubLogManager.self + logManager: StubLogManager.self, + riskSDK: stubRisk ) } @@ -348,3 +354,67 @@ extension CheckoutAPIServiceTests { } } } + +// Risk SDK Timeout Recovery Tests +extension CheckoutAPIServiceTests { + func testWhenRiskSDKCallsCompletionThenFramesReturnsSuccess() { + let card = StubProvider.createCard() + let tokenRequest = StubProvider.createTokenRequest() + let requestParameters = StubProvider.createRequestParameters() + let tokenResponse = StubProvider.createTokenResponse() + let tokenDetails = StubProvider.createTokenDetails() + + stubTokenRequestFactory.createToReturn = .success(tokenRequest) + stubRequestFactory.createToReturn = .success(requestParameters) + stubTokenDetailsFactory.createToReturn = tokenDetails + + var result: Result? + subject.createToken(.card(card)) { result = $0 } + stubRequestExecutor.executeCalledWithCompletion?(.response(tokenResponse), HTTPURLResponse()) + + XCTAssertEqual(stubRisk.configureCalledCount, 1) + XCTAssertEqual(stubRisk.publishDataCalledCount, 1) + XCTAssertEqual(result, .success(tokenDetails)) + } + + func testWhenRiskSDKConfigureHangsThenFramesSDKCancelsWaitingRiskSDKAndCallsCompletionBlockAnywayAfterTimeout() { + stubRisk.shouldConfigureFunctionCallCompletion = false // Configure function will hang forever before it calls its completion closure + verifyRiskSDKTimeoutRecovery(timeoutAddition: 1, expectedConfigureCallCount: 1, expectedPublishDataCallCount: 0) + } + + func testWhenRiskSDKPublishHangsThenFramesSDKCancelsWaitingRiskSDKAndCallsCompletionBlockAnywayAfterTimeout() { + stubRisk.shouldPublishFunctionCallCompletion = false // Publish data function will hang forever before it calls its completion closure + verifyRiskSDKTimeoutRecovery(timeoutAddition: 1, expectedConfigureCallCount: 1, expectedPublishDataCallCount: 1) + } + + func verifyRiskSDKTimeoutRecovery(timeoutAddition: Double, + expectedConfigureCallCount: Int, + expectedPublishDataCallCount: Int, + file: StaticString = #file, + line: UInt = #line) { + let card = StubProvider.createCard() + let tokenRequest = StubProvider.createTokenRequest() + let tokenResponse = StubProvider.createTokenResponse() + let requestParameters = StubProvider.createRequestParameters() + let tokenDetails = StubProvider.createTokenDetails() + + stubTokenRequestFactory.createToReturn = .success(tokenRequest) + stubRequestFactory.createToReturn = .success(requestParameters) + stubTokenDetailsFactory.createToReturn = tokenDetails + + let expectation = self.expectation(description: "Frames will time out awaiting Risk SDK result") + + var _: Result? + subject.createToken(.card(card)) { + + XCTAssertEqual(self.stubRisk.configureCalledCount, expectedConfigureCallCount, file: file, line: line) + XCTAssertEqual(self.stubRisk.publishDataCalledCount, expectedPublishDataCallCount, file: file, line: line) + XCTAssertEqual($0, .success(tokenDetails), file: file, line: line) + + expectation.fulfill() + } + stubRequestExecutor.executeCalledWithCompletion?(.response(tokenResponse), HTTPURLResponse()) + + waitForExpectations(timeout: subject.timeoutInterval + timeoutAddition) + } +} diff --git a/CheckoutTests/Validation/CardValidatorTests.swift b/CheckoutTests/Validation/CardValidatorTests.swift index e7a31eef0..3fcfb131e 100644 --- a/CheckoutTests/Validation/CardValidatorTests.swift +++ b/CheckoutTests/Validation/CardValidatorTests.swift @@ -161,12 +161,12 @@ extension CardValidatorTests { test_validate( expiryMonth: "11", - expiryYear: "2021", - expectedResult: .success(ExpiryDate(month: 11, year: 2021))) + expiryYear: "2030", + expectedResult: .success(ExpiryDate(month: 11, year: 2030))) let components = stubCalendar.dateFromComponentsCalledWith XCTAssertEqual(components?.month, 11) - XCTAssertEqual(components?.year, 2021) + XCTAssertEqual(components?.year, 2030) } func test_validate_expiryMonthYearString_providedMontInThePast_SameYear_returnsCorrectError() { diff --git a/Frames.podspec b/Frames.podspec index 5dbc218db..02966507c 100644 --- a/Frames.podspec +++ b/Frames.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Frames" - s.version = "4.3.1" + s.version = "4.5.0" s.summary = "Checkout API Client, Payment Form UI and Utilities in Swift" s.description = <<-DESC Checkout API Client and Payment Form Utilities in Swift. @@ -10,7 +10,7 @@ Pod::Spec.new do |s| s.swift_version = "5.0" s.license = "MIT" s.author = { "Checkout.com Integration" => "integration@checkout.com" } - s.platform = :ios, "12.0" + s.platform = :ios, "13.0" s.source = { :git => "https://github.com/checkout/frames-ios.git", :tag => s.version } s.source_files = 'Source/**/*.swift' @@ -19,8 +19,8 @@ Pod::Spec.new do |s| "Frames" => 'Source/Resources/**' } - s.dependency 'PhoneNumberKit' + s.dependency 'PhoneNumberKit', '~> 4.0' s.dependency 'CheckoutEventLoggerKit', '~> 1.2.4' - s.dependency 'Checkout', '4.3.0' + s.dependency 'Checkout', '4.5.0' end diff --git a/Package.swift b/Package.swift index ece677b60..9e6a9955d 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ let package = Package( defaultLocalization: "en", platforms: [ .macOS(.v10_12), - .iOS(.v12) + .iOS(.v13) ], products: [ .library( @@ -17,7 +17,10 @@ let package = Package( dependencies: [ .package( url: "https://github.com/marmelroy/PhoneNumberKit.git", - exact: "3.5.9"), + from: "4.0.0"), + .package( + url: "https://github.com/checkout/checkout-risk-sdk-ios.git", + from: "6.0.1"), .package( url: "https://github.com/checkout/checkout-event-logger-ios-framework.git", from: "1.2.4" @@ -29,6 +32,7 @@ let package = Package( dependencies: [ .product(name: "CheckoutEventLoggerKit", package: "checkout-event-logger-ios-framework"), + .product(name: "Risk", package: "checkout-risk-sdk-ios"), "PhoneNumberKit", "Checkout" ], @@ -43,6 +47,7 @@ let package = Package( dependencies: [ .product(name: "CheckoutEventLoggerKit", package: "checkout-event-logger-ios-framework"), + .product(name: "Risk", package: "checkout-risk-sdk-ios"), ], path: "Checkout/Source" ), diff --git a/README.md b/README.md index a3ebf577b..131deaf54 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ## Requirements -- iOS 12.0+ +- iOS 13.0+ - Xcode 12.4+ - Swift 5.3+ @@ -21,8 +21,6 @@ Frames for iOS tokenises consumer data for use within [Checkout.com](https://www.checkout.com)'s payment infrastructure. We abstract away the complexity of taking payments, building payment UIs, and handling sensitive data. -- [Demo projects](#Demo-projects): _We've created projects showcasing the range of functionality available in our SDKs while testing each distribution method offered_ - - [Integration](https://github.com/checkout/frames-ios/blob/main/.github/partial-readmes/Integration.md): _a guide for consuming our SDK in your iOS app_ - [Get started](https://github.com/checkout/frames-ios/blob/main/.github/partial-readmes/GetStarted.md): _Start testing what you can achieve by presenting inside your Applications UI_ @@ -35,8 +33,6 @@ Frames for iOS tokenises consumer data for use within [Checkout.com](https://www - [Migrating](https://github.com/checkout/frames-ios/blob/main/.github/partial-readmes/Migration.md): _If you have used 3.5.x version (or lower) before_ -- [License](#License) - More integration information can be found in the [Checkout Docs](https://docs.checkout.com/integrate/sdks/ios-sdk). @@ -60,6 +56,6 @@ Find our CHANGELOG.md [here](https://github.com/checkout/frames-ios/blob/main/.g Find our guide to start contributing [here](https://github.com/checkout/frames-ios/blob/main/.github/CONTRIBUTING.md). -## License +## Licence -Frames iOS is released under the MIT license. [See LICENSE](https://github.com/checkout/frames-ios/blob/main/LICENSE) for details. +Frames iOS is released under the MIT licence. [See LICENSE](https://github.com/checkout/frames-ios/blob/main/LICENSE) for details. diff --git a/Source/Core/CheckoutAPIService.swift b/Source/Core/CheckoutAPIService.swift index c7558433c..44472c0d5 100644 --- a/Source/Core/CheckoutAPIService.swift +++ b/Source/Core/CheckoutAPIService.swift @@ -12,7 +12,7 @@ import CheckoutEventLoggerKit protocol CheckoutAPIProtocol { var cardValidator: CardValidating { get } var logger: FramesEventLogging { get } - init(publicKey: String, environment: Environment) + init(publicKey: String, environment: Environment, baseURLPrefix: String?) func createToken(_ paymentSource: PaymentSource, completion: @escaping (Result) -> Void) func createSecurityCodeToken(securityCode: String, completion: @escaping (Result) -> Void) } @@ -23,8 +23,8 @@ public final class CheckoutAPIService: CheckoutAPIProtocol { let logger: FramesEventLogging private let checkoutAPIService: Checkout.CheckoutAPIProtocol - public init(publicKey: String, environment: Environment) { - let checkoutAPIService = Checkout.CheckoutAPIService(publicKey: publicKey, environment: environment.checkoutEnvironment) + public init(publicKey: String, environment: Environment, baseURLPrefix: String? = nil) { + let checkoutAPIService = Checkout.CheckoutAPIService(publicKey: publicKey, environment: environment.checkoutEnvironment, baseURLPrefix: baseURLPrefix) let cardValidator = CardValidator(environment: environment.checkoutEnvironment) let logger = FramesEventLogger(environment: environment, correlationID: checkoutAPIService.correlationID) diff --git a/Source/Core/Constants/Constants.swift b/Source/Core/Constants/Constants.swift index 4c1b00052..3e8ce72a3 100644 --- a/Source/Core/Constants/Constants.swift +++ b/Source/Core/Constants/Constants.swift @@ -8,7 +8,7 @@ enum Constants { static let productName = "frames-ios-sdk" - static let version = "4.3.1" + static let version = "4.5.0" static let userAgent = "checkout-sdk-frames-ios/\(version)" enum Logging { diff --git a/Source/Resources/PrivacyInfo.xcprivacy b/Source/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..8804494c8 --- /dev/null +++ b/Source/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,59 @@ + + + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + Device Model + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + SDK Version + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeDeviceID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + SDK Lifecyle Events + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyTracking + + + diff --git a/Source/UI/PaymentForm/Factory/PaymentFormFactory.swift b/Source/UI/PaymentForm/Factory/PaymentFormFactory.swift index c8856fc57..d92d2eee9 100644 --- a/Source/UI/PaymentForm/Factory/PaymentFormFactory.swift +++ b/Source/UI/PaymentForm/Factory/PaymentFormFactory.swift @@ -9,7 +9,8 @@ public enum PaymentFormFactory { let logger = FramesEventLogger(environment: configuration.environment, correlationID: UUID().uuidString) let cardValidator = CardValidator(environment: configuration.environment.checkoutEnvironment) let checkoutAPIService = CheckoutAPIService(publicKey: configuration.serviceAPIKey, - environment: configuration.environment) + environment: configuration.environment, + baseURLPrefix: configuration.baseURLPrefix) var viewModel = DefaultPaymentViewModel(checkoutAPIService: checkoutAPIService, cardValidator: cardValidator, logger: logger, diff --git a/Source/UI/PaymentForm/Model/PaymentFormConfiguration.swift b/Source/UI/PaymentForm/Model/PaymentFormConfiguration.swift index 1a739476d..e7810a9ca 100644 --- a/Source/UI/PaymentForm/Model/PaymentFormConfiguration.swift +++ b/Source/UI/PaymentForm/Model/PaymentFormConfiguration.swift @@ -13,6 +13,7 @@ public struct PaymentFormConfiguration { let environment: Environment let supportedSchemes: [Card.Scheme] let billingFormData: BillingForm? + let baseURLPrefix: String? /** Create a configuration for the Payment form @@ -22,14 +23,17 @@ public struct PaymentFormConfiguration { - environment: Enum describing the environment the SDK is running in - supportedSchemes: Card schemes supported for receiving payments. Accurate declaration of supported schemes will improve customer experience - billingFormData: Pre filled Billing form information to be included and help reduce user input if known + - baseURLPrefix: Optional subdomain prefix for the API base URL (e.g. "msdd" produces "msdd.api.checkout.com") */ public init(apiKey: String, environment: Environment, supportedSchemes: [CardScheme], - billingFormData: BillingForm?) { + billingFormData: BillingForm?, + baseURLPrefix: String? = nil) { self.serviceAPIKey = apiKey self.environment = environment self.supportedSchemes = supportedSchemes.compactMap { $0.mapToCheckoutCardScheme() } self.billingFormData = billingFormData + self.baseURLPrefix = baseURLPrefix } } diff --git a/Source/UI/PaymentForm/ViewModel/DefaultPaymentViewModel.swift b/Source/UI/PaymentForm/ViewModel/DefaultPaymentViewModel.swift index c93a48195..d5f3352d9 100644 --- a/Source/UI/PaymentForm/ViewModel/DefaultPaymentViewModel.swift +++ b/Source/UI/PaymentForm/ViewModel/DefaultPaymentViewModel.swift @@ -182,7 +182,9 @@ extension DefaultPaymentViewModel: PaymentViewControllerDelegate { checkoutAPIService.createToken(.card(card)) { [weak self] result in self?.logTokenResult(result) self?.isLoading = false - self?.cardTokenRequested?(result) + DispatchQueue.main.async { [weak self] in + self?.cardTokenRequested?(result) + } } } diff --git a/Source/UI/SecurityCodeComponent/SecurityCodeComponent.swift b/Source/UI/SecurityCodeComponent/SecurityCodeComponent.swift index d19878f66..1481ef0b8 100644 --- a/Source/UI/SecurityCodeComponent/SecurityCodeComponent.swift +++ b/Source/UI/SecurityCodeComponent/SecurityCodeComponent.swift @@ -48,7 +48,8 @@ extension SecurityCodeComponent { cardValidator = CardValidator(environment: configuration.environment.checkoutEnvironment) checkoutAPIService = CheckoutAPIService(publicKey: configuration.apiKey, - environment: configuration.environment) + environment: configuration.environment, + baseURLPrefix: configuration.baseURLPrefix) let viewModel = SecurityCodeViewModel(cardValidator: cardValidator) if let initialCardScheme = configuration.cardScheme { diff --git a/Source/UI/SecurityCodeComponent/SecurityCodeComponentConfiguration.swift b/Source/UI/SecurityCodeComponent/SecurityCodeComponentConfiguration.swift index ab401ec55..639b96b75 100644 --- a/Source/UI/SecurityCodeComponent/SecurityCodeComponentConfiguration.swift +++ b/Source/UI/SecurityCodeComponent/SecurityCodeComponentConfiguration.swift @@ -17,7 +17,9 @@ import UIKit - If provided, card scheme's validation rules apply (e.g. VISA = 3 digits, American Express = 4 digits etc.) - If not provided, security code is treated as valid for 3 and 4 digits - style: Security Code Component wraps a text field in a secure way. - To style the inner properties like font, textColor etc, you must alter the style. + To style the inner properties like font, textColor etc, you must alter the style. + - baseURLPrefix: Optional subdomain prefix for the API base URL (e.g. "msdd" produces "msdd.api.checkout.com"). + Whitespace is trimmed; empty or nil uses the default host. */ public struct SecurityCodeComponentConfiguration { @@ -25,14 +27,17 @@ public struct SecurityCodeComponentConfiguration { let environment: Environment public var style: SecurityCodeComponentStyle public var cardScheme: Card.Scheme? + let baseURLPrefix: String? public init(apiKey: String, environment: Environment, style: SecurityCodeComponentStyle? = nil, - cardScheme: Card.Scheme? = nil) { + cardScheme: Card.Scheme? = nil, + baseURLPrefix: String? = nil) { self.apiKey = apiKey self.environment = environment self.cardScheme = cardScheme + self.baseURLPrefix = baseURLPrefix if let style = style { self.style = style diff --git a/Source/UI/Validator/PhoneNumberValidator.swift b/Source/UI/Validator/PhoneNumberValidator.swift index 6eb28c191..1a5c412b2 100644 --- a/Source/UI/Validator/PhoneNumberValidator.swift +++ b/Source/UI/Validator/PhoneNumberValidator.swift @@ -4,9 +4,9 @@ import Checkout class PhoneNumberValidator: Validator { - var countryCode: String = PhoneNumberKit.defaultRegionCode() + var countryCode: String = PhoneNumberUtility.defaultRegionCode() private let validator = PhoneValidator() - private let phoneKit = PhoneNumberKit() + private let phoneKit = PhoneNumberUtility() private let validCharacterSet: CharacterSet = { var validInputs = "-+() " (0...9).forEach { validInputs.append("\($0)") } diff --git a/Tests/Mocks/StubCheckoutAPIService.swift b/Tests/Mocks/StubCheckoutAPIService.swift index fc736d28b..966c67cd7 100644 --- a/Tests/Mocks/StubCheckoutAPIService.swift +++ b/Tests/Mocks/StubCheckoutAPIService.swift @@ -27,7 +27,7 @@ final class StubCheckoutAPIService: Frames.CheckoutAPIProtocol { private(set) var cardValidatorCalled = false private(set) var loggerCalled = false - convenience init(publicKey: String, environment: Frames.Environment) { + convenience init(publicKey: String, environment: Frames.Environment, baseURLPrefix: String? = nil) { self.init() } diff --git a/Tests/UI/CountrySelection/CountrySelectionViewControllerTests.swift b/Tests/UI/CountrySelection/CountrySelectionViewControllerTests.swift index 913f1e8b0..4d24910c0 100644 --- a/Tests/UI/CountrySelection/CountrySelectionViewControllerTests.swift +++ b/Tests/UI/CountrySelection/CountrySelectionViewControllerTests.swift @@ -15,7 +15,7 @@ class MockDelegate: CountrySelectionViewControllerDelegate { class CountrySelectionViewControllerTests: XCTestCase { var countrySelectionViewController = CountrySelectionViewController() - let numberOfCountries = 256 + let numberOfCountries = 257 override func setUp() { super.setUp() diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/ExpiryDateEdgeCaseTests.swift b/iOS Example Frame SPM/iOS Example Frame Regression Tests/ExpiryDateEdgeCaseTests.swift index 91a550e06..6a6e6c92e 100644 --- a/iOS Example Frame SPM/iOS Example Frame Regression Tests/ExpiryDateEdgeCaseTests.swift +++ b/iOS Example Frame SPM/iOS Example Frame Regression Tests/ExpiryDateEdgeCaseTests.swift @@ -22,7 +22,8 @@ final class ExpiryDateEdgeCaseTests: XCTestCase { } let previousMonthDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())! - let previousMonth = String(Calendar.current.component(.month, from: previousMonthDate)) + var previousMonth = String(Calendar.current.component(.month, from: previousMonthDate)) + previousMonth = previousMonth.count == 1 ? "0" + previousMonth : previousMonth let currentYear = String(Calendar.current.component(.year, from: Date())).suffix(2) let expiryTextField = app.otherElements[AccessibilityIdentifiers.PaymentForm.cardExpiry] diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.1.png index ddec0de76..20d758188 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.10.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.10.png index 3a050fbad..04a537456 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.10.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.10.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.11.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.11.png index 150518a58..bd948c26a 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.11.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.11.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.2.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.2.png index 6a96fc63b..d5d292e7c 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.2.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.2.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.3.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.3.png index 4d2f09afc..2c54dfa59 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.3.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.3.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.4.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.4.png index e997e4240..475968f85 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.4.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.4.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.5.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.5.png index 9b94aa1e8..9a45c4793 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.5.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.5.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.6.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.6.png index 9e8e5d368..3b599331e 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.6.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.6.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.7.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.7.png index ae63aaac5..57c0be278 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.7.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.7.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.8.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.8.png index bb4945832..a2370290e 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.8.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.8.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.9.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.9.png index 1697456b0..3e45a350f 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.9.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.9.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.1.png index 14760b5f5..03ab007c7 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.2.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.2.png index 51449f574..e5c41943a 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.2.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.2.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.3.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.3.png index 40dbe61c9..5e6dca6cc 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.3.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.3.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.4.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.4.png index 730e1db7f..91ac1b716 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.4.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.4.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.5.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.5.png index 1940d22a4..ea4c7856c 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.5.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.5.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.6.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.6.png index 8146b6a53..d80fba088 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.6.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.6.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.7.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.7.png index 7aed3732a..4960ee5a0 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.7.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.7.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.8.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.8.png index d22bb1d70..1b3b48b4d 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.8.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.8.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Success.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Success.1.png index 078c91aeb..83c6c0443 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Success.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Success.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.1.png index 46ff1314f..14f612c48 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.2.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.2.png index ef9bfeff7..dc6c13d2e 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.2.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.2.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.3.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.3.png index 248f23ea6..6f32cc722 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.3.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.3.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.4.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.4.png index fd755c20c..3f9eadb07 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.4.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.4.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.5.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.5.png index 6bc094bf9..fcb8fab43 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.5.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.5.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.6.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.6.png index 9992c5604..e2efbcfa6 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.6.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.6.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.7.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.7.png index dae05a73d..4996caa38 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.7.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.7.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.8.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.8.png index b7e67904b..4ec10a811 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.8.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.8.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Success.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Success.1.png index dccdbf697..66ebc0459 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Success.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Success.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.1.png index 2abf8160d..83c6e9d4c 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.2.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.2.png index 2f2b2d6b3..a7c6a346d 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.2.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.2.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.3.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.3.png index 229301639..879271003 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.3.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.3.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.4.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.4.png index d0118e47a..5c4f48c29 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.4.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.4.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.5.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.5.png index f6382dcc2..8f9dbf6e5 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.5.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.5.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.6.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.6.png index cf6a732db..b2395adc4 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.6.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.6.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.7.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.7.png index 112d02681..c97066307 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.7.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.7.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.8.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.8.png index c6d334626..78f970640 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.8.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.8.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.1.png index f2505b68e..935703914 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.2.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.2.png index 926f88c66..577cf4194 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.2.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.2.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.3.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.3.png index fdb2fb51d..4c9cb8578 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.3.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.3.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.4.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.4.png index 797fae4fc..621d368bb 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.4.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.4.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.5.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.5.png index 444a8f56f..17e19f7ce 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.5.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.5.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.6.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.6.png index ad3f8485c..8943def3c 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.6.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.6.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.7.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.7.png index 707874ffd..1052c3f81 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.7.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.7.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.8.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.8.png index 9ee29006b..964f3c6df 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.8.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.8.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Success.1.png b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Success.1.png index cb4e0c5b7..1b9f41e1d 100644 Binary files a/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Success.1.png and b/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Success.1.png differ diff --git a/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj index a1fa79bfd..f9c6690fc 100644 --- a/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj +++ b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj @@ -24,7 +24,6 @@ 0BB538AD28B637980060A8DE /* Factory+UITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB538AC28B637980060A8DE /* Factory+UITest.swift */; }; 0BD2ECBF28B65DA10041A942 /* FrameUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD2ECBE28B65DA10041A942 /* FrameUITests.swift */; }; 0BD2ECC128B65EC20041A942 /* XCUIApplication+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD2ECC028B65EC20041A942 /* XCUIApplication+Extension.swift */; }; - 1629C08C2AF90379001BD3D9 /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = 1629C08B2AF90379001BD3D9 /* Frames */; }; 1629C08E2AF905A4001BD3D9 /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = 1629C08D2AF905A4001BD3D9 /* Frames */; }; 1629C0902AF905A8001BD3D9 /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = 1629C08F2AF905A8001BD3D9 /* Frames */; }; 162CD88E2A6827E900027FEF /* XCUIElement+TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162CD88D2A6827E900027FEF /* XCUIElement+TestHelpers.swift */; }; @@ -90,6 +89,10 @@ 95C8C13F28AD603700B8D3D0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95C8C13E28AD603700B8D3D0 /* Assets.xcassets */; }; 95EB97DC2A54753000EE6776 /* ThemeDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95EB97DA2A54753000EE6776 /* ThemeDemo.swift */; }; 95EB97DD2A54753000EE6776 /* ThemeDemo+Border.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95EB97DB2A54753000EE6776 /* ThemeDemo+Border.swift */; }; + AB60148E2F59BD6000526B0F /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = AB60148D2F59BD6000526B0F /* Frames */; }; + FFFC42F82F63186600BB6CC2 /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = 1629C08B2AF90379001BD3D9 /* Frames */; }; + FFFC42F92F63186600BB6CC2 /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = 958E51042DE74B3E0003F4B0 /* Frames */; }; + FFFC42FC2F6328EA00BB6CC2 /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = FFFC42FB2F6328EA00BB6CC2 /* Frames */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -227,7 +230,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1629C08C2AF90379001BD3D9 /* Frames in Frameworks */, + FFFC42FC2F6328EA00BB6CC2 /* Frames in Frameworks */, + FFFC42F92F63186600BB6CC2 /* Frames in Frameworks */, + FFFC42F82F63186600BB6CC2 /* Frames in Frameworks */, + AB60148E2F59BD6000526B0F /* Frames in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -529,6 +535,9 @@ name = "iOS Example Frame"; packageProductDependencies = ( 1629C08B2AF90379001BD3D9 /* Frames */, + 958E51042DE74B3E0003F4B0 /* Frames */, + AB60148D2F59BD6000526B0F /* Frames */, + FFFC42FB2F6328EA00BB6CC2 /* Frames */, ); productName = "iOS Example Frame"; productReference = 16AE74C32A5C1EBB0031F794 /* iOS Example Frame.app */; @@ -577,7 +586,7 @@ mainGroup = E6646F8120CE6C0900D8353A; packageReferences = ( 16C3F83E2A7927ED00690639 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, - 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */, + FFFC42FA2F6328EA00BB6CC2 /* XCRemoteSwiftPackageReference "frames-ios" */, ); productRefGroup = E6646F8120CE6C0900D8353A; projectDirPath = ""; @@ -850,7 +859,7 @@ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = E32XBQK4Q5; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; INFOPLIST_FILE = "../iOS Example Frame/iOS Example Frame/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -875,7 +884,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -900,7 +909,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = E32XBQK4Q5; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -924,7 +933,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = E32XBQK4Q5; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.checkout.iOS-Example-Frame-Regression-Tests"; @@ -947,7 +956,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = E32XBQK4Q5; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.checkout.iOS-Example-Frame-Regression-Tests"; @@ -970,7 +979,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -995,7 +1004,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "cko.iOS-Example-FrameUITests"; @@ -1140,7 +1149,7 @@ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = E32XBQK4Q5; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; INFOPLIST_FILE = "../iOS Example Frame/iOS Example Frame/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1168,7 +1177,7 @@ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = E32XBQK4Q5; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; INFOPLIST_FILE = "../iOS Example Frame/iOS Example Frame/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1231,20 +1240,20 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */ = { + 16C3F83E2A7927ED00690639 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/checkout/frames-ios"; + repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing"; requirement = { kind = exactVersion; - version = 4.3.1; + version = 1.12.0; }; }; - 16C3F83E2A7927ED00690639 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { + FFFC42FA2F6328EA00BB6CC2 /* XCRemoteSwiftPackageReference "frames-ios" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing"; + repositoryURL = "https://github.com/checkout/frames-ios"; requirement = { - kind = exactVersion; - version = 1.12.0; + kind = upToNextMajorVersion; + minimumVersion = 4.5.0; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -1252,17 +1261,14 @@ /* Begin XCSwiftPackageProductDependency section */ 1629C08B2AF90379001BD3D9 /* Frames */ = { isa = XCSwiftPackageProductDependency; - package = 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */; productName = Frames; }; 1629C08D2AF905A4001BD3D9 /* Frames */ = { isa = XCSwiftPackageProductDependency; - package = 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */; productName = Frames; }; 1629C08F2AF905A8001BD3D9 /* Frames */ = { isa = XCSwiftPackageProductDependency; - package = 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */; productName = Frames; }; 16C3F83F2A7927ED00690639 /* SnapshotTesting */ = { @@ -1270,6 +1276,19 @@ package = 16C3F83E2A7927ED00690639 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */; productName = SnapshotTesting; }; + 958E51042DE74B3E0003F4B0 /* Frames */ = { + isa = XCSwiftPackageProductDependency; + productName = Frames; + }; + AB60148D2F59BD6000526B0F /* Frames */ = { + isa = XCSwiftPackageProductDependency; + productName = Frames; + }; + FFFC42FB2F6328EA00BB6CC2 /* Frames */ = { + isa = XCSwiftPackageProductDependency; + package = FFFC42FA2F6328EA00BB6CC2 /* XCRemoteSwiftPackageReference "frames-ios" */; + productName = Frames; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = E6646F8220CE6C0900D8353A /* Project object */; diff --git a/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..a923b7c36 --- /dev/null +++ b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,60 @@ +{ + "originHash" : "f27d8fb9eaa74b44dc2ae0c3ea57528767b57ac6effdeb77f93fb990cfc04f3f", + "pins" : [ + { + "identity" : "checkout-event-logger-ios-framework", + "kind" : "remoteSourceControl", + "location" : "https://github.com/checkout/checkout-event-logger-ios-framework.git", + "state" : { + "revision" : "a914d754b4ffb1843730e8e1f8e7e60c4bf81cf9", + "version" : "1.2.4" + } + }, + { + "identity" : "checkout-risk-sdk-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/checkout/checkout-risk-sdk-ios.git", + "state" : { + "revision" : "7f944921720dc879b63ac3bb51f56dd6eb50919c", + "version" : "4.0.2" + } + }, + { + "identity" : "fingerprintjs-pro-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/fingerprintjs/fingerprintjs-pro-ios", + "state" : { + "revision" : "21bcfcfd2e1bce943f668a7748f8a7e1154f0ac2", + "version" : "2.13.0" + } + }, + { + "identity" : "frames-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/checkout/frames-ios", + "state" : { + "revision" : "335ea15376434f762d40b2d0db5c9c982582143d", + "version" : "4.4.0" + } + }, + { + "identity" : "phonenumberkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/marmelroy/PhoneNumberKit.git", + "state" : { + "revision" : "ad20aba8db84a6ba373abfcffe38b1c8e6f8258b", + "version" : "4.2.7" + } + }, + { + "identity" : "swift-snapshot-testing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-snapshot-testing", + "state" : { + "revision" : "26ed3a2b4a2df47917ca9b790a57f91285b923fb", + "version" : "1.12.0" + } + } + ], + "version" : 3 +} diff --git a/iOS Example Frame/Podfile b/iOS Example Frame/Podfile index 45e5257cf..cbb76bd1f 100644 --- a/iOS Example Frame/Podfile +++ b/iOS Example Frame/Podfile @@ -1,12 +1,13 @@ # Uncomment the next line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '13.0' target 'iOS Example Frame' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! - # Pods for iOS Example Custom - pod 'Frames', '4.3.1' + # Pods for iOS Example Custom (local Frames from repo root) + pod 'Frames', :path => '../' + pod 'Checkout', :path => '../' end diff --git a/iOS Example Frame/Podfile.lock b/iOS Example Frame/Podfile.lock index 35575afa2..8f2b9f957 100644 --- a/iOS Example Frame/Podfile.lock +++ b/iOS Example Frame/Podfile.lock @@ -1,34 +1,56 @@ PODS: - - Checkout (4.3.0): + - Checkout (4.5.0): - CheckoutEventLoggerKit (~> 1.2.4) + - Risk (~> 6.0.1) - CheckoutEventLoggerKit (1.2.4) - - Frames (4.3.0): - - Checkout (= 4.3.0) + - FingerprintJS (1.7.0): + - FingerprintJS/Core (= 1.7.0) + - FingerprintJS/Core (1.7.0): + - FingerprintJS/SystemControl + - FingerprintJS/SystemControl (1.7.0) + - FingerprintPro (2.17.2) + - Frames (4.5.0): + - Checkout (= 4.5.0) - CheckoutEventLoggerKit (~> 1.2.4) - - PhoneNumberKit - - PhoneNumberKit (3.7.4): - - PhoneNumberKit/PhoneNumberKitCore (= 3.7.4) - - PhoneNumberKit/UIKit (= 3.7.4) - - PhoneNumberKit/PhoneNumberKitCore (3.7.4) - - PhoneNumberKit/UIKit (3.7.4): + - PhoneNumberKit (~> 4.0) + - PhoneNumberKit (4.2.0): + - PhoneNumberKit/PhoneNumberKitCore (= 4.2.0) + - PhoneNumberKit/UIKit (= 4.2.0) + - PhoneNumberKit/PhoneNumberKitCore (4.2.0) + - PhoneNumberKit/UIKit (4.2.0): - PhoneNumberKit/PhoneNumberKitCore + - Risk (6.0.1): + - CheckoutEventLoggerKit (~> 1.2.4) + - FingerprintJS (< 2.0.0, >= 1.7.0) + - FingerprintPro (< 3.0.0, >= 2.12.0) DEPENDENCIES: - - Frames (= 4.3.0) + - Checkout (from `../`) + - Frames (from `../`) SPEC REPOS: trunk: - - Checkout - CheckoutEventLoggerKit - - Frames + - FingerprintJS + - FingerprintPro - PhoneNumberKit + - Risk + +EXTERNAL SOURCES: + Checkout: + :path: "../" + Frames: + :path: "../" SPEC CHECKSUMS: - Checkout: 942b292115d9d0a5e10738001a58370bb8d1ef9b + Checkout: e209a32fdbc31fc2e30dc70baf54ca73aaa70f27 CheckoutEventLoggerKit: b780dec46295a34942780ea6230d0d5fd08aa05a - Frames: d21139b41665842d9ede5228c62bc7c70aec31bf - PhoneNumberKit: e3c4dc9f65bc2036639898095c2ab1ef89348f64 + FingerprintJS: afb6185cf6951b60adc334f41d63e2e0a520bcf4 + FingerprintPro: 9a703bc7fb00413ffe5624bcbb07b62129f00ab6 + Frames: 08035f604e47851ae872b8989eca2cf73b23569e + PhoneNumberKit: 8b6138c92080c3f72a2c10f1d4e881bd316eef41 + Risk: 9fc0f6688a284ab40d41b1c5ac8301b62c4dc53c -PODFILE CHECKSUM: 77203c081fb461931e02ea92d808ea83d0c61cc9 +PODFILE CHECKSUM: 731ac4454e9a98bc4604ec10a2460a43b5c042a5 -COCOAPODS: 1.14.2 +COCOAPODS: 1.17.0 diff --git a/iOS Example Frame/iOS Example Frame.xcodeproj/project.pbxproj b/iOS Example Frame/iOS Example Frame.xcodeproj/project.pbxproj index af9d1e24d..2c0a3aaf8 100644 --- a/iOS Example Frame/iOS Example Frame.xcodeproj/project.pbxproj +++ b/iOS Example Frame/iOS Example Frame.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 53; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -648,7 +648,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -704,7 +704,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; @@ -723,7 +723,7 @@ DEVELOPMENT_TEAM = E32XBQK4Q5; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; INFOPLIST_FILE = "iOS Example Frame/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -746,7 +746,7 @@ DEVELOPMENT_TEAM = E32XBQK4Q5; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; INFOPLIST_FILE = "iOS Example Frame/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/iOS Example Frame/iOS Example Frame/Factory/Factory+UITest.swift b/iOS Example Frame/iOS Example Frame/Factory/Factory+UITest.swift index 375f80793..433d25d74 100644 --- a/iOS Example Frame/iOS Example Frame/Factory/Factory+UITest.swift +++ b/iOS Example Frame/iOS Example Frame/Factory/Factory+UITest.swift @@ -19,7 +19,8 @@ extension Factory { let configuration = PaymentFormConfiguration(apiKey: apiKey, environment: environment, supportedSchemes: supportedSchemes, - billingFormData: nil) + billingFormData: nil, + baseURLPrefix: baseURLPrefix) let style = ThemeDemo.buildMinimalUITest() let viewController = PaymentFormFactory.buildViewController(configuration: configuration, @@ -35,7 +36,8 @@ extension Factory { let configuration = PaymentFormConfiguration(apiKey: apiKey, environment: environment, supportedSchemes: supportedSchemes, - billingFormData: nil) + billingFormData: nil, + baseURLPrefix: baseURLPrefix) let style = ThemeDemo.buildCompleteUITest() let viewController = PaymentFormFactory.buildViewController(configuration: configuration, diff --git a/iOS Example Frame/iOS Example Frame/Factory/Factory.swift b/iOS Example Frame/iOS Example Frame/Factory/Factory.swift index a5004d663..bf0624a41 100644 --- a/iOS Example Frame/iOS Example Frame/Factory/Factory.swift +++ b/iOS Example Frame/iOS Example Frame/Factory/Factory.swift @@ -17,6 +17,8 @@ enum Factory { static let failureURL = URL(string: "https://httpstat.us/403")! static let apiKey = "pk_sbox_ym4kqv5lzvjni7utqbliqs2vhqc" static let environment: Frames.Environment = .sandbox + /// Optional subdomain prefix for API base URL (e.g. "sa" → "sa.api.sandbox.checkout.com"). Set to nil to use default host. + static let baseURLPrefix: String? = nil static func getDefaultPaymentViewController(completionHandler: @escaping (Result) -> Void) -> UIViewController { #if UITEST @@ -50,7 +52,8 @@ enum Factory { let configuration = PaymentFormConfiguration(apiKey: apiKey, environment: environment, supportedSchemes: supportedSchemes, - billingFormData: billingFormData) + billingFormData: billingFormData, + baseURLPrefix: baseURLPrefix) let style = PaymentStyle(paymentFormStyle: paymentFormStyle, billingFormStyle: billingFormStyle) @@ -76,7 +79,8 @@ enum Factory { let configuration = PaymentFormConfiguration(apiKey: apiKey, environment: environment, supportedSchemes: supportedSchemes, - billingFormData: billingFormData) + billingFormData: billingFormData, + baseURLPrefix: baseURLPrefix) let style = ThemeDemo.buildBorderExample() let viewController = PaymentFormFactory.buildViewController(configuration: configuration, style: style, @@ -112,7 +116,8 @@ enum Factory { let configuration = PaymentFormConfiguration(apiKey: apiKey, environment: environment, supportedSchemes: supportedSchemes, - billingFormData: billingFormData) + billingFormData: billingFormData, + baseURLPrefix: baseURLPrefix) let style = PaymentStyle(paymentFormStyle: paymentFormStyle, billingFormStyle: billingFormStyle) @@ -140,7 +145,8 @@ enum Factory { let configuration = PaymentFormConfiguration(apiKey: apiKey, environment: environment, supportedSchemes: supportedSchemes, - billingFormData: billingFormData) + billingFormData: billingFormData, + baseURLPrefix: baseURLPrefix) let style = ThemeDemo.buildCustom2Example() diff --git a/iOS Example Frame/iOS Example Frame/ViewController/HomeViewController.swift b/iOS Example Frame/iOS Example Frame/ViewController/HomeViewController.swift index 7bd66b3b0..5a9088477 100644 --- a/iOS Example Frame/iOS Example Frame/ViewController/HomeViewController.swift +++ b/iOS Example Frame/iOS Example Frame/ViewController/HomeViewController.swift @@ -23,7 +23,7 @@ class HomeViewController: UIViewController { @IBOutlet weak var securityCodeComponentButton: UIButton! private var notificationCenter: NotificationCenter = .default - private lazy var checkoutAPIService = Frames.CheckoutAPIService(publicKey: Factory.apiKey, environment: Factory.environment) + private lazy var checkoutAPIService = Frames.CheckoutAPIService(publicKey: Factory.apiKey, environment: Factory.environment, baseURLPrefix: Factory.baseURLPrefix) override func viewDidLoad() { super.viewDidLoad() diff --git a/iOS Example Frame/iOS Example Frame/ViewController/SecurityCodeViewController.swift b/iOS Example Frame/iOS Example Frame/ViewController/SecurityCodeViewController.swift index b4bc79374..3126738f5 100644 --- a/iOS Example Frame/iOS Example Frame/ViewController/SecurityCodeViewController.swift +++ b/iOS Example Frame/iOS Example Frame/ViewController/SecurityCodeViewController.swift @@ -18,7 +18,8 @@ final class SecurityCodeViewController: UIViewController { @IBOutlet private weak var customPayButton: UIButton! var configuration = SecurityCodeComponentConfiguration(apiKey: Factory.apiKey, - environment: Factory.environment) + environment: Factory.environment, + baseURLPrefix: Factory.baseURLPrefix) func setupDefaultSecurityCodeComponent() { configuration.cardScheme = Card.Scheme(rawValue: "VISA")