Files
Genarrative/apps/admin-web/src/pages/AdminEditorShowcaseReviewPage.test.tsx
T
kdletters 0b766c8bf9 统一音频素材封面缩略图
新增音频素材统一封面图。
素材库、创作主页精选和后台缩略图改为使用音频封面。
补充音频封面展示回归测试。
2026-07-06 14:10:16 +08:00

359 lines
9.7 KiB
TypeScript

/* @vitest-environment jsdom */
import {
fireEvent,
render,
screen,
waitFor,
within,
} from '@testing-library/react';
import { beforeEach, expect, test, vi } from 'vitest';
import {
getAdminAssetReadUrl,
getAdminEditorShowcaseCampaign,
listAdminEditorShowcaseAssets,
reviewAdminEditorShowcaseAsset,
updateAdminEditorShowcaseDisplay,
upsertAdminEditorShowcaseCampaign,
} from '../api/adminApiClient';
import type { AdminEditorShowcaseAssetPayload } from '../api/adminApiTypes';
import { AdminEditorShowcaseReviewPage } from './AdminEditorShowcaseReviewPage';
vi.mock('../api/adminApiClient', () => ({
getAdminAssetReadUrl: vi.fn(),
getAdminEditorShowcaseCampaign: vi.fn(),
listAdminEditorShowcaseAssets: vi.fn(),
reviewAdminEditorShowcaseAsset: vi.fn(),
updateAdminEditorShowcaseDisplay: vi.fn(),
upsertAdminEditorShowcaseCampaign: vi.fn(),
}));
const pendingShowcaseAsset: AdminEditorShowcaseAssetPayload = {
showcaseId: 'showcase-1',
assetId: 'asset-1',
ownerUserId: 'user-1',
authorDisplayName: '作者昵称',
authorPublicUserCode: 'SY-00000042',
label: '角色形象 1',
imageSrc: '/generated-character-drafts/editor/spec.png',
objectKey: 'generated-character-drafts/editor/spec.png',
width: 1024,
height: 1024,
prompt: '完整提示词内容',
actualPrompt: null,
model: 'gpt-image-2',
provider: 'character',
taskId: 'task-1',
assetKind: 'character',
generationInputs: { style: 'clay' },
generationCostMudPoints: 12,
refundMudPoints: 6,
reviewStatus: 'pending',
displayEnabled: false,
likeCount: 0,
assetDeletedWhilePending: false,
reviewedByAdminUserId: null,
reviewNote: null,
refundLedgerId: null,
refundCompletedAt: null,
submittedAt: '2026-07-04T10:00:00Z',
reviewedAt: null,
approvedAt: null,
rejectedAt: null,
updatedAt: '2026-07-04T10:00:00Z',
showcaseCategory: null,
};
const approvedShowcaseAsset: AdminEditorShowcaseAssetPayload = {
...pendingShowcaseAsset,
showcaseId: 'showcase-2',
assetId: 'asset-2',
label: '角色形象 2',
reviewStatus: 'approved',
displayEnabled: true,
showcaseCategory: 'characters',
reviewedAt: '2026-07-04T10:10:00Z',
approvedAt: '2026-07-04T10:10:00Z',
};
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValue({
entries: [pendingShowcaseAsset],
nextCursor: null,
});
vi.mocked(getAdminEditorShowcaseCampaign).mockResolvedValue({
campaign: {
enabled: true,
title: '活动卡',
imageSrc: '/campaign.png',
prompt: '活动提示词',
author: '官方',
costText: '12 泥点',
updatedAt: '2026-07-04T10:00:00Z',
},
});
vi.mocked(getAdminAssetReadUrl).mockResolvedValue({
read: {
objectKey: 'generated-character-drafts/editor/spec.png',
signedUrl: 'https://signed.example.com/spec.png',
expiresAt: '2026-07-04T11:00:00Z',
},
});
vi.mocked(reviewAdminEditorShowcaseAsset).mockResolvedValue({
entry: {
...pendingShowcaseAsset,
reviewStatus: 'approved',
displayEnabled: false,
reviewedAt: '2026-07-04T10:10:00Z',
approvedAt: '2026-07-04T10:10:00Z',
},
});
vi.mocked(updateAdminEditorShowcaseDisplay).mockResolvedValue({
entry: {
...approvedShowcaseAsset,
displayEnabled: false,
},
});
vi.mocked(upsertAdminEditorShowcaseCampaign).mockResolvedValue({
campaign: {
enabled: false,
title: '新活动卡',
imageSrc: '/new-campaign.png',
prompt: '新活动提示词',
author: '官方',
costText: '6 泥点',
updatedAt: '2026-07-04T10:20:00Z',
},
});
});
test('后台精选审核展示待审核素材和活动卡配置', async () => {
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
expect(await screen.findByText('作者昵称')).toBeTruthy();
expect(screen.getByText('SY-00000042')).toBeTruthy();
expect(screen.getAllByText('待审核').length).toBeGreaterThanOrEqual(2);
expect(screen.getByText('12 泥点')).toBeTruthy();
expect(await screen.findByDisplayValue('活动卡')).toBeTruthy();
expect(screen.getByLabelText('状态')).toHaveProperty('value', 'pending');
expect(listAdminEditorShowcaseAssets).toHaveBeenCalledWith('admin-token', {
ownerUserId: null,
reviewStatus: 'pending',
submittedAfter: null,
submittedBefore: null,
limit: 80,
});
});
test('后台精选审核格式化微秒时间并显示素材名', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [
{
...pendingShowcaseAsset,
submittedAt: '1783231493.573727Z',
},
],
nextCursor: null,
});
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
expect(await screen.findByText('角色形象 1')).toBeTruthy();
expect(screen.queryByText('showcase-1')).toBeNull();
expect(screen.queryByText('1783231493.573727Z')).toBeNull();
});
test('后台精选审核音频素材使用统一封面缩略图', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [
{
...pendingShowcaseAsset,
showcaseId: 'showcase-audio-1',
assetId: 'asset-audio-1',
label: '胜利音效',
imageSrc: '/generated-editor-audios/sfx.mp3',
objectKey: 'generated-editor-audios/sfx.mp3',
assetKind: 'sound-effect',
},
],
nextCursor: null,
});
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
const image = await screen.findByRole('img', { name: '精选素材:胜利音效' });
expect(image.getAttribute('src')).toBe(
'/creation-home/audio-asset-cover.svg',
);
expect(getAdminAssetReadUrl).not.toHaveBeenCalled();
});
test('后台精选审核可以通过素材并查看完整提示词', async () => {
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
fireEvent.change(await screen.findByLabelText('审核备注:角色形象 1'), {
target: { value: '质量通过' },
});
fireEvent.click(screen.getByRole('button', { name: '通过' }));
await waitFor(() => {
expect(reviewAdminEditorShowcaseAsset).toHaveBeenCalledWith('admin-token', {
showcaseId: 'showcase-1',
reviewStatus: 'approved',
reviewNote: '质量通过',
});
});
fireEvent.click(screen.getByRole('button', { name: '完整提示词内容' }));
const dialog = screen.getByRole('dialog', { name: '完整提示词' });
expect(within(dialog).getByText('完整提示词内容')).toBeTruthy();
});
test('后台精选审核可以切换展示和保存活动卡', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [approvedShowcaseAsset],
nextCursor: null,
});
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
fireEvent.click(await screen.findByRole('button', { name: '隐藏' }));
await waitFor(() => {
expect(updateAdminEditorShowcaseDisplay).toHaveBeenCalledWith(
'admin-token',
{
showcaseId: 'showcase-2',
displayEnabled: false,
showcaseCategory: 'characters',
},
);
});
fireEvent.change(await screen.findByLabelText('标题'), {
target: { value: '新活动卡' },
});
fireEvent.change(screen.getByLabelText('图片地址'), {
target: { value: '/new-campaign.png' },
});
fireEvent.change(screen.getByLabelText('成本文案'), {
target: { value: '6 泥点' },
});
fireEvent.click(screen.getByRole('button', { name: '保存活动卡' }));
await waitFor(() => {
expect(upsertAdminEditorShowcaseCampaign).toHaveBeenCalledWith(
'admin-token',
expect.objectContaining({
title: '新活动卡',
imageSrc: '/new-campaign.png',
costText: '6 泥点',
}),
);
});
});
test('后台精选审核已通过素材可以设置精选分类', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [
{
...approvedShowcaseAsset,
showcaseCategory: null,
displayEnabled: false,
},
],
nextCursor: null,
});
vi.mocked(updateAdminEditorShowcaseDisplay).mockResolvedValueOnce({
entry: {
...approvedShowcaseAsset,
showcaseCategory: 'ui',
displayEnabled: false,
},
});
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
fireEvent.change(await screen.findByLabelText('精选分类:角色形象 2'), {
target: { value: 'ui' },
});
await waitFor(() => {
expect(updateAdminEditorShowcaseDisplay).toHaveBeenCalledWith(
'admin-token',
{
showcaseId: 'showcase-2',
displayEnabled: false,
showcaseCategory: 'ui',
},
);
});
});
test('后台精选审核清空精选分类时自动隐藏素材', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [approvedShowcaseAsset],
nextCursor: null,
});
vi.mocked(updateAdminEditorShowcaseDisplay).mockResolvedValueOnce({
entry: {
...approvedShowcaseAsset,
showcaseCategory: null,
displayEnabled: false,
},
});
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
fireEvent.change(await screen.findByLabelText('精选分类:角色形象 2'), {
target: { value: '' },
});
await waitFor(() => {
expect(updateAdminEditorShowcaseDisplay).toHaveBeenCalledWith(
'admin-token',
{
showcaseId: 'showcase-2',
displayEnabled: false,
showcaseCategory: null,
},
);
});
});