import { api } from '@/lib/api'; // Mock localStorage const localStorageMock = (() => { let store: Record = {}; return { getItem: (key: string) => store[key] || null, setItem: (key: string, value: string) => { store[key] = value.toString(); }, removeItem: (key: string) => { delete store[key]; }, clear: () => { store = {}; }, }; })(); Object.defineProperty(window, 'localStorage', { value: localStorageMock, }); // Mock crypto.getRandomValues Object.defineProperty(global, 'crypto', { value: { getRandomValues: (arr: Uint8Array) => { for (let i = 0; i < arr.length; i++) { arr[i] = Math.floor(Math.random() * 256); } return arr; }, }, }); describe('API Service', () => { beforeEach(() => { localStorageMock.clear(); jest.clearAllMocks(); }); describe('Token Management', () => { it('should save and retrieve access token', async () => { const testToken = 'test-jwt-token'; localStorageMock.setItem('accessToken', testToken); const token = await api.getToken(); expect(token).toBe(testToken); }); it('should return null when no token exists', async () => { const token = await api.getToken(); expect(token).toBeNull(); }); }); describe('Email Management', () => { it('should save and retrieve email', async () => { const testEmail = 'test@example.com'; await api.saveEmail(testEmail); const email = await api.getStoredEmail(); expect(email).toBe(testEmail); }); it('should return null when no email is stored', async () => { const email = await api.getStoredEmail(); expect(email).toBeNull(); }); }); describe('Onboarding Status', () => { it('should save and retrieve onboarding completed flag', async () => { await api.setOnboardingCompleted(true); let isCompleted = await api.isOnboardingCompleted(); expect(isCompleted).toBe(true); await api.setOnboardingCompleted(false); isCompleted = await api.isOnboardingCompleted(); expect(isCompleted).toBe(false); }); it('should return false when onboarding flag is not set', async () => { const isCompleted = await api.isOnboardingCompleted(); expect(isCompleted).toBe(false); }); }); describe('Authentication Status', () => { it('should return true when token exists', async () => { localStorageMock.setItem('accessToken', 'test-token'); const isAuth = await api.isAuthenticated(); expect(isAuth).toBe(true); }); it('should return false when token does not exist', async () => { const isAuth = await api.isAuthenticated(); expect(isAuth).toBe(false); }); }); describe('Logout', () => { it('should clear all stored data', async () => { // Set up some data localStorageMock.setItem('accessToken', 'token'); localStorageMock.setItem('userId', '123'); localStorageMock.setItem('userEmail', 'test@example.com'); localStorageMock.setItem('legacyAccessToken', 'legacy-token'); await api.logout(); // Verify all data is cleared expect(localStorageMock.getItem('accessToken')).toBeNull(); expect(localStorageMock.getItem('userId')).toBeNull(); expect(localStorageMock.getItem('userEmail')).toBeNull(); expect(localStorageMock.getItem('legacyAccessToken')).toBeNull(); }); }); describe('Check Email', () => { it('should call the API with correct endpoint', async () => { global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve({ exists: true }), }) ) as jest.Mock; const result = await api.checkEmail('test@example.com'); expect(global.fetch).toHaveBeenCalledWith( 'https://wellnuo.smartlaunchhub.com/api/auth/check-email', expect.objectContaining({ method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'test@example.com' }), }) ); expect(result.ok).toBe(true); expect(result.data?.exists).toBe(true); }); it('should handle network errors', async () => { global.fetch = jest.fn(() => Promise.reject(new Error('Network error')) ) as jest.Mock; const result = await api.checkEmail('test@example.com'); expect(result.ok).toBe(false); expect(result.error?.message).toContain('Network error'); }); }); describe('Data Sync - Same Backend as Mobile App', () => { const WELLNUO_API_URL = 'https://wellnuo.smartlaunchhub.com/api'; it('should fetch beneficiaries from WellNuo API', async () => { const testToken = 'valid-jwt-token'; localStorageMock.setItem('accessToken', testToken); const mockBeneficiaries = { beneficiaries: [ { id: 1, name: 'John Doe', displayName: 'John Doe', email: 'john@example.com', equipmentStatus: 'active', hasDevices: true, }, ], }; global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve(mockBeneficiaries), }) ) as jest.Mock; const result = await api.getAllBeneficiaries(); expect(global.fetch).toHaveBeenCalledWith( `${WELLNUO_API_URL}/me/beneficiaries`, expect.objectContaining({ method: 'GET', headers: { 'Authorization': `Bearer ${testToken}`, }, }) ); expect(result.ok).toBe(true); expect(result.data).toHaveLength(1); expect(result.data?.[0].id).toBe(1); expect(result.data?.[0].displayName).toBe('John Doe'); }); it('should fetch user profile from WellNuo API', async () => { const testToken = 'valid-jwt-token'; localStorageMock.setItem('accessToken', testToken); const mockProfile = { id: 42, email: 'user@example.com', firstName: 'Test', lastName: 'User', phone: '+1234567890', user: { id: 42, email: 'user@example.com', firstName: 'Test', lastName: 'User', }, }; global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve(mockProfile), }) ) as jest.Mock; const result = await api.getProfile(); expect(global.fetch).toHaveBeenCalledWith( `${WELLNUO_API_URL}/auth/me`, expect.objectContaining({ method: 'GET', headers: { 'Authorization': `Bearer ${testToken}`, }, }) ); expect(result.ok).toBe(true); expect(result.data?.email).toBe('user@example.com'); expect(result.data?.firstName).toBe('Test'); }); it('should update profile via WellNuo API', async () => { const testToken = 'valid-jwt-token'; localStorageMock.setItem('accessToken', testToken); const mockResponse = { id: 42, email: 'user@example.com', firstName: 'Updated', lastName: 'Name', phone: '+1234567890', }; global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve(mockResponse), }) ) as jest.Mock; const result = await api.updateProfile({ firstName: 'Updated', lastName: 'Name', }); expect(global.fetch).toHaveBeenCalledWith( `${WELLNUO_API_URL}/auth/profile`, expect.objectContaining({ method: 'PATCH', headers: { 'Authorization': `Bearer ${testToken}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ firstName: 'Updated', lastName: 'Name' }), }) ); expect(result.ok).toBe(true); expect(result.data?.firstName).toBe('Updated'); }); it('should create beneficiary via WellNuo API', async () => { const testToken = 'valid-jwt-token'; localStorageMock.setItem('accessToken', testToken); const mockResponse = { beneficiary: { id: 123, name: 'New Beneficiary', }, }; global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve(mockResponse), }) ) as jest.Mock; const result = await api.createBeneficiary({ name: 'New Beneficiary', phone: '+1234567890', }); expect(global.fetch).toHaveBeenCalledWith( `${WELLNUO_API_URL}/me/beneficiaries`, expect.objectContaining({ method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${testToken}`, }, }) ); expect(result.ok).toBe(true); expect(result.data?.id).toBe(123); expect(result.data?.name).toBe('New Beneficiary'); }); it('should delete beneficiary via WellNuo API', async () => { const testToken = 'valid-jwt-token'; localStorageMock.setItem('accessToken', testToken); global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }), }) ) as jest.Mock; const result = await api.deleteBeneficiary(123); expect(global.fetch).toHaveBeenCalledWith( `${WELLNUO_API_URL}/me/beneficiaries/123`, expect.objectContaining({ method: 'DELETE', headers: { 'Authorization': `Bearer ${testToken}`, }, }) ); expect(result.ok).toBe(true); expect(result.data?.success).toBe(true); }); it('should handle 401 unauthorized by triggering callback', async () => { const testToken = 'expired-token'; localStorageMock.setItem('accessToken', testToken); global.fetch = jest.fn(() => Promise.resolve({ ok: false, status: 401, json: () => Promise.resolve({ error: 'Unauthorized' }), }) ) as jest.Mock; const result = await api.getAllBeneficiaries(); expect(result.ok).toBe(false); expect(result.error?.code).toBe('UNAUTHORIZED'); }); }); });