feat: include approved Code sidebar actions in combined trial source
This commit is contained in:
1 parent
16b10c44f1
commit
18e4be66da
12 files changed
+596
-61
No files matched your search
@@ -523,7 +523,15 @@ describe('CodingChatPanel first Conversation', () => {
|
||||
run: { status: 'running', runId: 'run-1' } });
|
||||
const { CodingChatPanel: CoreChatPanel } = await import('@/pages/Chat/CodingChatPanel');
|
||||
const { CodingProjectConversations } = await import('@/pages/Chat/CodingProjectConversations');
|
||||
const CodingChatPanel = (props: import('@/pages/Chat/CodingChatPanel').CodingChatPanelProps) => <><CodingProjectConversations projectId={project.id} /><CoreChatPanel {...props} /></>;
|
||||
const { useState } = await import('react');
|
||||
const CodingChatPanel = () => {
|
||||
const [archived, setArchived] = useState(false);
|
||||
return <>
|
||||
<button onClick={() => setArchived(true)}>打开归档列表</button>
|
||||
<CodingProjectConversations projectId={project.id} archived={archived} onArchivedChange={setArchived} />
|
||||
<CoreChatPanel />
|
||||
</>;
|
||||
};
|
||||
const { codingConversationStore } = await import('@/stores/coding-conversations');
|
||||
render(<CodingChatPanel />);
|
||||
const menu = await screen.findByRole('button', { name: '对话操作:新对话' });
|
||||
@@ -533,7 +541,8 @@ describe('CodingChatPanel first Conversation', () => {
|
||||
await screen.findByRole('heading', { name: '今天,你想创造什么?' });
|
||||
expect(projectApi.create).not.toHaveBeenCalled();
|
||||
expect(conversationApi.abort).not.toHaveBeenCalled();
|
||||
fireEvent.click(screen.getByRole('button', { name: '查看归档对话' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开归档列表' }));
|
||||
expect(screen.getByText('已归档对话')).toBeVisible();
|
||||
fireEvent.click(within(screen.getByTestId('project-conversations')).getByRole('button', { name: '新对话', exact: true }));
|
||||
await screen.findByText('此对话已归档,任务仍在运行。');
|
||||
expect(screen.queryByRole('button', { name: '发送', exact: true })).not.toBeInTheDocument();
|
||||
@@ -541,6 +550,92 @@ describe('CodingChatPanel first Conversation', () => {
|
||||
await waitFor(() => expect(screen.queryByRole('button', { name: '恢复对话' })).not.toBeInTheDocument());
|
||||
expect(codingConversationStore.getState().selectedConversationId).toBe(conversation.id);
|
||||
expect(projectApi.patch).toHaveBeenLastCalledWith(conversation.id, { archived: false });
|
||||
expect(screen.queryByText('已归档对话')).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '返回最近对话' })).not.toBeInTheDocument();
|
||||
expect(within(screen.getByTestId('project-conversations')).getByRole('button', { name: '新对话', exact: true })).toHaveAttribute('aria-current', 'page');
|
||||
expect(conversationApi.abort).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns to recent conversations when restoring an unselected archived conversation from its menu', async () => {
|
||||
const archivedConversation = {
|
||||
...conversation,
|
||||
id: 'archived-conversation',
|
||||
title: '归档中的对话',
|
||||
archivedAt: '2026-09-20T00:00:00Z',
|
||||
};
|
||||
projectApi.list.mockResolvedValue({ projects: [project], activeProjectId: project.id });
|
||||
projectApi.config.mockResolvedValue({ project, config });
|
||||
projectApi.conversations.mockResolvedValue([conversation, archivedConversation]);
|
||||
projectApi.patch.mockResolvedValue({ ...archivedConversation, archivedAt: null });
|
||||
conversationApi.events.mockResolvedValue(new FakeEventSource() as unknown as EventSource);
|
||||
const { createLocalConversationSnapshot } = await import('@/pages/Chat/coding-chat-snapshot');
|
||||
conversationApi.snapshot.mockResolvedValue(createLocalConversationSnapshot(project.id, conversation));
|
||||
const { CodingChatPanel: CoreChatPanel } = await import('@/pages/Chat/CodingChatPanel');
|
||||
const { CodingProjectConversations } = await import('@/pages/Chat/CodingProjectConversations');
|
||||
const { codingConversationStore } = await import('@/stores/coding-conversations');
|
||||
const { useState } = await import('react');
|
||||
const CodingChatPanel = () => {
|
||||
const [archived, setArchived] = useState(true);
|
||||
return <>
|
||||
<CodingProjectConversations projectId={project.id} archived={archived} onArchivedChange={setArchived} />
|
||||
<CoreChatPanel />
|
||||
</>;
|
||||
};
|
||||
render(<CodingChatPanel />);
|
||||
await waitFor(() => expect(codingConversationStore.getState().selectedConversationId).toBe(conversation.id));
|
||||
const list = within(screen.getByTestId('project-conversations'));
|
||||
expect(list.getByText('已归档对话')).toBeVisible();
|
||||
expect(list.queryByRole('button', { name: conversation.title, exact: true })).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.keyDown(list.getByRole('button', { name: `对话操作:${archivedConversation.title}` }), { key: 'Enter' });
|
||||
fireEvent.click(await screen.findByRole('menuitem', { name: '恢复到最近对话' }));
|
||||
|
||||
await waitFor(() => expect(list.queryByText('已归档对话')).not.toBeInTheDocument());
|
||||
expect(projectApi.patch).toHaveBeenCalledWith(archivedConversation.id, { archived: false });
|
||||
expect(list.getByRole('button', { name: archivedConversation.title, exact: true })).toBeVisible();
|
||||
expect(list.getByRole('button', { name: conversation.title, exact: true })).toHaveAttribute('aria-current', 'page');
|
||||
expect(codingConversationStore.getState().selectedConversationId).toBe(conversation.id);
|
||||
expect(conversationApi.snapshot).not.toHaveBeenCalledWith(archivedConversation.id);
|
||||
expect(projectApi.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps the new-conversation label visible in compact archive view and returns to recent conversations after creation', async () => {
|
||||
const archivedConversation = { ...conversation, archivedAt: '2026-09-20T00:00:00Z' };
|
||||
const createdConversation = { ...conversation, id: 'created-conversation', title: '新建的对话' };
|
||||
projectApi.list.mockResolvedValue({ projects: [project], activeProjectId: project.id });
|
||||
projectApi.config.mockResolvedValue({ project, config });
|
||||
projectApi.conversations.mockResolvedValue([archivedConversation]);
|
||||
projectApi.create.mockResolvedValue(createdConversation);
|
||||
conversationApi.events.mockResolvedValue(new FakeEventSource() as unknown as EventSource);
|
||||
const { createLocalConversationSnapshot } = await import('@/pages/Chat/coding-chat-snapshot');
|
||||
conversationApi.snapshot.mockResolvedValue(createLocalConversationSnapshot(project.id, createdConversation));
|
||||
const { CodingChatPanel: CoreChatPanel } = await import('@/pages/Chat/CodingChatPanel');
|
||||
const { CodingProjectConversations } = await import('@/pages/Chat/CodingProjectConversations');
|
||||
const { codingConversationStore } = await import('@/stores/coding-conversations');
|
||||
const { useState } = await import('react');
|
||||
const CodingChatPanel = () => {
|
||||
const [archived, setArchived] = useState(true);
|
||||
return <>
|
||||
<CodingProjectConversations projectId={project.id} compact archived={archived} onArchivedChange={setArchived} />
|
||||
<CoreChatPanel />
|
||||
</>;
|
||||
};
|
||||
render(<CodingChatPanel />);
|
||||
const list = within(await screen.findByTestId('project-conversations'));
|
||||
const create = list.getByRole('button', { name: '新建对话', exact: true });
|
||||
expect(create).toHaveTextContent('新对话');
|
||||
expect(list.getByText('已归档对话')).toBeVisible();
|
||||
expect(projectApi.create).not.toHaveBeenCalled();
|
||||
|
||||
fireEvent.click(create);
|
||||
|
||||
await waitFor(() => expect(codingConversationStore.getState().selectedConversationId).toBe(createdConversation.id));
|
||||
expect(projectApi.create).toHaveBeenCalledOnce();
|
||||
expect(list.queryByText('已归档对话')).not.toBeInTheDocument();
|
||||
expect(list.queryByRole('button', { name: '返回最近对话' })).not.toBeInTheDocument();
|
||||
expect(list.queryByRole('button', { name: archivedConversation.title, exact: true })).not.toBeInTheDocument();
|
||||
expect(list.getByRole('button', { name: createdConversation.title, exact: true })).toHaveAttribute('aria-current', 'page');
|
||||
expect(conversationApi.submit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renames an unselected conversation from its menu without preparing that conversation', async () => {
|
||||
@@ -959,7 +1054,7 @@ describe('CodingChatPanel first Conversation', () => {
|
||||
expect(screen.queryByText('metadata rejected')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('keeps project settings only in the Conversation list and removes legacy Header actions', async () => {
|
||||
it('removes project toolbar actions and legacy Header actions while keeping conversation creation', async () => {
|
||||
projectApi.list.mockResolvedValue({ projects: [project], activeProjectId: project.id });
|
||||
projectApi.config.mockResolvedValue({ project, config: configForAgents([agent, reviewer]) });
|
||||
projectApi.conversations.mockResolvedValue([conversation, reviewerConversation]);
|
||||
@@ -986,10 +1081,12 @@ describe('CodingChatPanel first Conversation', () => {
|
||||
expect(within(header).queryByRole('button', { name: /标为(已读|未读)/ })).not.toBeInTheDocument();
|
||||
expect(within(header).queryByRole('button', { name: '归档' })).not.toBeInTheDocument();
|
||||
expect(within(header).queryByRole('button', { name: '伙伴设置' })).not.toBeInTheDocument();
|
||||
expect(screen.getAllByRole('button', { name: '项目设置' })).toHaveLength(1);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '项目设置' }));
|
||||
expect(navigate).toHaveBeenCalledWith('/project-config');
|
||||
expect(screen.queryByRole('button', { name: '项目设置' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '查看归档对话' })).not.toBeInTheDocument();
|
||||
const list = within(screen.getByTestId('project-conversations'));
|
||||
expect(list.getByRole('button', { name: '新建对话', exact: true })).toHaveTextContent('新对话');
|
||||
expect(list.getByRole('button', { name: `对话操作:${conversation.title}` })).toBeInTheDocument();
|
||||
expect(onOpenProjectSettings).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('remounts pending interaction state when switching Conversations', async () => {
|
||||
|
||||
Reference in new issue
Block a user