import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { vi, test, expect, beforeEach } from 'vitest';
import FileExplorer from '../../src/components/FileExplorer';
import { listDocuments } from '../../src/api/client';
vi.mock('../../src/api/client');
beforeEach(() => {
vi.mocked(listDocuments).mockReset();
});
test('renders folders and files returned by listDocuments for the root path', async () => {
vi.mocked(listDocuments).mockResolvedValue({
folders: ['产品文档'],
files: [{ key: '需求说明.md', name: '需求说明.md', size: 100, modifiedAt: '2026-08-01T10:00:00Z' }],
});
render();
expect(await screen.findByText('产品文档')).toBeInTheDocument();
expect(await screen.findByText('需求说明.md')).toBeInTheDocument();
expect(listDocuments).toHaveBeenCalledWith('');
});
test('clicking a file calls onSelectFile with its key', async () => {
vi.mocked(listDocuments).mockResolvedValue({
folders: [],
files: [{ key: '架构设计.md', name: '架构设计.md', size: 200, modifiedAt: '2026-08-01T10:00:00Z' }],
});
const onSelectFile = vi.fn();
render();
const fileRow = await screen.findByText('架构设计.md');
fireEvent.click(fileRow);
expect(onSelectFile).toHaveBeenCalledWith('架构设计.md');
});
test('clicking a folder loads and shows its nested contents', async () => {
vi.mocked(listDocuments).mockImplementation((path: string) => {
if (path === '') {
return Promise.resolve({ folders: ['产品文档'], files: [] });
}
if (path === '产品文档') {
return Promise.resolve({
folders: [],
files: [{ key: '产品文档/架构设计.md', name: '架构设计.md', size: 300, modifiedAt: '2026-08-01T10:00:00Z' }],
});
}
return Promise.resolve({ folders: [], files: [] });
});
render();
const folderRow = await screen.findByText('产品文档');
fireEvent.click(folderRow);
expect(await screen.findByText('架构设计.md')).toBeInTheDocument();
expect(listDocuments).toHaveBeenCalledWith('产品文档');
});
test('shows an error message when listDocuments rejects', async () => {
vi.mocked(listDocuments).mockRejectedValue(new Error('network error'));
render();
expect(await screen.findByTestId('file-explorer-error')).toBeInTheDocument();
});
test('changing refreshKey re-fetches the root listing', async () => {
vi.mocked(listDocuments).mockResolvedValue({ folders: [], files: [] });
const { rerender } = render();
await waitFor(() => {
expect(listDocuments).toHaveBeenCalledTimes(1);
});
rerender();
await waitFor(() => {
expect(listDocuments).toHaveBeenCalledTimes(2);
});
});