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
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:
@@ -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 = '';
|
||||
|
||||
Reference in New Issue
Block a user