import React from 'react' import ReactTestRenderer, { act } from 'react-test-renderer' import { Platform } from 'react-native' jest.mock('../src/lib/auth-context', () => ({ useAuth: jest.fn() })) jest.mock('../src/lib/entitlement-context', () => ({ useEntitlement: jest.fn() })) jest.mock('../src/lib/native-config', () => ({ getMobileRuntimeConfig: jest.fn() })) jest.mock('../src/lib/supabase', () => ({ supabase: { functions: { invoke: jest.fn() } }, })) const mockedAuth = jest.requireMock('../src/lib/auth-context') as { useAuth: jest.Mock } const mockedEntitlement = jest.requireMock('../src/lib/entitlement-context') as { useEntitlement: jest.Mock } const mockedConfig = jest.requireMock('../src/lib/native-config') as { getMobileRuntimeConfig: jest.Mock } const mockedSupabase = jest.requireMock('../src/lib/supabase').supabase as { functions: { invoke: jest.Mock } } const mockedIap = jest.requireActual('react-native-iap') as { getAvailablePurchases: jest.Mock useIAP: jest.Mock __stableUseIapResult: Record & { restorePurchases: jest.Mock } } import { BillingProvider, useBilling } from '../src/lib/billing-context' const USER_ID = '11111111-1111-4111-8111-111111111111' const PURCHASE_ID = '22222222-2222-4222-8222-222222222222' const PRODUCT_ID = 'd3ro_voice_pro_monthly' const TOKEN = `play_${'a'.repeat(32)}` const originalPlatform = Platform.OS let latestBilling: ReturnType | null = null function Probe(): null { latestBilling = useBilling() return null } describe('BillingProvider explicit restore flow', () => { beforeAll(() => { Object.defineProperty(Platform, 'OS', { configurable: true, value: 'android' }) }) afterAll(() => { Object.defineProperty(Platform, 'OS', { configurable: true, value: originalPlatform }) }) beforeEach(() => { latestBilling = null mockedAuth.useAuth.mockReturnValue({ user: { id: USER_ID } }) mockedConfig.getMobileRuntimeConfig.mockReturnValue({ installedFromPlayStore: true }) mockedIap.__stableUseIapResult.restorePurchases.mockClear() mockedIap.__stableUseIapResult.connected = true mockedIap.__stableUseIapResult.subscriptions = [] mockedIap.useIAP.mockImplementation(() => mockedIap.__stableUseIapResult) mockedIap.getAvailablePurchases.mockReset().mockResolvedValue([{ id: 'order-1', productId: PRODUCT_ID, purchaseToken: TOKEN, purchaseState: 'purchased', store: 'google', transactionDate: Date.parse('2026-08-21T00:00:00.000Z'), quantity: 1, isAutoRenewing: true, packageNameAndroid: 'com.d3ro.voice', }]) mockedSupabase.functions.invoke.mockReset().mockResolvedValue({ data: { purchase: { purchase_id: PURCHASE_ID, acknowledged: true }, verification: { product_id: PRODUCT_ID, purchase_state: 'purchased', entitled: true, acknowledged: true, }, finish_transaction: false, server_acknowledged: true, }, error: null, }) mockedEntitlement.useEntitlement.mockReturnValue({ snapshot: { tier: 'free', provider: 'none', storeProductId: null, }, refresh: jest.fn(async () => ({ tier: 'pro', status: 'active', provider: 'google_play', paymentProvider: 'google_play', currentPeriodStart: '2026-08-21T00:00:00.000Z', currentPeriodEnd: '2026-09-21T00:00:00.000Z', cancelAt: null, autoRenewing: true, storeProductId: PRODUCT_ID, overageCredits: 0, usageToday: {}, purchases: [{ id: PURCHASE_ID, platform: 'google_play', productId: PRODUCT_ID, state: 'purchased', purchaseAt: '2026-08-21T00:00:00.000Z', expiresAt: '2026-09-21T00:00:00.000Z', autoRenewing: true, verifiedAt: '2026-08-21T00:00:01.000Z', }], adFree: true, refreshedAt: '2026-08-21T00:00:02.000Z', })), }) }) test('awaits the direct store list, server verification, and refreshed entitlement', async () => { let renderer: ReactTestRenderer.ReactTestRenderer await act(async () => { renderer = ReactTestRenderer.create( , ) await Promise.resolve() }) await act(async () => { await latestBilling!.restore() }) expect(latestBilling).toMatchObject({ connected: true, storeAvailable: true, operation: 'succeeded', errorCode: null, }) expect(mockedIap.getAvailablePurchases).toHaveBeenCalledWith({ includeSuspendedAndroid: true, }) expect(mockedIap.__stableUseIapResult.restorePurchases).not.toHaveBeenCalled() expect(mockedSupabase.functions.invoke).toHaveBeenCalledWith('iap-verify', { body: { platform: 'google_play', productId: PRODUCT_ID, purchaseToken: TOKEN, }, }) expect(mockedEntitlement.useEntitlement.mock.results[0].value.refresh) .toHaveBeenCalledTimes(1) act(() => renderer!.unmount()) }) })