{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-ios/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Testing | iOS Tap to Pay on iPhone SDK Reference","description":"Test your Finix Tap to Pay on iPhone SDK integration in Sandbox on a physical iPhone, with Apple's Sandbox test mode, the demo app, and unit tests.","siteUrl":"https://docs.finix.com/","llmstxt":{"hide":false,"sections":[{"title":"Getting Started","includeFiles":["guides/getting-started/**/*.md"],"excludeFiles":[]},{"title":"Online Payments","includeFiles":["guides/online-payments/**/*.md"],"excludeFiles":["guides/online-payments/payment-features/fsa-hsa-non-healthcare-mcc.md"]},{"title":"In-Person Payments","includeFiles":["guides/in-person-payments/**/*.md"],"excludeFiles":[]},{"title":"Subscriptions","includeFiles":["guides/subscriptions/**/*.md"],"excludeFiles":[]},{"title":"After the Payment","includeFiles":["guides/after-the-payment/**/*.md"],"excludeFiles":[]},{"title":"Managing Operations","includeFiles":["guides/managing-operations/**/*.md"],"excludeFiles":[]},{"title":"Platform Payments","includeFiles":["guides/platform-payments/**/*.md"],"excludeFiles":[]},{"title":"Payouts","includeFiles":["guides/payouts/**/*.md"],"excludeFiles":[]},{"title":"Low-Code / No-Code","includeFiles":["low-code-no-code/**/*.md"],"excludeFiles":[]},{"title":"Developers","includeFiles":["additional-resources/developers/**/*.md"],"excludeFiles":[]},{"title":"Plugins","includeFiles":["additional-resources/plugins/**/*.md"],"excludeFiles":[]},{"title":"Industry Considerations","includeFiles":["guides/industry-considerations/**/*.md"],"excludeFiles":[]},{"title":"Regional Considerations","includeFiles":["guides/regional-considerations/**/*.md"],"excludeFiles":[]},{"title":"Release Notes","includeFiles":["release-notes/**/*.md"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"test-your-integration","__idx":0},"children":["Test your integration"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"environments-and-test-setup","__idx":1},"children":["Environments and test setup"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Integration testing happens on a ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["physical iPhone"]}," (XS or later, iOS 18.1 or later) against the Finix Sandbox: Sandbox API credentials, a Sandbox merchant, a Device created against the Sandbox API, and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["environment: .sandbox"]}," in your configuration."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Testing in Sandbox"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Sandbox transactions don't move real money. Complete the Apple-side Sandbox setup below before your first tap. Without it, card reads run against Apple's live service."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"set-up-the-iphone-for-sandbox-testing","__idx":2},"children":["Set up the iPhone for Sandbox testing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Tap to Pay on iPhone has its own Apple-side test mode, driven by the Apple Account signed in on the test device:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Create a ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Sandbox Apple Account"]},": in ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://appstoreconnect.apple.com/"},"children":["App Store Connect"]},", go to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Users and Access ▸ Sandbox ▸ Testers"]}," and add a tester. The tester email must be a real address that has never been used as an Apple Account before. Reusing an existing Apple Account email fails silently. See ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://developer.apple.com/apple-pay/sandbox-testing/"},"children":["Apple's Sandbox testing guide"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["On the test iPhone, sign in with the Sandbox Apple Account as the device's ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["primary Apple Account"]},": sign out of the current account at the top of the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Settings"]}," app, then sign in with the Sandbox tester."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["With the Sandbox account signed in as the primary account, the Terms and Conditions flow and card reads run against Apple's Sandbox, and you can tap ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://developer.apple.com/apple-pay/sandbox-testing/"},"children":["Apple Pay Sandbox test cards"]},". Apple publishes test card numbers for Visa, Mastercard, American Express, and Discover that you can add to Wallet on a second (Sandbox-signed-in) device, alongside physical test cards if you have them."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Primary Apple Account, not the App Store Sandbox setting"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Settings ▸ App Store ▸ Sandbox Account"]}," only affects In-App Purchase testing. It has no effect on Tap to Pay on iPhone or Wallet. The Sandbox tester must be the account the whole device is signed in to. Because signing in replaces the device's iCloud identity (photos, messages, iCloud Drive), use a dedicated test iPhone rather than a personal one."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"No iOS betas"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Tap to Pay on iPhone does not work on beta releases of iOS. Test on release iOS versions."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"try-the-demo-app","__idx":3},"children":["Try the demo app"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://github.com/finix-payments/finix-taptopay-ios-sdk-demo-app"},"children":["Finix Tap to Pay on iPhone demo app"]}," is a small SwiftUI reference integration. Clone it, add your Sandbox credentials and Device ID in its configuration screen, and run it on a physical iPhone. It demonstrates support checks, linking, reader preparation, and sale, authorization, and refund transactions end to end, which makes it a useful reference before you build the flow into your own app."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"write-unit-tests","__idx":4},"children":["Write unit tests"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your app-level logic (receipts, persistence, UI state) can be tested without a device. The result type's memberwise initializer is internal; use the public ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mock"]}," factory to construct results in your test target:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","data-title":"ReceiptRendererTests.swift","header":{"title":"ReceiptRendererTests.swift","controls":{"copy":{}}},"source":"import XCTest\nimport FinixTapToPaySDK\n@testable import YourApp\n\nfinal class ReceiptRendererTests: XCTestCase {\n    func testRendersApprovedReceipt() {\n        let result = TapToPayTransactionResult.mock(\n            amount: 1250,\n            currency: \"USD\",\n            cardBrand: \"VISA\",\n            last4: \"4242\",\n            transferId: \"TRxxxxxxxxxxxxx\",\n            transferState: \"SUCCEEDED\"\n        )\n\n        let receipt = ReceiptRenderer().render(result)\n\n        XCTAssertTrue(receipt.contains(\"$12.50\"))\n        XCTAssertTrue(receipt.contains(\"VISA •••• 4242\"))\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mock(amount:currency:...)"]}," provides default values for the card fields and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["nil"]}," for the transfer fields. Override the fields your test asserts on."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"manual-test-checklist","__idx":5},"children":["Manual test checklist"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Run through these on a physical iPhone before requesting the distribution entitlement:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["First link"]},": fresh install, sign-in, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["linkAccount()"]}," presents Apple's Terms and Conditions."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Re-link"]},": call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["linkAccount()"]}," again; confirm your app treats ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".accountAlreadyLinked"]}," as success."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Cold and warm prepare"]},": first ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["prepareReader()"]}," after install (slow) and after foregrounding (fast); your indeterminate progress UI shows during user-visible preparation."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Sale, authorization, and refund"]},": one of each; verify each ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transferId"]}," in the Sandbox Finix Dashboard."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Cancel mid-read"]},": dismiss the tap sheet and cancel from your UI; both paths surface ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".transactionCancelled"]}," and return to checkout cleanly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Backgrounding"]},": background the app mid-flow; confirm you re-prepare on foreground and no reader call runs from the background."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Un-activated Device"]},": point at a Device that was never activated; confirm your recovery path (re-provision) works."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Unsupported device"]},": on the simulator or an old iPhone, confirm Tap to Pay on iPhone entry points are hidden by your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["isSupported()"]}," gate."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Next:"]}," ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/ios/tap-to-pay/privacy"},"children":["Privacy and data collection"]},"."]}]},"headings":[{"value":"Test your integration","id":"test-your-integration","depth":1},{"value":"Environments and test setup","id":"environments-and-test-setup","depth":2},{"value":"Set up the iPhone for Sandbox testing","id":"set-up-the-iphone-for-sandbox-testing","depth":2},{"value":"Try the demo app","id":"try-the-demo-app","depth":2},{"value":"Write unit tests","id":"write-unit-tests","depth":2},{"value":"Manual test checklist","id":"manual-test-checklist","depth":2}],"frontmatter":{"seo":{"title":"Testing | iOS Tap to Pay on iPhone SDK Reference","description":"Test your Finix Tap to Pay on iPhone SDK integration in Sandbox on a physical iPhone, with Apple's Sandbox test mode, the demo app, and unit tests."}},"lastModified":"2026-08-11T19:49:07.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/ios/tap-to-pay/testing","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}