Skip to content

Release 3.0.0

Latest

Choose a tag to compare

@Ramiz69 Ramiz69 released this 05 Sep 20:13
· 1 commit to main since this release
9187453

Completes the mockability work started in 2.0 by wrapping StoreKit.Transaction.

⚠️ Breaking change

purchase(productID:) returns a StoreTransaction instead of a raw StoreKit.Transaction, on both PurchasesProtocol and PurchasesManager. The fields you were reading carry the same names, and the raw value stays reachable as .transaction.

If you are coming from 1.x, everything in 2.0.0 applies as well — see the migration notes in the README.

Why

StoreKit.Transaction has no public initializer and cannot be constructed at all. While purchase returned one, a stand-in implementation of PurchasesProtocol could only ever throw from it: the successful path was impossible to express, and therefore impossible to test against. That defeated the point of having a protocol to mock — 2.0 had already fixed the same problem for StoreProduct, but the one method that matters most for a paywall stayed untestable.

What StoreTransaction carries

Both identifiers, both purchase dates, expirationDate, revocationDate, isUpgraded, purchasedQuantity, appAccountToken and subscriptionGroupID — what entitlement code actually reads. Anything else is still reachable through the raw transaction.

The identity fields default to the transaction itself: a one-off purchase has no original distinct from itself, so originalID falls back to id and originalPurchaseDate to purchaseDate.

Verified

A consumer package building a mock against the public API only now returns a successful purchase, reports nil for the backing transaction, and still throws for an unknown identifier. Tests go from 24 in 5 suites to 30 in 6, including the case that could not be written before.