UNPKG

@shined/reactive

Version:

⚛️ Proxy-driven state library for JavaScript application, Intuitive, Flexible and Written in TypeScript.

176 lines (123 loc) 4.8 kB
import { describe, expect, it, vi } from 'vitest' import { LISTENERS, SNAPSHOT } from '../utils/index.js' import { proxy } from './proxy.js' import { ref } from './ref.js' describe('proxy', () => { it('should be defined', () => { expect(proxy).toBeDefined() }) it('should return a reactive proxy object', () => { const state = { count: 0 } const reactiveState = proxy(state) expect(reactiveState.count).toBe(0) }) it('should update the reactive state when a property is set', async () => { const state = { count: 0 } const reactiveState = proxy(state) reactiveState.count = 5 await Promise.resolve() expect(reactiveState.count).toBe(5) }) it('should not update the reactive state when a property is ref', async () => { const state = { name: 0, refKey: ref({ count: 1 }) } as any const reactiveState = proxy(state) const snapshot = reactiveState[SNAPSHOT] reactiveState.refKey.count++ await Promise.resolve() expect(snapshot).toBe(reactiveState[SNAPSHOT]) expect(snapshot.refKey.count).toBe(2) }) it('should notify listeners when a property is set', async () => { const state = { count: 0 } as any const reactiveState = proxy(state) const listener = vi.fn() reactiveState[LISTENERS].add(listener) reactiveState.count = 10 await Promise.resolve() expect(listener).toHaveBeenCalledTimes(1) }) it('should create a non-extensible snapshot with recursive properties', () => { const initState = { person: { name: 'John' } } as any const proxyObj = proxy(initState) const snapshot = proxyObj[SNAPSHOT] expect(snapshot).toMatchObject(initState) expect(Object.isExtensible(snapshot)).toBe(false) }) it('should create a snapshot of the state', async () => { const state = { count: 0 } const reactiveState = proxy(state) const snapshot1 = (reactiveState as any)[SNAPSHOT] expect(snapshot1.count).toBe(0) reactiveState.count = 5 const snapshot2 = (reactiveState as any)[SNAPSHOT] await Promise.resolve() expect(snapshot2.count).toBe(5) expect(snapshot1).not.toBe(snapshot2) }) it('should handle nested objects and arrays', () => { const state = { nested: { array: [1, 2, 3] } } const reactiveState = proxy(state) expect(Array.isArray(reactiveState.nested.array)).toBe(true) reactiveState.nested.array.push(4) expect(reactiveState.nested.array.length).toBe(4) expect(reactiveState.nested.array[3]).toBe(4) }) it('should delete a property from the state', () => { const state = { count: 0 } as any const reactiveState = proxy(state) delete reactiveState.count expect(reactiveState.count).toBeUndefined() }) it('should notify listeners when a property is deleted', async () => { const state = { count: 0 } as any const reactiveState = proxy(state) const listener = vi.fn() ;(reactiveState as any)[LISTENERS].add(listener) delete reactiveState.count await Promise.resolve() expect(listener).toHaveBeenCalledTimes(1) }) it('should handle nested listeners correctly', async () => { const state = { nested: { prop: 0 } } as any const reactiveState = proxy(state) const listener1 = vi.fn() const listener2 = vi.fn() reactiveState.nested[LISTENERS].add(listener1) reactiveState[LISTENERS].add(listener2) reactiveState.nested.prop = 5 await Promise.resolve() expect(listener1).toHaveBeenCalledTimes(1) expect(listener2).toHaveBeenCalledTimes(1) }) it('should be handled correctly deletion logic', async () => { const state = { nested: { prop: 0 } } as any const reactiveState = proxy(state) const listener1 = vi.fn() const listener2 = vi.fn() reactiveState.nested[LISTENERS].add(listener1) reactiveState[LISTENERS].add(listener2) delete reactiveState.nested await Promise.resolve() expect(listener2).toHaveBeenCalledTimes(1) }) it('should be handled correctly Use cached listeners', async () => { const state = { nested: { prop: 0 } } as any const reactiveState = proxy(state) const listener1 = vi.fn() reactiveState.nested[LISTENERS].add(listener1) // biome-ignore lint/correctness/noSelfAssign: for test reactiveState.nested = reactiveState.nested reactiveState.nested.prop = 2 await Promise.resolve() expect(listener1).toHaveBeenCalledTimes(1) }) it('should not notify listeners when a property is not truly changed', async () => { const state = { count: 0 } as any const reactiveState = proxy(state) const listener = vi.fn() reactiveState[LISTENERS].add(listener) reactiveState.count = 0 await Promise.resolve() expect(listener).toHaveBeenCalledTimes(0) }) })