修复流式 Markdown 错误边界恢复
累计文本变化时清除错误边界状态并重新尝试 Markdown 渲染。 新增首次渲染失败后随文本更新恢复的回归测试。
This commit is contained in:
@@ -18,7 +18,7 @@ type MarkdownErrorBoundaryState = {
|
||||
hasError: boolean;
|
||||
};
|
||||
|
||||
class MarkdownErrorBoundary extends Component<
|
||||
export class MarkdownErrorBoundary extends Component<
|
||||
MarkdownErrorBoundaryProps,
|
||||
MarkdownErrorBoundaryState
|
||||
> {
|
||||
@@ -32,6 +32,15 @@ class MarkdownErrorBoundary extends Component<
|
||||
// Keep the original message visible without logging its potentially sensitive content.
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: MarkdownErrorBoundaryProps) {
|
||||
if (
|
||||
this.state.hasError &&
|
||||
prevProps.fallbackText !== this.props.fallbackText
|
||||
) {
|
||||
this.setState({ hasError: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { render } from '@testing-library/react';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { ChatMarkdownMessage } from '../src/components/ChatMarkdownMessage';
|
||||
import {
|
||||
ChatMarkdownMessage,
|
||||
MarkdownErrorBoundary,
|
||||
} from '../src/components/ChatMarkdownMessage';
|
||||
|
||||
function FailingChild({ shouldThrow }: { shouldThrow: boolean }) {
|
||||
if (shouldThrow) {
|
||||
throw new Error('transient render failure');
|
||||
}
|
||||
return <span>markdown recovered</span>;
|
||||
}
|
||||
|
||||
describe('ChatMarkdownMessage', () => {
|
||||
it('渲染 assistant 的 GFM 内容与代码块', () => {
|
||||
@@ -95,6 +105,31 @@ describe('ChatMarkdownMessage', () => {
|
||||
expect(code?.className).not.toContain('rounded');
|
||||
});
|
||||
|
||||
it('累计文本变化后可从 Markdown 错误回退中恢复', () => {
|
||||
const consoleError = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
try {
|
||||
const { container, rerender } = render(
|
||||
<MarkdownErrorBoundary fallbackText="partial">
|
||||
<FailingChild shouldThrow />
|
||||
</MarkdownErrorBoundary>,
|
||||
);
|
||||
|
||||
expect(container.textContent).toBe('partial');
|
||||
|
||||
rerender(
|
||||
<MarkdownErrorBoundary fallbackText="complete">
|
||||
<FailingChild shouldThrow={false} />
|
||||
</MarkdownErrorBoundary>,
|
||||
);
|
||||
|
||||
expect(container.textContent).toBe('markdown recovered');
|
||||
} finally {
|
||||
consoleError.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it('保留流式 assistant 文本并标记 streaming 状态', () => {
|
||||
const { container } = render(
|
||||
<ChatMarkdownMessage
|
||||
|
||||
Reference in New Issue
Block a user