import { describe, it, expect } from 'vitest';
import {
h,
render,
mount,
getComponentKey,
componentMap,
replaceWDom,
} from '@/index';
import type { CompKey } from '@/index';
describe('core: functional component returning VDom', () => {
it('restores the active component context after a failed replacement', () => {
const Healthy = () => healthy;
const Broken = () => {
throw new Error('broken component');
};
const container = document.createElement('div');
const original = ;
const dispose = render(original, container);
const previousKey = getComponentKey();
expect(() => replaceWDom(Broken, {}, [], original)).toThrow(
'broken component'
);
expect(getComponentKey()).toBe(previousKey);
const second = document.createElement('div');
const disposeSecond = render(, second);
expect(second.textContent).toBe('healthy');
disposeSecond();
dispose();
});
it('evaluates each nested stateless component once with its own key', () => {
const calls: string[] = [];
const keys: CompKey[] = [];
const Badge = () => {
calls.push('Badge');
keys.push(getComponentKey()!);
return badge;
};
const Card = () => {
calls.push('Card');
keys.push(getComponentKey()!);
const output = (
);
expect(getComponentKey()).toBe(keys[0]);
return output;
};
const root = document.createElement('div');
const destroy = render(, root);
expect(root.textContent).toBe('badge');
expect(calls).toEqual(['Card', 'Badge']);
expect(keys[0]).not.toBe(keys[1]);
expect(componentMap.get(keys[0])?.ctor).toBe(Card);
expect(componentMap.get(keys[1])?.ctor).toBe(Badge);
destroy();
});
it('re-renders when props change even without mount wrapper', async () => {
const testWrap = document.createElement('div');
const Follower = ({ pos }: { pos: { x: number; y: number } }) => (
cat
);
const Tracker = mount((renew, props: { pos: { x: number; y: number } }) => {
let pos = props.pos;
return () => (
);
});
const destroy = render(, testWrap);
const follower = testWrap.querySelector('.follower') as HTMLDivElement;
expect(follower.style.left).toBe('0px');
expect(follower.textContent).toContain('cat');
const button = testWrap.querySelector('button') as HTMLButtonElement;
button.click();
await Promise.resolve(); // flush microtask queue from redraw
expect(follower.style.left).toBe('10px');
expect(follower.style.top).toBe('5px');
destroy();
});
});