7e70fc4d32
iframes liegen dauerhaft in einem Behaelter im Portal-Rahmen und werden per position: fixed deckungsgleich ueber den Platzhalter der Modulseite gelegt; beim Wegnavigieren nur versteckt (visibility), nie neu eingehaengt. Name/Adresse je Modul im Sitzungsspeicher, Nachladen im Hintergrund, 404 verwirft. Abmelden und Loeschen leeren. Im Browser nachgewiesen: gleiches iframe-Element und kein neuer Seitenabruf nach Dashboard -> Modul B -> Modul A; folgt Seitenleiste ein-/ausgeklappt und Handybreite. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
84 lines
3.2 KiB
TypeScript
84 lines
3.2 KiB
TypeScript
import { beforeEach, describe, expect, it } from 'vitest';
|
|
import {
|
|
CUSTOM_MODULE_KEEP_ALIVE_MAX,
|
|
touchLru,
|
|
useCustomModuleCacheStore,
|
|
} from './custom-module-cache-store';
|
|
|
|
describe('touchLru', () => {
|
|
it('setzt ein neues Modul nach vorn ohne zu verwerfen', () => {
|
|
expect(touchLru(['a', 'b'], 'c', 5)).toEqual({ recent: ['c', 'a', 'b'], evicted: [] });
|
|
});
|
|
|
|
it('holt ein vorhandenes Modul nach vorn, ohne es zu verdoppeln', () => {
|
|
expect(touchLru(['a', 'b', 'c'], 'c', 5)).toEqual({ recent: ['c', 'a', 'b'], evicted: [] });
|
|
});
|
|
|
|
it('verwirft ueber der Grenze das am laengsten unbenutzte', () => {
|
|
expect(touchLru(['e', 'd', 'c', 'b', 'a'], 'f', 5)).toEqual({
|
|
recent: ['f', 'e', 'd', 'c', 'b'],
|
|
evicted: ['a'],
|
|
});
|
|
});
|
|
|
|
it('haelt das gerade benutzte Modul auch bei unsinniger Grenze', () => {
|
|
expect(touchLru(['a'], 'b', 0)).toEqual({ recent: ['b'], evicted: ['a'] });
|
|
});
|
|
});
|
|
|
|
describe('useCustomModuleCacheStore', () => {
|
|
const slot = () => document.createElement('div');
|
|
const remember = (id: string) =>
|
|
useCustomModuleCacheStore.getState().remember({ id, name: id, url: `https://x.test/${id}` });
|
|
|
|
beforeEach(() => {
|
|
useCustomModuleCacheStore.getState().clear();
|
|
});
|
|
|
|
it('haelt die Einhaengereihenfolge stabil und verwirft nach LRU', () => {
|
|
const ids = Array.from({ length: CUSTOM_MODULE_KEEP_ALIVE_MAX + 1 }, (_, i) => `m${i}`);
|
|
for (const id of ids) remember(id);
|
|
const { activate } = useCustomModuleCacheStore.getState();
|
|
for (const id of ids.slice(0, CUSTOM_MODULE_KEEP_ALIVE_MAX)) activate(id, slot());
|
|
// m0 erneut benutzen -> m1 ist jetzt am laengsten unbenutzt.
|
|
activate('m0', slot());
|
|
expect(useCustomModuleCacheStore.getState().openIds).toEqual(['m0', 'm1', 'm2', 'm3', 'm4']);
|
|
|
|
activate('m5', slot());
|
|
const state = useCustomModuleCacheStore.getState();
|
|
expect(state.openIds).toEqual(['m0', 'm2', 'm3', 'm4', 'm5']);
|
|
expect(state.recent[0]).toBe('m5');
|
|
// Metadaten bleiben — nur der offene Rahmen wird verworfen.
|
|
expect(state.modules.m1).toBeDefined();
|
|
});
|
|
|
|
it('aktiviert kein Modul ohne Metadaten', () => {
|
|
useCustomModuleCacheStore.getState().activate('unbekannt', slot());
|
|
expect(useCustomModuleCacheStore.getState().openIds).toEqual([]);
|
|
expect(useCustomModuleCacheStore.getState().active).toBeNull();
|
|
});
|
|
|
|
it('deaktiviert nur den eigenen Platzhalter', () => {
|
|
remember('a');
|
|
const first = slot();
|
|
const { activate, deactivate } = useCustomModuleCacheStore.getState();
|
|
activate('a', first);
|
|
deactivate(slot());
|
|
expect(useCustomModuleCacheStore.getState().active?.slot).toBe(first);
|
|
deactivate(first);
|
|
expect(useCustomModuleCacheStore.getState().active).toBeNull();
|
|
expect(useCustomModuleCacheStore.getState().openIds).toEqual(['a']);
|
|
});
|
|
|
|
it('vergisst ein Modul samt offenem Rahmen', () => {
|
|
remember('a');
|
|
useCustomModuleCacheStore.getState().activate('a', slot());
|
|
useCustomModuleCacheStore.getState().forget('a');
|
|
const state = useCustomModuleCacheStore.getState();
|
|
expect(state.modules).toEqual({});
|
|
expect(state.openIds).toEqual([]);
|
|
expect(state.recent).toEqual([]);
|
|
expect(state.active).toBeNull();
|
|
});
|
|
});
|