/* @vitest-environment jsdom */ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { beforeEach, expect, test, vi } from 'vitest'; import type { CustomWorldAgentSessionSnapshot } from '../../../packages/shared/src/contracts/customWorldAgent'; import { CustomWorldAgentWorkspace } from './CustomWorldAgentWorkspace'; const baseSession: CustomWorldAgentSessionSnapshot = { sessionId: 'custom-world-agent-session-1', currentTurn: 4, anchorContent: { worldPromise: { hook: '一个被潮雾改写航线秩序的群岛世界。', differentiator: '所有通路都要向未知代价借路。', desiredExperience: '压迫、潮湿、悬疑', }, playerFantasy: { playerRole: '玩家是被迫返乡的旧航路继承人。', corePursuit: '查清沉船夜背后的真相。', fearOfLoss: '一旦失败,就会再次失去唯一还活着的旧友。', }, themeBoundary: null, playerEntryPoint: null, coreConflict: null, keyRelationships: [], hiddenLines: null, iconicElements: null, }, progressPercent: 58, lastAssistantReply: '世界和玩家视角已经有了,下一步我想把最明面的冲突钉住。', stage: 'collecting_intent', focusCardId: null, creatorIntent: {}, creatorIntentReadiness: { isReady: false, completedKeys: ['world_hook', 'player_premise'], missingKeys: ['theme_and_tone', 'core_conflict', 'relationship_seed', 'iconic_element'], }, anchorPack: {}, lockState: {}, draftProfile: null, messages: [ { id: 'message-1', role: 'assistant', kind: 'chat', text: '先告诉我你想做一个怎样的世界。', createdAt: '2026-04-17T12:00:00.000Z', relatedOperationId: null, }, ], draftCards: [], pendingClarifications: [], suggestedActions: [], recommendedReplies: [], qualityFindings: [], assetCoverage: { roleAssets: [], sceneAssets: [], allRoleAssetsReady: false, allSceneAssetsReady: false, }, updatedAt: '2026-04-17T12:00:00.000Z', }; beforeEach(() => { if (!Element.prototype.scrollIntoView) { Element.prototype.scrollIntoView = () => {}; } }); test('workspace sends summary request from progress area', async () => { const user = userEvent.setup(); const onSubmitMessage = vi.fn(); render( {}} onSubmitMessage={onSubmitMessage} onExecuteAction={() => {}} />, ); await user.click(screen.getByRole('button', { name: '总结当前设定' })); expect(onSubmitMessage).toHaveBeenCalledWith( expect.objectContaining({ text: '请总结一下当前已经成形的世界设定。', }), ); }); test('workspace enables quick fill after at least two turns and submits quick fill request', async () => { const user = userEvent.setup(); const onSubmitMessage = vi.fn(); render( {}} onSubmitMessage={onSubmitMessage} onExecuteAction={() => {}} />, ); await user.click(screen.getByRole('button', { name: '补充剩余设定' })); expect(onSubmitMessage).toHaveBeenCalledWith( expect.objectContaining({ text: '请补充剩余设定。', quickFillRequested: true, }), ); }); test('workspace hides quick fill before two turns', () => { render( {}} onSubmitMessage={() => {}} onExecuteAction={() => {}} />, ); expect(screen.queryByRole('button', { name: '补全剩余设定' })).toBeNull(); }); test('workspace exposes draft action when progress reaches 100', async () => { const user = userEvent.setup(); const onExecuteAction = vi.fn(); render( {}} onSubmitMessage={() => {}} onExecuteAction={onExecuteAction} />, ); await user.click(screen.getByRole('button', { name: '生成游戏设定草稿' })); expect(onExecuteAction).toHaveBeenCalledWith({ action: 'draft_foundation', }); }); test('workspace hides draft action before progress reaches 100', () => { render( {}} onSubmitMessage={() => {}} onExecuteAction={() => {}} />, ); expect( screen.queryByRole('button', { name: '生成游戏设定草稿' }), ).toBeNull(); }); test('workspace submits recommended reply from thread', async () => { const user = userEvent.setup(); const onSubmitMessage = vi.fn(); render( {}} onSubmitMessage={onSubmitMessage} onExecuteAction={() => {}} />, ); await user.click( screen.getByRole('button', { name: '继续补充这个世界的核心冲突' }), ); expect(onSubmitMessage).toHaveBeenCalledWith( expect.objectContaining({ text: '继续补充这个世界的核心冲突', quickFillRequested: false, focusCardId: null, selectedCardIds: [], }), ); });