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:
+39
-2
@@ -29,7 +29,7 @@ describe('index.ts - 全局 API', () => {
|
||||
|
||||
test('VERSION 是字符串', () => {
|
||||
expect(typeof VERSION).toBe('string');
|
||||
expect(VERSION).toBe('0.2.5');
|
||||
expect(VERSION).toBe('0.4.0');
|
||||
});
|
||||
|
||||
test('api.default 是 api 本身', () => {
|
||||
@@ -81,6 +81,24 @@ describe('index.ts - 全局 API', () => {
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('全局 searchReplace 在新实例上可用(DOM 已就绪)', () => {
|
||||
destroy();
|
||||
use('searchReplace');
|
||||
const ed = create(container, { value: 'foo bar' });
|
||||
ed.textarea.dispatchEvent(new KeyboardEvent('keydown', { key: 'f', ctrlKey: true, bubbles: true }));
|
||||
expect(ed.el.querySelector('.me-search')).not.toBeNull();
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('全局插件与 config.plugins 同名时只安装一次', () => {
|
||||
destroy();
|
||||
use('autoSave');
|
||||
const ed = create(container, { value: 'test', plugins: ['autoSave'] });
|
||||
const count = ed.getPlugins().filter((p: any) => p.name === 'autoSave').length;
|
||||
expect(count).toBe(1);
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('on / off 全局钩子', () => {
|
||||
const fn = jest.fn();
|
||||
const unsub = on('afterCreate', fn);
|
||||
@@ -111,11 +129,30 @@ describe('index.ts - 全局 API', () => {
|
||||
});
|
||||
|
||||
test('destroy 清理全局资源', () => {
|
||||
expect(() => destroy()).not.toThrow();
|
||||
destroy();
|
||||
const status = getStatus();
|
||||
expect(status.globalPlugins.length).toBe(0);
|
||||
});
|
||||
|
||||
test('destroy 清理用户全局钩子但保留内部注入钩子', () => {
|
||||
destroy();
|
||||
const fn = jest.fn();
|
||||
on('afterCreate', fn);
|
||||
expect(MarkdownEditor._hooks.get('afterCreate')!.length).toBeGreaterThan(0);
|
||||
destroy();
|
||||
const hooks = MarkdownEditor._hooks.get('afterCreate') || [];
|
||||
expect(hooks.length).toBe(1); // 仅剩内部 injectGlobalPlugins
|
||||
expect(hooks[0]).not.toBe(fn);
|
||||
});
|
||||
|
||||
test('destroy 后 MeEditor.use 全局插件仍可用', () => {
|
||||
destroy();
|
||||
use('autoSave');
|
||||
const ed = create(container, { value: 'x' });
|
||||
expect(ed.getPlugins().some((p: any) => p.name === 'autoSave')).toBe(true);
|
||||
ed.destroy();
|
||||
});
|
||||
|
||||
test('window.MeEditor 被设置', () => {
|
||||
expect((window as any).MeEditor).toBeDefined();
|
||||
expect((window as any).MeEditor.VERSION).toBe(VERSION);
|
||||
|
||||
Reference in New Issue
Block a user