fix: show published big fish works in gallery
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -6,6 +6,7 @@ import { useState } from 'react';
|
||||
import { beforeEach, expect, test, vi } from 'vitest';
|
||||
|
||||
import type { CustomWorldAgentSessionSnapshot } from '../../../packages/shared/src/contracts/customWorldAgent';
|
||||
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
|
||||
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
||||
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
|
||||
import { ApiClientError } from '../../services/apiClient';
|
||||
@@ -15,6 +16,8 @@ import {
|
||||
executeBigFishCreationAction,
|
||||
getBigFishCreationSession,
|
||||
} from '../../services/big-fish-creation';
|
||||
import { listBigFishGallery } from '../../services/big-fish-gallery';
|
||||
import { startBigFishRuntimeRun } from '../../services/big-fish-runtime';
|
||||
import { listBigFishWorks } from '../../services/big-fish-works';
|
||||
import {
|
||||
createPuzzleAgentSession,
|
||||
@@ -145,6 +148,15 @@ vi.mock('../../services/big-fish-works', () => ({
|
||||
listBigFishWorks: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../services/big-fish-gallery', () => ({
|
||||
listBigFishGallery: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../services/big-fish-runtime', () => ({
|
||||
startBigFishRuntimeRun: vi.fn(),
|
||||
submitBigFishRuntimeInput: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../services/puzzle-agent', () => ({
|
||||
createPuzzleAgentSession: vi.fn(),
|
||||
executePuzzleAgentAction: vi.fn(),
|
||||
@@ -152,6 +164,69 @@ vi.mock('../../services/puzzle-agent', () => ({
|
||||
streamPuzzleAgentMessage: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../puzzle-agent/PuzzleAgentWorkspace', () => ({
|
||||
PuzzleAgentWorkspace: ({
|
||||
session,
|
||||
onBack,
|
||||
}: {
|
||||
session: { sessionId: string; messages: Array<{ text: string }> } | null;
|
||||
onBack: () => void;
|
||||
}) => (
|
||||
<div className="puzzle-agent-workspace-mock">
|
||||
<div>拼图工作区:{session?.sessionId ?? 'missing-session'}</div>
|
||||
{session?.messages.map((message) => (
|
||||
<div key={`${session.sessionId}-${message.text}`}>{message.text}</div>
|
||||
))}
|
||||
<button type="button" onClick={onBack}>
|
||||
返回
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('../puzzle-result/PuzzleResultView', () => ({
|
||||
PuzzleResultView: ({
|
||||
session,
|
||||
onBack,
|
||||
}: {
|
||||
session: { draft?: { levelName: string } | null };
|
||||
onBack: () => void;
|
||||
}) => (
|
||||
<div className="puzzle-result-view-mock">
|
||||
<div>拼图结果页</div>
|
||||
<label>
|
||||
关卡名
|
||||
<input readOnly value={session.draft?.levelName ?? ''} />
|
||||
</label>
|
||||
<button type="button" onClick={onBack}>
|
||||
返回
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('../puzzle-gallery/PuzzleGalleryDetailView', () => ({
|
||||
PuzzleGalleryDetailView: ({
|
||||
item,
|
||||
onBack,
|
||||
onStartGame,
|
||||
}: {
|
||||
item: { levelName: string };
|
||||
onBack: () => void;
|
||||
onStartGame: () => void;
|
||||
}) => (
|
||||
<div className="puzzle-gallery-detail-view-mock">
|
||||
<div>{item.levelName}</div>
|
||||
<button type="button" onClick={onStartGame}>
|
||||
进入第 1 关
|
||||
</button>
|
||||
<button type="button" onClick={onBack}>
|
||||
返回
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('../big-fish-creation/BigFishAgentWorkspace', () => ({
|
||||
BigFishAgentWorkspace: ({
|
||||
session,
|
||||
@@ -232,8 +307,7 @@ const mockSession: CustomWorldAgentSessionSnapshot = {
|
||||
'玩家以返乡守灯人继承者身份切入,回港首夜撞见禁航区假航灯重亮,动机是阻止更多船只误入死潮。',
|
||||
coreConflict:
|
||||
'守灯会与航运公会争夺航路解释权,有人在借假航灯持续清洗旧案证据,玩家返乡当夜就被卷进封航冲突。',
|
||||
keyRelationships:
|
||||
'玩家与沈砺旧友互疑,沈砺知道沉船夜的另一半真相。',
|
||||
keyRelationships: '玩家与沈砺旧友互疑,沈砺知道沉船夜的另一半真相。',
|
||||
hiddenLines:
|
||||
'沉船夜与假航灯骗局属于同一操盘链条,表面像海雾自然失控,揭示节奏是先见异常,再见旧案,再见操盘者。',
|
||||
iconicElements:
|
||||
@@ -956,6 +1030,34 @@ beforeEach(() => {
|
||||
vi.mocked(listBigFishWorks).mockResolvedValue({
|
||||
items: [],
|
||||
});
|
||||
vi.mocked(listBigFishGallery).mockResolvedValue({
|
||||
items: [],
|
||||
});
|
||||
vi.mocked(startBigFishRuntimeRun).mockResolvedValue({
|
||||
run: {
|
||||
runId: 'big-fish-run-1',
|
||||
sessionId: 'big-fish-session-public-1',
|
||||
status: 'running',
|
||||
tick: 0,
|
||||
playerLevel: 1,
|
||||
winLevel: 8,
|
||||
leaderEntityId: 'owned-1',
|
||||
ownedEntities: [
|
||||
{
|
||||
entityId: 'owned-1',
|
||||
level: 1,
|
||||
position: { x: 0, y: 0 },
|
||||
radius: 12,
|
||||
offscreenSeconds: 0,
|
||||
},
|
||||
],
|
||||
wildEntities: [],
|
||||
cameraCenter: { x: 0, y: 0 },
|
||||
lastInput: { x: 0, y: 0 },
|
||||
eventLog: ['机械鱼群开始巡游。'],
|
||||
updatedAt: '2026-04-25T12:12:00.000Z',
|
||||
},
|
||||
});
|
||||
vi.mocked(listPuzzleWorks).mockResolvedValue({
|
||||
items: [],
|
||||
});
|
||||
@@ -1329,6 +1431,7 @@ test('creation hub clears all private work shelves immediately after logout stat
|
||||
{
|
||||
workId: 'big-fish-logout-cache-1',
|
||||
sourceSessionId: 'big-fish-logout-cache-session',
|
||||
ownerUserId: 'user-1',
|
||||
title: '大鱼退出缓存作品',
|
||||
subtitle: '登出后不应继续可见',
|
||||
summary: '这条大鱼私有作品只能在登录态展示。',
|
||||
@@ -1427,6 +1530,48 @@ test('published puzzle works appear on home and category public shelves', async
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('published big fish works appear on home and category public shelves', async () => {
|
||||
const user = userEvent.setup();
|
||||
const publishedBigFishWork: BigFishWorkSummary = {
|
||||
workId: 'big-fish-work-public-1',
|
||||
sourceSessionId: 'big-fish-session-public-1',
|
||||
ownerUserId: 'user-2',
|
||||
title: '机械深海 大鱼吃小鱼',
|
||||
subtitle: '机械微生物吞并进化',
|
||||
summary: '从微光孢子一路吞并成长到深海巨鲲。',
|
||||
coverImageSrc: null,
|
||||
status: 'published',
|
||||
updatedAt: '2026-04-25T10:30:00.000Z',
|
||||
publishReady: true,
|
||||
levelCount: 8,
|
||||
levelMainImageReadyCount: 8,
|
||||
levelMotionReadyCount: 16,
|
||||
backgroundReady: true,
|
||||
};
|
||||
|
||||
vi.mocked(listBigFishGallery).mockResolvedValue({
|
||||
items: [publishedBigFishWork],
|
||||
});
|
||||
|
||||
render(<TestWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByText('机械深海 大鱼吃小鱼').length).toBeGreaterThan(
|
||||
0,
|
||||
);
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: '分类' }));
|
||||
|
||||
const categoryPanel = getPlatformTabPanel('category');
|
||||
expect(
|
||||
within(categoryPanel).getAllByText('机械深海 大鱼吃小鱼').length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
within(categoryPanel).getAllByRole('button', { name: /大鱼/u }).length,
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('published puzzle detail returns to the source platform tab', async () => {
|
||||
const user = userEvent.setup();
|
||||
const publishedPuzzleWork = {
|
||||
@@ -1797,8 +1942,9 @@ test('public code search opens a published puzzle by PZ code', async () => {
|
||||
|
||||
render(<TestWrapper withAuth />);
|
||||
|
||||
const searchInput =
|
||||
await screen.findByPlaceholderText('输入 SY / CW / PZ 编号');
|
||||
const searchInput = await screen.findByPlaceholderText(
|
||||
'输入 SY / CW / BF / PZ 编号',
|
||||
);
|
||||
await user.type(searchInput, 'PZ-EPUBLIC1');
|
||||
await user.click(screen.getByRole('button', { name: '搜索' }));
|
||||
|
||||
@@ -1812,6 +1958,49 @@ test('public code search opens a published puzzle by PZ code', async () => {
|
||||
expect(getRpgEntryWorldGalleryDetailByCode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('public code search opens a published big fish work by BF code', async () => {
|
||||
const user = userEvent.setup();
|
||||
const bigFishWork: BigFishWorkSummary = {
|
||||
workId: 'big-fish-work-public-1',
|
||||
sourceSessionId: 'big-fish-session-public-1',
|
||||
ownerUserId: 'user-2',
|
||||
title: '机械深海 大鱼吃小鱼',
|
||||
subtitle: '机械微生物吞并进化',
|
||||
summary: '从微光孢子一路吞并成长到深海巨鲲。',
|
||||
coverImageSrc: null,
|
||||
status: 'published',
|
||||
updatedAt: '2026-04-25T10:30:00.000Z',
|
||||
publishReady: true,
|
||||
levelCount: 8,
|
||||
levelMainImageReadyCount: 8,
|
||||
levelMotionReadyCount: 16,
|
||||
backgroundReady: true,
|
||||
};
|
||||
|
||||
vi.mocked(listBigFishGallery).mockResolvedValue({
|
||||
items: [bigFishWork],
|
||||
});
|
||||
|
||||
render(<TestWrapper withAuth />);
|
||||
|
||||
const searchInput = await screen.findByPlaceholderText(
|
||||
'输入 SY / CW / BF / PZ 编号',
|
||||
);
|
||||
await user.type(searchInput, 'BF-NPUBLIC1');
|
||||
await user.click(screen.getByRole('button', { name: '搜索' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(startBigFishRuntimeRun).toHaveBeenCalledWith(
|
||||
'big-fish-session-public-1',
|
||||
);
|
||||
});
|
||||
expect(await screen.findByText('Lv.1/8 · 进行中')).toBeTruthy();
|
||||
expect(getBigFishCreationSession).not.toHaveBeenCalledWith(
|
||||
'big-fish-session-public-1',
|
||||
);
|
||||
expect(getRpgEntryWorldGalleryDetailByCode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('big fish draft card restores the bound agent session and opens the result view', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -1820,6 +2009,7 @@ test('big fish draft card restores the bound agent session and opens the result
|
||||
{
|
||||
workId: 'big-fish-work-big-fish-session-1',
|
||||
sourceSessionId: 'big-fish-session-1',
|
||||
ownerUserId: 'user-1',
|
||||
title: '机械深海 大鱼吃小鱼',
|
||||
subtitle: '机械微生物吞并进化 · 偏爽快节奏',
|
||||
summary: '机械微生物吞并进化',
|
||||
@@ -1867,10 +2057,12 @@ test('big fish draft card restores the bound agent session and opens the result
|
||||
|
||||
test('big fish result publish action refreshes creation works', async () => {
|
||||
const user = userEvent.setup();
|
||||
const baseBigFishSession = (await getBigFishCreationSession('big-fish-session-1'))
|
||||
.session;
|
||||
const baseBigFishSession = (
|
||||
await getBigFishCreationSession('big-fish-session-1')
|
||||
).session;
|
||||
vi.mocked(getBigFishCreationSession).mockClear();
|
||||
vi.mocked(listBigFishWorks).mockClear();
|
||||
vi.mocked(listBigFishGallery).mockClear();
|
||||
const publishedBigFishSession = {
|
||||
...baseBigFishSession,
|
||||
stage: 'published',
|
||||
@@ -1894,6 +2086,7 @@ test('big fish result publish action refreshes creation works', async () => {
|
||||
{
|
||||
workId: 'big-fish-work-big-fish-session-1',
|
||||
sourceSessionId: 'big-fish-session-1',
|
||||
ownerUserId: 'user-1',
|
||||
title: '机械深海 大鱼吃小鱼',
|
||||
subtitle: '机械微生物吞并进化 · 偏爽快节奏',
|
||||
summary: '机械微生物吞并进化',
|
||||
@@ -1913,6 +2106,7 @@ test('big fish result publish action refreshes creation works', async () => {
|
||||
{
|
||||
workId: 'big-fish-work-big-fish-session-1',
|
||||
sourceSessionId: 'big-fish-session-1',
|
||||
ownerUserId: 'user-1',
|
||||
title: '机械深海 大鱼吃小鱼',
|
||||
subtitle: '机械微生物吞并进化 · 偏爽快节奏',
|
||||
summary: '机械微生物吞并进化',
|
||||
@@ -1959,6 +2153,9 @@ test('big fish result publish action refreshes creation works', async () => {
|
||||
await waitFor(() => {
|
||||
expect(listBigFishWorks).toHaveBeenCalled();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(listBigFishGallery).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
test('starting draft generation leaves the agent workspace and shows the generation progress view', async () => {
|
||||
|
||||
Reference in New Issue
Block a user