|
@@ -1,465 +0,0 @@
|
|
|
-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 { CreditBalanceDialog } from '../../src/components/CreditBalanceDialog';
|
|
|
|
|
-import { creditBalanceClient } from '../../src/api/creditBalanceClient';
|
|
|
|
|
-
|
|
|
|
|
-// 完整的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/creditBalanceClient', () => {
|
|
|
|
|
- const mockCreditBalanceClient = {
|
|
|
|
|
- ':userId': {
|
|
|
|
|
- $get: vi.fn(() => Promise.resolve({ status: 200, json: async () => ({}) })),
|
|
|
|
|
- $put: vi.fn(() => Promise.resolve({ status: 200, json: async () => ({}) })),
|
|
|
|
|
- adjust: {
|
|
|
|
|
- $post: vi.fn(() => Promise.resolve({ status: 200, json: async () => ({}) }))
|
|
|
|
|
- },
|
|
|
|
|
- logs: {
|
|
|
|
|
- $get: vi.fn(() => Promise.resolve({ status: 200, json: async () => ({ data: [], pagination: { total: 0, page: 1, pageSize: 10 } }) }))
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- checkout: {
|
|
|
|
|
- $post: vi.fn(() => Promise.resolve({ status: 200, json: async () => ({}) }))
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
- return {
|
|
|
|
|
- creditBalanceClient: mockCreditBalanceClient,
|
|
|
|
|
- };
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// 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(
|
|
|
|
|
- <QueryClientProvider client={queryClient}>
|
|
|
|
|
- {component as any}
|
|
|
|
|
- </QueryClientProvider>
|
|
|
|
|
- );
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-describe('信用额度管理对话框组件单元测试', () => {
|
|
|
|
|
- beforeEach(() => {
|
|
|
|
|
- vi.clearAllMocks();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该正确渲染对话框标题和描述', () => {
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- expect(screen.getByText('用户信用额度管理')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('管理用户 测试用户 (ID: 123) 的信用额度')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该显示三个标签页', () => {
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- expect(screen.getByText('额度概览')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('额度操作')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('变更记录')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该加载用户信用额度数据', async () => {
|
|
|
|
|
- const mockBalanceData = {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- userId: 123,
|
|
|
|
|
- totalLimit: 10000,
|
|
|
|
|
- usedAmount: 2500,
|
|
|
|
|
- availableAmount: 7500,
|
|
|
|
|
- isEnabled: 1,
|
|
|
|
|
- createdAt: '2024-01-01T00:00:00Z',
|
|
|
|
|
- updatedAt: '2024-01-01T00:00:00Z'
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].$get as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, mockBalanceData)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 等待数据加载
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(creditBalanceClient[':userId'].$get).toHaveBeenCalledWith({
|
|
|
|
|
- param: { userId: '123' }
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该显示额度概览信息', async () => {
|
|
|
|
|
- const mockBalanceData = {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- userId: 123,
|
|
|
|
|
- totalLimit: 10000,
|
|
|
|
|
- usedAmount: 2500,
|
|
|
|
|
- availableAmount: 7500,
|
|
|
|
|
- isEnabled: 1,
|
|
|
|
|
- createdAt: '2024-01-01T00:00:00Z',
|
|
|
|
|
- updatedAt: '2024-01-01T00:00:00Z'
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].$get as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, mockBalanceData)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 等待数据加载完成
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('总额度')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('已用额度')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('可用额度')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该加载额度变更记录', async () => {
|
|
|
|
|
- const mockLogsData = {
|
|
|
|
|
- data: [
|
|
|
|
|
- {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- userId: 123,
|
|
|
|
|
- type: 'SET_LIMIT',
|
|
|
|
|
- amount: 10000,
|
|
|
|
|
- previousLimit: 0,
|
|
|
|
|
- newLimit: 10000,
|
|
|
|
|
- description: '设置初始信用额度',
|
|
|
|
|
- createdAt: '2024-01-01T00:00:00Z'
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
- pagination: {
|
|
|
|
|
- total: 1,
|
|
|
|
|
- page: 1,
|
|
|
|
|
- pageSize: 10
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].logs.$get as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, mockLogsData)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 切换到变更记录标签页
|
|
|
|
|
- fireEvent.click(screen.getByText('变更记录'));
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(creditBalanceClient[':userId'].logs.$get).toHaveBeenCalledWith({
|
|
|
|
|
- param: { userId: '123' },
|
|
|
|
|
- query: {
|
|
|
|
|
- page: 1,
|
|
|
|
|
- pageSize: 10
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该显示设置额度表单', () => {
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 切换到额度操作标签页
|
|
|
|
|
- fireEvent.click(screen.getByText('额度操作'));
|
|
|
|
|
-
|
|
|
|
|
- expect(screen.getByText('设置信用额度')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('信用额度')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('是否启用')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该显示调整额度表单', () => {
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 切换到额度操作标签页
|
|
|
|
|
- fireEvent.click(screen.getByText('额度操作'));
|
|
|
|
|
-
|
|
|
|
|
- // 切换到调整额度标签
|
|
|
|
|
- fireEvent.click(screen.getByText('调整额度'));
|
|
|
|
|
-
|
|
|
|
|
- expect(screen.getByText('调整信用额度')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('调整金额')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('调整类型')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('备注说明')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该显示结账恢复额度表单', () => {
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 切换到额度操作标签页
|
|
|
|
|
- fireEvent.click(screen.getByText('额度操作'));
|
|
|
|
|
-
|
|
|
|
|
- // 切换到结账恢复标签
|
|
|
|
|
- fireEvent.click(screen.getByText('结账恢复'));
|
|
|
|
|
-
|
|
|
|
|
- expect(screen.getByText('结账恢复额度')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('恢复金额')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('订单号')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByLabelText('备注说明')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该处理设置额度表单提交', async () => {
|
|
|
|
|
- const mockBalanceData = {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- userId: 123,
|
|
|
|
|
- totalLimit: 10000,
|
|
|
|
|
- usedAmount: 2500,
|
|
|
|
|
- availableAmount: 7500,
|
|
|
|
|
- isEnabled: 1,
|
|
|
|
|
- createdAt: '2024-01-01T00:00:00Z',
|
|
|
|
|
- updatedAt: '2024-01-01T00:00:00Z'
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].$get as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, mockBalanceData)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].$put as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, { success: true })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- const { toast } = await import('sonner');
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 切换到额度操作标签页
|
|
|
|
|
- fireEvent.click(screen.getByText('额度操作'));
|
|
|
|
|
-
|
|
|
|
|
- // 填写表单
|
|
|
|
|
- fireEvent.change(screen.getByLabelText('信用额度'), { target: { value: '15000' } });
|
|
|
|
|
-
|
|
|
|
|
- // 提交表单
|
|
|
|
|
- fireEvent.click(screen.getByText('设置额度'));
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(creditBalanceClient[':userId'].$put).toHaveBeenCalledWith({
|
|
|
|
|
- param: { userId: '123' },
|
|
|
|
|
- json: {
|
|
|
|
|
- creditLimit: 15000,
|
|
|
|
|
- isActive: true
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- expect(toast.success).toHaveBeenCalledWith('额度设置成功');
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该处理调整额度表单提交', async () => {
|
|
|
|
|
- const mockBalanceData = {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- userId: 123,
|
|
|
|
|
- totalLimit: 10000,
|
|
|
|
|
- usedAmount: 2500,
|
|
|
|
|
- availableAmount: 7500,
|
|
|
|
|
- isEnabled: 1,
|
|
|
|
|
- createdAt: '2024-01-01T00:00:00Z',
|
|
|
|
|
- updatedAt: '2024-01-01T00:00:00Z'
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].$get as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, mockBalanceData)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].adjust.$post as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, { success: true })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- const { toast } = await import('sonner');
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 切换到额度操作标签页
|
|
|
|
|
- fireEvent.click(screen.getByText('额度操作'));
|
|
|
|
|
-
|
|
|
|
|
- // 切换到调整额度标签
|
|
|
|
|
- fireEvent.click(screen.getByText('调整额度'));
|
|
|
|
|
-
|
|
|
|
|
- // 填写表单
|
|
|
|
|
- fireEvent.change(screen.getByLabelText('调整金额'), { target: { value: '2000' } });
|
|
|
|
|
- fireEvent.click(screen.getByLabelText('调整类型'));
|
|
|
|
|
- fireEvent.click(screen.getByText('增加额度'));
|
|
|
|
|
-
|
|
|
|
|
- // 提交表单
|
|
|
|
|
- fireEvent.click(screen.getByText('调整额度'));
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(creditBalanceClient[':userId'].adjust.$post).toHaveBeenCalledWith({
|
|
|
|
|
- param: { userId: '123' },
|
|
|
|
|
- json: {
|
|
|
|
|
- amount: 2000,
|
|
|
|
|
- type: 'INCREASE',
|
|
|
|
|
- description: ''
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- expect(toast.success).toHaveBeenCalledWith('额度调整成功');
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该显示加载状态', () => {
|
|
|
|
|
- (creditBalanceClient[':userId'].$get as any).mockImplementation(
|
|
|
|
|
- () => new Promise(() => {}) // 永不解析的promise,模拟加载中
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 应该显示加载骨架屏
|
|
|
|
|
- expect(screen.getAllByRole('status')).toHaveLength(3); // 三个统计卡片
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该显示错误状态', async () => {
|
|
|
|
|
- (creditBalanceClient[':userId'].$get as any).mockRejectedValue(
|
|
|
|
|
- new Error('获取信用额度失败')
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- const { toast } = await import('sonner');
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(toast.error).toHaveBeenCalledWith('获取信用额度失败');
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('应该支持多租户上下文', async () => {
|
|
|
|
|
- const mockBalanceData = {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- userId: 123,
|
|
|
|
|
- totalLimit: 10000,
|
|
|
|
|
- usedAmount: 2500,
|
|
|
|
|
- availableAmount: 7500,
|
|
|
|
|
- isEnabled: 1,
|
|
|
|
|
- createdAt: '2024-01-01T00:00:00Z',
|
|
|
|
|
- updatedAt: '2024-01-01T00:00:00Z'
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- (creditBalanceClient[':userId'].$get as any).mockResolvedValue(
|
|
|
|
|
- createMockResponse(200, mockBalanceData)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- renderWithProviders(
|
|
|
|
|
- <CreditBalanceDialog
|
|
|
|
|
- userId={123}
|
|
|
|
|
- userName="测试用户"
|
|
|
|
|
- open={true}
|
|
|
|
|
- onOpenChange={() => {}}
|
|
|
|
|
- tenantId={456}
|
|
|
|
|
- />
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(creditBalanceClient[':userId'].$get).toHaveBeenCalledWith({
|
|
|
|
|
- param: { userId: '123' }
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-});
|
|
|