153 lines
6.8 KiB
JavaScript
153 lines
6.8 KiB
JavaScript
// Stage 7 tests: editor-theme.js
|
||
//
|
||
// 覆盖:
|
||
// - pickEditorTheme 按 body[data-theme] 返回对应的 extensions 数组
|
||
// - 暗色叠加 oneDark;亮色只用自己的覆盖
|
||
// - backgroundColor / color 必须带 !important(oneDark 后续注入的同 specificity
|
||
// 规则会赢,必须用 important 强制覆盖,否则编辑区会显示 #282c34 而不是 --bg-viewer)
|
||
//
|
||
// editorTheme / editorThemeLight 是 EditorView.theme() 返回的 extension 对象,
|
||
// 内部是 CM6 私有结构,不展开断言 —— 只验证 pickEditorTheme 的行为即可。
|
||
|
||
import { describe, it, expect } from 'vitest';
|
||
import { pickEditorTheme, editorTheme, editorThemeLight, __editorThemeSpecForTests } from '../../src/editor-theme.js';
|
||
|
||
describe('pickEditorTheme', () => {
|
||
it('theme === "light" → 只返回 editorThemeLight', () => {
|
||
const exts = pickEditorTheme('light');
|
||
expect(exts).toHaveLength(1);
|
||
expect(exts[0]).toBe(editorThemeLight);
|
||
});
|
||
|
||
it('theme === "dark" → 返回 [oneDark, editorTheme]', () => {
|
||
const exts = pickEditorTheme('dark');
|
||
expect(exts).toHaveLength(2);
|
||
expect(exts[1]).toBe(editorTheme);
|
||
});
|
||
|
||
it('theme === undefined → 当暗色处理', () => {
|
||
const exts = pickEditorTheme(undefined);
|
||
expect(exts).toHaveLength(2);
|
||
expect(exts[1]).toBe(editorTheme);
|
||
});
|
||
|
||
it('theme === "auto"(旧版本残留) → 当暗色处理(防御性)', () => {
|
||
const exts = pickEditorTheme('auto');
|
||
expect(exts).toHaveLength(2);
|
||
});
|
||
|
||
it('theme === ""(空字符串) → 当暗色处理', () => {
|
||
const exts = pickEditorTheme('');
|
||
expect(exts).toHaveLength(2);
|
||
});
|
||
|
||
it('theme === null → 当暗色处理', () => {
|
||
const exts = pickEditorTheme(null);
|
||
expect(exts).toHaveLength(2);
|
||
});
|
||
});
|
||
|
||
describe('editorThemeSpec background overrides (oneDark / base theme 互斥)', () => {
|
||
// oneDark 的 .cm-editor { background-color: #282c34 } 和 .cm-gutters 同色,
|
||
// 在 dark theme 下会导致编辑区底色跟 .editor-pane / .viewer 的 --bg-viewer 不一致。
|
||
// 必须用 !important 强制覆盖,否则 oneDark 后注入的同 specificity 规则会赢。
|
||
it('.cm-editor backgroundColor 必须是 var(--bg-viewer) !important', () => {
|
||
const v = __editorThemeSpecForTests.backgroundColor;
|
||
expect(v).toMatch(/var\(--bg-viewer\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
it('.cm-editor color 必须是 var(--fg-primary) !important', () => {
|
||
const v = __editorThemeSpecForTests.color;
|
||
expect(v).toMatch(/var\(--fg-primary\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
it('.cm-gutters backgroundColor 必须是 var(--bg-viewer) !important', () => {
|
||
const v = __editorThemeSpecForTests.gutterBackgroundColor;
|
||
expect(v).toMatch(/var\(--bg-viewer\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
it('.cm-gutters color 必须是 var(--fg-tertiary) !important', () => {
|
||
const v = __editorThemeSpecForTests.gutterColor;
|
||
expect(v).toMatch(/var\(--fg-tertiary\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
// @codemirror/view 的 base theme 用 `&light .cm-activeLineGutter` / `&dark` 规则
|
||
//(特异性 (0,2,0))给 active 行 gutter 涂硬编码色(亮 #e2f2ff / 暗 #222227)。
|
||
// 我们的 .cm-activeLineGutter 是 (0,1,0),必须用 !important 才能让 var(--bg-hover) 稳定生效。
|
||
// 否则亮色下「活动行 gutter 变浅蓝色块」就是这个原因。
|
||
it('.cm-activeLine backgroundColor 必须是 var(--bg-hover) !important', () => {
|
||
const v = __editorThemeSpecForTests.activeLineBackgroundColor;
|
||
expect(v).toMatch(/var\(--bg-hover\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
it('.cm-activeLineGutter backgroundColor 必须是 var(--bg-hover) !important', () => {
|
||
const v = __editorThemeSpecForTests.activeLineGutterBackgroundColor;
|
||
expect(v).toMatch(/var\(--bg-hover\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
it('.cm-activeLineGutter color 必须是 var(--fg-secondary) !important', () => {
|
||
const v = __editorThemeSpecForTests.activeLineGutterColor;
|
||
expect(v).toMatch(/var\(--fg-secondary\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
// base theme 给 .cm-cursor 设黑色,&dark 下设 #528bff(oneDark 的 cursor 蓝)。
|
||
// 我们用 var(--accent),需要 !important 才能不被覆盖。
|
||
it('.cm-cursor/.cm-dropCursor borderLeftColor 必须是 var(--accent) !important', () => {
|
||
const v = __editorThemeSpecForTests.cursorBorderLeftColor;
|
||
expect(v).toMatch(/var\(--accent\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
// .cm-content caretColor 同样被 base theme 影响 —— 加 !important 兜底。
|
||
it('.cm-content caretColor 必须是 var(--accent) !important', () => {
|
||
const v = __editorThemeSpecForTests.caretColor;
|
||
expect(v).toMatch(/var\(--accent\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
// base theme `&light .cm-panels { background: #f5f5f5; color: black }` /
|
||
// `&dark { background: #333338; color: white }` 会盖住搜索面板的颜色。
|
||
it('.cm-panels backgroundColor 必须是 var(--bg-elevated) !important', () => {
|
||
const v = __editorThemeSpecForTests.panelsBackgroundColor;
|
||
expect(v).toMatch(/var\(--bg-elevated\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
it('.cm-panels color 必须是 var(--fg-primary) !important', () => {
|
||
const v = __editorThemeSpecForTests.panelsColor;
|
||
expect(v).toMatch(/var\(--fg-primary\)/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
// base theme 给 .cm-line 设了 `padding: 0 2px 0 6px`,左侧 6px 内边距会
|
||
// 形成「行首死区」——鼠标点击这一段 6px 区域时光标无法可靠地放到该行最前面。
|
||
// 我们的覆盖必须是左内边距 0 + !important(与 base theme 同特异性 (0,1,0),
|
||
// 源序胜负不可靠,!important 兜底)。
|
||
it('.cm-line padding 必须覆盖 base theme 的左内边距 6px → 0(带 !important)', () => {
|
||
const v = __editorThemeSpecForTests.linePadding;
|
||
// 期望值形如 "0 2px 0 0 !important",左 0、右 2px、上 0、下 0
|
||
expect(v).toMatch(/^0\s+2px\s+0\s+0/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
|
||
// basicSetup 的 foldGutter() 渲染的 chevron 列默认宽度 ~16px,会从
|
||
// .cm-gutters 容器(CSS width 钉死 32px)溢出 ~10px,盖在 cm-line 的开头
|
||
// 字符上,导致点击「行首最前面」时 hit target 是 gutter SPAN 而非 cm-line
|
||
// —— CM6 监听挂在 view.contentDOM 上,gutter 不在 contentDOM 子树内,
|
||
// mousedown 不会冒泡过去,光标位置不变。
|
||
// 我们用 display:none + !important 隐藏 chevron 渲染部分。foldGutter()
|
||
// 的 keymap(Ctrl+Shift+[ / ])仍然有效,只是视觉上看不到 chevron。
|
||
it('.cm-foldGutter 必须 display:none(带 !important)— 隐藏溢出 chevron', () => {
|
||
const v = __editorThemeSpecForTests.foldGutterDisplay;
|
||
expect(v).toMatch(/^none/);
|
||
expect(v).toMatch(/!important/);
|
||
});
|
||
});
|