Skip to content

Commit 8271761

Browse files
committed
test: tracked reads in Computed equality
1 parent a90edf6 commit 8271761

File tree

1 file changed

+46
-1
lines changed

1 file changed

+46
-1
lines changed

packages/signal-polyfill/src/wrapper.spec.ts

+46-1
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,51 @@ describe("Custom equality", () => {
613613
expect(c.get()).toBe(2);
614614
expect(n).toBe(3);
615615
});
616+
it.only("does not leak tracking information", () => {
617+
const exact = new Signal.State(1);
618+
const epsilon = new Signal.State(0.1);
619+
const force = new Signal.State(null, { equals: () => false });
620+
621+
const cutoff = vi.fn((a, b) => Math.abs(a - b) < epsilon.get());
622+
const innerFn = vi.fn(() => exact.get());
623+
const inner = new Signal.Computed(innerFn, {
624+
equals: cutoff
625+
});
626+
627+
const outerFn = vi.fn(() => {
628+
force.get();
629+
return inner.get();
630+
});
631+
const outer = new Signal.Computed(outerFn);
632+
633+
outer.get();
634+
635+
expect(innerFn).toBeCalledTimes(1);
636+
expect(outerFn).toBeCalledTimes(1);
637+
638+
exact.set(2);
639+
force.set(null);
640+
641+
// Checks `force` first, and decides `outer` needs to rerun (without having
642+
// to recheck `inner` ahead of time).
643+
outer.get()
644+
645+
expect(innerFn).toBeCalledTimes(2);
646+
expect(outerFn).toBeCalledTimes(2);
647+
expect(cutoff).toBeCalledTimes(1);
648+
649+
// When we change `epsilon`, which Computeds should rerun?
650+
epsilon.set(0.2);
651+
outer.get();
652+
653+
// In this implementation it's `outer`, and not `inner`?
654+
expect(innerFn).toBeCalledTimes(2);
655+
expect(outerFn).toBeCalledTimes(3);
656+
657+
// ... Which is probably a bad idea, because if we had an `outer2` identical
658+
// to `outer` and ran it second, it would _not_ capture the leaked tracking
659+
// effect from `cutoff` and would not behave identically to `outer`!
660+
});
616661
});
617662

618663
describe("Receivers", () => {
@@ -983,4 +1028,4 @@ describe("currentComputed", () => {
9831028
// - Paths around writes being prohibited during computed/effect
9841029
// - Setters for various hooks
9851030
// - ngDevMode
986-
// - Some predicates/getters for convenience, e.g., isReactive
1031+
// - Some predicates/getters for convenience, e.g., isReactive

0 commit comments

Comments
 (0)