Add E2E test (#122)
This commit is contained in:
parent
b39ba4f47c
commit
e498f4488f
|
@ -59,6 +59,14 @@ jobs:
|
|||
- prep_environment
|
||||
- run: "bundle exec fastlane main_tests"
|
||||
|
||||
ringcon-only:
|
||||
executor: mac-executor
|
||||
|
||||
steps:
|
||||
- prep_environment
|
||||
- prep_bundler_carthage
|
||||
- run: "bundle exec fastlane ringcon-only"
|
||||
|
||||
ui-and-analyze-tests:
|
||||
executor: mac-executor
|
||||
|
||||
|
@ -123,6 +131,7 @@ jobs:
|
|||
- run: "./stripe3ds2-support/ci_scripts/run_analyzer.sh"
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build-and-test:
|
||||
jobs:
|
||||
- ci-builds
|
||||
|
@ -142,3 +151,13 @@ workflows:
|
|||
- linting-tests
|
||||
- install-tests
|
||||
- threeds2-tests
|
||||
e2e-only:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "56 * * * *" # at 56 minutes every hour
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- private
|
||||
jobs:
|
||||
- ringcon-only
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
3185126C252FE67E008C0C57 /* StripeTests-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 3185126B252FE67E008C0C57 /* StripeTests-Prefix.pch */; };
|
||||
31851272252FE770008C0C57 /* STPBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 31851271252FE770008C0C57 /* STPBlocks.h */; };
|
||||
3186371D25D1B51B00B31CF6 /* STPPaymentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 317ABDE725117C9E00CC59EF /* STPPaymentHandler.swift */; };
|
||||
31875B5C25DC63C800884BE0 /* STPE2ETest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31875B5B25DC63C800884BE0 /* STPE2ETest.swift */; };
|
||||
319490592513CC6200AD8F0B /* STPImageLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 317ABDD725117C9D00CC59EF /* STPImageLibrary.swift */; };
|
||||
319490612514041300AD8F0B /* STPBankSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 317ABD9825117C9900CC59EF /* STPBankSelectionViewController.swift */; };
|
||||
3194906625140BEF00AD8F0B /* STPCoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 317ABDC725117C9C00CC59EF /* STPCoreViewController.swift */; };
|
||||
|
@ -931,6 +932,7 @@
|
|||
318321E525C8910E00D96469 /* STPPaymentCardTextField+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "STPPaymentCardTextField+SwiftUI.swift"; sourceTree = "<group>"; };
|
||||
3185126B252FE67E008C0C57 /* StripeTests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StripeTests-Prefix.pch"; sourceTree = "<group>"; };
|
||||
31851271252FE770008C0C57 /* STPBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPBlocks.h; sourceTree = "<group>"; };
|
||||
31875B5B25DC63C800884BE0 /* STPE2ETest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPE2ETest.swift; sourceTree = "<group>"; };
|
||||
3194CF5B2314869400E1940F /* STPPaymentMethodFPXTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPaymentMethodFPXTest.m; sourceTree = "<group>"; };
|
||||
3194CF5D231487A100E1940F /* STPFPXBankBrandTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPFPXBankBrandTest.m; sourceTree = "<group>"; };
|
||||
31C26219255F887A000C5B50 /* Stripe-umbrella.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Stripe-umbrella.h"; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -1831,6 +1833,7 @@
|
|||
3111C3BF252BC79400207E32 /* STPPushProvisioningDetailsFunctionalTest.swift */,
|
||||
B640DB1922C69C01003C8810 /* STPSetupIntentFunctionalTest.m */,
|
||||
C1D7B5241E36C70D002181F5 /* STPSourceFunctionalTest.m */,
|
||||
31875B5B25DC63C800884BE0 /* STPE2ETest.swift */,
|
||||
);
|
||||
name = Functional;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2314,6 +2317,7 @@
|
|||
3111C5B7252BF66500207E32 /* STPColorUtilsTest.swift in Sources */,
|
||||
C17D24EE1E37DBAC005CB188 /* STPSourceTest.m in Sources */,
|
||||
3111C5FA252D1DC000207E32 /* STPShippingMethodsViewControllerLocalizationTests.swift in Sources */,
|
||||
31875B5C25DC63C800884BE0 /* STPE2ETest.swift in Sources */,
|
||||
B69CABB9246DCB620081B1EF /* STPPaymentHandlerFunctionalTest.m in Sources */,
|
||||
31C5B87C252E859300A481A7 /* STPPaymentConfigurationTest.m in Sources */,
|
||||
31C5B87E252E869D00A481A7 /* StripeErrorTest.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// STPE2ETest.swift
|
||||
// StripeiOS Tests
|
||||
//
|
||||
// Created by David Estes on 2/16/21.
|
||||
// Copyright © 2021 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Stripe
|
||||
|
||||
class STPE2ETest: XCTestCase {
|
||||
let E2ETestTimeout : TimeInterval = 120
|
||||
|
||||
struct E2EExpectation {
|
||||
var amount: Int
|
||||
var currency: String
|
||||
var accountID: String
|
||||
}
|
||||
|
||||
class E2EBackend {
|
||||
static let backendAPIURL = URL(string: "https://stp-e2e.glitch.me")!
|
||||
|
||||
func createPaymentIntent(completion: @escaping (STPPaymentIntentParams, E2EExpectation) -> Void) {
|
||||
requestAPI("create_pi", method: "POST") { (json) in
|
||||
let paymentIntentClientSecret = json["paymentIntent"] as! String
|
||||
let expectedAmount = json["expectedAmount"] as! Int
|
||||
let expectedCurrency = json["expectedCurrency"] as! String
|
||||
let expectedAccountID = json["expectedAccountID"] as! String
|
||||
let publishableKey = json["publishableKey"] as! String
|
||||
STPAPIClient.shared.publishableKey = publishableKey
|
||||
completion(STPPaymentIntentParams(clientSecret: paymentIntentClientSecret), E2EExpectation(amount: expectedAmount, currency: expectedCurrency, accountID: expectedAccountID))
|
||||
}
|
||||
}
|
||||
|
||||
func fetchPaymentIntent(id: String, completion: @escaping (E2EExpectation) -> Void) {
|
||||
requestAPI("fetch_pi", queryItems: [URLQueryItem(name: "pi", value: id)]) { (json) in
|
||||
let resultAmount = json["amount"] as! Int
|
||||
let resultCurrency = json["currency"] as! String
|
||||
let resultAccountID = json["on_behalf_of"] as! String
|
||||
completion(E2EExpectation(amount: resultAmount, currency: resultCurrency, accountID: resultAccountID))
|
||||
}
|
||||
}
|
||||
|
||||
private func requestAPI(_ resource: String, method: String = "GET", queryItems: [URLQueryItem] = [], completion: @escaping ([String : Any]) -> Void) {
|
||||
var url = URLComponents(url: Self.backendAPIURL.appendingPathComponent(resource), resolvingAgainstBaseURL: false)!
|
||||
url.queryItems = queryItems
|
||||
var request = URLRequest(url: url.url!)
|
||||
request.httpMethod = method
|
||||
let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
|
||||
guard let data = data,
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] else {
|
||||
XCTFail("Did not receive valid JSON response from E2E server. \(String(describing: error))")
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
completion(json)
|
||||
}
|
||||
})
|
||||
task.resume()
|
||||
}
|
||||
}
|
||||
|
||||
static let TestPM: STPPaymentMethodParams = {
|
||||
let testCard = STPPaymentMethodCardParams()
|
||||
testCard.number = "4242424242424242"
|
||||
testCard.expYear = 2050
|
||||
testCard.expMonth = 12
|
||||
testCard.cvc = "123"
|
||||
return STPPaymentMethodParams(card: testCard, billingDetails: nil, metadata: nil)
|
||||
}()
|
||||
|
||||
// MARK: LOG.04.01c
|
||||
// In this test, a PaymentIntent object is created from an example merchant backend,
|
||||
// confirmed by the iOS SDK, and then retrieved to validate that the original amount,
|
||||
// currency, and merchant are the same as the original inputs.
|
||||
func testE2E() throws {
|
||||
continueAfterFailure = false
|
||||
let backend = E2EBackend()
|
||||
let createPI = XCTestExpectation(description: "Create PaymentIntent")
|
||||
let fetchPIBackend = XCTestExpectation(description: "Fetch and check PaymentIntent via backend")
|
||||
let fetchPIClient = XCTestExpectation(description: "Fetch and check PaymentIntent via client")
|
||||
let confirmPI = XCTestExpectation(description: "Confirm PaymentIntent")
|
||||
|
||||
// Create a PaymentIntent
|
||||
backend.createPaymentIntent { (pip, expected) in
|
||||
createPI.fulfill()
|
||||
|
||||
// Confirm the PaymentIntent using a test card
|
||||
pip.paymentMethodParams = STPE2ETest.TestPM
|
||||
STPAPIClient.shared.confirmPaymentIntent(with: pip) { (confirmedPI, confirmError) in
|
||||
confirmPI.fulfill()
|
||||
XCTAssertNotNil(confirmedPI)
|
||||
XCTAssertNil(confirmError)
|
||||
|
||||
// Check the PI information using the backend
|
||||
backend.fetchPaymentIntent(id: pip.stripeId!) { (expectationResult) in
|
||||
XCTAssertEqual(expectationResult.amount, expected.amount)
|
||||
XCTAssertEqual(expectationResult.accountID, expected.accountID)
|
||||
XCTAssertEqual(expectationResult.currency, expected.currency)
|
||||
fetchPIBackend.fulfill()
|
||||
}
|
||||
|
||||
// Check the PI information using the client
|
||||
STPAPIClient.shared.retrievePaymentIntent(withClientSecret: pip.clientSecret) { (fetchedPI, fetchError) in
|
||||
XCTAssertNil(fetchError)
|
||||
let fetchedPI = fetchedPI!
|
||||
XCTAssertEqual(fetchedPI.status, .succeeded)
|
||||
XCTAssertEqual(fetchedPI.amount, expected.amount)
|
||||
XCTAssertEqual(fetchedPI.currency, expected.currency)
|
||||
// The client can't check the "on_behalf_of" field, so we check it via the merchant test above.
|
||||
fetchPIClient.fulfill()
|
||||
}
|
||||
}
|
||||
}
|
||||
wait(for: [createPI, confirmPI, fetchPIBackend, fetchPIClient], timeout: E2ETestTimeout)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
|
||||
function info {
|
||||
echo "[$(basename "${0}")] [INFO] ${1}"
|
||||
}
|
||||
|
||||
function die {
|
||||
echo "[$(basename "${0}")] [ERROR] ${1}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Verify xcpretty is installed
|
||||
if ! command -v xcpretty > /dev/null; then
|
||||
if [[ "${CI}" != "true" ]]; then
|
||||
die "Please install xcpretty: https://github.com/supermarin/xcpretty#installation"
|
||||
fi
|
||||
|
||||
info "Installing xcpretty..."
|
||||
gem install xcpretty --no-document || die "Executing \`gem install xcpretty\` failed"
|
||||
fi
|
||||
|
||||
# Install test dependencies
|
||||
info "Installing test dependencies..."
|
||||
|
||||
carthage bootstrap --platform iOS --configuration Release --no-use-binaries --cache-builds --use-xcframeworks
|
||||
carthage_exit_code="$?"
|
||||
|
||||
if [[ "${carthage_exit_code}" != 0 ]]; then
|
||||
die "Executing carthage failed with status code: ${carthage_exit_code}"
|
||||
fi
|
||||
|
||||
info "Executing E2E tests (iPhone 8 @ iOS 13.7)..."
|
||||
|
||||
xcodebuild test \
|
||||
-workspace "Stripe.xcworkspace" \
|
||||
-scheme "StripeiOS" \
|
||||
-configuration "Debug" \
|
||||
-sdk "iphonesimulator" \
|
||||
-destination "platform=iOS Simulator,name=iPhone 8,OS=13.7" \
|
||||
-only-testing:"StripeiOS Tests/STPE2ETest" \
|
||||
| xcpretty
|
||||
exit_code="${PIPESTATUS[0]}"
|
||||
|
||||
if [[ "${exit_code}" != 0 ]]; then
|
||||
die "xcodebuild exited with non-zero status code: ${exit_code}"
|
||||
fi
|
||||
|
||||
info "All good!"
|
|
@ -98,6 +98,12 @@ platform :ios do
|
|||
end
|
||||
end
|
||||
|
||||
lane :e2e_only do
|
||||
Dir.chdir("..") do
|
||||
sh("./ci_scripts/e2e_test.sh")
|
||||
end
|
||||
end
|
||||
|
||||
lane :analyze do
|
||||
Dir.chdir("..") do
|
||||
sh("./ci_scripts/run_analyzer.sh")
|
||||
|
|
Loading…
Reference in New Issue