import { setPaymentPending, getPaymentPending, clearPaymentPending } from './payment-utils'; const STORAGE_KEY = 'masterpass_rest_payment_pending'; const TTL_MS = 30 * 60 * 1000; describe('payment pending record', () => { it('reports nothing pending when no payment has started', () => { expect(getPaymentPending()).toBeNull(); }); it('remembers the order number the transaction was opened with', () => { setPaymentPending('ORDER-123'); expect(getPaymentPending()).toEqual({ orderNo: 'ORDER-123', startedAt: expect.any(Number) }); }); it('still marks a payment pending when no order number is known', () => { setPaymentPending(null); const record = getPaymentPending(); expect(record).not.toBeNull(); expect(record?.orderNo).toBeNull(); }); it('stops reporting pending once cleared', () => { setPaymentPending('ORDER-123'); clearPaymentPending(); expect(getPaymentPending()).toBeNull(); expect(window.sessionStorage.getItem(STORAGE_KEY)).toBeNull(); }); it('keeps a record that is still inside the ttl', () => { window.sessionStorage.setItem( STORAGE_KEY, JSON.stringify({ orderNo: 'ORDER-123', startedAt: Date.now() - TTL_MS + 60_000 }) ); expect(getPaymentPending()?.orderNo).toBe('ORDER-123'); }); it('expires and purges a record past the ttl so an abandoned tab recovers', () => { window.sessionStorage.setItem( STORAGE_KEY, JSON.stringify({ orderNo: 'ORDER-123', startedAt: Date.now() - TTL_MS - 1 }) ); expect(getPaymentPending()).toBeNull(); expect(window.sessionStorage.getItem(STORAGE_KEY)).toBeNull(); }); it('treats an unparseable record as not pending', () => { window.sessionStorage.setItem(STORAGE_KEY, 'not-json'); expect(getPaymentPending()).toBeNull(); }); it('treats a record without a timestamp as not pending', () => { window.sessionStorage.setItem( STORAGE_KEY, JSON.stringify({ orderNo: 'ORDER-123' }) ); expect(getPaymentPending()).toBeNull(); }); it('degrades quietly when session storage is unavailable', () => { const proto = Object.getPrototypeOf(window.sessionStorage); const boom = () => { throw new Error('storage disabled'); }; jest.spyOn(proto, 'setItem').mockImplementation(boom); jest.spyOn(proto, 'getItem').mockImplementation(boom); jest.spyOn(proto, 'removeItem').mockImplementation(boom); expect(() => setPaymentPending('ORDER-123')).not.toThrow(); expect(getPaymentPending()).toBeNull(); expect(() => clearPaymentPending()).not.toThrow(); jest.restoreAllMocks(); }); });