const mockClearHistory = jest.fn() const mockClearEntitlements = jest.fn() const mockClearPreferences = jest.fn() const mockCancelRecorder = jest.fn() const mockClearQueuedAudio = jest.fn() const mockClearActions = jest.fn() const mockClearGenerationKeys = jest.fn() const mockDeletePush = jest.fn() jest.mock('../src/features/history/history-cache', () => ({ clearAllHistoryCaches: () => mockClearHistory(), })) jest.mock('../src/lib/entitlement-context', () => ({ clearAllEntitlementCaches: () => mockClearEntitlements(), })) jest.mock('../src/lib/preferences-context', () => ({ clearAllUserPreferenceCaches: () => mockClearPreferences(), })) jest.mock('../src/lib/audio-recorder', () => ({ audioRecorder: { cancel: () => mockCancelRecorder() }, })) jest.mock('../src/features/recording/durable-processing-queue', () => ({ clearAllQueuedAudio: () => mockClearQueuedAudio(), })) jest.mock('../src/features/actions/action-service', () => ({ clearAllActionHistories: () => mockClearActions(), })) jest.mock('../src/features/templates', () => ({ clearEveryGenerationIdempotencyKey: () => mockClearGenerationKeys(), })) jest.mock('../src/features/notifications/notification-native', () => ({ deleteNativePushRegistration: () => mockDeletePush(), })) import { AccountLocalDataPurgeError, purgeAllAccountLocalData, } from '../src/lib/account-local-data' const operations = [ mockClearHistory, mockClearEntitlements, mockClearPreferences, mockCancelRecorder, mockClearQueuedAudio, mockClearActions, mockClearGenerationKeys, mockDeletePush, ] describe('account local privacy purge', () => { beforeEach(() => { for (const operation of operations) operation.mockReset().mockResolvedValue(undefined) }) it('awaits every account-scoped cleanup operation', async () => { await expect(purgeAllAccountLocalData()).resolves.toBeUndefined() for (const operation of operations) expect(operation).toHaveBeenCalledTimes(1) }) it('finishes the remaining cleanup work and returns a stable failure', async () => { let finishQueueCleanup: (() => void) | null = null mockClearHistory.mockRejectedValue(new Error('private filesystem detail')) mockClearQueuedAudio.mockReturnValue(new Promise((resolve) => { finishQueueCleanup = resolve })) const purge = purgeAllAccountLocalData() let settled = false void purge.finally(() => { settled = true }).catch(() => undefined) await Promise.resolve() expect(settled).toBe(false) finishQueueCleanup?.() await expect(purge).rejects.toBeInstanceOf(AccountLocalDataPurgeError) await expect(purge).rejects.not.toThrow('private filesystem detail') for (const operation of operations) expect(operation).toHaveBeenCalledTimes(1) }) it('single-flights concurrent privacy boundaries and allows a later retry', async () => { let finishQueueCleanup: (() => void) | null = null mockClearQueuedAudio.mockReturnValueOnce(new Promise((resolve) => { finishQueueCleanup = resolve })) const first = purgeAllAccountLocalData() const concurrent = purgeAllAccountLocalData() expect(concurrent).toBe(first) for (const operation of operations) expect(operation).toHaveBeenCalledTimes(1) finishQueueCleanup?.() await expect(Promise.all([first, concurrent])).resolves.toEqual([undefined, undefined]) await expect(purgeAllAccountLocalData()).resolves.toBeUndefined() for (const operation of operations) expect(operation).toHaveBeenCalledTimes(2) }) })