update
This commit is contained in:
77
tests/unit/editor-mode-reset.test.js
Normal file
77
tests/unit/editor-mode-reset.test.js
Normal file
@@ -0,0 +1,77 @@
|
||||
// src/editor-mode-reset.js —— splitRatio 重置决策的纯函数测试
|
||||
//
|
||||
// 背景(audit P0-4 + Memory-2):
|
||||
// - 编辑双栏(splitRatio)每次「打开」都默认对半分,drag 比例仅本次会话内
|
||||
// 有效,不跨应用重启保留。
|
||||
// - 旧实现:applyEditorMode 内部用 `document.body.dataset.editorMode !== 'split'`
|
||||
// 做闸 —— 但默认 editorMode='split' 冷启动时,dataset 已是 'split',闸永远为
|
||||
// 假,上次拖的 70% 在冷启动被恢复。
|
||||
// - 修复:applyEditorMode 内部无条件按 visualMode 决定 —— visualMode='split'
|
||||
// 时调 settingsStore.update({ splitRatio: 0.5 }),其它不动。
|
||||
// - 顺带:mountSplitter.onDragEnd 改为 noop(drag 不再持久化)。
|
||||
//
|
||||
// 这里只测纯函数;mountSplitter 那个 onDragEnd noop 改动是单行「删除
|
||||
// settingsStore.update 调用」,没分支可测,留在 app.js commit 里人工 review。
|
||||
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { applySplitRatioResetIfEnteringSplit } from '../../src/editor-mode-reset.js';
|
||||
|
||||
describe('applySplitRatioResetIfEnteringSplit', () => {
|
||||
let updateMock;
|
||||
let settingsStore;
|
||||
|
||||
beforeEach(() => {
|
||||
updateMock = vi.fn().mockResolvedValue({ ok: true });
|
||||
settingsStore = { update: updateMock };
|
||||
});
|
||||
|
||||
it('visualMode = split → 调 settingsStore.update({ splitRatio: 0.5 })', () => {
|
||||
applySplitRatioResetIfEnteringSplit('split', settingsStore);
|
||||
expect(updateMock).toHaveBeenCalledTimes(1);
|
||||
expect(updateMock).toHaveBeenCalledWith({ splitRatio: 0.5 });
|
||||
});
|
||||
|
||||
it('visualMode = edit → 不调 update', () => {
|
||||
applySplitRatioResetIfEnteringSplit('edit', settingsStore);
|
||||
expect(updateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('visualMode = preview → 不调 update', () => {
|
||||
applySplitRatioResetIfEnteringSplit('preview', settingsStore);
|
||||
expect(updateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('visualMode 是未知字符串(防御性)→ 不调 update', () => {
|
||||
// 防止未来 schema 加新模式时这里误触 reset
|
||||
applySplitRatioResetIfEnteringSplit('unknown', settingsStore);
|
||||
expect(updateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('update reject → onError 被调,函数不抛', async () => {
|
||||
updateMock.mockRejectedValue(new Error('disk full'));
|
||||
const onError = vi.fn();
|
||||
// 不 await:函数本身 fire-and-forget;测试用 microtask flush 等待 catch 跑完
|
||||
applySplitRatioResetIfEnteringSplit('split', settingsStore, onError);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
expect(onError).toHaveBeenCalledTimes(1);
|
||||
expect(onError.mock.calls[0][0]).toMatch(/disk full/);
|
||||
});
|
||||
|
||||
it('update reject + 未传 onError → 不抛(用 console.warn 兜底,不让布局重置炸掉 app)', async () => {
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
updateMock.mockRejectedValue(new Error('disk full'));
|
||||
expect(() => applySplitRatioResetIfEnteringSplit('split', settingsStore)).not.toThrow();
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
expect(warnSpy).toHaveBeenCalled();
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('update 成功 → onError 不被调(成功路径不打扰用户)', async () => {
|
||||
const onError = vi.fn();
|
||||
applySplitRatioResetIfEnteringSplit('split', settingsStore, onError);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
expect(onError).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user