80 lines
2.1 KiB
TypeScript
80 lines
2.1 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { batch, computed, effect, resource, signal, watch } from "../src/index.ts";
|
|
|
|
describe("reactive primitives", () => {
|
|
test("signals skip no-op updates", () => {
|
|
const value = signal(1);
|
|
const seen: number[] = [];
|
|
value.subscribe((next) => seen.push(next));
|
|
value.set(1);
|
|
value.set(2);
|
|
expect(seen).toEqual([2]);
|
|
});
|
|
|
|
test("batch coalesces notifications", () => {
|
|
const value = signal(0);
|
|
const seen: number[] = [];
|
|
value.subscribe((next) => seen.push(next));
|
|
batch(() => {
|
|
value.set(1);
|
|
value.set(2);
|
|
value.set(3);
|
|
});
|
|
expect(seen).toEqual([3]);
|
|
});
|
|
|
|
test("computed values and effects track dependencies", () => {
|
|
const count = signal(2);
|
|
const doubled = computed(() => count.get() * 2);
|
|
const seen: number[] = [];
|
|
const dispose = effect(() => {
|
|
seen.push(doubled.get());
|
|
});
|
|
count.set(3);
|
|
dispose();
|
|
count.set(4);
|
|
expect(seen).toEqual([4, 6]);
|
|
});
|
|
|
|
test("effects ignore accidental non-function return values", () => {
|
|
const value = signal(0);
|
|
const seen: number[] = [];
|
|
const dispose = effect(() => seen.push(value.get()) as unknown as void);
|
|
value.set(1);
|
|
dispose();
|
|
expect(seen).toEqual([0, 1]);
|
|
});
|
|
});
|
|
|
|
test("watch reports undefined as the previous value for an immediate run", () => {
|
|
const value = signal(1);
|
|
const seen: Array<[number, number | undefined]> = [];
|
|
const stop = watch(
|
|
() => value.get(),
|
|
(next, previous) => void seen.push([next, previous]),
|
|
{ immediate: true },
|
|
);
|
|
value.set(2);
|
|
stop();
|
|
|
|
expect(seen).toEqual([
|
|
[1, undefined],
|
|
[2, 1],
|
|
]);
|
|
});
|
|
|
|
test("aborting a pending resource does not dereference a cleared controller", async () => {
|
|
let resolve!: (value: string) => void;
|
|
const pending = new Promise<string>((done) => {
|
|
resolve = done;
|
|
});
|
|
const value = resource(() => pending);
|
|
const run = value.run();
|
|
value.abort("cancelled");
|
|
resolve("late");
|
|
|
|
await expect(run).resolves.toBeUndefined();
|
|
expect(value.status.get()).toBe("idle");
|
|
expect(value.data.get()).toBeUndefined();
|
|
});
|