rdesign/frontend/node_modules/signal-polyfill/tests/Signal/subtle/watch-unwatch.test.ts

194 lines
5.1 KiB
TypeScript

import {describe, expect, it, vi} from 'vitest';
import {Signal} from '../../../src/wrapper.js';
describe('watch and unwatch', () => {
it('handles multiple watchers well', () => {
const s = new Signal.State(1);
const s2 = new Signal.State(2);
let n = 0;
const w = new Signal.subtle.Watcher(() => n++);
w.watch(s, s2);
s.set(4);
expect(n).toBe(1);
expect(w.getPending()).toStrictEqual([]);
w.watch();
s2.set(8);
expect(n).toBe(2);
w.unwatch(s);
s.set(3);
expect(n).toBe(2);
w.watch();
s2.set(3);
expect(n).toBe(3);
w.watch();
s.set(2);
expect(n).toBe(3);
});
it('understands dynamic dependency sets', () => {
let w1 = 0,
u1 = 0,
w2 = 0,
u2 = 0,
n = 0,
d = 0;
let s1 = new Signal.State(1, {
[Signal.subtle.watched]() {
w1++;
},
[Signal.subtle.unwatched]() {
u1++;
},
});
let s2 = new Signal.State(2, {
[Signal.subtle.watched]() {
w2++;
},
[Signal.subtle.unwatched]() {
u2++;
},
});
let which: {get(): number} = s1;
let c = new Signal.Computed(() => (d++, which.get()));
let w = new Signal.subtle.Watcher(() => n++);
w.watch(c);
expect(w1 + w2 + u1 + u2 + n + d).toBe(0);
expect(Signal.subtle.hasSinks(s1)).toBe(false);
expect(Signal.subtle.hasSinks(s2)).toBe(false);
expect(w.getPending()).toStrictEqual([c]);
expect(c.get()).toBe(1);
expect(w1).toBe(1);
expect(u1).toBe(0);
expect(w2).toBe(0);
expect(u2).toBe(0);
expect(n).toBe(0);
expect(Signal.subtle.hasSinks(s1)).toBe(true);
expect(Signal.subtle.hasSinks(s2)).toBe(false);
expect(w.getPending()).toStrictEqual([]);
expect(d).toBe(1);
s1.set(3);
expect(w1).toBe(1);
expect(u1).toBe(0);
expect(w2).toBe(0);
expect(u2).toBe(0);
expect(n).toBe(1);
expect(Signal.subtle.hasSinks(s1)).toBe(true);
expect(Signal.subtle.hasSinks(s2)).toBe(false);
expect(w.getPending()).toStrictEqual([c]);
expect(d).toBe(1);
expect(c.get()).toBe(3);
expect(w1).toBe(1);
expect(u1).toBe(0);
expect(w2).toBe(0);
expect(u2).toBe(0);
expect(n).toBe(1);
expect(Signal.subtle.hasSinks(s1)).toBe(true);
expect(Signal.subtle.hasSinks(s2)).toBe(false);
expect(w.getPending()).toStrictEqual([]);
expect(d).toBe(2);
which = s2;
w.watch();
s1.set(4);
expect(w1).toBe(1);
expect(u1).toBe(0);
expect(w2).toBe(0);
expect(u2).toBe(0);
expect(n).toBe(2);
expect(Signal.subtle.hasSinks(s1)).toBe(true);
expect(Signal.subtle.hasSinks(s2)).toBe(false);
expect(w.getPending()).toStrictEqual([c]);
expect(d).toBe(2);
expect(c.get()).toBe(2);
expect(w1).toBe(1);
expect(u1).toBe(1);
expect(w2).toBe(1);
expect(u2).toBe(0);
expect(n).toBe(2);
expect(Signal.subtle.hasSinks(s1)).toBe(false);
expect(Signal.subtle.hasSinks(s2)).toBe(true);
expect(w.getPending()).toStrictEqual([]);
expect(d).toBe(3);
w.watch();
which = {
get() {
return 10;
},
};
s1.set(5);
expect(c.get()).toBe(2);
expect(w1).toBe(1);
expect(u1).toBe(1);
expect(w2).toBe(1);
expect(u2).toBe(0);
expect(n).toBe(2);
expect(Signal.subtle.hasSinks(s1)).toBe(false);
expect(Signal.subtle.hasSinks(s2)).toBe(true);
expect(w.getPending()).toStrictEqual([]);
expect(d).toBe(3);
w.watch();
s2.set(0);
expect(w1).toBe(1);
expect(u1).toBe(1);
expect(w2).toBe(1);
expect(u2).toBe(0);
expect(n).toBe(3);
expect(Signal.subtle.hasSinks(s1)).toBe(false);
expect(Signal.subtle.hasSinks(s2)).toBe(true);
expect(w.getPending()).toStrictEqual([c]);
expect(d).toBe(3);
expect(c.get()).toBe(10);
expect(w1).toBe(1);
expect(u1).toBe(1);
expect(w2).toBe(1);
expect(u2).toBe(1);
expect(n).toBe(3);
expect(Signal.subtle.hasSinks(s1)).toBe(false);
expect(Signal.subtle.hasSinks(s2)).toBe(false);
expect(w.getPending()).toStrictEqual([]);
expect(d).toBe(4);
});
it('can unwatch multiple signals', async () => {
const signals = [...Array(7)].map((_, i) => new Signal.State(i));
const notify = vi.fn();
const watcher = new Signal.subtle.Watcher(notify);
const expectSources = (expected: typeof signals) => {
const sources = Signal.subtle.introspectSources(watcher) as typeof signals;
sources.sort((a, b) => signals.indexOf(a) - signals.indexOf(b));
expected.sort((a, b) => signals.indexOf(a) - signals.indexOf(b));
return expect(sources).toEqual(expected);
};
watcher.watch(...signals);
expectSources(signals);
const unwatched = [0, 3, 4, 6].map((i) => signals[i]);
const watched = signals.filter((s) => !unwatched.includes(s));
watcher.unwatch(...unwatched);
expectSources(watched);
let expectedNotifyCalls = 0;
for (const signal of signals) {
signal.set(signal.get() + 1);
if (watched.includes(signal)) ++expectedNotifyCalls;
expect(notify).toHaveBeenCalledTimes(expectedNotifyCalls);
watcher.watch();
}
});
});