2026-05-14 17:12:01 +08:00
|
|
|
// test/dom.test.js
|
2026-06-06 11:45:52 +08:00
|
|
|
window.testDom = async function() {
|
2026-06-06 23:16:17 +08:00
|
|
|
const { ___unsafeRefreshState, $, $$, NewState } = ApigoState;
|
2026-05-14 17:12:01 +08:00
|
|
|
console.log('Testing dom.js...');
|
|
|
|
|
|
2026-06-06 11:45:52 +08:00
|
|
|
const wait = () => new Promise(r => setTimeout(r, 10));
|
|
|
|
|
|
2026-05-14 17:12:01 +08:00
|
|
|
// 1. Basic $text binding
|
2026-06-06 11:45:52 +08:00
|
|
|
document.body.innerHTML = '<div id="test-text" $text="state.msg"></div>';
|
|
|
|
|
const state = NewState({ msg: 'hello' });
|
|
|
|
|
window.state = state; // TRY: 确保在非 ESM 环境下 state 全局可见
|
|
|
|
|
document.documentElement._thisObj = { state };
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(document.documentElement);
|
2026-06-06 11:45:52 +08:00
|
|
|
if ($('#test-text').textContent !== 'hello') throw new Error('$text binding failed');
|
|
|
|
|
|
2026-05-14 17:12:01 +08:00
|
|
|
state.msg = 'world';
|
2026-06-06 11:45:52 +08:00
|
|
|
await wait();
|
|
|
|
|
if ($('#test-text').textContent !== 'world') throw new Error('$text update failed');
|
2026-05-14 17:12:01 +08:00
|
|
|
|
|
|
|
|
// 2. $if directive
|
2026-06-06 11:45:52 +08:00
|
|
|
document.body.innerHTML = '<template $if="state.show"><div id="test-if">visible</div></template>';
|
2026-05-14 17:12:01 +08:00
|
|
|
state.show = false;
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(document.documentElement);
|
2026-06-06 11:45:52 +08:00
|
|
|
if ($('#test-if')) throw new Error('$if fail: should be hidden');
|
2026-05-17 16:48:29 +08:00
|
|
|
|
2026-05-14 17:12:01 +08:00
|
|
|
state.show = true;
|
2026-05-17 16:48:29 +08:00
|
|
|
await wait();
|
2026-06-06 11:45:52 +08:00
|
|
|
if (!$('#test-if')) throw new Error('$if fail: should be visible');
|
2026-05-14 17:12:01 +08:00
|
|
|
|
2026-06-06 11:45:52 +08:00
|
|
|
// 3. $each directive
|
|
|
|
|
document.body.innerHTML = '<template $each="state.items"><div class="test-item" $text="item"></div></template>';
|
|
|
|
|
state.items = ['A', 'B'];
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(document.documentElement);
|
2026-06-06 11:45:52 +08:00
|
|
|
if ($$('.test-item').length !== 2) throw new Error('$each fail: count mismatch');
|
|
|
|
|
if ($$('.test-item')[0].textContent !== 'A') throw new Error('$each fail: content mismatch');
|
2026-05-14 17:12:01 +08:00
|
|
|
|
2026-06-06 11:45:52 +08:00
|
|
|
state.items = ['A', 'B', 'C'];
|
2026-05-17 16:48:29 +08:00
|
|
|
await wait();
|
2026-06-06 11:45:52 +08:00
|
|
|
if ($$('.test-item').length !== 3) throw new Error('$each update fail');
|
2026-05-14 17:12:01 +08:00
|
|
|
|
2026-06-06 11:45:52 +08:00
|
|
|
// 4. Event binding $onclick
|
|
|
|
|
document.body.innerHTML = '<button id="test-click" $onclick="state.count++"></button>';
|
|
|
|
|
state.count = 0;
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(document.documentElement);
|
2026-06-06 11:45:52 +08:00
|
|
|
$('#test-click').click();
|
|
|
|
|
if (state.count !== 1) throw new Error('$onclick failed');
|
|
|
|
|
|
|
|
|
|
// 5. $bind (input)
|
|
|
|
|
document.body.innerHTML = '<input id="test-bind" $bind="state.val">';
|
|
|
|
|
state.val = 'init';
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(document.documentElement);
|
2026-06-06 11:45:52 +08:00
|
|
|
await wait(); // TRY: 等待 $bind 的 setTimeout 完成
|
|
|
|
|
const input = $('#test-bind');
|
|
|
|
|
if (input.value !== 'init') throw new Error('$bind initial failed');
|
2026-05-14 17:12:01 +08:00
|
|
|
|
|
|
|
|
input.value = 'changed';
|
2026-06-06 11:45:52 +08:00
|
|
|
input.dispatchEvent(new Event('input'));
|
|
|
|
|
if (state.val !== 'changed') throw new Error('$bind writeback failed');
|
2026-05-14 17:12:01 +08:00
|
|
|
|
2026-05-27 00:04:38 +08:00
|
|
|
// 6. Double evaluation ($$ prefix)
|
|
|
|
|
console.log('Testing double evaluation ($$)...');
|
|
|
|
|
document.body.innerHTML = `
|
|
|
|
|
<div id="double-eval-root">
|
2026-06-06 11:45:52 +08:00
|
|
|
<template $$if="state.innerExp">
|
|
|
|
|
<div id="inner-node">Dynamic Visible</div>
|
|
|
|
|
</template>
|
2026-05-27 00:04:38 +08:00
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
const doubleState = NewState({
|
|
|
|
|
innerExp: 'state.innerShow',
|
|
|
|
|
innerShow: false
|
|
|
|
|
});
|
|
|
|
|
window.state = doubleState;
|
2026-06-06 11:45:52 +08:00
|
|
|
const root = $('#double-eval-root');
|
|
|
|
|
root._thisObj = { state: doubleState };
|
2026-05-27 00:04:38 +08:00
|
|
|
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(root);
|
2026-05-27 00:04:38 +08:00
|
|
|
await wait();
|
|
|
|
|
if ($('#inner-node')) throw new Error('$$if failed: should be hidden initially');
|
|
|
|
|
|
|
|
|
|
console.log('Enabling inner node...');
|
|
|
|
|
doubleState.innerShow = true;
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(root);
|
2026-05-27 00:04:38 +08:00
|
|
|
await wait();
|
|
|
|
|
const inner = $('#inner-node');
|
|
|
|
|
if (!inner) throw new Error('$$if failed: should be visible after innerShow=true');
|
|
|
|
|
|
|
|
|
|
// 7. Nested $$if
|
|
|
|
|
console.log('Testing nested $$if...');
|
|
|
|
|
document.body.innerHTML = `
|
|
|
|
|
<div id="nested-double-test">
|
|
|
|
|
<template $if="state.outer">
|
2026-06-06 11:45:52 +08:00
|
|
|
<template $$if="state.innerExp">
|
|
|
|
|
<div id="nested-inner">Nested Visible</div>
|
|
|
|
|
</template>
|
2026-05-27 00:04:38 +08:00
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
2026-06-06 11:45:52 +08:00
|
|
|
const nestedRoot = $('#nested-double-test');
|
|
|
|
|
nestedRoot._thisObj = { state: doubleState };
|
2026-05-27 00:04:38 +08:00
|
|
|
doubleState.outer = true;
|
|
|
|
|
doubleState.innerShow = false;
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(nestedRoot);
|
2026-05-27 00:04:38 +08:00
|
|
|
await wait();
|
|
|
|
|
if ($('#nested-inner')) throw new Error('nested $$if failed: should be hidden initially');
|
|
|
|
|
|
|
|
|
|
doubleState.innerShow = true;
|
2026-06-06 23:16:17 +08:00
|
|
|
___unsafeRefreshState(nestedRoot);
|
2026-05-27 00:04:38 +08:00
|
|
|
await wait();
|
|
|
|
|
if (!$('#nested-inner')) throw new Error('nested $$if failed: should be visible after update');
|
|
|
|
|
|
2026-05-14 17:12:01 +08:00
|
|
|
console.log('dom.js tests passed');
|
|
|
|
|
return true;
|
|
|
|
|
}
|