fix(design): restore streamed replies and quote handoff
This commit is contained in:
1 parent
229b1b1ce3
commit
23f96a523e
9 files changed
+362
-19
No files matched your search
@@ -93,11 +93,12 @@ describe('youth AI Design Canvas page', () => {
|
||||
expect(screen.queryByText(/规格版本|编译器|生成策略|字段决策/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('keeps unfinished AI output out of the conversation while send status stays visible', () => {
|
||||
prepareWorkspace();
|
||||
const unfinishedDraft = '收到,我们要收到,我们要制作一张社团活动海报。';
|
||||
it('shows one unfinished assistant reply incrementally and replaces it with the canonical turn', async () => {
|
||||
const { workspace } = prepareWorkspace();
|
||||
const firstChunk = '收到,我们要制作';
|
||||
const unfinishedDraft = `${firstChunk}一张社团活动海报。`;
|
||||
useImageWorkspaceStore.setState({
|
||||
assistantStreams: { 'operation-chat-1': unfinishedDraft },
|
||||
assistantStreams: { 'operation-chat-1': firstChunk },
|
||||
pendingOperations: {
|
||||
'operation-chat-1': {
|
||||
id: 'operation-chat-1',
|
||||
@@ -124,10 +125,66 @@ describe('youth AI Design Canvas page', () => {
|
||||
const pendingMessage = within(conversation).getByTestId('pending-design-chat-operation-chat-1');
|
||||
expect(within(pendingMessage).getByText('做一张社团活动海报')).toBeInTheDocument();
|
||||
expect(within(pendingMessage).getByText('发送中')).toBeInTheDocument();
|
||||
expect(within(conversation).queryByRole('button', { name: '下一步:看看制作方案' }))
|
||||
.not.toBeInTheDocument();
|
||||
expect(within(conversation).queryByTestId('design-assistant-progress')).not.toBeInTheDocument();
|
||||
expect(within(conversation).queryByText('AI 正在整理你的想法')).not.toBeInTheDocument();
|
||||
expect(within(conversation).getByText('我已经整理了用途、受众和初步概念,请确认右侧建议。')).toBeInTheDocument();
|
||||
expect(within(conversation).queryByText(unfinishedDraft)).not.toBeInTheDocument();
|
||||
const streamingReply = within(conversation)
|
||||
.getByTestId('streaming-design-assistant-operation-chat-1');
|
||||
expect(streamingReply).toHaveTextContent(firstChunk);
|
||||
|
||||
act(() => {
|
||||
useImageWorkspaceStore.setState({
|
||||
assistantStreams: { 'operation-chat-1': unfinishedDraft },
|
||||
});
|
||||
});
|
||||
expect(streamingReply).toHaveTextContent(unfinishedDraft);
|
||||
|
||||
act(() => {
|
||||
useImageWorkspaceStore.setState({
|
||||
workspace: {
|
||||
...workspace,
|
||||
turns: [...workspace.turns, {
|
||||
turnId: 'turn-2',
|
||||
rawTurnSequence: 2,
|
||||
userMessage: '做一张社团活动海报',
|
||||
assistantMessage: unfinishedDraft,
|
||||
}],
|
||||
},
|
||||
pendingOperations: {},
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(within(conversation).queryByTestId('streaming-design-assistant-operation-chat-1'))
|
||||
.not.toBeInTheDocument();
|
||||
});
|
||||
expect(within(conversation).getAllByText(unfinishedDraft)).toHaveLength(1);
|
||||
expect(within(conversation).getByRole('button', { name: '下一步:看看制作方案' }))
|
||||
.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('opens the mobile quote confirmation from the ready conversation without starting a paid task', async () => {
|
||||
const { actions } = prepareWorkspace();
|
||||
const quotedWorkspace = designWorkspaceFixture({
|
||||
form: designFormFixture({ activeQuotes: [designQuoteFixture()] }),
|
||||
});
|
||||
actions.requestQuote.mockImplementationOnce(async () => {
|
||||
useImageWorkspaceStore.setState({ workspace: quotedWorkspace });
|
||||
return quotedWorkspace;
|
||||
});
|
||||
render(<ImageCanvas />);
|
||||
|
||||
const conversation = screen.getByTestId('image-workspace-conversation');
|
||||
fireEvent.click(within(conversation).getByRole('button', { name: '下一步:看看制作方案' }));
|
||||
|
||||
expect(actions.requestQuote).toHaveBeenCalledOnce();
|
||||
expect(actions.confirmGeneration).not.toHaveBeenCalled();
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: '制作方案准备好了' })).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByTestId('design-offered-quote')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows a submitted message immediately and replaces it with the canonical turn', async () => {
|
||||
@@ -338,9 +395,13 @@ describe('youth AI Design Canvas page', () => {
|
||||
});
|
||||
render(<ImageCanvas />);
|
||||
|
||||
expect(within(screen.getByTestId('image-workspace-conversation'))
|
||||
.getByRole('button', { name: '正在准备方案' })).toBeDisabled();
|
||||
openMobileCreationCard();
|
||||
expect(screen.getByText('还在确认刚才的操作')).toBeInTheDocument();
|
||||
expect(screen.getByText(/不会重复制作或重复扣费/)).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '看看制作方案', exact: true })).toBeDisabled();
|
||||
expect(actions.requestQuote).not.toHaveBeenCalled();
|
||||
fireEvent.click(screen.getByRole('button', { name: '查看原来的结果' }));
|
||||
expect(actions.retryOperation).toHaveBeenCalledWith('operation-1');
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user