/** * NavigationWrapper Component Tests * * 測試目標: * 1. 元件能正確渲染 * 2. 元件能正確呼叫廠商 navigation.js * 3. 元件卸載時能正確 cleanup */ import React from 'react'; import { render, waitFor, cleanup as rtlCleanup } from '@testing-library/react'; import NavigationWrapper from '@/components/aia/navigation-wrapper'; import * as vendorNavigation from '@vendor-web/js/patterns/navigation.js'; // Mock 廠商 navigation.js jest.mock('@vendor-web/js/patterns/navigation.js', () => ({ navigation: jest.fn(), })); describe('NavigationWrapper Component', () => { let mockCleanup: jest.Mock; beforeEach(() => { mockCleanup = jest.fn(); (vendorNavigation.navigation as jest.Mock).mockReturnValue(mockCleanup); }); afterEach(() => { rtlCleanup(); jest.clearAllMocks(); }); it('應該渲染 navigation 和 children', () => { const { getByText } = render( ); expect(getByText('Home')).toBeInTheDocument(); expect(getByText('About')).toBeInTheDocument(); }); it('應該呼叫廠商 navigation 初始化函式', async () => { render( ); await waitFor(() => { expect(vendorNavigation.navigation).toHaveBeenCalledTimes(1); }); }); it('應該在元件卸載時呼叫 cleanup 函式', async () => { const { unmount } = render( ); await waitFor(() => { expect(vendorNavigation.navigation).toHaveBeenCalled(); }); unmount(); expect(mockCleanup).toHaveBeenCalledTimes(1); }); it('應該能處理廠商 JS 未返回 cleanup 的情況', async () => { (vendorNavigation.navigation as jest.Mock).mockReturnValue(undefined); const { unmount } = render( ); // 不應該拋出錯誤 expect(() => unmount()).not.toThrow(); }); it('應該支援自訂 className', () => { const { container } = render( ); expect(container.firstChild).toHaveClass('custom-nav'); }); it('應該設定預設空字串 className', () => { const { container } = render( ); // 檢查元素存在但沒有特定 class(空字串) expect(container.firstChild).toBeInTheDocument(); expect(container.firstChild).not.toHaveClass('custom-nav'); }); });