From f2750b4831b4512c8c41a73f9d1b1456749bebd5 Mon Sep 17 00:00:00 2001 From: Ian Lin <128665735+ianlin-bbpos@users.noreply.github.com> Date: Fri, 2 Aug 2024 00:03:22 +0800 Subject: [PATCH] Add unit test on iOS (#764) * add test func. * Example of using a mirror protocol for testing allowing a mock struct to be used in the tests * derp; I forgot to git add the Protocols.swift file * implement mapper test & add test command in bitrise.yml. * improve test method. --------- Co-authored-by: Brian Cooke --- bitrise.yml | 14 +-- ios/Protocols.swift | 65 +++++++++++++ ios/Tests/MappersTests.swift | 180 +++++++++++++++++++++++++++++++++++ package.json | 1 + 4 files changed, 254 insertions(+), 6 deletions(-) create mode 100644 ios/Protocols.swift diff --git a/bitrise.yml b/bitrise.yml index 74d25340..5456cdbb 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -260,12 +260,14 @@ workflows: - complete_all unit-ios: steps: - - xcode-test@5: - inputs: - - project_path: dev-app/ios/StripeTerminalReactNativeDevApp.xcworkspace - - scheme: UnitTests - - destination: platform=iOS Simulator,name=iPhone 14,OS=latest - title: xcodebuild iOS Unit Tests + - xcode-test@5: + inputs: + - project_path: dev-app/ios/StripeTerminalReactNativeDevApp.xcworkspace + - scheme: UnitTests + - destination: platform=iOS Simulator,name=iPhone 14,OS=latest + - command: yarn unit-test:ios + - cache_local_deps: 'yes' + title: xcodebuild iOS Unit Tests before_run: - prep_all - setup_cocoapods diff --git a/ios/Protocols.swift b/ios/Protocols.swift new file mode 100644 index 00000000..8307f132 --- /dev/null +++ b/ios/Protocols.swift @@ -0,0 +1,65 @@ +import StripeTerminal + +/** + This file includes a collection of protocols that mirror a selection of the StripeTerminal iOS public classes. + This enables writing swift unit tests against these protocols since the Terminal iOS SDK + classes prevent instantiating them (init and new are annotated as unavailable). + + Note the naming here is exactly as they are named in the native SDK so we can use them interchangeably. We will + need to keep them in sync. + */ + +protocol CollectInputsResult { + var skipped: Bool { get } +} + +protocol TextResult : CollectInputsResult { + var text: String? { get } + var toggles: [NSNumber] { get } +} + +protocol NumericResult : CollectInputsResult { + var numericString: String? { get } + var toggles: [NSNumber] { get } +} + +protocol PhoneResult : CollectInputsResult { + var phone: String? { get } + var toggles: [NSNumber] { get } +} + +protocol EmailResult : CollectInputsResult { + var email: String? { get } + var toggles: [NSNumber] { get } +} + +protocol SignatureResult : CollectInputsResult { + var signatureSvg: String? { get } + var toggles: [NSNumber] { get } +} + +protocol SelectionResult : CollectInputsResult { + var selection: String? { get } + var toggles: [NSNumber] { get } +} + +extension StripeTerminal.TextResult : TextResult { +} + +extension StripeTerminal.NumericResult : NumericResult { +} + +extension StripeTerminal.PhoneResult : PhoneResult { +} + +extension StripeTerminal.EmailResult : EmailResult { +} + +extension StripeTerminal.SignatureResult : SignatureResult { +} + +extension StripeTerminal.SelectionResult : SelectionResult { +} + +extension StripeTerminal.CollectInputsResult : CollectInputsResult { +} diff --git a/ios/Tests/MappersTests.swift b/ios/Tests/MappersTests.swift index 562e82ce..a8e9339c 100644 --- a/ios/Tests/MappersTests.swift +++ b/ios/Tests/MappersTests.swift @@ -19,4 +19,184 @@ final class MappersTests: XCTestCase { XCTAssertEqual(Mappers.mapFromLocationStatus(.notSet), "notSet") } + func testCollectInputsReturnsMapper() { + let textResult = TestableTextResult(skipped: false, text: "Written text from the reader", toggles: [ + ToggleResult.enabled.rawValue as NSNumber, + ToggleResult.skipped.rawValue as NSNumber, + ]) + let numericResult = TestableNumericResult(skipped: false, numericString: "123456", toggles: [ + ToggleResult.enabled.rawValue as NSNumber, + ToggleResult.skipped.rawValue as NSNumber, + ]) + let phoneResult = TestablePhoneResult(skipped: false, phone: "+1 425-555-1234", toggles: [ + ToggleResult.enabled.rawValue as NSNumber, + ToggleResult.skipped.rawValue as NSNumber, + ]) + let emailResult = TestableEmailResult(skipped: false, email: "unit.test@abc.com", toggles: [ + ToggleResult.enabled.rawValue as NSNumber, + ToggleResult.skipped.rawValue as NSNumber, + ]) + let selectionResult = TestableSelectionResult(skipped: false, selection: "Yes", toggles: [ + ToggleResult.enabled.rawValue as NSNumber, + ToggleResult.skipped.rawValue as NSNumber, + ]) + let signatureResult = TestableSignatureResult(skipped: false, signatureSvg: "", toggles: [ + ToggleResult.enabled.rawValue as NSNumber, + ToggleResult.skipped.rawValue as NSNumber, + ]) + var output: NSDictionary = Mappers.mapFromCollectInputsResults([ + textResult + ]) + XCTAssertNotNil(output.object(forKey: "collectInputResults")) + XCTAssertTrue(output["collectInputResults"] is [NSDictionary]) + + var results: [NSDictionary] = output["collectInputResults"] as! [NSDictionary] + + XCTAssertEqual(results.count, 1) + guard let result = results.first else { + XCTFail("CollectInput result should have had a result") + return + } + guard + let skipped = result["skipped"] as? Bool, + let toggles = result["toggles"] as? [String], + let text = result["text"] as? String else { + XCTFail("CollectInput TestResult should have had text, skipped and toggles") + return + } + XCTAssertFalse(skipped) + XCTAssertEqual(toggles.count, 2) + XCTAssertEqual(toggles[0], "enabled") + XCTAssertEqual(toggles[1], "skipped") + XCTAssertEqual(text, "Written text from the reader") + + output = Mappers.mapFromCollectInputsResults([ + numericResult, phoneResult, emailResult, selectionResult, signatureResult + ]) + XCTAssertNotNil(output.object(forKey: "collectInputResults")) + XCTAssertTrue(output["collectInputResults"] is [NSDictionary]) + + results = output["collectInputResults"] as! [NSDictionary] + + let testNumericString = "numericString" + let testPhone = "phone" + let testEmail = "email" + let testSelection = "selection" + let testSignatureSvg = "signatureSvg" + XCTAssertEqual(results.count, 5) + XCTAssertTrue(results[0][testNumericString] != nil) + XCTAssertTrue(results[1][testPhone] != nil) + XCTAssertTrue(results[2][testEmail] != nil) + XCTAssertTrue(results[3][testSelection] != nil) + XCTAssertTrue(results[4][testSignatureSvg] != nil) + + for result in results { + if ((result.object(forKey: testNumericString)) != nil) { + guard + let skipped = result["skipped"] as? Bool, + let toggles = result["toggles"] as? [String], + let numericString = result[testNumericString] as? String else { + XCTFail("CollectInput NumericResult should have had numericString, skipped and toggles") + return + } + XCTAssertFalse(skipped) + XCTAssertEqual(toggles.count, 2) + XCTAssertEqual(toggles[0], "enabled") + XCTAssertEqual(toggles[1], "skipped") + XCTAssertEqual(numericString, "123456") + } + if ((result.object(forKey: testPhone)) != nil) { + guard + let skipped = result["skipped"] as? Bool, + let toggles = result["toggles"] as? [String], + let phone = result[testPhone] as? String else { + XCTFail("CollectInput PhoneResult should have had phone, skipped and toggles") + return + } + XCTAssertFalse(skipped) + XCTAssertEqual(toggles.count, 2) + XCTAssertEqual(toggles[0], "enabled") + XCTAssertEqual(toggles[1], "skipped") + XCTAssertEqual(phone, "+1 425-555-1234") + } + if ((result.object(forKey: testEmail)) != nil) { + guard + let skipped = result["skipped"] as? Bool, + let toggles = result["toggles"] as? [String], + let email = result[testEmail] as? String else { + XCTFail("CollectInput EmailResult should have had email, skipped and toggles") + return + } + XCTAssertFalse(skipped) + XCTAssertEqual(toggles.count, 2) + XCTAssertEqual(toggles[0], "enabled") + XCTAssertEqual(toggles[1], "skipped") + XCTAssertEqual(email, "unit.test@abc.com") + } + if ((result.object(forKey: testSelection)) != nil) { + guard + let skipped = result["skipped"] as? Bool, + let toggles = result["toggles"] as? [String], + let selection = result[testSelection] as? String else { + XCTFail("CollectInput SelectionResult should have had selection, skipped and toggles") + return + } + XCTAssertFalse(skipped) + XCTAssertEqual(toggles.count, 2) + XCTAssertEqual(toggles[0], "enabled") + XCTAssertEqual(toggles[1], "skipped") + XCTAssertEqual(selection, "Yes") + } + if ((result.object(forKey: testSignatureSvg)) != nil) { + guard + let skipped = result["skipped"] as? Bool, + let toggles = result["toggles"] as? [String], + let signatureSvg = result[testSignatureSvg] as? String else { + XCTFail("CollectInput SignatureResult should have had signatureSvg, skipped and toggles") + return + } + XCTAssertFalse(skipped) + XCTAssertEqual(toggles.count, 2) + XCTAssertEqual(toggles[0], "enabled") + XCTAssertEqual(toggles[1], "skipped") + XCTAssertEqual(signatureSvg, "") + } + } + } +} + +struct TestableTextResult : stripe_terminal_react_native.TextResult { + var skipped: Bool + var text: String? + var toggles: [NSNumber] +} + +struct TestableNumericResult : stripe_terminal_react_native.NumericResult { + var skipped: Bool + var numericString: String? + var toggles: [NSNumber] +} + +struct TestablePhoneResult : stripe_terminal_react_native.PhoneResult { + var skipped: Bool + var phone: String? + var toggles: [NSNumber] +} + +struct TestableEmailResult : stripe_terminal_react_native.EmailResult { + var skipped: Bool + var email: String? + var toggles: [NSNumber] +} + +struct TestableSelectionResult : stripe_terminal_react_native.SelectionResult { + var skipped: Bool + var selection: String? + var toggles: [NSNumber] +} + +struct TestableSignatureResult : stripe_terminal_react_native.SignatureResult { + var skipped: Bool + var signatureSvg: String? + var toggles: [NSNumber] } diff --git a/package.json b/package.json index 2dae66ff..9f5f8f7f 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "get:testbutler": "curl -f -o ./test-butler-app.apk https://repo1.maven.org/maven2/com/linkedin/testbutler/test-butler-app/2.2.1/test-butler-app-2.2.1.apk", "docs": "npx typedoc ./src/index.tsx --out ./docs/api-reference --tsconfig ./tsconfig.json --readme none", "unit-test:android": "cd android && ./gradlew testDebugUnitTest", + "unit-test:ios": "xcodebuild test -workspace dev-app/ios/StripeTerminalReactNativeDevApp.xcworkspace -destination 'platform=iOS Simulator,name=iPhone 15' -scheme UnitTests", "unit-test:js": "jest" }, "keywords": [