fix: 修复 AI 设计任务栏同步与独立滚动

问题:生成任务未及时出现在右侧栏,任务区与会话区还会共享外层滚动。

实现:补齐 Agent 回合与 Quote 确认后的任务同步,锁定左右滚动容器并增加桌面布局和异步任务回归测试。
This commit is contained in:
2026-08-01 23:12:24 +08:00
parent 592bdfbc70
commit 83e21563dc
3 changed files with 118 additions and 8 deletions

View File

@@ -220,6 +220,38 @@ describe('ImageCanvas Workspace-first design experience', () => {
expect(screen.queryByText(/当前 Agent/)).not.toBeInTheDocument();
});
it('keeps the task list visible in a 1404px desktop workspace', async () => {
const previousWidth = window.innerWidth;
Object.defineProperty(window, 'innerWidth', { configurable: true, value: 1404 });
try {
render(<MemoryRouter><ImageCanvas /></MemoryRouter>);
await screen.findByTestId('image-workspace-conversation');
expect(screen.getByTestId('design-task-list')).toBeInTheDocument();
expect(screen.getByTestId('design-pane-divider')).toHaveClass('lg:block');
} finally {
Object.defineProperty(window, 'innerWidth', {
configurable: true,
value: previousWidth,
});
}
});
it('keeps conversation and task scrolling isolated', async () => {
render(<MemoryRouter><ImageCanvas /></MemoryRouter>);
await screen.findByTestId('image-workspace-conversation');
expect(screen.getByTestId('image-canvas-page'))
.toHaveClass('h-full', 'overflow-hidden');
expect(screen.getByTestId('image-workspace-conversation'))
.toHaveClass('overflow-y-auto', 'overscroll-contain');
expect(screen.getByTestId('design-task-list'))
.toHaveClass('lg:h-full', 'overflow-hidden');
expect(screen.getByTestId('design-task-scroll'))
.toHaveClass('lg:h-[calc(100%-57px)]', 'overflow-y-auto', 'overscroll-contain');
});
it('explains the project model before the first Workspace is created', async () => {
fetchImageWorkspaceMock.mockResolvedValueOnce({
...bootstrapFixture,
@@ -250,6 +282,35 @@ describe('ImageCanvas Workspace-first design experience', () => {
expect(confirmImageWorkspaceGenerationMock).not.toHaveBeenCalled();
});
it('refreshes tasks after an Agent turn creates a generation task', async () => {
const queuedTask = {
...taskFixture,
taskId: 'task-two',
status: 'queued' as const,
resultAssets: [],
};
fetchImageWorkspaceTasksMock
.mockResolvedValueOnce([])
.mockResolvedValueOnce([queuedTask]);
render(<MemoryRouter><ImageCanvas /></MemoryRouter>);
await screen.findByTestId('design-quote-quote-one');
const confirmationReply = workspaceFixture().messages[1].quickReplies[0];
fireEvent.change(screen.getByLabelText('设计需求'), {
target: { value: confirmationReply },
});
fireEvent.click(screen.getByRole('button', { name: '发送给设计 Agent' }));
await waitFor(() => expect(sendImageWorkspaceMessageMock).toHaveBeenCalledWith(
'workspace-cloud',
1,
confirmationReply,
));
await waitFor(() => expect(fetchImageWorkspaceTasksMock).toHaveBeenCalledTimes(2));
expect(await screen.findByTestId('design-task-task-two')).toBeInTheDocument();
});
it('creates a generation task only through explicit Quote confirmation', async () => {
fetchImageWorkspaceTasksMock
.mockResolvedValueOnce([taskFixture])
@@ -268,4 +329,28 @@ describe('ImageCanvas Workspace-first design experience', () => {
.toHaveBeenCalledWith('workspace-cloud', 1, 'quote-one'));
await waitFor(() => expect(fetchImageWorkspaceTasksMock).toHaveBeenCalledTimes(2));
});
it('keeps checking after Quote confirmation until the new task becomes visible', async () => {
const queuedTask = {
...taskFixture,
taskId: 'task-delayed',
status: 'queued' as const,
resultAssets: [],
};
fetchImageWorkspaceTasksMock
.mockResolvedValueOnce([])
.mockResolvedValueOnce([])
.mockResolvedValueOnce([queuedTask]);
render(<MemoryRouter><ImageCanvas /></MemoryRouter>);
await screen.findByTestId('design-quote-quote-one');
fireEvent.click(screen.getByRole('button', { name: '确认并开始生成' }));
await waitFor(() => expect(confirmImageWorkspaceGenerationMock)
.toHaveBeenCalledWith('workspace-cloud', 1, 'quote-one'));
await waitFor(() => expect(fetchImageWorkspaceTasksMock).toHaveBeenCalledTimes(3));
expect(await screen.findByTestId('design-task-task-delayed'))
.toBeInTheDocument();
});
});