Files
wehub-resource-sync 2114b14ee0
Sync main into demo / sync (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:26 +08:00

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');
});
});