* Introduce PurchaseParams to allow passing extra configuration info when making a purchase
* simplify naming
* fallback to old method when flag is not enabled
* Add $(inherited) to the test targets so they pick up compiler flags from Local.xcconfig
* Include product/package inside PurchaseParams
* fix tests
* add compiler flag check
* update purchase tester
* fix docs
* add tests
* Update Sources/Networking/Operations/PostReceiptDataOperation.swift
Co-authored-by: Toni Rico <toni.rico.diez@revenuecat.com>
---------
Co-authored-by: Toni Rico <toni.rico.diez@revenuecat.com>
### Description
This moves the offline backend integration tests to run on M1 machines
in CircleCI.
Since this causes tests to be much more flaky, this includes a
cherry-pick of the changes in the 5.0 branch that improves those:
https://github.com/RevenueCat/purchases-ios/pull/3902
---------
Co-authored-by: Josh Holtz <me@joshholtz.com>
Co-authored-by: Will Taylor <wtaylor151@gmail.com>
Co-authored-by: Andy Boedo <andresboedo@gmail.com>
Follow up to #3599 and #3600.
These `@MainActor` annotations don't work anymore because of this:
> Main actor-isolated class '...' has different actor isolation from
nonisolated superclass 'TestCase'; this is an error in Swift 6
They were necessary with an older version of Xcode (likely 13.x), but
not anymore.
---------
Co-authored-by: Mark Villacampa <m@markvillacampa.com>
This modifies `BaseStoreKitIntegrationTests.printReceipt` to also log
`StoreKit 2` transactions which can be used to debug failures of
`OfflineStoreKitIntegrationTests`.
`PurchasedProductsFetcher` also logs how many `currentEntitlements` it
found since failures are coming from there.
Good news: offline entitlements are amazing, and our SDK is very
resilient to the backend being down.
Bad news: this is kind of a false positive, this behavior is already
verified by `OfflineStoreKitIntegrationTests`.
I refactored `BaseStoreKitIntegrationTests` because it had grown a lot.
I put this verification in the `purchase` methods so all tests benefit
from this.
So that `OfflineStoreKitIntegrationTests` don't fail, I added a
parameter to ignore that verification in those tests.
There were some questions about these in #2841, and realized we had no
test coverage for them.
This also improves the documentation of `CustomerInfo.nonSubscriptions`
and `NonSubscriptionTransaction`.
This adds tests and a fix for a scenario discovered by @aboedo and
@mcastany.
### Timeline:
- Make a purchase of product_1
- Close app
- Renewals happen in the background
- Subscription expires
- Open app, renewals are in the queue but not processed yet
- Start a purchase of `product_1` (`SKPaymentQueue.add`)
- StoreKit queue shows renewal from step 3 as finished, it's expired
- SDK sees finished transaction in the queue for `product_1`
- SDK sees completion block for `product_1`, considers it a successful
`.purchase`
- SDK posts receipt, `initiation_source: .purchase` 💥
- Backend replies with 422 because StoreKit hasn't processed the
transaction from 6
### Fix:
The fix looks at the date when the completion block was added (the time
`.purchase()` is called).
If the transaction was created _before_ this, we know it didn't come
from the actual purchase, and therefore it should be identified as
`.queue`.
This extracts the purchasing code into a new `ExternalPurchasesManager`
and `ObserverModeManager`, which can be used to perform purchases
without using the SDK.
I've also bumped the deployment target of integration tests to 15.0 to
simplify the code.
This is a similar change to #2532.
I noticed yet another source of crashes in our integration tests.
This is what [the
result](https://app.circleci.com/pipelines/github/RevenueCat/purchases-ios/13247/workflows/52fd2014-7a19-442f-a572-64116393abec/jobs/94728)
was:
```
failed - Message 'Finishing transaction' should not have been logged
expected to not find object in collection that satisfies predicate
```
That came from this code:
```swift
self.logger.verifyMessageWasNotLogged("Finishing transaction")
let info1 = try await Purchases.shared.customerInfo()
```
After that assertion failure, `XCTest` continued execution, while it had
already tear down `Purchases`, which lead to this crash:
```
Thread 0 Crashed:
0 libswiftCore.dylib 0x103b84e81 _assertionFailure(_:_:file:line:flags:) + 353
1 RevenueCat 0x1332516d0 static Purchases.shared.getter + 352 (Purchases.swift:65)
2 BackendIntegrationTests 0x130f7048a OfflineStoreKit1IntegrationTests.testPurchaseWhileServerIsDownPostsReceiptWhenForegroundingApp() + 362 (OfflineStoreKitIntegrationTests.swift:289)
3 BackendIntegrationTests 0x130f75ee1 @objc closure #1 in OfflineStoreKit1IntegrationTests.testPurchaseWhileServerIsDownPostsReceiptWhenForegroundingApp() + 1
4 BackendIntegrationTests 0x130f77d91 partial apply for @objc closure #1 in OfflineStoreKit1IntegrationTests.testPurchaseWhileServerIsDownPostsReceiptWhenForegroundingApp() + 1
```
To prevent this, instead of using `Purchases.shared` this replaces that
with a throwing `self.purchases`.
Just like we don't use force-unwraps in tests and instead use
`XCTUwnrap`, this now will fail the test instead of crashing it.
Trying to work around `FB11799675`, this was suggested by @joshdholtz
and it seems to be working really well. This now calls
`deleteAllTransactions` and `SKTestSession.clearTransactions` _after_
every test, not only before.
The problem is that `clearTransactions` only seems to delete stuff from
`SKTestSession.allTransactions`, but not from
`StoreKit.Transaction.unfinished`. Doing this at the end of every test
seems to do a much better job at ensuring that each test invocation has
no leftover transaction, hopefully leading to fewer flaky failures.
Fixes SDK-3158.
### Changes:
- Added new `BackendCustomEntitlementsIntegrationTests` target that
depends on the `RevenueCat_CustomEntitlementComputation` SPM
- Updated `BaseBackendIntegrationTests` and
`BaseStoreKitIntegrationTests` to support
`RevenueCat_CustomEntitlementComputation`
- Added `CustomEntitlementsComputationIntegrationTests` with custom
`Purchases.configureInCustomEntitlementsComputationMode` initialization
- Added integration tests for basic operations
- Verify that none of those integration tests ever use
`GetCustomerInfoOperation`
- Added `testGetCustomerInfo` to `OtherIntegrationTests` (we didn't have
an explicit test for this)
### TODO:
- [x] Verify v3 integration tests
- [x] Verify SPM commit is updated when running tests
- Fixes [TRIAGE-221] for `SK1`.
- Filed `FB11889732` for `SK2`.
### Changes:
- Added 2 `IntroEligibilityCalculatorTests` unit tests to cover this
scenario
- Added 1 `IntroEligibilityCalculatorTests` unit tests to cover the
equivalent of the `testIneligibleForIntroAfterPurchaseExpires`
integration test
- Added 2 `StoreKitIntegrationTests` to cover this scenario (one of them
disabled in SK2)
- Updated `IntroEligibilityCalculator` logic to fix the new tests.
- Refactored `IntroEligibilityCalculatorTests` to avoid duplication and
allow adding new cases more easily.
- Added a few more tests to ensure other cases are correct.
[TRIAGE-221]:
https://revenuecats.atlassian.net/browse/TRIAGE-221?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
With #2069 this file grew up a bit too much.
This splits up `BaseStoreKitIntegrationTests` and
`StoreKitObserverModeIntegrationTests` to make them more maintainable.