Add big fish settlement actions and publish feedback
This commit is contained in:
24
docs/experience/BIG_FISH_PUBLISH_FEEDBACK_FIX_2026-04-26.md
Normal file
24
docs/experience/BIG_FISH_PUBLISH_FEEDBACK_FIX_2026-04-26.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 大鱼吃小鱼发布反馈修复 2026-04-26
|
||||
|
||||
## 背景
|
||||
|
||||
大鱼吃小鱼结果页的“发布”按钮已经会向后端发送 `big_fish_publish_game` action。后端发布成功后会把当前 Agent session 的 `stage` 改成 `published`,作品列表也会从 session 聚合出已发布作品。
|
||||
|
||||
问题出在前端发布成功后的反馈链路不完整:
|
||||
|
||||
1. 结果页没有把 `stage: published` 显示成“已发布”状态,用户点击后看起来没有变化。
|
||||
2. 平台父层没有在大鱼发布成功后刷新“大鱼吃小鱼”作品列表,创作中心仍可能保留旧的草稿状态。
|
||||
|
||||
## 落地口径
|
||||
|
||||
1. `BigFishResultView` 以 `session.stage === 'published'` 作为已发布态真相。
|
||||
2. 已发布态下发布按钮显示“已发布”并禁用,避免重复提交。
|
||||
3. 已发布态下发布校验区显示“已发布”状态,继续保留资源完成度信息。
|
||||
4. `PlatformEntryFlowShellImpl` 在 `big_fish_publish_game` 成功后刷新 `bigFishWorks`。
|
||||
5. 发布失败仍沿用既有错误模态,展示后端 `details.message` 里的具体校验原因。
|
||||
|
||||
## 验收
|
||||
|
||||
1. 在大鱼结果页点击“发布”会调用 `/api/runtime/big-fish/agent/sessions/{sessionId}/actions` 的 `big_fish_publish_game`。
|
||||
2. 后端返回已发布 session 后,结果页按钮变为“已发布”。
|
||||
3. 返回创作中心后,该作品卡片状态通过刷新后的作品列表体现为已发布。
|
||||
@@ -30,3 +30,4 @@
|
||||
- [PLATFORM_HOME_BANNER_IMAGE_SIZE_FIX_2026-04-25.md](./PLATFORM_HOME_BANNER_IMAGE_SIZE_FIX_2026-04-25.md):记录首页 banner 背景图不能进入普通布局流的修复经验。
|
||||
- [RPG_PUBLISH_GALLERY_REFRESH_FIX_2026-04-25.md](./RPG_PUBLISH_GALLERY_REFRESH_FIX_2026-04-25.md):记录 RPG 发布后首页 / 分类页公开作品列表刷新链路。
|
||||
- [AGENT_EMPTY_SESSION_DRAFT_VISIBILITY_2026-04-26.md](./AGENT_EMPTY_SESSION_DRAFT_VISIBILITY_2026-04-26.md):记录 Agent 空会话不应进入作品草稿列表的后端判定规则。
|
||||
- [BIG_FISH_PUBLISH_FEEDBACK_FIX_2026-04-26.md](./BIG_FISH_PUBLISH_FEEDBACK_FIX_2026-04-26.md):记录大鱼吃小鱼发布成功后结果页反馈与作品列表刷新的修复口径。
|
||||
|
||||
@@ -242,6 +242,7 @@
|
||||
2. 发送聊天、action 和摇杆输入。
|
||||
3. 根据后端 snapshot 渲染实体。
|
||||
4. 当后端 snapshot 返回 `won` 或 `failed` 时,必须在玩法舞台中央显示清晰结算浮层;通关与失败都不能只依赖顶部状态标签或事件日志。
|
||||
5. 结算浮层必须提供可继续操作的出口:`failed` 至少包含“重来”和“退出”,`won` 至少包含“退出”。“重来”只能重新启动当前大鱼作品的一局后端 run,不能在前端本地篡改旧 run snapshot;“退出”回到当前作品结果页或直达入口的上级页面。
|
||||
|
||||
前端禁止:
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
## 验收口径
|
||||
|
||||
1. 浏览器访问 `/big-fish` 后直接显示竖屏大鱼吃小鱼舞台。
|
||||
2. 左下摇杆可移动玩家实体。
|
||||
2. 屏幕任意位置按下并拖动可移动玩家实体。
|
||||
3. 玩家碰到不高于自身等级的实体后成长,并在事件日志显示成长结果。
|
||||
4. 左上返回按钮在直达页语义为重开当前占位局。
|
||||
4. 左上返回按钮在直达页语义为退出到平台首页。
|
||||
5. 直达页通关或失败后,结算浮层继续复用正式运行态出口;失败态点击“重来”重开本地占位局,点击“退出”回到平台首页。
|
||||
|
||||
@@ -208,11 +208,16 @@ export default function BigFishPlaygroundApp() {
|
||||
setRun(buildInitialRun());
|
||||
}, []);
|
||||
|
||||
const handleExit = useCallback(() => {
|
||||
window.location.assign('/');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<BigFishRuntimeShell
|
||||
run={run}
|
||||
assetSlots={assetSlots}
|
||||
onBack={handleRestart}
|
||||
onBack={handleExit}
|
||||
onRestart={handleRestart}
|
||||
onSubmitInput={handleSubmitInput}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -170,4 +170,35 @@ describe('BigFishResultView', () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '知道了' }));
|
||||
expect(onDismissError).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('shows published state and prevents duplicate publish clicks', () => {
|
||||
const onExecuteAction = vi.fn();
|
||||
|
||||
render(
|
||||
<BigFishResultView
|
||||
session={{
|
||||
...createSession(),
|
||||
stage: 'published',
|
||||
publishReady: true,
|
||||
assetCoverage: {
|
||||
levelMainImageReadyCount: 1,
|
||||
levelMotionReadyCount: 2,
|
||||
backgroundReady: true,
|
||||
requiredLevelCount: 1,
|
||||
publishReady: true,
|
||||
blockers: [],
|
||||
},
|
||||
}}
|
||||
onBack={() => {}}
|
||||
onExecuteAction={onExecuteAction}
|
||||
onStartTestRun={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
const publishedButton = screen.getByRole('button', { name: '已发布' });
|
||||
expect((publishedButton as HTMLButtonElement).disabled).toBe(true);
|
||||
expect(screen.getAllByText('已发布').length).toBeGreaterThan(0);
|
||||
fireEvent.click(publishedButton);
|
||||
expect(onExecuteAction).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
Sparkles,
|
||||
Waves,
|
||||
} from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import type {
|
||||
BigFishAssetSlotResponse,
|
||||
@@ -338,6 +338,7 @@ export function BigFishResultView({
|
||||
}: BigFishResultViewProps) {
|
||||
const [studioTarget, setStudioTarget] =
|
||||
useState<BigFishAssetStudioTarget | null>(null);
|
||||
const [isPublishSubmitting, setIsPublishSubmitting] = useState(false);
|
||||
const draft = session.draft;
|
||||
const backgroundSlot = findAssetSlot(session.assetSlots, 'stage_background');
|
||||
const backgroundPreviewUrl = buildLevelAssetPreview(backgroundSlot);
|
||||
@@ -345,6 +346,8 @@ export function BigFishResultView({
|
||||
() => session.assetCoverage.blockers.filter(Boolean),
|
||||
[session.assetCoverage.blockers],
|
||||
);
|
||||
const isPublished = session.stage === 'published';
|
||||
const canClickPublish = !isPublished && !isBusy;
|
||||
const studioPreviewUrl = useMemo(() => {
|
||||
if (!studioTarget) {
|
||||
return null;
|
||||
@@ -352,6 +355,12 @@ export function BigFishResultView({
|
||||
return buildStudioAssetPreview(session.assetSlots, studioTarget);
|
||||
}, [session.assetSlots, studioTarget]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isBusy || isPublished || error) {
|
||||
setIsPublishSubmitting(false);
|
||||
}
|
||||
}, [error, isBusy, isPublished]);
|
||||
|
||||
if (!draft) {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
@@ -388,14 +397,23 @@ export function BigFishResultView({
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
disabled={!canClickPublish}
|
||||
onClick={() => {
|
||||
setIsPublishSubmitting(true);
|
||||
onExecuteAction({ action: 'big_fish_publish_game' });
|
||||
}}
|
||||
className="inline-flex items-center gap-2 rounded-full bg-cyan-200 px-4 py-2 text-sm font-bold text-slate-950 disabled:opacity-45"
|
||||
>
|
||||
<CheckCircle2 className="h-4 w-4" />
|
||||
发布
|
||||
{isPublishSubmitting && isBusy && !isPublished ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<CheckCircle2 className="h-4 w-4" />
|
||||
)}
|
||||
{isPublished
|
||||
? '已发布'
|
||||
: isPublishSubmitting && isBusy
|
||||
? '发布中'
|
||||
: '发布'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -487,7 +505,11 @@ export function BigFishResultView({
|
||||
背景 {session.assetCoverage.backgroundReady ? '已完成' : '待生成'}
|
||||
</div>
|
||||
</div>
|
||||
{blockers.length > 0 ? (
|
||||
{isPublished ? (
|
||||
<div className="mt-3 text-sm font-semibold text-emerald-600">
|
||||
已发布
|
||||
</div>
|
||||
) : blockers.length > 0 ? (
|
||||
<div className="mt-3 space-y-1 text-xs leading-5 text-amber-700">
|
||||
{blockers.slice(0, 4).map((blocker) => (
|
||||
<div key={blocker}>{blocker}</div>
|
||||
|
||||
80
src/components/big-fish-runtime/BigFishRuntimeShell.test.tsx
Normal file
80
src/components/big-fish-runtime/BigFishRuntimeShell.test.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import type { BigFishRuntimeSnapshotResponse } from '../../../packages/shared/src/contracts/bigFish';
|
||||
import { BigFishRuntimeShell } from './BigFishRuntimeShell';
|
||||
|
||||
vi.mock('../ResolvedAssetImage', () => ({
|
||||
ResolvedAssetImage: ({
|
||||
src,
|
||||
alt,
|
||||
className,
|
||||
}: {
|
||||
src?: string | null;
|
||||
alt?: string;
|
||||
className?: string;
|
||||
}) => (src ? <img src={src} alt={alt} className={className} /> : null),
|
||||
}));
|
||||
|
||||
function createRun(
|
||||
status: BigFishRuntimeSnapshotResponse['status'],
|
||||
): BigFishRuntimeSnapshotResponse {
|
||||
return {
|
||||
runId: 'big-fish-run-1',
|
||||
sessionId: 'big-fish-session-1',
|
||||
status,
|
||||
tick: 18,
|
||||
playerLevel: 2,
|
||||
winLevel: 5,
|
||||
leaderEntityId: null,
|
||||
ownedEntities: [],
|
||||
wildEntities: [],
|
||||
cameraCenter: { x: 0, y: 0 },
|
||||
lastInput: { x: 0, y: 0 },
|
||||
eventLog: ['己方鱼群已经耗尽'],
|
||||
updatedAt: '2026-04-26T12:00:00.000Z',
|
||||
};
|
||||
}
|
||||
|
||||
describe('BigFishRuntimeShell', () => {
|
||||
test('renders restart and exit actions after a failed run', () => {
|
||||
const onBack = vi.fn();
|
||||
const onRestart = vi.fn();
|
||||
|
||||
render(
|
||||
<BigFishRuntimeShell
|
||||
run={createRun('failed')}
|
||||
onBack={onBack}
|
||||
onRestart={onRestart}
|
||||
onSubmitInput={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '重来' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '退出' }));
|
||||
|
||||
expect(screen.getByText('本轮失败')).toBeTruthy();
|
||||
expect(onRestart).toHaveBeenCalledTimes(1);
|
||||
expect(onBack).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('keeps an exit action after a won run', () => {
|
||||
const onBack = vi.fn();
|
||||
|
||||
render(
|
||||
<BigFishRuntimeShell
|
||||
run={createRun('won')}
|
||||
onBack={onBack}
|
||||
onSubmitInput={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('通关完成')).toBeTruthy();
|
||||
expect(screen.queryByRole('button', { name: '重来' })).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '退出' }));
|
||||
expect(onBack).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ArrowLeft, Loader2 } from 'lucide-react';
|
||||
import { useEffect, useRef, useState, type PointerEvent } from 'react';
|
||||
import { ArrowLeft, Loader2, RotateCcw } from 'lucide-react';
|
||||
import { type PointerEvent, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import type {
|
||||
BigFishAssetSlotResponse,
|
||||
@@ -21,6 +21,7 @@ type BigFishRuntimeShellProps = {
|
||||
isBusy?: boolean;
|
||||
error?: string | null;
|
||||
onBack: () => void;
|
||||
onRestart?: () => void;
|
||||
onSubmitInput: (payload: SubmitBigFishInputRequest) => void;
|
||||
};
|
||||
|
||||
@@ -188,6 +189,7 @@ export function BigFishRuntimeShell({
|
||||
isBusy = false,
|
||||
error = null,
|
||||
onBack,
|
||||
onRestart,
|
||||
onSubmitInput,
|
||||
}: BigFishRuntimeShellProps) {
|
||||
const stageRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -200,6 +202,10 @@ export function BigFishRuntimeShell({
|
||||
}, [stick]);
|
||||
|
||||
useEffect(() => {
|
||||
if (run?.status !== 'running') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const timer = window.setInterval(() => {
|
||||
const current = stickRef.current;
|
||||
// 即使没有方向输入也持续回传当前状态,让后端持续推进刷怪、清理与胜负裁决。
|
||||
@@ -209,7 +215,7 @@ export function BigFishRuntimeShell({
|
||||
return () => {
|
||||
window.clearInterval(timer);
|
||||
};
|
||||
}, [onSubmitInput]);
|
||||
}, [onSubmitInput, run?.status]);
|
||||
|
||||
const submitDirection = (direction: SubmitBigFishInputRequest) => {
|
||||
setStick(direction);
|
||||
@@ -318,16 +324,39 @@ export function BigFishRuntimeShell({
|
||||
</div>
|
||||
|
||||
{settlementCopy ? (
|
||||
<div className="pointer-events-none absolute inset-0 z-40 flex items-center justify-center px-5">
|
||||
<div className="absolute inset-0 z-40 flex items-center justify-center px-5">
|
||||
<div
|
||||
className={`w-full max-w-[20rem] rounded-[2rem] border border-white/24 bg-gradient-to-br ${settlementCopy.tone} p-6 text-center shadow-2xl shadow-slate-950/45 backdrop-blur-xl`}
|
||||
className={`w-full max-w-[20rem] rounded-[1.5rem] border border-white/24 bg-gradient-to-br ${settlementCopy.tone} p-6 text-center shadow-2xl shadow-slate-950/45 backdrop-blur-xl`}
|
||||
>
|
||||
<div className="text-3xl font-black tracking-[0.22em] text-white [text-shadow:0_2px_12px_rgba(2,6,23,0.6)]">
|
||||
<div className="text-3xl font-black text-white [text-shadow:0_2px_12px_rgba(2,6,23,0.6)]">
|
||||
{settlementCopy.title}
|
||||
</div>
|
||||
<div className="mt-3 text-sm font-semibold leading-6 text-white/82">
|
||||
{settlementCopy.message}
|
||||
</div>
|
||||
<div className="mt-5 grid grid-cols-2 gap-2">
|
||||
{run.status === 'failed' && onRestart ? (
|
||||
<button
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
onClick={onRestart}
|
||||
className="inline-flex h-11 items-center justify-center gap-2 rounded-full bg-white px-4 text-sm font-bold text-slate-950 shadow-lg shadow-slate-950/20 disabled:opacity-45"
|
||||
>
|
||||
<RotateCcw className="h-4 w-4" />
|
||||
重来
|
||||
</button>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
onClick={onBack}
|
||||
className={`inline-flex h-11 items-center justify-center gap-2 rounded-full border border-white/30 bg-black/24 px-4 text-sm font-bold text-white backdrop-blur ${
|
||||
run.status === 'failed' && onRestart ? '' : 'col-span-2'
|
||||
}`}
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
退出
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -755,6 +755,9 @@ export function PlatformEntryFlowShellImpl({
|
||||
},
|
||||
onActionComplete: ({ payload, response, setSession }) => {
|
||||
setSession(response.session);
|
||||
if (payload.action === 'big_fish_publish_game') {
|
||||
void refreshBigFishShelf();
|
||||
}
|
||||
if (payload.action !== 'big_fish_compile_draft') {
|
||||
return;
|
||||
}
|
||||
@@ -1099,7 +1102,11 @@ export function PlatformEntryFlowShellImpl({
|
||||
|
||||
const submitBigFishInput = useCallback(
|
||||
(payload: SubmitBigFishInputRequest) => {
|
||||
if (!bigFishRun || bigFishInputInFlightRef.current) {
|
||||
if (
|
||||
!bigFishRun ||
|
||||
bigFishRun.status !== 'running' ||
|
||||
bigFishInputInFlightRef.current
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2096,6 +2103,9 @@ export function PlatformEntryFlowShellImpl({
|
||||
onBack={() => {
|
||||
setSelectionStage('big-fish-result');
|
||||
}}
|
||||
onRestart={() => {
|
||||
void startBigFishRun();
|
||||
}}
|
||||
onSubmitInput={submitBigFishInput}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
} from '../../services/rpg-entry';
|
||||
import {
|
||||
createBigFishCreationSession,
|
||||
executeBigFishCreationAction,
|
||||
getBigFishCreationSession,
|
||||
} from '../../services/big-fish-creation';
|
||||
import { listBigFishWorks } from '../../services/big-fish-works';
|
||||
@@ -172,13 +173,23 @@ vi.mock('../big-fish-result/BigFishResultView', () => ({
|
||||
BigFishResultView: ({
|
||||
session,
|
||||
onBack,
|
||||
onExecuteAction,
|
||||
}: {
|
||||
session: { draft?: { title: string } | null };
|
||||
onBack: () => void;
|
||||
onExecuteAction: (payload: { action: string }) => void;
|
||||
}) => (
|
||||
<div className="big-fish-result-view-mock">
|
||||
<div>大鱼吃小鱼结果页</div>
|
||||
<div>{session.draft?.title ?? '缺少草稿标题'}</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onExecuteAction({ action: 'big_fish_publish_game' });
|
||||
}}
|
||||
>
|
||||
发布
|
||||
</button>
|
||||
<button type="button" onClick={onBack}>
|
||||
返回
|
||||
</button>
|
||||
@@ -1815,6 +1826,102 @@ test('big fish draft card restores the bound agent session and opens the result
|
||||
expect(screen.getByText('我想做机械深海里微生物互相吞并进化。')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('big fish result publish action refreshes creation works', async () => {
|
||||
const user = userEvent.setup();
|
||||
const baseBigFishSession = (await getBigFishCreationSession('big-fish-session-1'))
|
||||
.session;
|
||||
vi.mocked(getBigFishCreationSession).mockClear();
|
||||
vi.mocked(listBigFishWorks).mockClear();
|
||||
const publishedBigFishSession = {
|
||||
...baseBigFishSession,
|
||||
stage: 'published',
|
||||
publishReady: true,
|
||||
assetCoverage: {
|
||||
levelMainImageReadyCount: 8,
|
||||
levelMotionReadyCount: 16,
|
||||
backgroundReady: true,
|
||||
requiredLevelCount: 8,
|
||||
publishReady: true,
|
||||
blockers: [],
|
||||
},
|
||||
updatedAt: '2026-04-22T12:20:00.000Z',
|
||||
};
|
||||
vi.mocked(executeBigFishCreationAction).mockResolvedValue({
|
||||
session: publishedBigFishSession,
|
||||
});
|
||||
vi.mocked(listBigFishWorks)
|
||||
.mockResolvedValueOnce({
|
||||
items: [
|
||||
{
|
||||
workId: 'big-fish-work-big-fish-session-1',
|
||||
sourceSessionId: 'big-fish-session-1',
|
||||
title: '机械深海 大鱼吃小鱼',
|
||||
subtitle: '机械微生物吞并进化 · 偏爽快节奏',
|
||||
summary: '机械微生物吞并进化',
|
||||
coverImageSrc: null,
|
||||
status: 'draft',
|
||||
updatedAt: '2026-04-22T12:10:00.000Z',
|
||||
publishReady: true,
|
||||
levelCount: 8,
|
||||
levelMainImageReadyCount: 8,
|
||||
levelMotionReadyCount: 16,
|
||||
backgroundReady: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
workId: 'big-fish-work-big-fish-session-1',
|
||||
sourceSessionId: 'big-fish-session-1',
|
||||
title: '机械深海 大鱼吃小鱼',
|
||||
subtitle: '机械微生物吞并进化 · 偏爽快节奏',
|
||||
summary: '机械微生物吞并进化',
|
||||
coverImageSrc: null,
|
||||
status: 'published',
|
||||
updatedAt: '2026-04-22T12:20:00.000Z',
|
||||
publishReady: true,
|
||||
levelCount: 8,
|
||||
levelMainImageReadyCount: 8,
|
||||
levelMotionReadyCount: 16,
|
||||
backgroundReady: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
render(<TestWrapper withAuth />);
|
||||
|
||||
await openCreationHub(user);
|
||||
const title = await screen.findByText('机械深海 大鱼吃小鱼');
|
||||
const card = title.closest('.platform-surface');
|
||||
if (!(card instanceof HTMLElement)) {
|
||||
throw new Error('Missing big fish draft card');
|
||||
}
|
||||
|
||||
await user.click(card);
|
||||
await waitFor(() => {
|
||||
expect(getBigFishCreationSession).toHaveBeenCalledWith(
|
||||
'big-fish-session-1',
|
||||
);
|
||||
});
|
||||
vi.mocked(listBigFishWorks).mockClear();
|
||||
|
||||
expect(await screen.findByText('大鱼吃小鱼结果页')).toBeTruthy();
|
||||
await user.click(await screen.findByRole('button', { name: '发布' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(executeBigFishCreationAction).toHaveBeenCalledWith(
|
||||
'big-fish-session-1',
|
||||
{
|
||||
action: 'big_fish_publish_game',
|
||||
},
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(listBigFishWorks).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
test('starting draft generation leaves the agent workspace and shows the generation progress view', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user