@@ -613,6 +613,51 @@ describe("Custom equality", () => {
613
613
expect ( c . get ( ) ) . toBe ( 2 ) ;
614
614
expect ( n ) . toBe ( 3 ) ;
615
615
} ) ;
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
+ } ) ;
616
661
} ) ;
617
662
618
663
describe ( "Receivers" , ( ) => {
@@ -983,4 +1028,4 @@ describe("currentComputed", () => {
983
1028
// - Paths around writes being prohibited during computed/effect
984
1029
// - Setters for various hooks
985
1030
// - ngDevMode
986
- // - Some predicates/getters for convenience, e.g., isReactive
1031
+ // - Some predicates/getters for convenience, e.g., isReactive
0 commit comments