From 934c7aa8043b8cb14c873dac446c5b94640e95b7 Mon Sep 17 00:00:00 2001 From: oudecheng <13802883547@139.com> Date: Fri, 7 Aug 2026 06:54:51 +0800 Subject: [PATCH] =?UTF-8?q?test(web):=20=E8=A1=A5=E5=85=85=E6=B5=81?= =?UTF-8?q?=E5=BC=8F=E6=96=AD=E8=BF=9E=E7=9A=84=E5=AF=B9=E6=8A=97=E6=80=A7?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=88stream=5Fend=20=E5=B9=82=E7=AD=89?= =?UTF-8?q?=E6=80=A7=20+=20=E5=A4=9A=E5=91=A8=E6=9C=9F=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对抗性审查 commit 30b7d90 的修复健壮性,新增两个边缘场景测试: - 用例 18: 验证断连后 stream_end 到达是幂等的(不崩溃、不改变 已 flush 内容),且后续 assistant_response 能正常按 id 替换 - 用例 19: 验证多次断连-重连循环下 finishStreaming 幂等 (连续调用不崩溃,消息状态稳定) --- web/src/hooks/useChat.test.ts | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/web/src/hooks/useChat.test.ts b/web/src/hooks/useChat.test.ts index 3384bf3..a7dab48 100644 --- a/web/src/hooks/useChat.test.ts +++ b/web/src/hooks/useChat.test.ts @@ -523,4 +523,56 @@ describe('useChat - handleServerMessage characterization', () => { const s1 = result.current.messages.find((m) => m.id === 's1'); expect(s1?.content).toBe('part1part2'); }); + + it('18. stream_end arriving after onDisconnect is idempotent (no crash, no side effect)', () => { + const { result } = renderUseChat(); + act(() => { + result.current.handleServerMessage({ type: 'stream_delta', id: 'e1', delta: 'partial' }); + }); + expect(result.current.messages[0].content).toBe('partial'); + + // 断连:finishStreaming 重置 streamingRef + act(() => result.current.finishStreaming()); + + // 重连后 stream_end 到达(可能在断连前已发出,重连后才收到) + expect(() => { + act(() => result.current.handleServerMessage({ type: 'stream_end', id: 'e1' })); + }).not.toThrow(); + // stream_end 不应改变已 flush 的内容 + const e1 = result.current.messages.find((m) => m.id === 'e1'); + expect(e1?.content).toBe('partial'); + + // 紧接着 assistant_response 到达,应正常按 id 替换(断连后的正常恢复路径) + act(() => + result.current.handleServerMessage({ + type: 'assistant_response', + id: 'e1', + content: 'final', + role: 'assistant', + }), + ); + expect(result.current.messages.find((m) => m.id === 'e1')?.content).toBe('final'); + }); + + it('19. multiple disconnect-reconnect cycles: finishStreaming is idempotent across cycles', () => { + const { result } = renderUseChat(); + + // 周期 1 + act(() => result.current.handleServerMessage({ type: 'stream_delta', id: 'c1', delta: 'a' })); + act(() => result.current.finishStreaming()); + expect(result.current.messages.find((m) => m.id === 'c1')?.content).toBe('a'); + + // 周期 2:新流式消息 + act(() => result.current.handleServerMessage({ type: 'stream_delta', id: 'c2', delta: 'b' })); + act(() => result.current.finishStreaming()); + expect(result.current.messages.find((m) => m.id === 'c2')?.content).toBe('b'); + // c1 不受影响 + expect(result.current.messages.find((m) => m.id === 'c1')?.content).toBe('a'); + + // 周期 3:连续两次 finishStreaming(无 delta 间隔),验证幂等 + act(() => result.current.finishStreaming()); + act(() => result.current.finishStreaming()); + // 不崩溃,消息状态稳定 + expect(result.current.messages).toHaveLength(2); + }); });