Files
Notes/tests/unit/toolbar-close-file.test.js
2026-09-21 02:30:48 +08:00

107 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// src/toolbar.js 的 onCloseFile 接线测试
//
// 覆盖:
// - btnCloseFile click → onCloseFile 被调用
// - 缺失 onCloseFile 时不挂 listener(防御)
// - 缺失 btnCloseFile 时不挂 listener
//
// 真实运行链路:app.js 在 syncSaveButton() 末尾调 syncCloseFileButton(),
// 把按钮从 disabled → enabled;用户点击 → Toolbar 构造时挂的 listener 触发
// onCloseFile() → closeCurrentFile()。本测试只覆盖 Toolbar 自身的接线
// 段(构造时是否挂对 listener),不覆盖 closeCurrentFile 内部逻辑
// (那个由 app.js 模块顶层,单元测试触不到)。
/* @vitest-environment jsdom */
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { Toolbar } from '../../src/toolbar.js';
describe('toolbar.onCloseFile 接线', () => {
let btnCloseFile;
let elements;
beforeEach(() => {
document.body.innerHTML = `
<button id="btn-close-file" type="button" disabled>关闭文件</button>
<button id="btn-theme">主题</button>
<button id="btn-pin">置顶</button>
<button id="btn-settings">设置</button>
<button id="btn-reset-layout">重置布局</button>
<button id="btn-min">最小化</button>
<button id="btn-max">最大化</button>
<button id="btn-close">关闭窗口</button>
`;
btnCloseFile = document.getElementById('btn-close-file');
elements = {
btnTheme: document.getElementById('btn-theme'),
btnPin: document.getElementById('btn-pin'),
btnSettings: document.getElementById('btn-settings'),
btnResetLayout: document.getElementById('btn-reset-layout'),
btnMin: document.getElementById('btn-min'),
btnMax: document.getElementById('btn-max'),
btnClose: document.getElementById('btn-close'),
btnCloseFile,
};
});
/** 用 dispatchEvent 触发 click —— jsdom 的 .click() 在 form 容器里行为不稳。 */
function clickEl(el) {
el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
}
it('btnCloseFile click → onCloseFile 被调用一次', () => {
const onCloseFile = vi.fn();
new Toolbar({ elements, onCloseFile });
clickEl(btnCloseFile);
expect(onCloseFile).toHaveBeenCalledTimes(1);
});
it('多次点击 → onCloseFile 调用相应次数(无去重)', () => {
const onCloseFile = vi.fn();
new Toolbar({ elements, onCloseFile });
clickEl(btnCloseFile);
clickEl(btnCloseFile);
clickEl(btnCloseFile);
expect(onCloseFile).toHaveBeenCalledTimes(3);
});
it('btnCloseFile 缺失 → onCloseFile 不被调用也不抛错', () => {
const onCloseFile = vi.fn();
const elementsNoBtn = { ...elements };
delete elementsNoBtn.btnCloseFile;
expect(() => new Toolbar({ elements: elementsNoBtn, onCloseFile })).not.toThrow();
expect(onCloseFile).not.toHaveBeenCalled();
});
it('btnCloseFile 存在但 onCloseFile 缺失 → 不挂 listener', () => {
// 验证方式:btnCloseFile.click() 时不应触发任何引用错误。
// 由于 listener 没挂,调用就是一个空操作;测试"不抛错"即可。
expect(() => new Toolbar({ elements })).not.toThrow();
// 没有 onCloseFile 时 listener 没挂,逻辑无副作用。
// (更深层的"没挂"需要 spy addEventListener,超出本测试范围。)
});
it('按钮 disabled 状态不影响 listener 挂载', () => {
// 浏览器层面 disabled 按钮 click 不派发,但 listener 应在构造时已挂。
// jsdom 不会模拟浏览器的 disabled-click 抑制(disabled 后 click 仍派发),
// 所以这个测试主要防回归:listener 必须挂上、调用 click 不抛错。
btnCloseFile.disabled = true;
const onCloseFile = vi.fn();
new Toolbar({ elements, onCloseFile });
expect(() => clickEl(btnCloseFile)).not.toThrow();
expect(onCloseFile).toHaveBeenCalled();
});
it('btnClose 与 btnCloseFile 互不影响', () => {
const onClose = vi.fn();
const onCloseFile = vi.fn();
new Toolbar({ elements, onClose, onCloseFile });
clickEl(document.getElementById('btn-close'));
expect(onClose).toHaveBeenCalledTimes(1);
expect(onCloseFile).not.toHaveBeenCalled();
clickEl(btnCloseFile);
expect(onClose).toHaveBeenCalledTimes(1);
expect(onCloseFile).toHaveBeenCalledTimes(1);
});
});