frontend/test/application-effects.test.ts
Rama master · réplica de lectura del repositorio original.
import { afterEach, expect, it, vi } from 'vitest';
import { ApplicationEffects } from '../src/application/effects';
afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); vi.unstubAllGlobals(); });
it('暂停与销毁隔断监听,恢复保留监听目标身份', () => {
const effects = new ApplicationEffects(), target = new EventTarget();
const seen: unknown[] = [];
effects.listen(target, 'sample', function (this: EventTarget) { seen.push(this); });
target.dispatchEvent(new Event('sample'));
effects.pause(); target.dispatchEvent(new Event('sample'));
effects.resume(); target.dispatchEvent(new Event('sample'));
effects.dispose(); effects.resume(); target.dispatchEvent(new Event('sample'));
expect(seen).toEqual([target, target]);
expect(effects.signal.aborted).toBe(true);
});
it('属性处理器保留 this,清理只恢复自己拥有的属性', () => {
const effects = new ApplicationEffects(), previous = vi.fn();
const target = { onclick: previous };
const seen: unknown[] = [];
effects.handler(target, 'onclick', function (this: typeof target) { seen.push(this); });
target.onclick(new Event('click'));
effects.dispose(); expect(target.onclick).toBe(previous); expect(seen).toEqual([target]);
const next = new ApplicationEffects(), replacement = vi.fn();
next.handler(target, 'onclick', vi.fn()); target.onclick = replacement;
next.dispose(); expect(target.onclick).toBe(replacement);
});
it('已完成调度释放句柄,销毁取消未完成定时与帧', () => {
vi.useFakeTimers();
const effects = new ApplicationEffects(), called = vi.fn();
effects.delay(called, 10); vi.advanceTimersByTime(10);
expect(called).toHaveBeenCalledTimes(1);
effects.delay(called, 50); effects.frame(called); effects.dispose();
vi.runAllTimers(); expect(called).toHaveBeenCalledTimes(1);
});
it('观察者销毁后不能再次观察,晚到回调不发布', () => {
const observe = vi.fn(), disconnect = vi.fn(), changed = vi.fn();
let fire = () => {};
vi.stubGlobal('MutationObserver', class {
observe = observe; disconnect = disconnect; takeRecords = () => [];
constructor(callback: MutationCallback) { fire = () => callback([], this); }
});
const effects = new ApplicationEffects(), observer = effects.mutation(changed);
observer.observe(document.body, { childList: true }); fire();
effects.dispose(); observer.observe(document.body, { childList: true }); fire();
expect(observe).toHaveBeenCalledTimes(1); expect(disconnect).toHaveBeenCalledTimes(1);
expect(changed).toHaveBeenCalledTimes(1);
});
it('清理异常仍释放其他资源,晚交资源立即释放一次', () => {
const effects = new ApplicationEffects(), first = vi.fn(), last = vi.fn(), late = vi.fn();
effects.own(first); effects.own(() => { throw new Error('清理失败'); }); effects.own(last);
expect(() => effects.dispose()).toThrow(AggregateError);
expect(first).toHaveBeenCalledTimes(1); expect(last).toHaveBeenCalledTimes(1);
const release = effects.own(late); release(); effects.dispose();
expect(late).toHaveBeenCalledTimes(1);
});