rdesign/frontend/node_modules/signal-polyfill/tests/behaviors/custom-equality.test.ts

109 lines
2.6 KiB
TypeScript

import {describe, expect, it, vi} from 'vitest';
import {Signal} from '../../src/wrapper.js';
describe('Custom equality', () => {
it('works for State', () => {
let answer = true;
const s = new Signal.State(1, {
equals() {
return answer;
},
});
let n = 0;
const c = new Signal.Computed(() => (n++, s.get()));
expect(c.get()).toBe(1);
expect(n).toBe(1);
s.set(2);
expect(s.get()).toBe(1);
expect(c.get()).toBe(1);
expect(n).toBe(1);
answer = false;
s.set(2);
expect(s.get()).toBe(2);
expect(c.get()).toBe(2);
expect(n).toBe(2);
s.set(2);
expect(s.get()).toBe(2);
expect(c.get()).toBe(2);
expect(n).toBe(3);
});
it('works for Computed', () => {
let answer = true;
let value = 1;
const u = new Signal.State(1);
const s = new Signal.Computed(() => (u.get(), value), {
equals() {
return answer;
},
});
let n = 0;
const c = new Signal.Computed(() => (n++, s.get()));
expect(c.get()).toBe(1);
expect(n).toBe(1);
u.set(2);
value = 2;
expect(s.get()).toBe(1);
expect(c.get()).toBe(1);
expect(n).toBe(1);
answer = false;
u.set(3);
expect(s.get()).toBe(2);
expect(c.get()).toBe(2);
expect(n).toBe(2);
u.set(4);
expect(s.get()).toBe(2);
expect(c.get()).toBe(2);
expect(n).toBe(3);
});
it('does not leak tracking information', () => {
const exact = new Signal.State(1);
const epsilon = new Signal.State(0.1);
const counter = new Signal.State(1);
const cutoff = vi.fn((a, b) => Math.abs(a - b) < epsilon.get());
const innerFn = vi.fn(() => exact.get());
const inner = new Signal.Computed(innerFn, {
equals: cutoff,
});
const outerFn = vi.fn(() => {
counter.get();
return inner.get();
});
const outer = new Signal.Computed(outerFn);
outer.get();
// Everything runs the first time.
expect(innerFn).toBeCalledTimes(1);
expect(outerFn).toBeCalledTimes(1);
exact.set(2);
counter.set(2);
outer.get();
// `outer` reruns because `counter` changed, `inner` reruns when called by
// `outer`, and `cutoff` is called for the first time.
expect(innerFn).toBeCalledTimes(2);
expect(outerFn).toBeCalledTimes(2);
expect(cutoff).toBeCalledTimes(1);
epsilon.set(0.2);
outer.get();
// Changing something `cutoff` depends on makes `inner` need to rerun, but
// (since the new and old values are equal) not `outer`.
expect(innerFn).toBeCalledTimes(3);
expect(outerFn).toBeCalledTimes(2);
expect(cutoff).toBeCalledTimes(2);
});
});