Files
Literature-Management/tests/unit/renderer/components/import-no-auto-open.test.ts
2026-10-21 14:42:59 +08:00

90 lines
4.0 KiB
TypeScript

// tests/unit/renderer/components/import-no-auto-open.test.ts
//
// 守卫(r177):「导入文件后不应该马上自动打开」。
//
// 旧行为(notes 侧 audit-r22 引入的 macOS Finder 风格、literature 侧同款):
// 导入成功 → select(最后一条导入的资源) + setActive('notes'/'library')
// + requestFocusNote(光标丢进 body)
// → 右侧面板被强制切到刚导入的文件,用户正在读的笔记/PDF 被顶掉,读一半
// 的内容被切走,还得再点回去。
//
// 期望契约:导入只做「落盘(必要时搬进当前文件夹)+ toast(+ 列表滚到新行)」,
// **不改变选中态、不切面板、不抢焦点**。要打开,用户自己点那一行。
//
// 本测是**源码契约 guard**:两个列表组件的 importFiles 回调体里不允许出现
// select( / setActive( / requestFocusNote(
// 为什么用源码扫描而不是渲染组件测:
// NotesList / LiteratureList 都依赖 react-virtuoso,jsdom 下容器高度为 0,
// 行根本不渲染 —— 渲染测测不到「点了导入之后有没有自动打开」这个行为,
// 只能退到源码契约。仓库里 layering / i18n-parity 同款做法。
import { describe, expect, it } from 'vitest';
import { readFileSync } from 'fs';
import { join } from 'path';
const ROOT = process.cwd();
/**
* 从 `const importFiles = useCallback(` 起,做花括号配平,截出回调体文本。
* 先剥掉注释(注释里可能有花括号),字符串字面量里的花括号在本仓库这两个
* 回调里不存在(importFiles 的文案 key 都不带 '{}')。
*/
function extractCallbackBody(fileRel: string, marker: string): string {
const src = readFileSync(join(ROOT, fileRel), 'utf8');
const start = src.indexOf(marker);
expect(start, `${fileRel} 里找不到 ${marker}`).toBeGreaterThan(-1);
const open = src.indexOf('{', start);
expect(open, `${fileRel} 里 ${marker} 之后没有 '{'`).toBeGreaterThan(-1);
const stripped = src
.slice(open)
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/^[ \t]*\/\/.*$/gm, '');
let depth = 0;
for (let i = 0; i < stripped.length; i++) {
const ch = stripped[i];
if (ch === '{') depth++;
else if (ch === '}') {
depth--;
if (depth === 0) return stripped.slice(0, i);
}
}
throw new Error(`${fileRel}: ${marker} 的回调体花括号没配平,提取失败`);
}
const NOTES = 'src/renderer/src/components/notes/NotesList.tsx';
const LIT = 'src/renderer/src/components/literature/LiteratureList.tsx';
describe('导入后不自动打开(r177)', () => {
it('notes 侧 importFiles 不 select / 不切面板 / 不抢焦点', () => {
const body = extractCallbackBody(NOTES, 'const importFiles = useCallback(');
expect(body).not.toMatch(/\bselect\(/);
expect(body).not.toMatch(/\bsetActive\(/);
expect(body).not.toMatch(/\brequestFocusNote\(/);
});
it('literature 侧 importFiles 不 select / 不切面板', () => {
const body = extractCallbackBody(LIT, 'const importFiles = useCallback(');
expect(body).not.toMatch(/\bselect\(/);
expect(body).not.toMatch(/\bsetActive\(/);
expect(body).not.toMatch(/\brequestFocusNote\(/);
});
it('notes 侧导入仍然落盘 + 仍搬进当前文件夹 + 仍出成功 toast', () => {
const body = extractCallbackBody(NOTES, 'const importFiles = useCallback(');
expect(body).toMatch(/\bimportFromFile\(/);
expect(body).toMatch(/\bmoveToFolder\(/);
expect(body).toMatch(/toast\.importSuccess/);
});
it('literature 侧导入仍然落盘 + 仍搬进当前文件夹 + 仍出成功 toast', () => {
const body = extractCallbackBody(LIT, 'const importFiles = useCallback(');
expect(body).toMatch(/\bimportFromFile\(/);
expect(body).toMatch(/\bapi\.litMove\(/);
expect(body).toMatch(/literature\.importSuccess/);
});
it('notes 侧仍把新行滚进视野(落点可见),但只是滚动不是选中', () => {
const body = extractCallbackBody(NOTES, 'const importFiles = useCallback(');
expect(body).toMatch(/scrollToIndex/);
});
});