Files
purchases-ios/Tests/StoreKitUnitTests/StoreKitConfigTestCase.swift
T
NachoSoto 2fff5b0b75 CI: also run tests on watchOS (#2340)
This is a follow up to #717.
In order to be able to reproduce #2338, which seems to be an issue only
on `watchOS`, it's important that we now run tests on `watchOS` as well.
We probably won't be able to fully replicate that issue since we don't
run tests on actual devices, so they'll still run on 64 bits. But this
way we might be able to prevent issues that are only reproducible on
`watchOS` in the future.

## Changes:
- Added CircleCI job
- Added lane
- Simplified `UnitTestsHostApp` definition using `SwiftUI`
- Increased _test only_ `watchOS` deployment target to 7.0 (this was
necessary to be able to have a common `@main` for the host app)
- Increased _test only_ `tvOS` deployment target to `14.0` (same as
above, plus we only run tvOS tests on the latest version anyway. We test
backwards compatibility through iOS already)
- Fixed test compilation on `watchOS`
- Disabled `HTTPClient` tests on `watchOS` (see
https://github.com/AliSoftware/OHHTTPStubs/issues/287)
- `StoreKitConfigTestCase` is only available from `watchOS 7.0` since
that's when `SKTestSession` was introduced
- Added `watchOS` support to `UnitTests` target
- Added `watchOS` support to `ReceiptParserTests` target
- Fixed `isFamilySharable` `watchOS` version checks for version 8.0
- Created new `CI-RevenueCat` Test Plan to only run unit tests and not
StoreKit tests on `watchOS`
2023-03-16 13:11:24 -07:00

122 lines
3.7 KiB
Swift

//
// 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
//
// StoreKitConfigTestCase.swift
//
// Created by Andrés Boedo on 23/9/21.
import Foundation
import Nimble
@testable import RevenueCat
import StoreKitTest
import XCTest
/// Available from iOS 14.0 because that's when `SKTestSession` was introduced.
@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *)
class StoreKitConfigTestCase: TestCase {
static var requestTimeout: TimeInterval = 60
static var requestDispatchTimeout: DispatchTimeInterval {
return .seconds(Int(Self.requestTimeout))
}
private static var hasWaited = false
private static let waitLock = Lock()
private static let waitTimeInSeconds: Double? = {
ProcessInfo.processInfo.environment["CIRCLECI_STOREKIT_TESTS_DELAY_SECONDS"]
.flatMap(Double.init)
}()
var testSession: SKTestSession!
var userDefaults: UserDefaults!
@MainActor
override func setUp() async throws {
try await super.setUp()
try AvailabilityChecks.iOS14APIAvailableOrSkipTest()
self.testSession = try SKTestSession(configurationFileNamed: "UnitTestsConfiguration")
self.testSession.resetToDefaultState()
self.testSession.disableDialogs = true
self.testSession.clearTransactions()
if #available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *) {
await self.finishAllUnfinishedTransactions()
}
self.waitForStoreKitTestIfNeeded()
let suiteName = "StoreKitConfigTests"
self.userDefaults = UserDefaults(suiteName: suiteName)
self.userDefaults.removePersistentDomain(forName: suiteName)
}
override func tearDown() {
super.tearDown()
self.clearReceiptIfExists()
}
// MARK: - Transactions observation
private static var transactionsObservation: Task<Void, Never>?
override class func setUp() {
if #available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *) {
Self.transactionsObservation?.cancel()
Self.transactionsObservation = Task {
// Silence warning in tests:
// "Making a purchase without listening for transaction updates risks missing successful purchases.
for await _ in Transaction.updates {}
}
}
}
override class func tearDown() {
Self.transactionsObservation?.cancel()
Self.transactionsObservation = nil
}
}
@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *)
private extension StoreKitConfigTestCase {
func waitForStoreKitTestIfNeeded() {
// StoreKitTest seems to take a few seconds to initialize, and running tests before that
// might result in failure. So we give it a few seconds to load before testing.
guard let waitTime = Self.waitTimeInSeconds else { return }
Self.waitLock.perform {
if !Self.hasWaited {
Logger.warn("Delaying tests for \(waitTime) seconds for StoreKit initialization...")
Thread.sleep(forTimeInterval: waitTime)
Self.hasWaited = true
}
}
}
func clearReceiptIfExists() {
let manager = FileManager.default
guard let url = Bundle.main.appStoreReceiptURL, manager.fileExists(atPath: url.path) else { return }
do {
try manager.removeItem(at: url)
} catch {
Logger.appleWarning("Error attempting to remove receipt URL '\(url)': \(error)")
}
}
}