Nudge-Screen
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import Testing
|
||||
@testable import bookstax
|
||||
import Foundation
|
||||
|
||||
// MARK: - DonationPurchaseState Enum
|
||||
|
||||
@Suite("DonationPurchaseState – Computed Properties")
|
||||
struct DonationPurchaseStateTests {
|
||||
|
||||
@Test("activePurchasingID returns id when purchasing")
|
||||
func activePurchasingID() {
|
||||
let state = DonationPurchaseState.purchasing(productID: "donatebook")
|
||||
#expect(state.activePurchasingID == "donatebook")
|
||||
}
|
||||
|
||||
@Test("activePurchasingID returns nil for non-purchasing states")
|
||||
@available(iOS 18.0, *)
|
||||
func activePurchasingIDNil() {
|
||||
#expect(DonationPurchaseState.idle.activePurchasingID == nil)
|
||||
#expect(DonationPurchaseState.thankYou(productID: "x").activePurchasingID == nil)
|
||||
#expect(DonationPurchaseState.pending(productID: "x").activePurchasingID == nil)
|
||||
#expect(DonationPurchaseState.failed(productID: "x", message: "err").activePurchasingID == nil)
|
||||
}
|
||||
|
||||
@Test("thankYouID returns id when in thankYou state")
|
||||
func thankYouID() {
|
||||
let state = DonationPurchaseState.thankYou(productID: "doneatepage")
|
||||
#expect(state.thankYouID == "doneatepage")
|
||||
}
|
||||
|
||||
@Test("thankYouID returns nil for other states")
|
||||
func thankYouIDNil() {
|
||||
#expect(DonationPurchaseState.idle.thankYouID == nil)
|
||||
#expect(DonationPurchaseState.purchasing(productID: "x").thankYouID == nil)
|
||||
}
|
||||
|
||||
@Test("pendingID returns id when in pending state")
|
||||
func pendingID() {
|
||||
let state = DonationPurchaseState.pending(productID: "donateencyclopaedia")
|
||||
#expect(state.pendingID == "donateencyclopaedia")
|
||||
}
|
||||
|
||||
@Test("pendingID returns nil for other states")
|
||||
func pendingIDNil() {
|
||||
#expect(DonationPurchaseState.idle.pendingID == nil)
|
||||
#expect(DonationPurchaseState.thankYou(productID: "x").pendingID == nil)
|
||||
}
|
||||
|
||||
@Test("errorMessage returns message when failed for matching id")
|
||||
func errorMessageMatch() {
|
||||
let state = DonationPurchaseState.failed(productID: "donatebook", message: "Payment declined")
|
||||
#expect(state.errorMessage(for: "donatebook") == "Payment declined")
|
||||
}
|
||||
|
||||
@Test("errorMessage returns nil for wrong product id")
|
||||
func errorMessageNoMatch() {
|
||||
let state = DonationPurchaseState.failed(productID: "donatebook", message: "error")
|
||||
#expect(state.errorMessage(for: "doneatepage") == nil)
|
||||
}
|
||||
|
||||
@Test("errorMessage returns nil for non-failed states")
|
||||
func errorMessageNotFailed() {
|
||||
#expect(DonationPurchaseState.idle.errorMessage(for: "x") == nil)
|
||||
#expect(DonationPurchaseState.purchasing(productID: "x").errorMessage(for: "x") == nil)
|
||||
}
|
||||
|
||||
@Test("isIdle returns true only for .idle")
|
||||
func isIdleCheck() {
|
||||
#expect(DonationPurchaseState.idle.isIdle == true)
|
||||
#expect(DonationPurchaseState.purchasing(productID: "x").isIdle == false)
|
||||
#expect(DonationPurchaseState.thankYou(productID: "x").isIdle == false)
|
||||
#expect(DonationPurchaseState.failed(productID: "x", message: "e").isIdle == false)
|
||||
}
|
||||
|
||||
@Test("Equatable: same purchasing states are equal")
|
||||
func equatablePurchasing() {
|
||||
#expect(DonationPurchaseState.purchasing(productID: "a") == DonationPurchaseState.purchasing(productID: "a"))
|
||||
#expect(DonationPurchaseState.purchasing(productID: "a") != DonationPurchaseState.purchasing(productID: "b"))
|
||||
}
|
||||
|
||||
@Test("Equatable: idle equals idle")
|
||||
func equatableIdle() {
|
||||
#expect(DonationPurchaseState.idle == DonationPurchaseState.idle)
|
||||
#expect(DonationPurchaseState.idle != DonationPurchaseState.purchasing(productID: "x"))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - shouldShowNudge Timing
|
||||
|
||||
@Suite("DonationService – shouldShowNudge", .serialized)
|
||||
@MainActor
|
||||
struct DonationServiceNudgeTests {
|
||||
|
||||
private let installKey = "bookstax.installDate"
|
||||
private let nudgeKey = "bookstax.lastNudgeDate"
|
||||
private let historyKey = "bookstax.donationHistory"
|
||||
|
||||
init() {
|
||||
// Clean UserDefaults before each test so DonationService reads fresh state
|
||||
UserDefaults.standard.removeObject(forKey: installKey)
|
||||
UserDefaults.standard.removeObject(forKey: nudgeKey)
|
||||
UserDefaults.standard.removeObject(forKey: historyKey)
|
||||
}
|
||||
|
||||
@Test("Within 3-day grace period: nudge should not show")
|
||||
func gracePeriodPreventsNudge() {
|
||||
let recentInstall = Date().addingTimeInterval(-(2 * 24 * 3600)) // 2 days ago
|
||||
UserDefaults.standard.set(recentInstall, forKey: installKey)
|
||||
#expect(DonationService.shared.shouldShowNudge == false)
|
||||
}
|
||||
|
||||
@Test("After 3-day grace period: nudge should show")
|
||||
func afterGracePeriodNudgeShows() {
|
||||
let oldInstall = Date().addingTimeInterval(-(4 * 24 * 3600)) // 4 days ago
|
||||
UserDefaults.standard.set(oldInstall, forKey: installKey)
|
||||
#expect(DonationService.shared.shouldShowNudge == true)
|
||||
}
|
||||
|
||||
@Test("No install date recorded: nudge should not show (safe fallback)")
|
||||
func noInstallDateFallback() {
|
||||
// No install date stored — graceful fallback
|
||||
#expect(DonationService.shared.shouldShowNudge == false)
|
||||
}
|
||||
|
||||
@Test("Nudge recently dismissed: should not show again")
|
||||
func recentNudgeHidden() {
|
||||
let oldInstall = Date().addingTimeInterval(-(90 * 24 * 3600))
|
||||
let recentNudge = Date().addingTimeInterval(-(10 * 24 * 3600)) // dismissed 10 days ago
|
||||
UserDefaults.standard.set(oldInstall, forKey: installKey)
|
||||
UserDefaults.standard.set(recentNudge, forKey: nudgeKey)
|
||||
#expect(DonationService.shared.shouldShowNudge == false)
|
||||
}
|
||||
|
||||
@Test("Nudge dismissed ~6 months ago: should show again")
|
||||
func sixMonthsLaterShowAgain() {
|
||||
let oldInstall = Date().addingTimeInterval(-(200 * 24 * 3600))
|
||||
let oldNudge = Date().addingTimeInterval(-(183 * 24 * 3600)) // ~6 months ago
|
||||
UserDefaults.standard.set(oldInstall, forKey: installKey)
|
||||
UserDefaults.standard.set(oldNudge, forKey: nudgeKey)
|
||||
#expect(DonationService.shared.shouldShowNudge == true)
|
||||
}
|
||||
|
||||
@Test("Nudge not yet 6 months: should not show")
|
||||
func beforeSixMonthsHidden() {
|
||||
let oldInstall = Date().addingTimeInterval(-(200 * 24 * 3600))
|
||||
let recentNudge = Date().addingTimeInterval(-(100 * 24 * 3600)) // only 100 days
|
||||
UserDefaults.standard.set(oldInstall, forKey: installKey)
|
||||
UserDefaults.standard.set(recentNudge, forKey: nudgeKey)
|
||||
#expect(DonationService.shared.shouldShowNudge == false)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user