import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { OrderManagement } from '../../src/components/OrderManagement';
import { adminOrderClient } from '../../src/api/orderClient';
// 完整的mock响应对象
const createMockResponse = (status: number, data?: any) => ({
status,
ok: status >= 200 && status < 300,
body: null,
bodyUsed: false,
statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
headers: new Headers(),
url: '',
redirected: false,
type: 'basic' as ResponseType,
json: async () => data || {},
text: async () => '',
blob: async () => new Blob(),
arrayBuffer: async () => new ArrayBuffer(0),
formData: async () => new FormData(),
clone: function() { return this; }
});
// Mock API client
vi.mock('../../src/api/orderClient', () => {
const mockAdminOrderClient = {
$get: vi.fn(() => Promise.resolve({ status: 200, body: null })),
':id': {
$put: vi.fn(() => Promise.resolve({ status: 200, body: null })),
},
};
const mockOrderClientManager = {
getAdminOrderClient: vi.fn(() => mockAdminOrderClient),
};
return {
orderClientManager: mockOrderClientManager,
adminOrderClient: mockAdminOrderClient,
};
});
// Mock toast
vi.mock('sonner', () => ({
toast: {
success: vi.fn(() => {}),
error: vi.fn(() => {}),
},
}));
const createTestQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const renderWithProviders = (component: React.ReactElement) => {
const queryClient = createTestQueryClient();
return render(
{component as any}
);
};
describe('订单管理集成测试', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('应该加载订单列表并显示数据', async () => {
const mockOrders = {
data: [
{
id: 1,
orderNo: 'ORDER001',
user: { username: 'testuser' },
userPhone: '13800138000',
recevierName: '张三',
receiverMobile: '13800138001',
amount: 100.00,
payAmount: 100.00,
freightAmount: 0.00,
state: 0,
payState: 2,
orderType: 1,
payType: 1,
address: '北京市朝阳区',
remark: '测试订单',
createdAt: '2024-01-01T00:00:00Z',
},
],
pagination: {
total: 1,
page: 1,
pageSize: 10,
},
};
// Mock initial order list
(adminOrderClient.$get as any).mockResolvedValue(createMockResponse(200, mockOrders));
renderWithProviders();
// Wait for initial data to load
await waitFor(() => {
expect(screen.getByText('ORDER001')).toBeInTheDocument();
expect(screen.getByText('testuser')).toBeInTheDocument();
expect(screen.getByText('张三')).toBeInTheDocument();
// Use getAllByText for amount since there are multiple elements with the same text
const amountElements = screen.getAllByText('¥100.00');
expect(amountElements.length).toBeGreaterThan(0);
});
// Verify API was called with correct parameters
expect(adminOrderClient.$get).toHaveBeenCalledWith({
query: {
page: 1,
pageSize: 10,
keyword: '',
filters: undefined,
},
});
});
it('应该处理订单搜索功能', async () => {
const mockOrders = {
data: [],
pagination: { total: 0, page: 1, pageSize: 10 },
};
(adminOrderClient.$get as any).mockResolvedValue(createMockResponse(200, mockOrders));
renderWithProviders();
// Wait for search elements to be available (search area is always available even during loading)
await waitFor(() => {
expect(screen.getByTestId('order-search-input')).toBeInTheDocument();
expect(screen.getByTestId('order-search-button')).toBeInTheDocument();
});
// Test search
const searchInput = screen.getByTestId('order-search-input');
fireEvent.change(searchInput, { target: { value: 'ORDER001' } });
const searchButton = screen.getByTestId('order-search-button');
fireEvent.click(searchButton);
await waitFor(() => {
expect(adminOrderClient.$get).toHaveBeenCalledWith({
query: {
page: 1,
pageSize: 10,
keyword: 'ORDER001',
filters: undefined,
},
});
});
});
it('应该处理订单状态过滤', async () => {
const mockOrders = {
data: [],
pagination: { total: 0, page: 1, pageSize: 10 },
};
(adminOrderClient.$get as any).mockResolvedValue(createMockResponse(200, mockOrders));
renderWithProviders();
// Wait for component to load
await waitFor(() => {
expect(screen.getByTestId('order-status-select')).toBeInTheDocument();
});
// Test status filter
const statusSelect = screen.getByTestId('order-status-select');
fireEvent.click(statusSelect);
const statusOption = screen.getByText('已发货');
fireEvent.click(statusOption);
await waitFor(() => {
expect(adminOrderClient.$get).toHaveBeenCalledWith({
query: {
page: 1,
pageSize: 10,
keyword: '',
filters: expect.stringContaining('"state":1'),
},
});
});
});
it('应该处理支付状态过滤', async () => {
const mockOrders = {
data: [],
pagination: { total: 0, page: 1, pageSize: 10 },
};
(adminOrderClient.$get as any).mockResolvedValue(createMockResponse(200, mockOrders));
renderWithProviders();
// Wait for component to load
await waitFor(() => {
expect(screen.getByTestId('order-pay-status-select')).toBeInTheDocument();
});
// Test pay status filter
const payStatusSelect = screen.getByTestId('order-pay-status-select');
fireEvent.click(payStatusSelect);
const payStatusOption = screen.getByText('支付成功');
fireEvent.click(payStatusOption);
await waitFor(() => {
expect(adminOrderClient.$get).toHaveBeenCalledWith({
query: {
page: 1,
pageSize: 10,
keyword: '',
filters: expect.stringContaining('"payState":2'),
},
});
});
});
it('应该处理订单编辑功能', async () => {
const { toast } = await import('sonner');
const mockOrders = {
data: [
{
id: 1,
orderNo: 'ORDER001',
state: 0,
payState: 2,
remark: '原始备注',
user: { username: 'testuser' },
userPhone: '13800138000',
recevierName: '张三',
receiverMobile: '13800138001',
amount: 100.00,
payAmount: 100.00,
freightAmount: 0.00,
orderType: 1,
payType: 1,
address: '北京市朝阳区',
createdAt: '2024-01-01T00:00:00Z',
},
],
pagination: {
total: 1,
page: 1,
pageSize: 10,
},
};
(adminOrderClient.$get as any).mockResolvedValue(createMockResponse(200, mockOrders));
renderWithProviders();
// Wait for data to load
await waitFor(() => {
expect(screen.getByText('ORDER001')).toBeInTheDocument();
});
// Click edit button using test ID
const editButtons = screen.getAllByTestId('order-edit-button');
fireEvent.click(editButtons[0]);
// Wait for edit modal to open and form elements to be available
await waitFor(() => {
expect(screen.getByText('编辑订单')).toBeInTheDocument();
expect(screen.getByTestId('edit-order-status-select')).toBeInTheDocument();
expect(screen.getByTestId('edit-remark-textarea')).toBeInTheDocument();
}, { timeout: 5000 });
// Change order status
const statusSelect = screen.getByTestId('edit-order-status-select');
fireEvent.click(statusSelect);
// Use getAllByText and select the first option
const newStatusOptions = screen.getAllByText('已发货');
fireEvent.click(newStatusOptions[0]);
// Change remark
const remarkTextarea = screen.getByTestId('edit-remark-textarea');
fireEvent.change(remarkTextarea, { target: { value: '更新后的备注' } });
// Mock successful update
(adminOrderClient[':id']['$put'] as any).mockResolvedValue(createMockResponse(200));
// Submit form using test ID
const saveButton = screen.getByTestId('order-save-button');
fireEvent.click(saveButton);
await waitFor(() => {
expect(adminOrderClient[':id']['$put']).toHaveBeenCalledWith({
param: { id: '1' },
json: {
state: 0,
payState: 2,
remark: '更新后的备注',
},
});
expect(toast.success).toHaveBeenCalledWith('订单更新成功');
});
});
it('应该处理订单详情查看', async () => {
const mockOrders = {
data: [
{
id: 1,
orderNo: 'ORDER001',
state: 0,
payState: 2,
remark: '测试订单',
user: { username: 'testuser' },
userPhone: '13800138000',
recevierName: '张三',
receiverMobile: '13800138001',
amount: 100.00,
payAmount: 100.00,
freightAmount: 0.00,
orderType: 1,
payType: 1,
address: '北京市朝阳区',
createdAt: '2024-01-01T00:00:00Z',
},
],
pagination: {
total: 1,
page: 1,
pageSize: 10,
},
};
(adminOrderClient.$get as any).mockResolvedValue(createMockResponse(200, mockOrders));
renderWithProviders();
// Wait for data to load
await waitFor(() => {
expect(screen.getByText('ORDER001')).toBeInTheDocument();
});
// Click view details button using test ID
const viewButtons = screen.getAllByTestId('order-view-button');
fireEvent.click(viewButtons[0]);
// Wait for detail modal to open
await waitFor(() => {
expect(screen.getByText('订单详情')).toBeInTheDocument();
}, { timeout: 5000 });
// Check modal content
expect(screen.getByText('订单详情')).toBeInTheDocument();
// Use getAllByText for ORDER001 since there are multiple elements with the same text
const orderNoElements = screen.getAllByText('ORDER001');
expect(orderNoElements.length).toBeGreaterThan(0);
// Use getAllByText for 实物订单 since there are multiple elements with the same text
const orderTypeElements = screen.getAllByText('实物订单');
expect(orderTypeElements.length).toBeGreaterThan(0);
// Use getAllByText for amount since there are multiple elements with the same text
const amountElements = screen.getAllByText('¥100.00');
expect(amountElements.length).toBeGreaterThan(0);
expect(screen.getByText('测试订单')).toBeInTheDocument();
});
it('应该优雅处理API错误', async () => {
const { toast } = await import('sonner');
// Mock API error
(adminOrderClient.$get as any).mockRejectedValue(new Error('API Error'));
renderWithProviders();
// Should handle error without crashing
await waitFor(() => {
expect(screen.getByText('订单管理')).toBeInTheDocument();
});
// Test edit error scenario
const mockOrders = {
data: [
{
id: 1,
orderNo: 'ORDER001',
state: 0,
payState: 2,
remark: '测试订单',
user: { username: 'testuser' },
userPhone: '13800138000',
recevierName: '张三',
receiverMobile: '13800138001',
amount: 100.00,
payAmount: 100.00,
freightAmount: 0.00,
orderType: 1,
payType: 1,
address: '北京市朝阳区',
createdAt: '2024-01-01T00:00:00Z',
},
],
pagination: {
total: 1,
page: 1,
pageSize: 10,
},
};
// Mock successful data load
(adminOrderClient.$get as any).mockResolvedValue(createMockResponse(200, mockOrders));
// Re-render with data
renderWithProviders();
await waitFor(() => {
expect(screen.getByText('ORDER001')).toBeInTheDocument();
});
// Click edit button using test ID
const editButtons = screen.getAllByTestId('order-edit-button');
fireEvent.click(editButtons[0]);
await waitFor(() => {
expect(screen.getByText('编辑订单')).toBeInTheDocument();
});
// Mock update error
(adminOrderClient[':id']['$put'] as any).mockRejectedValue(new Error('Update failed'));
// Submit form using test ID
const saveButton = screen.getByTestId('order-save-button');
fireEvent.click(saveButton);
await waitFor(() => {
expect(toast.error).toHaveBeenCalledWith('更新失败,请重试');
});
});
});