Skip to content

Commit

Permalink
Created PurchasesLoginTests (#1832)
Browse files Browse the repository at this point in the history
Working on [CSDK-394], I realized that `Purchases.logIn` and `Purchases.logOut` had no tests.

[CSDK-394]: https://revenuecats.atlassian.net/browse/CSDK-394?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
NachoSoto authored Aug 15, 2022
1 parent d8cbae0 commit 06a1085
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 3 deletions.
4 changes: 4 additions & 0 deletions RevenueCat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@
57D5412E27F6311C004CC35C /* OfferingsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D5412D27F6311C004CC35C /* OfferingsResponse.swift */; };
57D5414227F656D9004CC35C /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D5414127F656D9004CC35C /* NetworkError.swift */; };
57D56FCA2853C005009E8E1E /* StringExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D56FC92853C005009E8E1E /* StringExtensionsTests.swift */; };
57DBFA5D28AADA43002D18CA /* PurchasesLogInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57DBFA5C28AADA43002D18CA /* PurchasesLogInTests.swift */; };
57DC9F4627CC2E4900DA6AF9 /* HTTPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57DC9F4527CC2E4900DA6AF9 /* HTTPRequest.swift */; };
57DC9F4A27CD37BA00DA6AF9 /* HTTPStatusCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57DC9F4927CD37BA00DA6AF9 /* HTTPStatusCodeTests.swift */; };
57DE806D28074976008D6C6F /* Storefront.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57DE806C28074976008D6C6F /* Storefront.swift */; };
Expand Down Expand Up @@ -797,6 +798,7 @@
57D5414127F656D9004CC35C /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = "<group>"; };
57D56FC92853C005009E8E1E /* StringExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionsTests.swift; sourceTree = "<group>"; };
57DB9EE7281B3C6100BBAA21 /* __Snapshots__ */ = {isa = PBXFileReference; lastKnownFileType = folder; path = __Snapshots__; sourceTree = "<group>"; };
57DBFA5C28AADA43002D18CA /* PurchasesLogInTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PurchasesLogInTests.swift; sourceTree = "<group>"; };
57DC9F4527CC2E4900DA6AF9 /* HTTPRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPRequest.swift; sourceTree = "<group>"; };
57DC9F4927CD37BA00DA6AF9 /* HTTPStatusCodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStatusCodeTests.swift; sourceTree = "<group>"; };
57DE806C28074976008D6C6F /* Storefront.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storefront.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1707,6 +1709,7 @@
57E415FE28469EAB00EA5460 /* PurchasesGetProductsTests.swift */,
57FDAA952846BDE2009A48F1 /* PurchasesTransactionHandlingTests.swift */,
57FDAA992846C2BD009A48F1 /* PurchasesDelegateTests.swift */,
57DBFA5C28AADA43002D18CA /* PurchasesLogInTests.swift */,
);
path = Purchases;
sourceTree = "<group>";
Expand Down Expand Up @@ -2615,6 +2618,7 @@
35D8330A262FBA9A00E60AC5 /* MockUserDefaults.swift in Sources */,
2DDF41DF24F6F527005BC22D /* MockProductsManager.swift in Sources */,
351B514F26D44ACE00BD2BD7 /* PurchasesSubscriberAttributesTests.swift in Sources */,
57DBFA5D28AADA43002D18CA /* PurchasesLogInTests.swift in Sources */,
57D04BB827D947C6006DAC06 /* HTTPResponseTests.swift in Sources */,
5796A38127D6B78500653165 /* BaseBackendTest.swift in Sources */,
351B516226D44BEE00BD2BD7 /* CustomerInfoManagerTests.swift in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion Sources/Networking/IdentityAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import Foundation

class IdentityAPI {

typealias LogInResponseHandler = (Result<(info: CustomerInfo, created: Bool), BackendError>) -> Void
typealias LogInResponse = Result<(info: CustomerInfo, created: Bool), BackendError>
typealias LogInResponseHandler = (LogInResponse) -> Void

private let logInCallbacksCache: CallbackCache<LogInCallback>
private let backendConfig: BackendConfiguration
Expand Down
24 changes: 22 additions & 2 deletions Tests/UnitTests/Mocks/MockIdentityManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,32 @@ class MockIdentityManager: IdentityManager {
return mockIsAnonymous
}

// MARK: - LogIn

var mockLogInResult: IdentityAPI.LogInResponse!
var invokedLogIn = false
var invokedLogInCount = 0
var invokedLogInParametersList: [String] = []

override func logIn(appUserID: String, completion: @escaping IdentityAPI.LogInResponseHandler) {
fatalError("Logging in not supported on mock")
self.invokedLogIn = true
self.invokedLogInCount += 1
self.invokedLogInParametersList.append(appUserID)

completion(self.mockLogInResult)
}

// MARK: - LogOut

var mockLogOutError: BackendError?
var invokedLogOut = false
var invokedLogOutCount = 0

override func logOut(completion: @escaping (Error?) -> Void) {
fatalError("Logging out not supported on mock")
self.invokedLogOut = true
self.invokedLogOutCount += 1

completion(self.mockLogOutError)
}

}
143 changes: 143 additions & 0 deletions Tests/UnitTests/Purchasing/Purchases/PurchasesLogInTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// PurchasesLogInTests.swift
//
// Created by Nacho Soto on 8/15/22.

import Nimble
import StoreKit
import XCTest

@testable import RevenueCat

class PurchasesLogInTests: BasePurchasesTests {

private typealias LogInResult = Result<(customerInfo: CustomerInfo, created: Bool), Error>
private typealias LogOutResult = Result<CustomerInfo, Error>

override func setUpWithError() throws {
try super.setUpWithError()

self.setupAnonPurchases()
}

func testLogInWithSuccess() {
let created = Bool.random()

self.identityManager.mockLogInResult = .success((Self.mockLoggedInInfo, created))

var result: LogInResult!

self.purchases.logIn(Self.appUserID) { customerInfo, created, error in
result = Self.logInResult(customerInfo, created, error)
}

expect(result).toEventuallyNot(beNil())

expect(result).to(beSuccess())
expect(result.value) == (Self.mockLoggedInInfo, created)
expect(self.identityManager.invokedLogInCount) == 1
expect(self.identityManager.invokedLogInParametersList) == [Self.appUserID]
}

func testLogInWithFailure() {
let error: BackendError = .networkError(.offlineConnection())
self.identityManager.mockLogInResult = .failure(error)

var result: LogInResult!

self.purchases.logIn(Self.appUserID) { customerInfo, created, error in
result = Self.logInResult(customerInfo, created, error)
}

expect(result).toEventuallyNot(beNil())

expect(result).to(beFailure())
expect(result.error).to(matchError(error))
expect(self.identityManager.invokedLogInCount) == 1
expect(self.identityManager.invokedLogInParametersList) == [Self.appUserID]
}

func testLogOutWithSuccess() {
self.identityManager.mockLogOutError = nil
self.backend.overrideCustomerInfoResult = .success(Self.mockLoggedOutInfo)

expect(self.backend.getSubscriberCallCount) == 1

var result: Result<CustomerInfo, Error>!
self.purchases.logOut { customerInfo, error in
result = .init(customerInfo, error)
}

expect(result).toEventuallyNot(beNil())
expect(result).to(beSuccess())
expect(result.value) == Self.mockLoggedOutInfo

expect(self.backend.getSubscriberCallCount) == 2
expect(self.identityManager.invokedLogOutCount) == 1
}

func testLogOutWithFailure() {
let error: BackendError = .networkError(.offlineConnection())

self.identityManager.mockLogOutError = error

var result: Result<CustomerInfo, Error>!
self.purchases.logOut { customerInfo, error in
result = .init(customerInfo, error)
}

expect(result).toEventuallyNot(beNil())
expect(result).to(beFailure())
expect(result.error).to(matchError(error))

expect(self.backend.getSubscriberCallCount) == 1
expect(self.identityManager.invokedLogOutCount) == 1
}

}

// MARK: -

private extension PurchasesLogInTests {

// swiftlint:disable force_try
static let mockLoggedInInfo = try! CustomerInfo(data: PurchasesLogInTests.loggedInCustomerInfoData)
static let mockLoggedOutInfo = try! CustomerInfo(data: PurchasesLogInTests.loggedOutCustomerInfoData)
// swiftlint:enable force_try

private static let loggedInCustomerInfoData: [String: Any] = [
"request_date": "2019-08-16T10:30:42Z",
"subscriber": [
"first_seen": "2019-07-17T00:05:54Z",
"original_app_user_id": "user",
"subscriptions": [:],
"other_purchases": [:],
"original_application_version": NSNull()
]
]

private static let loggedOutCustomerInfoData: [String: Any] = [
"request_date": "2019-08-16T10:30:42Z",
"subscriber": [
"first_seen": "2019-07-17T00:05:54Z",
"original_app_user_id": "$RCAnonymousID:5b6fdbad3a0c4f879e43d269ecdf9ba1",
"subscriptions": [:],
"other_purchases": [:],
"original_application_version": NSNull()
]
]

/// Converts the result of `Purchases.logIn` into `LogInResult`
private static func logInResult(_ info: CustomerInfo?, _ created: Bool, _ error: Error?) -> LogInResult {
return .init(info.map { ($0, created) }, error)
}

}

0 comments on commit 06a1085

Please sign in to comment.