Files
xiaoxia-saas/apps/web/src/test/pages/VoiceLibrary.test.tsx
T
xiaoxia d336382f3a
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 7s
CI/CD Pipeline / Build Staging API Image (push) Successful in 40s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 40s
CI/CD Pipeline / Integration Tests (push) Successful in 2m35s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m17s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 6s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 23s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 18s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 19s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 5s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m53s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m18s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 23s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m33s
AI Code Review / AI Code Review (pull_request) Successful in 6m39s
fix(tests): 修复 CI 全量测试失败 — 后端黑屏过滤 + 前端 icon mock 缺失
1. test_duplicate_rate_scope: 测试数据用 5 个相同 phash 被
   _is_bad_fingerprint() 拦截(PR #1688),改为 5 个不同 phash
2. VoiceLibrary.test: @ant-design/icons mock 缺少
   VideoCameraOutlined/InboxOutlined/CloseOutlined(PR #1654/#1656)
2026-09-04 23:30:08 +08:00

145 lines
5.6 KiB
TypeScript

import React from "react"
import { describe, expect, it, vi } from "vitest"
import { render } from "@testing-library/react"
import { MemoryRouter } from "react-router-dom"
vi.mock("@/components/layout/PageHead", () => ({
default: ({ title }: { title: string }) => <div data-testid="page-head">{title}</div>,
}))
vi.mock("@tanstack/react-query", () => ({
useQuery: () => ({ data: [], isLoading: false, isError: false, refetch: vi.fn() }),
useMutation: () => ({ mutate: vi.fn(), mutateAsync: vi.fn(), isLoading: false }),
useQueryClient: () => ({ invalidateQueries: vi.fn(), setQueryData: vi.fn() }),
useInfiniteQuery: () => ({
data: { pages: [] },
isLoading: false,
fetchNextPage: vi.fn(),
hasNextPage: false,
}),
}))
vi.mock("@/components/ui", () => ({
Button: ({ children, onClick }: any) => <button onClick={onClick}>{children}</button>,
Input: ({ placeholder }: any) => <input placeholder={placeholder} />,
Select: ({ options }: any) => (
<select>
{options?.map((o: any) => (
<option key={o.value}>{o.label}</option>
))}
</select>
),
Modal: ({ open, children }: any) => (open ? <div role="dialog">{children}</div> : null),
Empty: () => <div>Empty</div>,
Card: ({ children }: any) => <div>{children}</div>,
Tag: ({ children }: any) => <span>{children}</span>,
Tooltip: ({ children }: any) => <span>{children}</span>,
Upload: ({ children }: any) => <div>{children}</div>,
Progress: () => <div />,
}))
vi.mock("antd", () => ({
Table: () => <div />,
Pagination: () => <div />,
Tabs: () => <div />,
Modal: ({ open, children }: any) => (open ? <div role="dialog">{children}</div> : null),
message: { success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn() },
Popconfirm: ({ children }: any) => <span>{children}</span>,
Form: ({ children }: any) => <form>{children}</form>,
Input: ({ placeholder }: any) => <input placeholder={placeholder} />,
InputNumber: () => <input type="number" />,
Select: () => <select />,
Empty: () => <div>Empty</div>,
Space: ({ children }: any) => <div>{children}</div>,
Tag: ({ children }: any) => <span>{children}</span>,
Badge: ({ children }: any) => <span>{children}</span>,
Tooltip: ({ children }: any) => <span>{children}</span>,
Upload: ({ children }: any) => <div>{children}</div>,
Progress: () => <div />,
Switch: () => <input type="checkbox" />,
Radio: ({ children }: any) => <span>{children}</span>,
RadioGroup: ({ children }: any) => <div>{children}</div>,
Checkbox: ({ children }: any) => (
<label>
<input type="checkbox" />
{children}
</label>
),
DatePicker: () => <input type="date" />,
Col: ({ children }: any) => <div>{children}</div>,
Row: ({ children }: any) => <div>{children}</div>,
Card: ({ children }: any) => <div>{children}</div>,
List: () => <ul />,
Grid: { useBreakpoint: () => ({ xs: true, sm: true, md: true, lg: true }) },
Descriptions: ({ children }: any) => <div>{children}</div>,
Divider: () => <hr />,
Avatar: () => <span />,
Dropdown: ({ children }: any) => <span>{children}</span>,
Menu: ({ children }: any) => <ul>{children}</ul>,
Drawer: ({ open, children }: any) => (open ? <div>{children}</div> : null),
Typography: {
Title: ({ children }: any) => <h2>{children}</h2>,
Text: ({ children }: any) => <span>{children}</span>,
Paragraph: ({ children }: any) => <p>{children}</p>,
},
Spin: ({ spinning }: any) => (spinning ? <div>Loading...</div> : <></>),
Slider: () => <input type="range" />,
Rate: () => <div />,
Collapse: ({ children }: any) => <div>{children}</div>,
Steps: ({ children }: any) => <div>{children}</div>,
Button: ({ children }: any) => <button>{children}</button>,
}))
vi.mock("@ant-design/icons", () => ({
AudioOutlined: () => <span />,
CloseCircleOutlined: () => <span />,
DeleteOutlined: () => <span />,
HeartOutlined: () => <span />,
PauseCircleOutlined: () => <span />,
PlayCircleOutlined: () => <span />,
PlusOutlined: () => <span />,
ReloadOutlined: () => <span />,
RobotOutlined: () => <span />,
SearchOutlined: () => <span />,
SoundOutlined: () => <span />,
UploadOutlined: () => <span />,
UserOutlined: () => <span />,
VideoCameraOutlined: () => <span />,
InboxOutlined: () => <span />,
CloseOutlined: () => <span />,
}))
vi.mock("@/store/authStore", () => ({
useAuthStore: (sel: any) => sel({ user: { id: "1" }, isAuthenticated: true }),
}))
vi.mock("@/api/voice-clone", () => ({
createVoiceClone: vi.fn().mockResolvedValue({ success: true }),
deleteVoiceClone: vi.fn().mockResolvedValue({ success: true }),
retryVoiceClone: vi.fn().mockResolvedValue({ success: true }),
}))
vi.mock("@/api/voices", () => ({
fetchVoices: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
fetchPresetVoices: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
getVoices: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
createVoice: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
updateVoice: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
deleteVoice: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
generateAIVoice: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
}))
vi.mock("@/pages/voices/VoiceLibrary.css", () => ({}))
import VoiceLibrary from "@/pages/voices/VoiceLibrary"
describe("VoiceLibrary Page", () => {
it("should render without crashing", () => {
const { container } = render(
<MemoryRouter>
<VoiceLibrary />
</MemoryRouter>,
)
expect(container.firstChild).toBeTruthy()
})
})