import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { beforeEach, expect, it, vi } from 'vitest'; import GiveawaysPage from '@/pages/Giveaways'; import { apiRequest } from '@/services/api'; import { mockLocation } from '../umiMock'; vi.mock('@/services/api', () => ({ apiRequest: vi.fn(), downloadFile: vi.fn(), jsonOptions: (method: string, body: unknown) => ({ method, body: JSON.stringify(body) }), })); beforeEach(() => { vi.clearAllMocks(); mockLocation.search = ''; vi.mocked(apiRequest).mockImplementation(async (path) => { if (path.startsWith('/chats?')) { return { items: [{ chat_id: '-100123', title: '抽奖测试群', type: 'supergroup', accessible: true }], total: 1, page: 1, page_size: 100, }; } if (path.startsWith('/giveaways?')) { return { items: [{ giveaway_id: 'draw-1', chat_id: '-100123', title: '七月抽奖', status: 'running', prizes: [{ name: '一等奖', count: 1, points_reward: 50 }], minimum_points: 20, entry_cost: 5, participation_reward: 2, starts_at: '2026-07-24T00:00:00Z', ends_at: '2026-07-25T08:00:00Z', created_at: '2026-07-24T08:00:00Z', }], total: 1, page: 1, page_size: 20, }; } if (path.includes('/participants?')) { return { items: [{ giveaway_id: 'draw-1', chat_id: '-100123', user_id: '10001', username: 'alice', display_name: '爱丽丝 示例', active: true, entry_cost: 5, joined_at: '2026-07-24T08:00:00Z' }], total: 1, page: 1, page_size: 100, }; } if (path.endsWith('/finish')) return { status: 'finished' }; return {}; }); }); it('参与者优先显示 Telegram 昵称', async () => { render(); await screen.findByText('七月抽奖'); fireEvent.click(screen.getByRole('button', { name: '参与者' })); expect(await screen.findByText('爱丽丝 示例')).toBeInTheDocument(); expect(screen.queryByText('@alice')).not.toBeInTheDocument(); }); it('展示抽奖积分配置并在危险操作确认后开奖', async () => { render(); expect(await screen.findByText('七月抽奖')).toBeInTheDocument(); expect(screen.getByText('门槛 20')).toBeInTheDocument(); expect(screen.getByText('消耗 5')).toBeInTheDocument(); expect(screen.getByText('参与 +2')).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: /开\s*奖/ })); expect(vi.mocked(apiRequest).mock.calls.some(([path]) => path.endsWith('/finish'))).toBe(false); fireEvent.click(await screen.findByRole('button', { name: /确\s*认\s*执\s*行/ })); await waitFor(() => { const call = vi.mocked(apiRequest).mock.calls.find(([path]) => path.endsWith('/finish')); expect(call).toBeTruthy(); expect(JSON.parse(String(call?.[1]?.body))).toEqual({ confirm: true }); }); }); it('创建表单包含积分联动字段且发布前必须二次确认', async () => { mockLocation.search = '?chat_id=-100123'; render(); await screen.findByText('七月抽奖'); fireEvent.click(screen.getByRole('button', { name: /创\s*建\s*抽\s*奖/ })); expect(await screen.findByLabelText('最低积分')).toBeInTheDocument(); expect(screen.getByLabelText('报名消耗')).toBeInTheDocument(); expect(screen.getByLabelText('参与奖励')).toBeInTheDocument(); expect(screen.getByLabelText('报名开始时间')).toBeInTheDocument(); expect(screen.getByLabelText('开奖时间')).toBeInTheDocument(); expect(screen.getByPlaceholderText('中奖积分')).toBeInTheDocument(); fireEvent.change(screen.getByLabelText('标题'), { target: { value: '八月抽奖' } }); fireEvent.click(screen.getByRole('button', { name: /创\s*建\s*并\s*发\s*布/ })); expect( vi.mocked(apiRequest).mock.calls.some( ([path, options]) => path === '/giveaways' && options?.method === 'POST', ), ).toBe(false); fireEvent.click(await screen.findByRole('button', { name: /确\s*认\s*发\s*布/ })); await waitFor(() => { const call = vi.mocked(apiRequest).mock.calls.find( ([path, options]) => path === '/giveaways' && options?.method === 'POST', ); expect(call).toBeTruthy(); expect(JSON.parse(String(call?.[1]?.body))).toMatchObject({ chat_id: '-100123', title: '八月抽奖', minimum_points: 0, entry_cost: 0, participation_reward: 0, starts_at: expect.any(String), ends_at: expect.any(String), confirm: true, }); expect(JSON.parse(String(call?.[1]?.body))).not.toHaveProperty('duration_minutes'); }); }); it('选择群组后提供抽奖资格封禁管理', async () => { mockLocation.search = '?chat_id=-100123'; vi.mocked(apiRequest).mockImplementation(async (path) => { if (path.startsWith('/chats?')) { return { items: [{ chat_id: '-100123', title: '抽奖测试群', type: 'supergroup', accessible: true }], total: 1, page: 1, page_size: 100, }; } if (path.startsWith('/giveaways?')) return { items: [], total: 0, page: 1, page_size: 20 }; if (path.includes('/giveaway-bans?')) { return { items: [{ chat_id: '-100123', user_id: '10009', reason: '恶意刷报名', created_at: '2026-07-24T08:00:00Z' }], total: 1, page: 1, page_size: 20, }; } return {}; }); render(); fireEvent.click(await screen.findByRole('button', { name: /资\s*格\s*封\s*禁/ })); expect(await screen.findByText('恶意刷报名')).toBeInTheDocument(); expect(screen.getByRole('button', { name: /添\s*加\s*封\s*禁/ })).toBeInTheDocument(); });