feat: integrate pixel teacher presence and resilient classroom preview
This commit is contained in:
@@ -49,7 +49,7 @@ const first = topic('first'),
|
||||
second = topic('second');
|
||||
function request(overrides: Partial<TeacherRequest> = {}): TeacherRequest {
|
||||
return {
|
||||
id: 'request-1', text: '老师,帮我看看', references: [], createdAt: 'now',
|
||||
id: 'request-1', text: '老师帮我看看', references: [], createdAt: 'now',
|
||||
sourceCursor: { workerGeneration: 1, seq: 1 }, sourceCapturedAt: 'now',
|
||||
includedSourceMessageIds: [], omittedMessages: 0, status: 'completed', response: '',
|
||||
...overrides,
|
||||
@@ -198,12 +198,14 @@ describe('teacher side chat', () => {
|
||||
expect(api.create).not.toHaveBeenCalled();
|
||||
expect(api.send).not.toHaveBeenCalled();
|
||||
if (role === 'teacher') {
|
||||
expect(screen.getByRole('button', { name: '老师,帮我看看', exact: true })).toBeEnabled();
|
||||
expect(screen.getByRole('button', { name: '老师帮我看看', exact: true })).toBeEnabled();
|
||||
expect(screen.getByTestId('consultation-composer-actions')).toContainElement(screen.getByRole('button', { name: '老师帮我看看', exact: true }));
|
||||
expect(screen.queryByText('把你的困惑说出来就好')).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '固定的通用问题' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '我还没想好下一步做什么' })).not.toBeInTheDocument();
|
||||
} else {
|
||||
expect(screen.getByRole('button', { name: '固定的通用问题' })).toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '老师,帮我看看', exact: true })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '老师帮我看看', exact: true })).not.toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -213,7 +215,7 @@ describe('teacher side chat', () => {
|
||||
...first, revision: 2, requests: [suggestionsRequest({ id: input.requestId, status: 'running', response: streamingJson, suggestedQuestions: undefined })],
|
||||
}));
|
||||
render(<TeacherChatPanel projectId="p" sourceId="c" role="teacher" />);
|
||||
const help = screen.getByRole('button', { name: '老师,帮我看看', exact: true });
|
||||
const help = screen.getByRole('button', { name: '老师帮我看看', exact: true });
|
||||
await waitFor(() => expect(help).toBeEnabled());
|
||||
fireEvent.change(screen.getByLabelText('向老师提问'), { target: { value: '我自己还想问的另一件事' } });
|
||||
fireEvent.click(help);
|
||||
@@ -222,10 +224,10 @@ describe('teacher side chat', () => {
|
||||
expect(screen.queryByText(streamingJson)).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '尚未确认的问题' })).not.toBeInTheDocument();
|
||||
expect(api.send).toHaveBeenCalledWith('p/teacher', 'first', expect.objectContaining({
|
||||
intent: 'suggestions', text: '老师,帮我看看', sourceConversationId: 'c',
|
||||
intent: 'suggestions', text: '老师帮我看看', sourceConversationId: 'c',
|
||||
}));
|
||||
expect(screen.getByLabelText('向老师提问')).toHaveValue('我自己还想问的另一件事');
|
||||
expect(screen.getByRole('button', { name: '老师,帮我看看', exact: true })).toBeDisabled();
|
||||
expect(screen.getByRole('button', { name: '老师帮我看看', exact: true })).toBeDisabled();
|
||||
await waitFor(() => expect(streams.has('first')).toBe(true));
|
||||
const sent = api.send.mock.calls[0][2] as TeacherSend;
|
||||
act(() => streams.get('first')!.dispatchEvent(new MessageEvent('snapshot', { data: JSON.stringify({
|
||||
@@ -236,7 +238,7 @@ describe('teacher side chat', () => {
|
||||
expect(screen.queryByText('我看看你最近做到了哪里…')).not.toBeInTheDocument();
|
||||
for (const question of suggestedQuestions) expect(screen.getByRole('button', { name: question })).toBeEnabled();
|
||||
expect(screen.getByRole('button', { name: '我也说不清,你带我看看', exact: true })).toBeEnabled();
|
||||
expect(screen.getByRole('button', { name: '老师,帮我看看', exact: true })).toBeEnabled();
|
||||
expect(screen.getByRole('button', { name: '老师帮我看看', exact: true })).toBeEnabled();
|
||||
expect(api.send).toHaveBeenCalledTimes(1);
|
||||
expect(screen.getByLabelText('向老师提问')).toHaveValue('我自己还想问的另一件事');
|
||||
});
|
||||
@@ -273,20 +275,20 @@ describe('teacher side chat', () => {
|
||||
it('retries an uncertain suggestions request after reopening without losing the student draft', async () => {
|
||||
api.send.mockRejectedValue(new Error('网络暂不可用'));
|
||||
const view = render(<TeacherChatPanel projectId="p" sourceId="c" role="teacher" />);
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: '老师,帮我看看', exact: true })).toBeEnabled());
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: '老师帮我看看', exact: true })).toBeEnabled());
|
||||
fireEvent.change(screen.getByLabelText('向老师提问'), { target: { value: '我还没写完的问题' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '老师,帮我看看', exact: true }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '老师帮我看看', exact: true }));
|
||||
await screen.findByText('网络暂不可用');
|
||||
const originalRequest = api.send.mock.calls[0][2] as TeacherSend;
|
||||
expect(originalRequest.intent).toBe('suggestions');
|
||||
view.unmount();
|
||||
|
||||
render(<TeacherChatPanel projectId="p" sourceId="c" role="teacher" />);
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: '老师,帮我看看', exact: true })).toBeEnabled());
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: '老师帮我看看', exact: true })).toBeEnabled());
|
||||
expect(screen.getByLabelText('向老师提问')).toHaveValue('我还没写完的问题');
|
||||
expect(api.send).toHaveBeenCalledTimes(1);
|
||||
fireEvent.change(screen.getByLabelText('向老师提问'), { target: { value: '我又补了一点自己的想法' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '老师,帮我看看', exact: true }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '老师帮我看看', exact: true }));
|
||||
await screen.findByText('网络暂不可用');
|
||||
expect(api.send.mock.calls[1][2]).toEqual(originalRequest);
|
||||
expect(screen.getByLabelText('向老师提问')).toHaveValue('我又补了一点自己的想法');
|
||||
@@ -314,10 +316,10 @@ describe('teacher side chat', () => {
|
||||
...first, revision: 3, requests: [accepted, suggestionsRequest({ id: input.requestId })],
|
||||
}));
|
||||
const view = render(<TeacherChatPanel projectId="p" sourceId="c" role="teacher" />);
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: '老师,帮我看看', exact: true })).toBeEnabled());
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: '老师帮我看看', exact: true })).toBeEnabled());
|
||||
await waitFor(() => expect(streams.has('first')).toBe(true));
|
||||
fireEvent.change(screen.getByLabelText('向老师提问'), { target: { value: '我的自由提问继续留着' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '老师,帮我看看', exact: true }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '老师帮我看看', exact: true }));
|
||||
await screen.findByText('响应中途断开');
|
||||
const originalRequest = api.send.mock.calls[0][2] as TeacherSend;
|
||||
accepted = suggestionsRequest({ id: originalRequest.requestId, status: 'failed', response: '', suggestedQuestions: undefined, error: '老师已接到,但这次回复失败了' });
|
||||
@@ -356,7 +358,7 @@ describe('teacher side chat', () => {
|
||||
expect(api.send.mock.calls[0][2].intent).toBeUndefined();
|
||||
expect(screen.getByLabelText('向老师提问')).toHaveValue('');
|
||||
expect(screen.queryByRole('button', { name: '移除引用' })).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '老师,帮我看看', exact: true })).toBeEnabled();
|
||||
expect(screen.getByRole('button', { name: '老师帮我看看', exact: true })).toBeEnabled();
|
||||
view.unmount();
|
||||
render(<TeacherChatPanel projectId="p" sourceId="c" role="teacher" />);
|
||||
expect(screen.getByLabelText('向老师提问')).toHaveValue('');
|
||||
@@ -412,20 +414,19 @@ describe('teacher side chat', () => {
|
||||
expect(api.send.mock.calls[1][2]).toEqual(originalRequest);
|
||||
});
|
||||
|
||||
it('returns to the operation chat without importing advice or offering a notes workflow', async () => {
|
||||
const returnToWork = vi.fn();
|
||||
it.each(['teacher', 'friend'] as const)('shows %s replies without redundant actions or importing advice', async (role) => {
|
||||
const bringBack = vi.fn();
|
||||
api.read.mockResolvedValue({ ...first, requests: [{
|
||||
id: 'reply', text: '游戏不好玩', references: [], createdAt: 'now',
|
||||
sourceCursor: { workerGeneration: 1, seq: 1 }, sourceCapturedAt: 'now',
|
||||
includedSourceMessageIds: [], omittedMessages: 0, status: 'completed', response: '先观察别人在哪儿停下来。',
|
||||
}] });
|
||||
render(<TeacherChatPanel projectId="p" sourceId="c" role="teacher" onReturnToWork={returnToWork} onBringBack={bringBack} />);
|
||||
render(<TeacherChatPanel projectId="p" sourceId="c" role={role} onBringBack={bringBack} />);
|
||||
await screen.findByText('先观察别人在哪儿停下来。');
|
||||
expect(screen.queryByRole('button', { name: '带回主会话草稿' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/记一下|项目共识|记入共识|待办/)).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: '我去试一试' }));
|
||||
expect(returnToWork).toHaveBeenCalledOnce();
|
||||
expect(screen.queryByRole('button', { name: '我去试一试' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '复制', exact: true })).not.toBeInTheDocument();
|
||||
expect(bringBack).not.toHaveBeenCalled();
|
||||
expect(api.send).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -442,7 +443,7 @@ describe('teacher side chat', () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '运营配置的预览问题' }));
|
||||
expect(screen.getByLabelText('向老师提问')).toHaveValue('运营配置的预览问题');
|
||||
expect(api.send).not.toHaveBeenCalled();
|
||||
expect(screen.queryByRole('button', { name: '老师,帮我看看', exact: true })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '老师帮我看看', exact: true })).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: '老师新话题' }));
|
||||
await waitFor(() => expect(api.create).toHaveBeenCalledWith('preview/sample', 7, '学生的练习代码'));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user