From 67013de016b794b5462e9a1430feb636659fff5f Mon Sep 17 00:00:00 2001 From: David Maskasky Date: Fri, 3 Jan 2025 23:39:25 -0700 Subject: [PATCH] put original effect tests back --- tests/vanilla/effect.test.ts | 92 +++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/tests/vanilla/effect.test.ts b/tests/vanilla/effect.test.ts index c815a65e8d..03fa638b06 100644 --- a/tests/vanilla/effect.test.ts +++ b/tests/vanilla/effect.test.ts @@ -1,4 +1,4 @@ -import { expect, it } from 'vitest' +import { expect, it, vi } from 'vitest' import type { Atom, Getter, Setter } from 'jotai/vanilla' import { atom, createStore } from 'jotai/vanilla' @@ -70,7 +70,9 @@ export function syncEffect(effect: Effect): Atom { ++ref.inProgress return store.set(a, ...args) } finally { - Array.from(currDeps.keys(), get) // TODO: do we still need this? + // we previously needed this because jotai store would forget deps between runs + // TODO - do we still need this? + Array.from(currDeps.keys(), get) --ref.inProgress } } @@ -200,3 +202,89 @@ it('fires after recomputeDependents and before atom listeners', async function t store.set(a, { v: 0 }) expect(r).toBe(1) }) + +it('responds to changes to atoms when subscribed', () => { + const store = createStore() + const a = atom(1) + const b = atom(1) + const w = atom(null, (_get, set, value: number) => { + set(a, value) + set(b, value) + }) + const results: number[] = [] + const cleanup = vi.fn() + const effect = vi.fn((get: Getter) => { + results.push(get(a) * 10 + get(b)) + return cleanup + }) + const e = syncEffect(effect) + const unsub = store.sub(e, () => {}) // mount syncEffect + expect(effect).toBeCalledTimes(1) + expect(results).toStrictEqual([11]) // initial values at time of effect mount + store.set(a, 2) + expect(results).toStrictEqual([11, 21]) + store.set(b, 2) + expect(results).toStrictEqual([11, 21, 22]) + store.set(w, 3) + // intermediate state of '32' should not be recorded since the effect runs _after_ graph has been computed + expect(results).toStrictEqual([11, 21, 22, 33]) + expect(cleanup).toBeCalledTimes(3) + expect(effect).toBeCalledTimes(4) + unsub() + expect(cleanup).toBeCalledTimes(4) + expect(effect).toBeCalledTimes(4) + store.set(a, 4) + // the effect is unmounted so no more updates + expect(results).toStrictEqual([11, 21, 22, 33]) + expect(effect).toBeCalledTimes(4) +}) + +it('responds to changes to atoms when mounted with get', () => { + const store = createStore() + const a = atom(1) + const b = atom(1) + const w = atom(null, (_get, set, value: number) => { + set(a, value) + set(b, value) + }) + const results: number[] = [] + const cleanup = vi.fn() + const effect = vi.fn((get: Getter) => { + results.push(get(a) * 10 + get(b)) + return cleanup + }) + const e = syncEffect(effect) + const d = atom((get) => get(e)) + const unsub = store.sub(d, () => {}) // mount syncEffect + expect(effect).toBeCalledTimes(1) + expect(results).toStrictEqual([11]) // initial values at time of effect mount + store.set(a, 2) + expect(results).toStrictEqual([11, 21]) + store.set(b, 2) + expect(results).toStrictEqual([11, 21, 22]) + store.set(w, 3) + // intermediate state of '32' should not be recorded since the effect runs _after_ graph has been computed + expect(results).toStrictEqual([11, 21, 22, 33]) + expect(cleanup).toBeCalledTimes(3) + expect(effect).toBeCalledTimes(4) + unsub() + expect(cleanup).toBeCalledTimes(4) + expect(effect).toBeCalledTimes(4) +}) + +it('sets values to atoms without causing infinite loop', () => { + const store = createStore() + const a = atom(1) + const effect = vi.fn((get: Getter, set: Setter) => { + set(a, get(a) + 1) + }) + const e = syncEffect(effect) + const unsub = store.sub(e, () => {}) // mount syncEffect + expect(effect).toBeCalledTimes(1) + expect(store.get(a)).toBe(2) // initial values at time of effect mount + store.set(a, (v) => ++v) + expect(store.get(a)).toBe(4) + expect(effect).toBeCalledTimes(2) + unsub() + expect(effect).toBeCalledTimes(2) +})