123 lines
3.3 KiB
TypeScript
123 lines
3.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
createVolatileAppStore,
|
|
getAllStoreStates,
|
|
registerStateAdapter,
|
|
invalidateStateCache,
|
|
} from '../os/createAppStore';
|
|
|
|
let uid = 0;
|
|
function uniqueId() { return `test_app_${++uid}_${Date.now()}`; }
|
|
|
|
describe('getAllStoreStates caching', () => {
|
|
it('returns cached result when store state has not changed', () => {
|
|
const appId = uniqueId();
|
|
createVolatileAppStore(appId, { count: 0 });
|
|
|
|
const first = getAllStoreStates();
|
|
const second = getAllStoreStates();
|
|
|
|
expect(second[appId]).toBe(first[appId]);
|
|
});
|
|
|
|
it('returns fresh result after store state changes', () => {
|
|
const appId = uniqueId();
|
|
const store = createVolatileAppStore(appId, { count: 0 });
|
|
|
|
const first = getAllStoreStates();
|
|
expect(first[appId].count).toBe(0);
|
|
|
|
store.setState({ count: 1 });
|
|
const second = getAllStoreStates();
|
|
expect(second[appId].count).toBe(1);
|
|
expect(second[appId]).not.toBe(first[appId]);
|
|
});
|
|
|
|
it('strips function values from store state', () => {
|
|
const appId = uniqueId();
|
|
createVolatileAppStore(appId, {
|
|
value: 42,
|
|
action: () => {},
|
|
} as any);
|
|
|
|
const states = getAllStoreStates();
|
|
expect(states[appId].value).toBe(42);
|
|
expect(states[appId].action).toBeUndefined();
|
|
});
|
|
|
|
it('applies state adapter on cache miss', () => {
|
|
const appId = uniqueId();
|
|
createVolatileAppStore(appId, { base: 1 });
|
|
|
|
registerStateAdapter(appId, (raw) => ({
|
|
...raw,
|
|
derived: raw.base * 10,
|
|
}));
|
|
|
|
const states = getAllStoreStates();
|
|
expect(states[appId].base).toBe(1);
|
|
expect(states[appId].derived).toBe(10);
|
|
});
|
|
|
|
it('invalidates cache when adapter is registered after first read', () => {
|
|
const appId = uniqueId();
|
|
createVolatileAppStore(appId, { base: 1 });
|
|
|
|
const before = getAllStoreStates();
|
|
expect(before[appId].derived).toBeUndefined();
|
|
|
|
registerStateAdapter(appId, (raw) => ({
|
|
...raw,
|
|
derived: raw.base * 10,
|
|
}));
|
|
|
|
const after = getAllStoreStates();
|
|
expect(after[appId].derived).toBe(10);
|
|
expect(after[appId]).not.toBe(before[appId]);
|
|
});
|
|
|
|
it('caches adapted result until store changes', () => {
|
|
const appId = uniqueId();
|
|
const store = createVolatileAppStore(appId, { base: 1 });
|
|
|
|
let adapterCallCount = 0;
|
|
registerStateAdapter(appId, (raw) => {
|
|
adapterCallCount++;
|
|
return { ...raw, derived: raw.base * 10 };
|
|
});
|
|
|
|
getAllStoreStates();
|
|
const countAfterFirst = adapterCallCount;
|
|
|
|
getAllStoreStates();
|
|
expect(adapterCallCount).toBe(countAfterFirst);
|
|
|
|
store.setState({ base: 2 });
|
|
getAllStoreStates();
|
|
expect(adapterCallCount).toBe(countAfterFirst + 1);
|
|
});
|
|
|
|
it('invalidateStateCache forces re-evaluation even if store ref unchanged', () => {
|
|
const appId = uniqueId();
|
|
createVolatileAppStore(appId, { base: 1 });
|
|
|
|
let externalValue = 'old';
|
|
registerStateAdapter(appId, (raw) => ({
|
|
...raw,
|
|
external: externalValue,
|
|
}));
|
|
|
|
const first = getAllStoreStates();
|
|
expect(first[appId].external).toBe('old');
|
|
|
|
externalValue = 'new';
|
|
// Without invalidation, cache would still return 'old'
|
|
const stale = getAllStoreStates();
|
|
expect(stale[appId].external).toBe('old');
|
|
|
|
invalidateStateCache(appId);
|
|
const fresh = getAllStoreStates();
|
|
expect(fresh[appId].external).toBe('new');
|
|
});
|
|
});
|