Last active
January 26, 2024 10:35
-
-
Save hastebrot/14de4cd864ffb3a37929b9c33a5535bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ❯ bun add -d [email protected] vitest zod | |
// ❯ bun run test --watch signia.test.tsx | |
import { atom, computed, type Atom, type Computed, type Signal } from "signia"; | |
import { expect, test } from "vitest"; | |
import { z } from "zod"; | |
// repo for "signia" package: https://github.com/tldraw/signia | |
test("signia condition with atom() and computed()", () => { | |
const BlockProps = z.object({ | |
field1Input: zodAtom<number>(), | |
field1Link: zodAtom<null | Signal<number>>(), | |
field1: zodComputed<number>(), | |
field2: zodComputed<number>(), | |
}); | |
type BlockProps = z.infer<typeof BlockProps>; | |
// create field1Input and empty field1Link and check fields. | |
let block = {} as BlockProps; | |
block.field1Input = atom("field1Input", 100); | |
block.field1Link = atom("field1Link", null); | |
block.field1 = computed("field1", () => { | |
return block.field1Link.value?.value ?? block.field1Input.value; | |
}); | |
block.field2 = computed("field2", () => { | |
return block.field1.value + 1; | |
}); | |
block = BlockProps.parse(block); | |
expect(block.field1.value).toBe(100); | |
expect(block.field2.value).toBe(101); | |
// change field1Input and check fields. | |
block.field1Input.set(200); | |
expect(block.field1.value).toBe(200); | |
expect(block.field2.value).toBe(201); | |
// set field1Link atom and check fields. | |
const field1LinkSignal = atom("field1LinkSignal", 1); | |
block.field1Link.set(field1LinkSignal); | |
expect(block.field1.value).toBe(1); | |
expect(block.field2.value).toBe(2); | |
// update field1Link atom and check fields. | |
field1LinkSignal.update((value) => value + 1); | |
expect(block.field1.value).toBe(2); | |
expect(block.field2.value).toBe(3); | |
// set field1Link computed and check fields. | |
block.field1Link.set(computed("field1LinkSignal", () => 3)); | |
expect(block.field1.value).toBe(3); | |
expect(block.field2.value).toBe(4); | |
// set field1Link computed atom and check fields. | |
block.field1Link.set(computed("field1LinkSignal", () => atom("foo", 4).value)); | |
expect(block.field1.value).toBe(4); | |
expect(block.field2.value).toBe(5); | |
// unset field1Link and check fields. | |
block.field1Link.set(null); | |
expect(block.field1.value).toBe(200); | |
expect(block.field2.value).toBe(201); | |
}); | |
test("signia iteration with atom() and computed()", () => { | |
const BlockProps = z.object({ | |
field1Links: zodAtom<Signal<number>[]>(), | |
field1: zodComputed<number>(), | |
}); | |
type BlockProps = z.infer<typeof BlockProps>; | |
// create field1 and empty field1Links and check fields. | |
let block = {} as BlockProps; | |
block.field1Links = atom("field1Links", []); | |
block.field1 = computed("field1", () => { | |
let sum = 0; | |
for (const signal of block.field1Links.value) { | |
sum += signal.value; | |
} | |
return sum; | |
}); | |
block = BlockProps.parse(block); | |
expect(block.field1.value).toBe(0); | |
// change field1Links and check fields. | |
block.field1Links.set([atom("value1", 1)]); | |
expect(block.field1.value).toBe(1); | |
// change field1Links and check fields. | |
block.field1Links.set([atom("value1", 1), atom("value2", 2)]); | |
expect(block.field1.value).toBe(3); | |
// change field1Links and check fields. | |
block.field1Links.set([atom("value2", 2)]); | |
expect(block.field1.value).toBe(2); | |
// change field1Links and check fields. | |
block.field1Links.set([]); | |
expect(block.field1.value).toBe(0); | |
}); | |
const isAtom = (data: any) => data?.constructor?.name === "_Atom"; | |
const isComputed = (data: any) => data?.constructor?.name === "_Computed"; | |
export const zodSignal = <Value,>() => { | |
return z | |
.custom((data: any) => isAtom(data) || isComputed(data), { | |
message: `must be type Atom or type Computed`, | |
}) | |
.transform((data) => data as Signal<Value, unknown>); | |
}; | |
export const zodAtom = <Value,>() => { | |
return z | |
.custom((data: any) => isAtom(data), { | |
message: `must be type Atom`, | |
}) | |
.transform((data) => data as Atom<Value, unknown>); | |
}; | |
export const zodComputed = <Value,>() => { | |
return z | |
.custom((data: any) => isComputed(data), { | |
message: `must be type Computed`, | |
}) | |
.transform((data) => data as Computed<Value, unknown>); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ❯ bun add -d [email protected] vitest zod | |
// ❯ bun run test --watch valtio.test.tsx | |
import { cleanup } from "@testing-library/react"; | |
import { Window } from "happy-dom"; | |
import { getVersion, proxy, snapshot } from "valtio"; | |
import { derive } from "valtio/utils"; | |
import { beforeAll, beforeEach, expect, test } from "vitest"; | |
// repo for "valtio" package: https://github.com/pmndrs/valtio | |
// repo for "derive-valtio" package: https://github.com/valtiojs/derive-valtio | |
beforeAll(() => { | |
const window = new Window(); | |
global.window = window as any; | |
global.document = window.document as any; | |
}); | |
beforeEach(() => { | |
cleanup(); | |
}); | |
test("valtio condition with proxy() and derive()", async () => { | |
// given: | |
const field1Input = proxy({ value: 0 }); | |
const field1Link = proxy<{ value: number | null }>({ value: null }); | |
const field1 = derive({ | |
// when dependencies change, value() getter is updated after the next tick. | |
value(get) { | |
// dependencies with derived value: | |
return get(field1Link).value ?? get(field1Input).value; | |
}, | |
}); | |
const field2 = proxy({ | |
// dependencies: | |
field1Link, | |
field1Input, | |
// when dependencies change, value() getter is updated immediately. | |
get value() { | |
// derived value: | |
return field1Link.value ?? field1Input.value; | |
}, | |
}); | |
// when: | |
console.log("version", getVersion(field1), getVersion(field2)); | |
field1Input.value = 100; | |
await tick(); | |
console.log("version", getVersion(field1), getVersion(field2)); | |
// then: | |
expect(snapshot(field1Input).value).toBe(100); | |
expect(snapshot(field1).value).toBe(100); | |
expect(snapshot(field2).value).toBe(100); | |
// when: | |
field1Link.value = 200; | |
await tick(); | |
console.log("version", getVersion(field1), getVersion(field2)); | |
// then: | |
expect(snapshot(field1).value).toBe(200); | |
expect(snapshot(field2).value).toBe(200); | |
// when: | |
field1Link.value = null; | |
await tick(); | |
console.log("version", getVersion(field1), getVersion(field2)); | |
// then: | |
expect(snapshot(field1).value).toBe(100); | |
expect(snapshot(field2).value).toBe(100); | |
}); | |
export const tick = () => { | |
// schedules a function to be executed in the next iteration of the event loop, | |
// after the current event loop cycle completes. | |
return new Promise((resolve) => { | |
setImmediate(resolve); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment