Files
UI/packages/core/frame/scripts/smoke.mjs
T

100 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*** 作用:@ui-arch/frame 内核冒烟——信号 / 副作用 / 计算值的语义断言(纯 JS,无需 DOM;跑 npm run smoke 执行) ***/
import { computed, effect, signal } from '../dist/signal.js';
let pass = 0;
let fail = 0;
/*** 断言:失败也继续跑完,最后统一给退出码(否则第一个红就看不到后面) ***/
const ok = (label, cond) => {
if (cond) {
pass += 1;
console.log(`ok - ${label}`);
return;
}
fail += 1;
console.error(`NOT OK - ${label}`);
};
// —— 1. 信号的读写与同值短路 ——
const count = signal(0);
let hits = 0;
effect(() => {
count();
hits += 1;
});
ok('effect 创建时立即执行一次', hits === 1);
count(1);
ok('写值后重跑', hits === 2);
count(1);
ok('写入相同值不触发(Object.is 短路)', hits === 2);
// —— 2. 注销后不再重跑 ——
const live = signal('a');
let liveHits = 0;
const dispose = effect(() => {
live();
liveHits += 1;
});
live('b');
ok('注销前正常重跑', liveHits === 2);
dispose();
live('c');
ok('注销后写值不再重跑(dispose 必须真的摘订阅)', liveHits === 2);
// —— 3. 条件分支重追踪:上一轮读过、这一轮不读的信号不该再唤它 ——
const flag = signal(true);
const left = signal(0);
const right = signal(0);
let branchHits = 0;
effect(() => {
branchHits += 1;
if (flag()) left();
else right();
});
const afterInit = branchHits;
flag(false);
ok('切分支本身触发一次重跑', branchHits === afterInit + 1);
const afterSwitch = branchHits;
left(9);
ok('切走后旧的依赖不再唤它(重追踪要清旧订阅)', branchHits === afterSwitch);
right(9);
ok('切走后新依赖仍唤它', branchHits === afterSwitch + 1);
// —— 4. computed:派生、链式、同值短路 ——
const price = signal(10);
const qty = signal(2);
const total = computed(() => price() * qty());
ok('computed 首次读即得派生值', total() === 20);
price(3);
ok('源变化后 computed 立即跟着变', total() === 6);
let derivedHits = 0;
effect(() => {
total();
derivedHits += 1;
});
const derivedBase = derivedHits;
qty(3);
ok('computed 变更会唤上层 effect(链式依赖成立)', derivedHits === derivedBase + 1);
ok('链式计算值正确', total() === 9);
// —— 5. 多订阅者:扇出与互不影响 ——
const fan = signal(0);
let a = 0;
let b = 0;
const disposeA = effect(() => {
fan();
a += 1;
});
effect(() => {
fan();
b += 1;
});
fan(1);
ok('一次写值唤全部订阅者', a === 2 && b === 2);
disposeA();
fan(2);
ok('注销一个订阅者不影响另一个', a === 2 && b === 3);
console.log(`\n${fail === 0 ? 'SMOKE OK' : 'SMOKE FAILED'}(${pass} 通过 / ${fail} 失败)`);
process.exit(fail === 0 ? 0 : 1);