feat: v0.4.0 — 安全修复×6 + 增量性能×3 + Playwright E2E + 实例级 i18n
CI / test-parser (push) Successful in 9m27s
CI / test-core (push) Successful in 9m34s
CI / test-rest (push) Successful in 9m27s
CI / e2e (push) Failing after 5m15s
CI / verify (20.x) (push) Successful in 9m54s
CI / verify (18.x) (push) Successful in 9m56s
CI / verify (24.x) (push) Successful in 9m48s

0.3.0 修复版:
- 脚注 id 属性注入 XSS 防护(行内引用 + 脚注区)
- 全局插件注入移至 afterCreate(searchReplace 等依赖 textarea 的插件真正生效)+ use() 同名防重
- 行内渲染缓存附加 refs 指纹,防跨文档引用链接串数据
- 白名单裸标签 <u>/</u> 透传,underline(Ctrl+U)预览可见
- getStatus()/渲染 env 使用实例 locale;replaceAll 替换文本按字面处理
- replaceAllRegex 保留 $1 捕获组语义

0.3.1 性能版:
- 高亮规则按语言缓存(registerLanguage 覆盖失效),bench +33%
- 统计增量计算:字数/词数/行数差异区间,击键零全量扫描
- outline 树构建 O(n²) → 迭代栈 O(n)
- 拖放图片 >500KB 拦截、scrollToLine 真实行高、undo/redo 光标恢复
- selectionChange/cursorMove 与浮动工具栏解耦、unregisterShortcut 大小写归一
- toast 接入 7 种 ANIMATIONS、实例主题订阅随 destroy 断开(dispose)

0.4.0 工程版:
- Playwright 真实浏览器冒烟测试(e2e/,22 项断言)+ CI e2e job
- sideEffects: false 便于 tree-shaking
- MeEditor.destroy() 全面复位(全局钩子清理 + 内部注入钩子重建)
- 实例 locale 统一作用于全部 UI 文案(状态栏/工具栏/右键菜单/大纲)

测试 782 → 826,全绿;typecheck/lint/build 通过
This commit is contained in:
2026-08-09 12:31:14 +08:00
parent 64aedb9546
commit cb0caff4cf
24 changed files with 1122 additions and 129 deletions
+51
View File
@@ -758,6 +758,57 @@ describe('v0.1.5 watch 外部主题源', () => {
});
});
describe('v0.3.1 实例主题 dispose', () => {
test('dispose 断开外部跟随的 MutationObserver', () => {
const div = document.createElement('div');
div.setAttribute('data-theme', 'dark');
document.body.appendChild(div);
const mockEditor = {
el: div,
container: div,
config: { theme: 'light' },
_emit: jest.fn(),
refresh: jest.fn(),
};
const ctx = createInstanceTheme(mockEditor);
const disconnectSpy = jest.spyOn(MutationObserver.prototype, 'disconnect');
ctx.syncWithElement(div);
ctx.dispose();
expect(disconnectSpy).toHaveBeenCalled();
disconnectSpy.mockRestore();
document.body.removeChild(div);
});
test('dispose 后可重复调用且不抛错', () => {
const div = document.createElement('div');
document.body.appendChild(div);
const mockEditor = {
el: div,
container: div,
config: { theme: 'light' },
_emit: jest.fn(),
refresh: jest.fn(),
};
const ctx = createInstanceTheme(mockEditor);
expect(() => { ctx.dispose(); ctx.dispose(); }).not.toThrow();
document.body.removeChild(div);
});
test('MarkdownEditor destroy 时断开实例主题订阅', () => {
document.body.innerHTML = '';
const c = document.createElement('div');
c.setAttribute('data-theme', 'dark');
document.body.appendChild(c);
const ed = new MarkdownEditor(c, {});
const ctx = ed.getThemeContext();
const disconnectSpy = jest.spyOn(MutationObserver.prototype, 'disconnect');
ctx.adopt();
ed.destroy();
expect(disconnectSpy).toHaveBeenCalled();
disconnectSpy.mockRestore();
});
});
describe('v0.1.5 MarkdownEditor 实例主题 API', () => {
test('setTheme / getTheme 实例方法', () => {
document.body.innerHTML = '';