import { describe, it, expect } from 'vitest' /** * PR #669 測試: 防止 null token 導致未授權的 API 調用 * * 問題:當用戶未登入時(user/token 為 null),SWR 仍然會使用空 key 發起 API 請求 * 修復:在 SWR key 中添加 `user && token` 檢查,當未登入時返回 null,阻止 API 調用 */ describe('API Guard Logic (PR #669)', () => { /** * 測試 SWR key 生成邏輯 * 核心修復:key 必須包含 user && token 檢查 */ describe('SWR key generation', () => { it('should return null when user is null', () => { const user = null const token = 'valid-token' const traderId = '123' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should return null when token is null', () => { const user = { id: '1', email: 'test@example.com' } const token = null const traderId = '123' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should return null when both user and token are null', () => { const user = null const token = null const traderId = '123' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should return null when currentPage is not trader', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = '123' const currentPage: string = 'competition' // Not 'trader', so key should be null const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should return null when traderId is not set', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = null const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should return valid key when all conditions are met', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = '123' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBe('status-123') }) }) /** * 測試不同 API 端點的條件邏輯 * 所有需要認證的端點都應該檢查 user && token */ describe('multiple API endpoints', () => { it('should guard status API', () => { const user = null const token = null const traderId = '123' const currentPage = 'trader' const statusKey = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(statusKey).toBeNull() }) it('should guard account API', () => { const user = null const token = null const traderId = '123' const currentPage = 'trader' const accountKey = user && token && currentPage === 'trader' && traderId ? `account-${traderId}` : null expect(accountKey).toBeNull() }) it('should guard positions API', () => { const user = null const token = null const traderId = '123' const currentPage = 'trader' const positionsKey = user && token && currentPage === 'trader' && traderId ? `positions-${traderId}` : null expect(positionsKey).toBeNull() }) it('should guard decisions API', () => { const user = null const token = null const traderId = '123' const currentPage = 'trader' const decisionsKey = user && token && currentPage === 'trader' && traderId ? `decisions/latest-${traderId}` : null expect(decisionsKey).toBeNull() }) it('should guard statistics API', () => { const user = null const token = null const traderId = '123' const currentPage = 'trader' const statsKey = user && token && currentPage === 'trader' && traderId ? `statistics-${traderId}` : null expect(statsKey).toBeNull() }) it('should allow all API calls when authenticated', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = '123' const currentPage = 'trader' const statusKey = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null const accountKey = user && token && currentPage === 'trader' && traderId ? `account-${traderId}` : null const positionsKey = user && token && currentPage === 'trader' && traderId ? `positions-${traderId}` : null expect(statusKey).toBe('status-123') expect(accountKey).toBe('account-123') expect(positionsKey).toBe('positions-123') }) }) /** * 測試 EquityChart 組件的條件邏輯 * PR #669 同時修復了 EquityChart 中的相同問題 */ describe('EquityChart API guard', () => { it('should return null key when user is not authenticated', () => { const user = null const token = null const traderId = '123' const equityKey = user && token && traderId ? `equity-history-${traderId}` : null expect(equityKey).toBeNull() }) it('should return null key when traderId is missing', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = null const equityKey = user && token && traderId ? `equity-history-${traderId}` : null expect(equityKey).toBeNull() }) it('should return valid key when authenticated with traderId', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = '123' const equityKey = user && token && traderId ? `equity-history-${traderId}` : null const accountKey = user && token && traderId ? `account-${traderId}` : null expect(equityKey).toBe('equity-history-123') expect(accountKey).toBe('account-123') }) }) /** * 測試邊界情況和特殊值 */ describe('edge cases', () => { it('should treat empty string token as falsy', () => { const user = { id: '1', email: 'test@example.com' } const token = '' const traderId = '123' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should treat empty string traderId as falsy', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = '' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should handle undefined user', () => { const user = undefined const token = 'valid-token' const traderId = '123' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should handle undefined token', () => { const user = { id: '1', email: 'test@example.com' } const token = undefined const traderId = '123' const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() }) it('should handle numeric traderId', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = 123 // 數字而非字串 const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBe('status-123') }) it('should handle zero traderId as falsy', () => { const user = { id: '1', email: 'test@example.com' } const token = 'valid-token' const traderId = 0 const currentPage = 'trader' const key = user && token && currentPage === 'trader' && traderId ? `status-${traderId}` : null expect(key).toBeNull() // 0 is falsy }) }) /** * 測試防止 API 調用的邏輯流程 */ describe('API call prevention flow', () => { it('should prevent API call when key is null', () => { const key = null const shouldCallAPI = key !== null expect(shouldCallAPI).toBe(false) }) it('should allow API call when key is valid', () => { const key = 'status-123' const shouldCallAPI = key !== null expect(shouldCallAPI).toBe(true) }) it('should simulate SWR behavior with null key', () => { // SWR 不會在 key 為 null 時發起請求 const key = null const fetcher = (k: string) => `API response for ${k}` // 模擬 SWR 行為:key 為 null 時不調用 fetcher const data = key ? fetcher(key) : undefined expect(data).toBeUndefined() }) it('should simulate SWR behavior with valid key', () => { const key = 'status-123' const fetcher = (k: string) => `API response for ${k}` const data = key ? fetcher(key) : undefined expect(data).toBe('API response for status-123') }) }) })