{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","admonition"]},"type":"markdown"},"seo":{"title":"Testing","description":"Transform your commerce with PXP's unified platform—seamless payments, real-time insights, and global growth in one powerful integration.","lang":"en-UK","siteUrl":"https://developer.pxp.io","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"testing","__idx":0},"children":["Testing"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test your Drop-in integration in sandbox before going live."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test your Drop-in integration in the sandbox environment before accepting real payments. The sandbox environment allows you to test all payment methods without processing actual transactions."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"use-the-test-environment","__idx":2},"children":["Use the test environment"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set the environment to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".test"]}," when initialising Drop-in:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"CheckoutDropInConfig(\n    environment: .test,  // Use sandbox\n    // ... rest of config\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Key points about sandbox testing:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No real money is charged."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use test card numbers and sandbox accounts."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Payment methods behave like production, with the same SDK constraints."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Backend verification still required using test API credentials."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"test-card-payments","__idx":3},"children":["Test card payments"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"test-card-numbers","__idx":4},"children":["Test card numbers"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the following test cards in sandbox to simulate different scenarios."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The test card numbers below are examples. Actual available test cards depend on your merchant and test processor configuration."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"successful-payments","__idx":5},"children":["Successful payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following test cards represent successful payment scenarios:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Card number"},"children":["Card number"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Network"},"children":["Network"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"3DS behaviour"},"children":["3DS behaviour"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4111 1111 1111 1111"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Visa"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No challenge"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5555 5555 5555 4444"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Mastercard"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No challenge"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["3782 822463 10005"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["American Express"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No challenge"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0002"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Visa"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Challenge required"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For all test cards:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Expiry date:"]}," Any future date (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["12/25"]},")."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["CVV:"]}," Any 3 digits (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["123"]},")."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Cardholder name:"]}," Any name."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"failed-payments","__idx":6},"children":["Failed payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following test cards simulate payment failures:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Card number"},"children":["Card number"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Network"},"children":["Network"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Result"},"children":["Result"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0077"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Visa"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Insufficient funds"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0051"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Visa"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Card declined"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0069"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Visa"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Expired card"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0101"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Visa"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["CVV failure"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"testing-3ds-authentication","__idx":7},"children":["Testing 3DS authentication"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When using the challenge test card (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0002"]},"), a 3D Secure authentication screen appears. The exact 3DS flow depends on your payment processor and card network provider."]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["To pass:"]}," enter any code (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["1234"]},")."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["To fail:"]}," leave empty or enter wrong code multiple times."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["To timeout:"]}," wait for authentication to timeout."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expected callback behaviour:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Success:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback fires with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInSubmitResult"]}," containing transaction details."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Failure:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," callback fires with the authentication error (e.g., SDK1114 for authentication failed)."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Verify that your backend receives the transaction details after successful authentication."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"test-paypal","__idx":8},"children":["Test PayPal"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"paypal-sandbox-accounts","__idx":9},"children":["PayPal sandbox accounts"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You need a PayPal sandbox account for testing. Create one in the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://developer.paypal.com/dashboard/","target":"_blank"},"children":["PayPal Developer Dashboard"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a personal (buyer) account for testing customer payments."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"test-paypal-payments","__idx":10},"children":["Test PayPal payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The PayPal button only appears when ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["session.allowedFundingTypes.wallets.paypal.allowedFundingOptions"]}," is present and non-empty in your session configuration."]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Tap the PayPal button in the drop-in."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Log in with your PayPal sandbox account in the web view."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Approve the payment."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify that ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," fires with transaction details."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify your backend receives the payment notification."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test both transaction intents:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Purchase intent:"]}," Funds captured immediately."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Authorisation intent:"]}," Funds authorised but not captured (capture later via backend API)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"test-apple-pay","__idx":11},"children":["Test Apple Pay"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"requirements","__idx":12},"children":["Requirements"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["iOS 14.0 or higher"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Apple Pay capability enabled in Xcode"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Valid Apple Pay merchant identifier"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Test card added to Apple Wallet"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"test-apple-pay-payments","__idx":13},"children":["Test Apple Pay payments"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Open your app on an iOS device or simulator."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure Apple Pay is set up with test cards."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Add a test card to Apple Wallet (use test card numbers from above)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Tap the Apple Pay button in Drop-in."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Authenticate with Face ID, Touch ID, or passcode."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify that ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," fires with transaction details."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The Apple Pay button only appears when:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The user has cards in their Apple Wallet and Apple Pay is properly configured."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["session.allowedFundingTypes.wallets.applePay.merchantId"]}," is present in your session configuration."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"testing-on-simulator","__idx":14},"children":["Testing on simulator"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To test Apple Pay on an iOS simulator:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use Simulator with iOS 14.0 or higher."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["In the Simulator menu, click ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Wallet > Add Credit or Debit Card"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Add test cards manually using the card numbers above."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Run your app and test Apple Pay integration."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Apple Pay sandbox testing requires proper Xcode project configuration with the Apple Pay capability and a valid merchant identifier registered in your Apple Developer account."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"test-error-handling","__idx":15},"children":["Test error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test that your error handling works correctly by simulating failures:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"card-errors","__idx":16},"children":["Card errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the failed payment test cards to trigger different error types:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Insufficient funds: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0077"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Card declined: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0051"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Expired card: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0069"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["CVV failure: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["4000 0000 0000 0101"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Verify that your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," callback receives the error and displays an appropriate message to the customer."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"expected-sdk-error-codes","__idx":17},"children":["Expected SDK error codes"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," callback may receive the following SDK error codes:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"general-payment-errors","__idx":18},"children":["General payment errors"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK0204"]},": No payment methods available. Drop-in calls ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentMethod: nil"]}," during ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["create()"]}," when no payment methods can be rendered (an inline ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["noPaymentMethodsError"]}," message is still shown). To test in sandbox, use a session with no wallets and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInCardConfig(showCOF: false, showNewCard: false)"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1114"]},": Authentication failed (3DS or similar authentication failure)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1115"]},": Authorisation failed (payment declined by issuer/processor)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1116"]},": Card payment failed (general card payment error)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1117"]},": PayPal payment failed (general PayPal error)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1119"]},": Apple Pay payment failed (general Apple Pay error)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1120"]},": Invalid PayPal entry type (configuration mismatch)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"apple-pay-specific-errors","__idx":19},"children":["Apple Pay-specific errors"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK0602"]},": Apple Pay configuration error."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK0615"]},": Apple Pay session cancelled by the user."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK0616"]},": Apple Pay merchant validation failed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK0617"]},": Custom API processing failed during Apple Pay payment."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"network-errors","__idx":20},"children":["Network errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test offline behaviour:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enable airplane mode on your device."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Try to submit a payment."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify that your error handling shows a network error message."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Alternatively, use Network Link Conditioner in Xcode or your app's backend/mock layer to simulate network failures."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Pseudocode example - adapt to your app's architecture\n// Use your app's backend mock layer or dependency injection\n// to simulate network failures in tests\nclass NetworkErrorTest: XCTestCase {\n    func testNetworkError() async throws {\n        // Configure your backend mock to return network errors\n        // or use URLProtocol/URLSession mocks in your app\n        \n        // Verify error handling in your app\n        // ... test implementation\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"user-cancellation","__idx":21},"children":["User cancellation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To test cancellation handling:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PayPal:"]}," close the web view without completing payment. This doesn't trigger ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global.onCancel"]}," because Drop-in overrides the PayPal cancel handler with an internal handler to clear processing state."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Apple Pay:"]}," tap outside the payment sheet or cancel the authentication. This triggers ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global.onCancel(.applePay, error)"]}," if configured."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"test-backend-verification","__idx":22},"children":["Test backend verification"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Always verify payments on your backend before fulfilling orders. The frontend callbacks can be manipulated by users."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"essential-backend-tests","__idx":23},"children":["Essential backend tests"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test these critical security checks:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transaction exists:"]}," query the PXP API with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["systemTransactionId"]}," to verify that the transaction exists."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Amount matches:"]}," verify that the transaction amount matches your expected amount."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Transaction succeeded:"]}," check that the transaction state is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Authorised"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Captured"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Prevent replay attacks:"]}," ensure the same transaction can't be processed twice."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Example verification:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// Backend verification endpoint (Node.js/Express example)\napp.post('/api/verify-payment', async (req, res) => {\n  const { systemTransactionId, merchantTransactionId } = req.body;\n  \n  // Get expected amount from your database\n  const order = await db.orders.findOne({ merchantTransactionId });\n  \n  // Guard against missing order\n  if (!order) {\n    return res.status(404).json({ success: false, error: 'Order not found' });\n  }\n  \n  const expectedAmount = order.amount;\n  \n  // Query PXP API to verify transaction\n  const transaction = await unityApi.getTransaction(systemTransactionId);\n  \n  // Verify transaction is successful\n  if (transaction.state !== 'Authorised' && transaction.state !== 'Captured') {\n    return res.json({ success: false, error: 'Transaction not authorised' });\n  }\n  \n  // Verify amount matches\n  const txnAmount = transaction.amounts?.transactionValue || transaction.amount;\n  if (Math.abs(txnAmount - expectedAmount) > 0.01) {\n    return res.json({ success: false, error: 'Amount mismatch' });\n  }\n  \n  // Check for duplicate processing\n  const alreadyProcessed = await db.transactions.findOne({ systemTransactionId });\n  if (alreadyProcessed) {\n    return res.json({ success: true, orderId: alreadyProcessed.orderId });\n  }\n  \n  // Process order\n  const orderId = await fulfillOrder(order);\n  await db.transactions.create({ systemTransactionId, orderId });\n  \n  res.json({ success: true, orderId });\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"test-on-physical-devices","__idx":24},"children":["Test on physical devices"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test on real iOS devices to ensure the best user experience:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"recommended-test-devices","__idx":25},"children":["Recommended test devices"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test on devices that represent your user base:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Budget device:"]}," iPhone SE (2nd/3rd generation)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Standard device:"]}," iPhone 13, iPhone 14"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Pro device:"]}," iPhone 15 Pro, iPhone 14 Pro"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tablet:"]}," iPad Air, iPad Pro"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"device-specific-testing","__idx":26},"children":["Device-specific testing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test the following on each device:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Card field rendering and keyboard input."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["3D Secure authentication UI."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Apple Pay integration and authentication."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["PayPal web view interaction."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Screen rotation handling."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Different screen sizes (iPhone vs iPad)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Performance and responsiveness."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"screen-size-testing","__idx":27},"children":["Screen size testing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test on different screen sizes:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Use SwiftUI Previews for different screen sizes\nstruct CheckoutView_Previews: PreviewProvider {\n    static var previews: some View {\n        Group {\n            CheckoutView()\n                .previewDevice(PreviewDevice(rawValue: \"iPhone SE (3rd generation)\"))\n                .previewDisplayName(\"iPhone SE\")\n            \n            CheckoutView()\n                .previewDevice(PreviewDevice(rawValue: \"iPhone 15 Pro\"))\n                .previewDisplayName(\"iPhone 15 Pro\")\n            \n            CheckoutView()\n                .previewDevice(PreviewDevice(rawValue: \"iPad Pro (12.9-inch)\"))\n                .previewDisplayName(\"iPad Pro\")\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"automated-testing","__idx":28},"children":["Automated testing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Write automated tests for your Drop-in integration:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"unit-tests","__idx":29},"children":["Unit tests"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test your configuration and callback logic. Card-only examples below use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GBP"]},"."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import XCTest\nimport PXPCheckoutSDK\n\nclass CheckoutConfigTests: XCTestCase {\n    func testConfigCreation() {\n        let config = CheckoutDropInConfig(\n            environment: .test,\n            session: mockSessionData(),\n            transactionData: DropInTransactionData(\n                amount: Decimal(string: \"99.99\") ?? 0,\n                currency: \"GBP\",\n                entryType: .ecom,\n                intent: DropInTransactionIntentData(\n                    card: .authorisation\n                ),\n                merchantTransactionId: \"test-txn-123\",\n                merchantTransactionDate: { Date() }\n            ),\n            merchantShopperId: \"shopper-123\",\n            ownerId: \"MERCHANT-1\"\n        )\n        \n        XCTAssertEqual(config.environment, .test)\n        XCTAssertEqual(config.ownerId, \"MERCHANT-1\")\n        XCTAssertEqual(config.transactionData.currency, \"GBP\")\n    }\n    \n    func testCallbackExecution() {\n        var successCalled = false\n        var errorCalled = false\n        \n        let config = CheckoutDropInConfig(\n            environment: .test,\n            session: mockSessionData(),\n            transactionData: DropInTransactionData(\n                amount: Decimal(string: \"99.99\") ?? 0,\n                currency: \"GBP\",\n                entryType: .ecom,\n                intent: DropInTransactionIntentData(\n                    card: .authorisation\n                ),\n                merchantTransactionId: \"test-txn-callback-123\",\n                merchantTransactionDate: { Date() }\n            ),\n            merchantShopperId: \"shopper-callback-123\",\n            ownerId: \"MERCHANT-1\",\n            onSuccess: { result in\n                Task { @MainActor in\n                    successCalled = true\n                }\n            },\n            onError: { paymentMethod, error in\n                Task { @MainActor in\n                    errorCalled = true\n                }\n            }\n        )\n        \n        // Test callbacks\n        config.onSuccess?(mockSuccessResult())\n        XCTAssertTrue(successCalled)\n        XCTAssertFalse(errorCalled)\n    }\n    \n    func mockSessionData(includePaze: Bool = false) -> SessionData {\n        return SessionData(\n            sessionId: \"test-session-id\",\n            hmacKey: \"test-hmac-key\",\n            encryptionKey: \"test-encryption-key\",\n            sessionExpiry: nil,\n            allowedFundingTypes: AllowedFundingType(\n                cardSchemes: [\"Visa\", \"Mastercard\"],\n                cards: [],\n                wallets: Wallets(\n                    paypal: Paypal(\n                        allowedFundingOptions: [\"paypal\"],\n                        merchantId: \"test-merchant-id\"\n                    ),\n                    applePay: ApplePay(merchantId: \"merchant.test.app\"),\n                    paze: includePaze\n                        ? Paze(clientId: \"test-paze-client-id\", merchantCategoryCode: \"5812\")\n                        : nil\n                )\n            ),\n            restrictions: nil\n        )\n    }\n    \n    func testPazeConfigUsesUSD() {\n        let config = CheckoutDropInConfig(\n            environment: .test,\n            session: mockSessionData(includePaze: true),\n            transactionData: DropInTransactionData(\n                amount: Decimal(string: \"49.99\") ?? 0,\n                currency: \"USD\",\n                entryType: .ecom,\n                intent: DropInTransactionIntentData(card: .authorisation),\n                merchantTransactionId: \"test-paze-txn-123\",\n                merchantTransactionDate: { Date() }\n            ),\n            merchantShopperId: \"shopper-123\",\n            ownerId: \"MERCHANT-1\",\n            onSuccess: { _ in },\n            onError: { _, _ in }\n        )\n        \n        XCTAssertEqual(config.transactionData.currency, \"USD\")\n        XCTAssertEqual(config.transactionData.entryType, .ecom)\n    }\n    \n    func mockSuccessResult(paymentMethod: DropInPaymentMethod = .card) -> DropInSubmitResult {\n        return DropInSubmitResult(\n            systemTransactionId: \"sys-txn-123\",\n            merchantTransactionId: \"test-txn-123\",\n            paymentMethod: paymentMethod\n            // paymentData is nil for card, PayPal, and Apple Pay; optional .paze for Paze\n        )\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"async-drop-in-test-pattern","__idx":30},"children":["Async Drop-in test pattern"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test async Drop-in initialisation:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"class AsyncDropInTests: XCTestCase {\n    func testAsyncDropInCreation() async throws {\n        let config = CheckoutDropInConfig(\n            environment: .test,\n            session: mockSessionData(),\n            transactionData: DropInTransactionData(\n                amount: Decimal(string: \"49.99\") ?? 0,\n                currency: \"GBP\",\n                entryType: .ecom,\n                intent: DropInTransactionIntentData(\n                    card: .authorisation\n                ),\n                merchantTransactionId: \"test-async-txn-123\",\n                merchantTransactionDate: { Date() }\n            ),\n            merchantShopperId: \"shopper-async-123\",\n            ownerId: \"MERCHANT-1\"\n        )\n        \n        // Test async initialisation\n        let dropIn = try CheckoutDropIn(config: config)\n        await dropIn.create()\n        \n        // Verify Drop-in is ready\n        XCTAssertNotNil(dropIn)\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"ui-tests","__idx":31},"children":["UI tests"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test the full payment flow:"]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The UI test selectors shown below (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"Card\""]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"PayPal\""]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"Card number\""]},") are examples and aren't guaranteed by the SDK. The SDK may change button labels, field names, or accessibility identifiers in future releases. For robust UI testing, use your merchant app's own stable accessibility identifiers rather than relying on localised text or SDK-provided labels."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import XCTest\n\nclass CheckoutFlowUITests: XCTestCase {\n    var app: XCUIApplication!\n    \n    override func setUp() {\n        super.setUp()\n        continueAfterFailure = false\n        app = XCUIApplication()\n        app.launch()\n    }\n    \n    func testCardPaymentFlow() {\n        // Wait for Drop-in to render\n        let cardButton = app.buttons[\"Card\"]\n        XCTAssertTrue(cardButton.waitForExistence(timeout: 5))\n        \n        // Verify payment methods are displayed\n        XCTAssertTrue(app.buttons[\"Card\"].exists)\n        XCTAssertTrue(app.buttons[\"PayPal\"].exists)\n        // If Paze is enabled in your session:\n        // XCTAssertTrue(app.buttons[\"Paze\"].exists)\n        \n        // Select card payment\n        cardButton.tap()\n        \n        // Verify card form is displayed\n        XCTAssertTrue(app.textFields[\"Card number\"].exists)\n        XCTAssertTrue(app.textFields[\"Expiry date\"].exists)\n        XCTAssertTrue(app.textFields[\"CVV\"].exists)\n    }\n    \n    func testPaymentSubmission() {\n        let cardButton = app.buttons[\"Card\"]\n        XCTAssertTrue(cardButton.waitForExistence(timeout: 5))\n        \n        // Fill card details and submit\n        cardButton.tap()\n        \n        let cardNumberField = app.textFields[\"Card number\"]\n        cardNumberField.tap()\n        cardNumberField.typeText(\"4111111111111111\")\n        \n        let expiryField = app.textFields[\"Expiry date\"]\n        expiryField.tap()\n        expiryField.typeText(\"1225\")\n        \n        let cvvField = app.textFields[\"CVV\"]\n        cvvField.tap()\n        cvvField.typeText(\"123\")\n        \n        // Submit payment\n        app.buttons[\"Pay\"].tap()\n        \n        // Verify success screen appears\n        let successMessage = app.staticTexts[\"Payment successful\"]\n        XCTAssertTrue(successMessage.waitForExistence(timeout: 10))\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"pre-production-checklist","__idx":32},"children":["Pre-production checklist"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before going live, verify the following:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"configuration","__idx":33},"children":["Configuration"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Change the environment to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".live"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use production API credentials."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify that the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ownerId"]}," is correct."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Confirm the currency and amount formatting."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify that all required session fields are present and valid:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sessionId"]},": Valid session identifier from your backend."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["hmacKey"]},": Valid HMAC key for request signing."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["encryptionKey"]},": Valid encryption key for sensitive data."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes.cardSchemes"]}," and/or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes.cards"]},": At least one non-empty list of enabled card networks (or set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["acceptedCardNetworks"]}," in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInGlobalConfig"]},"). The SDK resolves networks in priority order: merchant ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["acceptedCardNetworks"]}," → session ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cardSchemes"]}," → session ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cards"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes.wallets.paypal.allowedFundingOptions"]},": Present and non-empty if PayPal is enabled."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes.wallets.applePay.merchantId"]},": Present if Apple Pay is enabled."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["restrictions"]},": Correct merchant-specific restrictions (if any)."]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"testing-1","__idx":34},"children":["Testing"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Test all enabled payment methods."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Test successful payments."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Test failed payments and error handling."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify backend verification works correctly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Test on physical devices (not just simulators)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"security","__idx":35},"children":["Security"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Backend verification implemented."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Replay attack prevention in place."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["HTTPS enabled on all backend endpoints."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No sensitive data logged."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Code signing and provisioning profiles configured for production."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"user-experience","__idx":36},"children":["User experience"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Test on different screen sizes and orientations."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Loading states display correctly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Success screen implemented."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Error messages are user-friendly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Accessibility features tested (VoiceOver, Dynamic Type)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"performance","__idx":37},"children":["Performance"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["App startup time is acceptable."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Payment submission is responsive."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No memory leaks detected (use Xcode Instruments)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Network timeouts configured appropriately."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"code-quality","__idx":38},"children":["Code quality"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["SwiftLint checks pass."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Unit tests pass."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["UI tests pass."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Code review completed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Documentation updated."]}]}]},"headings":[{"value":"Testing","id":"testing","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Use the test environment","id":"use-the-test-environment","depth":2},{"value":"Test card payments","id":"test-card-payments","depth":2},{"value":"Test card numbers","id":"test-card-numbers","depth":3},{"value":"Successful payments","id":"successful-payments","depth":4},{"value":"Failed payments","id":"failed-payments","depth":4},{"value":"Testing 3DS authentication","id":"testing-3ds-authentication","depth":3},{"value":"Test PayPal","id":"test-paypal","depth":2},{"value":"PayPal sandbox accounts","id":"paypal-sandbox-accounts","depth":3},{"value":"Test PayPal payments","id":"test-paypal-payments","depth":3},{"value":"Test Apple Pay","id":"test-apple-pay","depth":2},{"value":"Requirements","id":"requirements","depth":3},{"value":"Test Apple Pay payments","id":"test-apple-pay-payments","depth":3},{"value":"Testing on simulator","id":"testing-on-simulator","depth":3},{"value":"Test error handling","id":"test-error-handling","depth":2},{"value":"Card errors","id":"card-errors","depth":3},{"value":"Expected SDK error codes","id":"expected-sdk-error-codes","depth":3},{"value":"General payment errors","id":"general-payment-errors","depth":4},{"value":"Apple Pay-specific errors","id":"apple-pay-specific-errors","depth":4},{"value":"Network errors","id":"network-errors","depth":3},{"value":"User cancellation","id":"user-cancellation","depth":3},{"value":"Test backend verification","id":"test-backend-verification","depth":2},{"value":"Essential backend tests","id":"essential-backend-tests","depth":3},{"value":"Test on physical devices","id":"test-on-physical-devices","depth":2},{"value":"Recommended test devices","id":"recommended-test-devices","depth":3},{"value":"Device-specific testing","id":"device-specific-testing","depth":3},{"value":"Screen size testing","id":"screen-size-testing","depth":3},{"value":"Automated testing","id":"automated-testing","depth":2},{"value":"Unit tests","id":"unit-tests","depth":3},{"value":"Async Drop-in test pattern","id":"async-drop-in-test-pattern","depth":3},{"value":"UI tests","id":"ui-tests","depth":3},{"value":"Pre-production checklist","id":"pre-production-checklist","depth":2},{"value":"Configuration","id":"configuration","depth":3},{"value":"Testing","id":"testing-1","depth":3},{"value":"Security","id":"security","depth":3},{"value":"User experience","id":"user-experience","depth":3},{"value":"Performance","id":"performance","depth":3},{"value":"Code quality","id":"code-quality","depth":3}],"frontmatter":{"seo":{"title":"Testing"}},"lastModified":"2026-07-14T09:12:22.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/drop-in/ios/testing","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}