51 lines
2.3 KiB
JavaScript
51 lines
2.3 KiB
JavaScript
// settings-dialog.js 的纯函数测试。
|
||
//
|
||
// settings-dialog 整个类没有单测(mount 路径太重、依赖 modal-stack / settingsStore
|
||
// / window.api 等太多胶水),但其中有几个无副作用的小函数值得保护。
|
||
// 本文件只覆盖那些 —— 别引整个 dialog 进来,那会拖一堆 stub。
|
||
|
||
import { describe, it, expect } from 'vitest';
|
||
import { clearAiKeyDefaultValue } from '../../src/settings-dialog.js';
|
||
|
||
describe('clearAiKeyDefaultValue(Sec-M3 修复:防 dataset 残留真 Key)', () => {
|
||
// 背景:reveal flow 会先写 input.dataset.defaultValue = 真 Key,再把
|
||
// .value 同步暴露给用户;关 dialog 时必须把 dataset.defaultValue 删掉,
|
||
// 否则 XSS / DevTools / 复制粘贴能直接读出真 Key,绕过 arm/reveal 5 秒窗口。
|
||
// 这条函数被 3 处调用:mount 后 / modal.setOnClose 早期 handler / 主 close handler。
|
||
|
||
it('正常 input 元素:删掉 defaultValue,保留其他 dataset 属性', () => {
|
||
const input = {
|
||
dataset: { defaultValue: 'sk-real-key', other: 'untouched' },
|
||
};
|
||
clearAiKeyDefaultValue(input);
|
||
expect(input.dataset.defaultValue).toBeUndefined();
|
||
expect(input.dataset.other).toBe('untouched');
|
||
});
|
||
|
||
it('dataset 上没有 defaultValue 时不抛错(幂等)', () => {
|
||
const input = { dataset: { other: 'x' } };
|
||
expect(() => clearAiKeyDefaultValue(input)).not.toThrow();
|
||
expect(input.dataset.other).toBe('x');
|
||
});
|
||
|
||
it('null / undefined 输入静默 no-op,不抛', () => {
|
||
expect(() => clearAiKeyDefaultValue(null)).not.toThrow();
|
||
expect(() => clearAiKeyDefaultValue(undefined)).not.toThrow();
|
||
});
|
||
|
||
it('没有 dataset 属性的对象静默 no-op', () => {
|
||
// 防御:如果调用方传错对象(比如 element ref 但还没 mount、或者 wrapper),
|
||
// 不能让 reveal 关 dialog 流程崩。真实 DOM 元素总有 dataset,所以这是兜底。
|
||
const fake = {};
|
||
expect(() => clearAiKeyDefaultValue(fake)).not.toThrow();
|
||
});
|
||
|
||
it('多次调用幂等(连续关 dialog / 双保险路径不会破坏)', () => {
|
||
const input = { dataset: { defaultValue: 'k' } };
|
||
clearAiKeyDefaultValue(input);
|
||
clearAiKeyDefaultValue(input);
|
||
clearAiKeyDefaultValue(input);
|
||
expect(input.dataset.defaultValue).toBeUndefined();
|
||
});
|
||
});
|