The problem is not that an observer cannot be added but an observer is worked async.
So, it should be written by using expectation.
For using expectation's fulfill, it need to callback after observer is updated or removed transaction.
class ProxySKProductTransactionObserver: NSObject, SKPaymentTransactionObserver {
var origin: SKPaymentTransactionObserver
var updatedTransactionsPostCallback: ((SKPaymentQueue, [SKPaymentTransaction]) -> Void)?
var removedTransactionsPostCallback: ((SKPaymentQueue, [SKPaymentTransaction]) -> Void)?
init(_ origin: SKPaymentTransactionObserver) {
self.origin = origin
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
origin.paymentQueue(queue, updatedTransactions: transactions)
updatedTransactionsPostCallback?(queue, transactions)
}
func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
origin.paymentQueue?(queue, removedTransactions: transactions)
removedTransactionsPostCallback?(queue, transactions)
}
}
After using expectation, test is passed
import XCTest
import StoreKitTest
@available(iOS 14.0, *)
final class SimpleSKProductTransactionObserverTest: XCTestCase {
var sut: MockSKProductTransactionObserver!
var proxy: ProxySKProductTransactionObserver!
var session: SKTestSession!
override func setUpWithError() throws {
session = try SKTestSession(configurationFileNamed: "ShopStoreKitConfig")
session.resetToDefaultState()
session.disableDialogs = true
session.clearTransactions()
sut = .init()
proxy = .init(sut)
SKPaymentQueue.default().add(proxy)
}
override func tearDownWithError() throws {
SKPaymentQueue.default().remove(proxy)
proxy = nil
sut = nil
session = nil
}
func testPaymentQueue() throws {
let productId = "prod_sale1_battery_1_day"
let expectation = self.expectation(description: "updatedTransaction is called")
proxy.updatedTransactionsPostCallback = { _, _ in
expectation.fulfill()
}
try session.buyProduct(productIdentifier: productId)
waitForExpectations(timeout: 5)
XCTAssertTrue(sut.isPaymentQueueCalled)
XCTAssertEqual(sut.previousTransactions.first?.payment.productIdentifier, productId)
}
}
class MockSKProductTransactionObserver: NSObject, SKPaymentTransactionObserver {
var previousTransactions = [SKPaymentTransaction]()
var isPaymentQueueCalled = false
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
isPaymentQueueCalled = true
previousTransactions = transactions
}
}
Post
Replies
Boosts
Views
Activity
This is the example of storekit file. You can save it as file named ShopStoreKitConfig.storekit in your project.
{
"identifier" : "BB337E99",
"nonRenewingSubscriptions" : [
],
"products" : [
{
"displayPrice" : "4.99",
"familyShareable" : false,
"internalID" : "60FA6345",
"localizations" : [
{
"description" : "Unlimited battery for 1 day",
"displayName" : "Unlimited battery for 1 day",
"locale" : "en_US"
}
],
"productID" : "prod_sale1_battery_1_day",
"referenceName" : “Unlimited battery for 1 day”,
"type" : "Consumable"
},
],
"settings" : {
},
"subscriptionGroups" : [
],
"version" : {
"major" : 1,
"minor" : 1
}
}