Add E2E test (#122)

This commit is contained in:
davidme-stripe 2021-02-23 15:45:07 -08:00 committed by GitHub
parent b39ba4f47c
commit e498f4488f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 195 additions and 0 deletions

View File

@ -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

View File

@ -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 */,

View File

@ -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)
}
}

48
ci_scripts/e2e_test.sh Executable file
View File

@ -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!"

View File

@ -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")