aopSlice.test.ts5.0 KBView on GitHub /**
* Tests for AopSlice — setAops (full replace, not merge), getAopById, getAops, isAopsLoaded
*/
import { act } from '@testing-library/react';
import { useCedarStore } from '@/modules/cedar-os/src/store/CedarStore';
// Minimal Aop shape compatible with the store type
const makeAop = (overrides: Partial<{ id: string; name: string }> = {}) =>
({
id: 'aop-1',
name: 'Test AOP',
...overrides,
}) as Parameters<ReturnType<typeof useCedarStore.getState>['setAops']>[0][number];
const resetAops = () =>
useCedarStore.setState((s) => ({
...s,
aopsById: {},
isAopsLoaded: false,
}));
beforeEach(resetAops);
afterEach(resetAops);
// ---------------------------------------------------------------------------
// setAops
// ---------------------------------------------------------------------------
describe('setAops', () => {
it('sets isAopsLoaded to true after first call', () => {
act(() => useCedarStore.getState().setAops([]));
expect(useCedarStore.getState().isAopsLoaded).toBe(true);
});
it('stores AOPs keyed by id', () => {
const aop = makeAop({ id: 'aop-1' });
act(() => useCedarStore.getState().setAops([aop]));
expect(useCedarStore.getState().aopsById['aop-1']).toEqual(aop);
});
it('stores multiple AOPs', () => {
const aops = [makeAop({ id: 'aop-1' }), makeAop({ id: 'aop-2', name: 'Second' })];
act(() => useCedarStore.getState().setAops(aops));
expect(Object.keys(useCedarStore.getState().aopsById)).toHaveLength(2);
});
it('completely replaces existing cache (does NOT merge)', () => {
act(() => useCedarStore.getState().setAops([makeAop({ id: 'aop-old' })]));
act(() => useCedarStore.getState().setAops([makeAop({ id: 'aop-new' })]));
const state = useCedarStore.getState();
expect(state.aopsById['aop-old']).toBeUndefined();
expect(state.aopsById['aop-new']).toBeDefined();
});
it('clears all AOPs when called with empty array', () => {
act(() => useCedarStore.getState().setAops([makeAop()]));
act(() => useCedarStore.getState().setAops([]));
expect(useCedarStore.getState().aopsById).toEqual({});
expect(useCedarStore.getState().isAopsLoaded).toBe(true);
});
it('last entry wins when duplicate IDs provided', () => {
const first = makeAop({ id: 'aop-1', name: 'First' });
const second = makeAop({ id: 'aop-1', name: 'Second' });
act(() => useCedarStore.getState().setAops([first, second]));
expect(useCedarStore.getState().aopsById['aop-1'].name).toBe('Second');
});
});
// ---------------------------------------------------------------------------
// getAopById
// ---------------------------------------------------------------------------
describe('getAopById', () => {
it('returns the AOP with the given id', () => {
const aop = makeAop({ id: 'aop-42' });
act(() => useCedarStore.getState().setAops([aop]));
expect(useCedarStore.getState().getAopById('aop-42')).toEqual(aop);
});
it('returns undefined for an unknown id', () => {
act(() => useCedarStore.getState().setAops([makeAop({ id: 'aop-1' })]));
expect(useCedarStore.getState().getAopById('does-not-exist')).toBeUndefined();
});
it('returns undefined when the cache is empty', () => {
expect(useCedarStore.getState().getAopById('any-id')).toBeUndefined();
});
});
// ---------------------------------------------------------------------------
// getAops
// ---------------------------------------------------------------------------
describe('getAops', () => {
it('returns an empty array when no AOPs are loaded', () => {
expect(useCedarStore.getState().getAops()).toEqual([]);
});
it('returns all stored AOPs as an array', () => {
const aops = [makeAop({ id: 'a' }), makeAop({ id: 'b' }), makeAop({ id: 'c' })];
act(() => useCedarStore.getState().setAops(aops));
const result = useCedarStore.getState().getAops();
expect(result).toHaveLength(3);
expect(result.map((a) => a.id).sort()).toEqual(['a', 'b', 'c']);
});
it('reflects the latest setAops call (full replace)', () => {
act(() => useCedarStore.getState().setAops([makeAop({ id: 'old' })]));
act(() => useCedarStore.getState().setAops([makeAop({ id: 'new' })]));
const result = useCedarStore.getState().getAops();
expect(result).toHaveLength(1);
expect(result[0].id).toBe('new');
});
});
// ---------------------------------------------------------------------------
// isAopsLoaded flag
// ---------------------------------------------------------------------------
describe('isAopsLoaded', () => {
it('starts as false', () => {
expect(useCedarStore.getState().isAopsLoaded).toBe(false);
});
it('becomes true after setAops is called', () => {
act(() => useCedarStore.getState().setAops([]));
expect(useCedarStore.getState().isAopsLoaded).toBe(true);
});
it('stays true on subsequent setAops calls', () => {
act(() => useCedarStore.getState().setAops([]));
act(() => useCedarStore.getState().setAops([makeAop()]));
expect(useCedarStore.getState().isAopsLoaded).toBe(true);
});
});