0b766c8bf9
新增音频素材统一封面图。 素材库、创作主页精选和后台缩略图改为使用音频封面。 补充音频封面展示回归测试。
359 lines
9.7 KiB
TypeScript
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,
|
|
},
|
|
);
|
|
});
|
|
});
|