This commit is contained in:
2026-05-14 21:33:34 +08:00
193 changed files with 17051 additions and 1203 deletions

View File

@@ -143,6 +143,8 @@ import {
listSquareHoleGallery,
listSquareHoleWorks,
} from '../../services/square-hole-works';
import { listVisualNovelGallery } from '../../services/visual-novel-runtime';
import { listVisualNovelWorks } from '../../services/visual-novel-works';
import { type CustomWorldProfile, WorldType } from '../../types';
import {
AuthUiContext,
@@ -319,6 +321,17 @@ const testCreationEntryConfig = {
sortOrder: 80,
updatedAtMicros: 1,
},
{
id: 'baby-object-match',
title: '宝贝识物',
subtitle: '亲子识物分类',
badge: '可创建',
imageSrc: '/child-motion-demo/picture-book-grass-stage.png',
visible: true,
open: true,
sortOrder: 90,
updatedAtMicros: 1,
},
],
} satisfies CreationEntryConfig;
@@ -527,6 +540,28 @@ vi.mock('../../services/square-hole-works', () => ({
listSquareHoleWorks: vi.fn(),
}));
vi.mock('../../services/visual-novel-runtime', () => ({
listVisualNovelGallery: vi.fn(),
startVisualNovelRun: vi.fn(),
streamVisualNovelRuntimeAction: vi.fn(),
}));
vi.mock('../../services/visual-novel-works', () => ({
deleteVisualNovelWork: vi.fn(),
getVisualNovelWorkDetail: vi.fn(),
listVisualNovelWorks: vi.fn(),
publishVisualNovelWork: vi.fn(),
updateVisualNovelWork: vi.fn(),
}));
vi.mock('../../services/visual-novel-creation', () => ({
compileVisualNovelWorkProfile: vi.fn(),
createVisualNovelSession: vi.fn(),
executeVisualNovelAction: vi.fn(),
getVisualNovelSession: vi.fn(),
streamVisualNovelMessage: vi.fn(),
}));
vi.mock('../../services/creative-agent', () => ({
cancelCreativeAgentSession: vi.fn(),
confirmCreativePuzzleTemplate: vi.fn(),
@@ -1969,6 +2004,8 @@ beforeEach(() => {
vi.mocked(upsertProfileBrowseHistory).mockResolvedValue([]);
vi.mocked(clearProfileBrowseHistory).mockResolvedValue([]);
vi.mocked(deleteRpgEntryWorldProfile).mockResolvedValue([]);
vi.mocked(listVisualNovelGallery).mockResolvedValue({ works: [] });
vi.mocked(listVisualNovelWorks).mockResolvedValue({ works: [] });
vi.mocked(recordBigFishPlay).mockResolvedValue({ items: [] });
vi.mocked(recordRpgEntryWorldGalleryPlay).mockImplementation(
async (ownerUserId, profileId) => ({
@@ -2848,6 +2885,9 @@ test('create tab shows template tabs and embeds puzzle form by default', async (
expect(
screen.getByRole('tab', { name: '抓大鹅' }).querySelector('img')?.src,
).toContain('/creation-type-references/match3d.webp');
expect(
screen.getByRole('tab', { name: '宝贝识物' }).querySelector('img')?.src,
).toContain('/child-motion-demo/picture-book-grass-stage.png');
expect(
screen.getByRole('tab', { name: '拼图' }).querySelector('.text-white'),
).toBeTruthy();
@@ -2860,6 +2900,7 @@ test('create tab shows template tabs and embeds puzzle form by default', async (
expect(screen.queryByRole('tab', { name: /方洞挑战/u })).toBeNull();
expect(screen.queryByRole('tab', { name: '视觉小说' })).toBeNull();
expect(screen.getByRole('tab', { name: /抓大鹅/u })).toBeTruthy();
expect(screen.getByRole('tab', { name: /宝贝识物/u })).toBeTruthy();
expect(createRpgCreationSession).not.toHaveBeenCalled();
expect(match3dCreationClient.createSession).not.toHaveBeenCalled();
expect(createPuzzleAgentSession).not.toHaveBeenCalled();
@@ -4769,6 +4810,30 @@ test('creation hub clears all private work shelves immediately after logout stat
});
});
test('creation draft hub skips visual novel shelves when entry is not open', async () => {
const user = userEvent.setup();
vi.mocked(fetchCreationEntryConfig).mockResolvedValue({
...testCreationEntryConfig,
creationTypes: testCreationEntryConfig.creationTypes.map((entry) =>
entry.id === 'visual-novel' ? { ...entry, open: false } : entry,
),
});
vi.mocked(listVisualNovelGallery).mockRejectedValue(
new Error('该玩法入口暂不可用'),
);
vi.mocked(listVisualNovelWorks).mockRejectedValue(
new Error('该玩法入口暂不可用'),
);
render(<TestWrapper withAuth />);
await openDraftHub(user);
expect(listVisualNovelGallery).not.toHaveBeenCalled();
expect(listVisualNovelWorks).not.toHaveBeenCalled();
expect(screen.queryByText('该玩法入口暂不可用')).toBeNull();
});
test('published puzzle works appear on home and mobile game category channel', async () => {
const user = userEvent.setup();
const publishedPuzzleWork = {