diff options
| author | Asko Nõmm <asko@nmm.ee> | 2025-04-18 18:48:20 +0300 |
|---|---|---|
| committer | Asko Nõmm <asko@nmm.ee> | 2025-04-18 18:48:20 +0300 |
| commit | 3014ce30b733d16cbf79f8e066a30db245e6c59d (patch) | |
| tree | e4a808d58aebbe4c7da31d9ae8a2ffc4b189ce7c /src/shapex.test.ts | |
| parent | dd6adf7febf45aa72e9754f13059d40648114027 (diff) | |
Refactor to use Deno for everything.
Diffstat (limited to 'src/shapex.test.ts')
| -rw-r--r-- | src/shapex.test.ts | 485 |
1 files changed, 284 insertions, 201 deletions
diff --git a/src/shapex.test.ts b/src/shapex.test.ts index d605c3a..0e7b08d 100644 --- a/src/shapex.test.ts +++ b/src/shapex.test.ts @@ -1,284 +1,367 @@ -import { describe, test, expect, vi, beforeEach } from "vitest"; -import ShapeX from "./shapex.ts"; +import { assertArrayIncludes, assertEquals } from "@std/assert"; +import { assertSpyCall, spy } from "@std/testing/mock"; +import { describe, it } from "@std/testing/bdd"; +import ShapeX, { EventCallback } from "./shapex.ts"; + +describe("subscribe", () => { + it("subscribes to an event", () => { + const $ = ShapeX({ counter: 1 }); + const id = $.subscribe("test-event", (state) => ({ state })); + + assertEquals(id, 1); + assertEquals($.subscriptionCount("test-event"), 1); + }); -describe("EventX", () => { - describe("subscribe", () => { - test("subscribes to an event", () => { - const $ = ShapeX({ counter: 1 }); - const id = $.subscribe("test-event", (state) => ({ state })); + it("subscribes to an event once", () => { + const $ = ShapeX({ counter: 1 }); + const id = $.subscribeOnce("test-event", (state) => ({ state })); - expect(id).toBe(1); - expect($.subscriptionCount("test-event")).toBe(1); - }); + assertEquals(id, 1); + assertEquals($.subscriptionCount("test-event"), 1); + }); - test("subscribes to an event once", () => { - const $ = ShapeX({ counter: 1 }); - const id = $.subscribeOnce("test-event", (state) => ({ state })); + it("unsubscribes from an event", () => { + const $ = ShapeX({ counter: 1 }); - expect(id).toBe(1); - expect($.subscriptionCount("test-event")).toBe(1); + $.subscribe("test-event", (state) => ({ state })); + assertEquals($.subscriptionCount("test-event"), 1); - $.dispatch("test-event"); - expect($.subscriptionCount("test-event")).toBe(0); - }); + $.unsubscribe("test-event"); + assertEquals($.subscriptionCount("test-event"), 0); + }); +}); - test("unsubscribes from an event", () => { - const $ = ShapeX({ counter: 1 }); +describe("dispatch", () => { + it("dispatches an event without arguments", () => { + type AppState = { + counter: number; + }; - $.subscribe("test-event", (state) => ({ state })); - expect($.subscriptionCount("test-event")).toBe(1); + const $ = ShapeX<AppState>({ counter: 1 }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); - $.unsubscribe("test-event"); - expect($.subscriptionCount("test-event")).toBe(0); + $.subscribe("test-event", spyCb); + $.dispatch("test-event"); + + assertSpyCall(spyCb, 0, { + args: [{ counter: 1 }], }); }); - describe("dispatch", () => { - test("dispatches an event without arguments", () => { - const $ = ShapeX({ counter: 1 }); - const callback = vi.fn((state) => ({ state })); + it("dispatches an event with arguments", () => { + type AppState = { + counter: number; + }; - $.subscribe("test-event", callback); - $.dispatch("test-event"); + const $ = ShapeX<AppState>({ counter: 1 }); - expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith({ counter: 1 }); + // deno-lint-ignore no-unused-vars + const testEventCb: EventCallback<AppState> = (state, arg1, arg2) => ({ + state, }); - test("dispatches an event with arguments", () => { - const $ = ShapeX({ counter: 1 }); - const callback = vi.fn((state, arg1, arg2) => ({ state })); + const callback = spy(testEventCb); - $.subscribe("test-event", callback); - $.dispatch("test-event", "arg1-value", "arg2-value"); + $.subscribe("test-event", callback); + $.dispatch("test-event", "arg1-value", "arg2-value"); - expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith({ counter: 1 }, "arg1-value", "arg2-value"); + assertSpyCall(callback, 0, { + args: [ + { counter: 1 }, + "arg1-value", + "arg2-value", + ], }); + }); + + it("updates state when event handler returns new state", () => { + type AppState = { + counter: number; + }; - test("updates state when event handler returns new state", () => { - const $ = ShapeX({ counter: 1 }); - const stateChangeSpy = vi.fn((state) => ({ state })); + const $ = ShapeX<AppState>({ counter: 1 }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); - $.subscribe("$.counter", stateChangeSpy); + $.subscribe("$.counter", spyCb); - $.subscribe("increment", (state) => ({ - state: { ...state, counter: state.counter + 1 }, - })); + $.subscribe("increment", (state) => ({ + state: { ...state, counter: state.counter + 1 }, + })); - $.dispatch("increment"); + $.dispatch("increment"); - expect(stateChangeSpy).toHaveBeenCalledTimes(1); - expect(stateChangeSpy).toHaveBeenCalledWith({ counter: 2 }); + assertSpyCall(spyCb, 0, { + args: [ + { counter: 2 }, + ], }); + }); - test("dispatches nested events", () => { - const $ = ShapeX({ counter: 1 }); - const nestedEventSpy = vi.fn((state) => ({ state })); + it("dispatches nested events", () => { + type AppState = { + counter: number; + }; - $.subscribe("nested-event", nestedEventSpy); + const $ = ShapeX({ counter: 1 }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); - $.subscribe("parent-event", (state) => ({ - state, - dispatch: { eventName: "nested-event" }, - })); + $.subscribe("nested-event", spyCb); - $.dispatch("parent-event"); + $.subscribe("parent-event", (state) => ({ + state, + dispatch: { eventName: "nested-event" }, + })); - expect(nestedEventSpy).toHaveBeenCalledTimes(1); - }); + $.dispatch("parent-event"); + + assertSpyCall(spyCb, 0); + }); - test("dispatches multiple nested events", () => { - const $ = ShapeX({ counter: 1 }); - const nestedEvent1Spy = vi.fn((state) => ({ state })); - const nestedEvent2Spy = vi.fn((state) => ({ state })); + it("dispatches multiple nested events", () => { + type AppState = { + counter: number; + }; - $.subscribe("nested-event-1", nestedEvent1Spy); + const $ = ShapeX({ counter: 1 }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); + const spyCb2 = spy(cb); - $.subscribe("nested-event-2", nestedEvent2Spy); + $.subscribe("nested-event-1", spyCb); - $.subscribe("parent-event", (state) => ({ - state, - dispatch: [{ eventName: "nested-event-1" }, { eventName: "nested-event-2" }], - })); + $.subscribe("nested-event-2", spyCb2); - $.dispatch("parent-event"); + $.subscribe("parent-event", (state) => ({ + state, + dispatch: [{ eventName: "nested-event-1" }, { + eventName: "nested-event-2", + }], + })); - expect(nestedEvent1Spy).toHaveBeenCalledTimes(1); - expect(nestedEvent2Spy).toHaveBeenCalledTimes(1); - }); + $.dispatch("parent-event"); + + assertSpyCall(spyCb, 0); + assertSpyCall(spyCb2, 0); + }); + + it("dispatches nested events with arguments", () => { + type AppState = { + counter: number; + }; - test("dispatches nested events with arguments", () => { - const $ = ShapeX({ counter: 1 }); - const nestedEventSpy = vi.fn((state, arg) => ({ state })); + const $ = ShapeX<AppState>({ counter: 1 }); + // deno-lint-ignore no-unused-vars + const cb: EventCallback<AppState> = (state, arg) => ({ state }); + const spyCb = spy(cb); - $.subscribe("nested-event", nestedEventSpy); + $.subscribe("nested-event", spyCb); - $.subscribe("parent-event", (state) => ({ - state, - dispatch: { eventName: "nested-event", args: ["arg-value"] }, - })); + $.subscribe("parent-event", (state) => ({ + state, + dispatch: { eventName: "nested-event", args: ["arg-value"] }, + })); - $.dispatch("parent-event"); + $.dispatch("parent-event"); - expect(nestedEventSpy).toHaveBeenCalledTimes(1); - expect(nestedEventSpy).toHaveBeenCalledWith({ counter: 1 }, "arg-value"); + assertSpyCall(spyCb, 0, { + args: [{ counter: 1 }, "arg-value"], }); }); +}); - describe("state change detection", () => { - test("detects value changes in state", () => { - const $ = ShapeX({ counter: 1, nested: { value: "test" } }); - const counterChangeSpy = vi.fn((state) => ({ state })); +describe("state change detection", () => { + it("detects value changes in state", () => { + type AppState = { + counter: number; + nested: { + value: string; + }; + }; - $.subscribe("$.counter", counterChangeSpy); + const $ = ShapeX<AppState>({ counter: 1, nested: { value: "test" } }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); - $.subscribe("change-counter", (state) => ({ - state: { ...state, counter: 2 }, - })); + $.subscribe("$.counter", spyCb); - $.dispatch("change-counter"); + $.subscribe("change-counter", (state) => ({ + state: { ...state, counter: 2 }, + })); - expect(counterChangeSpy).toHaveBeenCalledTimes(1); - expect(counterChangeSpy).toHaveBeenCalledWith({ counter: 2, nested: { value: "test" } }); + $.dispatch("change-counter"); + + assertSpyCall(spyCb, 0, { + args: [{ counter: 2, nested: { value: "test" } }], }); + }); - test("detects nested value changes in state", () => { - const $ = ShapeX({ counter: 1, nested: { value: "test" } }); - const nestedValueChangeSpy = vi.fn((state) => ({ state })); + it("detects nested value changes in state", () => { + type AppState = { + counter: number; + nested: { + value: string; + }; + }; + + const $ = ShapeX<AppState>({ counter: 1, nested: { value: "test" } }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); + + $.subscribe("$.nested.value", spyCb); + + $.subscribe("change-nested-value", (state) => ({ + state: { + ...state, + nested: { ...state.nested, value: "new value" }, + }, + })); + + $.subscribe("change-nested-value-again", (state) => ({ + state: { + ...state, + nested: { ...state.nested, value: "new value again" }, + }, + })); + + $.dispatch("change-nested-value"); + $.dispatch("change-nsted-value-again"); + + assertSpyCall(spyCb, 0, { + args: [{ counter: 1, nested: { value: "new value" } }], + }); + }); - $.subscribe("$.nested.value", nestedValueChangeSpy); + it("detects addition in state", () => { + type AppState = { + view?: string; + }; - $.subscribe("change-nested-value", (state) => ({ - state: { - ...state, - nested: { ...state.nested, value: "new value" }, - }, - })); + const $ = ShapeX<AppState>({}); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); + + $.subscribe("$.view", spyCb); - $.subscribe("change-nested-value-again", (state) => ({ + $.subscribe("set-view", (state) => { + return { state: { ...state, - nested: { ...state.nested, value: "new value again" }, + view: "test", }, - })); - - $.dispatch("change-nested-value"); - $.dispatch("change-nsted-value-again"); - - expect(nestedValueChangeSpy).toHaveBeenCalledTimes(1); - expect(nestedValueChangeSpy).toHaveBeenCalledWith({ - counter: 1, - nested: { value: "new value" }, - }); + }; }); - test("detects addition in state", () => { - const $ = ShapeX({} as { view?: string }); - const additionChangeSpy = vi.fn((state) => ({ state })); + $.dispatch("set-view"); + + assertSpyCall(spyCb, 0); + }); - $.subscribe("$.view", additionChangeSpy); + it("detects nested addition in state", () => { + type AppState = { + nested?: { + value?: string; + }; + }; - $.subscribe("set-view", (state) => { - return { - state: { - ...state, - view: "test", - }, - }; - }); + const $ = ShapeX<AppState>({}); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); + const spyCb2 = spy(cb); - $.dispatch("set-view"); + $.subscribe("$.nested", spyCb); + $.subscribe("$.nested.value", spyCb2); - expect(additionChangeSpy).toHaveBeenCalledTimes(1); + $.subscribe("set-nested-value", (state) => { + return { + state: { + ...state, + nested: { value: "test" }, + }, + }; }); - test("detects nested addition in state", () => { - const $ = ShapeX({} as { nested?: { value?: string } }); - const additionChangeSpy = vi.fn((state) => ({ state })); - const additionChangeSpy2 = vi.fn((state) => ({ state })); - - $.subscribe("$.nested", additionChangeSpy); - $.subscribe("$.nested.value", additionChangeSpy2); - - $.subscribe("set-nested-value", (state) => { - return { - state: { - ...state, - nested: { value: "test" }, - }, - }; - }); - - $.subscribe("set-nested-value-again", (state) => { - return { - state: { - ...state, - nested: { value: "test-again" }, - }, - }; - }); - - $.dispatch("set-nested-value"); - $.dispatch("set-nested-value-again"); - - expect(additionChangeSpy).toHaveBeenCalledTimes(2); - expect(additionChangeSpy2).toHaveBeenCalledTimes(2); + $.subscribe("set-nested-value-again", (state) => { + return { + state: { + ...state, + nested: { value: "test-again" }, + }, + }; }); - test("detects deleted properties in state", () => { - const $ = ShapeX({ counter: 1, toDelete: "value" } as { counter: number; toDelete?: string }); - const deleteChangeSpy = vi.fn((state) => ({ state })); + $.dispatch("set-nested-value"); + $.dispatch("set-nested-value-again"); - $.subscribe("$.toDelete", deleteChangeSpy); - $.subscribe("delete-property", (state) => { - const newState = { counter: state.counter }; - return { state: newState }; - }); + assertSpyCall(spyCb, 1); + assertSpyCall(spyCb2, 1); + }); + + it("detects deleted properties in state", () => { + type AppState = { + counter: number; + toDelete?: string; + }; - $.dispatch("delete-property"); + const $ = ShapeX<AppState>({ counter: 1, toDelete: "value" }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); - expect(deleteChangeSpy).toHaveBeenCalledTimes(1); + $.subscribe("$.toDelete", spyCb); + $.subscribe("delete-property", (state) => { + const newState = { counter: state.counter }; + return { state: newState }; }); - test("detects type changes in state", () => { - const $ = ShapeX({ counter: 1 } as { counter: string | number }); - const counterChangeSpy = vi.fn((state) => ({ state })); + $.dispatch("delete-property"); + + assertSpyCall(spyCb, 0); + }); - $.subscribe("$.counter", counterChangeSpy); - $.subscribe("change-counter-type", (state) => ({ - state: { ...state, counter: "string now" }, - })); + it("detects type changes in state", () => { + type AppState = { + counter: string | number; + }; - $.dispatch("change-counter-type"); + const $ = ShapeX<AppState>({ counter: 1 }); + const cb: EventCallback<AppState> = (state) => ({ state }); + const spyCb = spy(cb); - expect(counterChangeSpy).toHaveBeenCalledTimes(1); - }); + $.subscribe("$.counter", spyCb); + $.subscribe("change-counter-type", (state) => ({ + state: { ...state, counter: "string now" }, + })); + + $.dispatch("change-counter-type"); + + assertSpyCall(spyCb, 0); }); +}); - describe("utility methods", () => { - test("returns all subscription names", () => { - const $ = ShapeX({ counter: 1 }); +describe("utility methods", () => { + it("returns all subscription names", () => { + const $ = ShapeX({ counter: 1 }); - $.subscribe("event1", (state) => ({ state })); - $.subscribe("event2", (state) => ({ state })); + $.subscribe("event1", (state) => ({ state })); + $.subscribe("event2", (state) => ({ state })); - const subs = $.subscriptions(); + const subs = $.subscriptions(); - expect(subs).toContain("event1"); - expect(subs).toContain("event2"); - expect(subs.length).toBe(2); - }); + assertArrayIncludes(subs, ["event1"]); + assertArrayIncludes(subs, ["event2"]); + assertEquals(subs.length, 2); + }); - test("returns subscription count for specific event", () => { - const $ = ShapeX({ counter: 1 }); + it("returns subscription count for specific event", () => { + const $ = ShapeX({ counter: 1 }); - $.subscribe("event1", (state) => ({ state })); - $.subscribe("event1", (state) => ({ state })); - $.subscribe("event2", (state) => ({ state })); + $.subscribe("event1", (state) => ({ state })); + $.subscribe("event1", (state) => ({ state })); + $.subscribe("event2", (state) => ({ state })); - expect($.subscriptionCount("event1")).toBe(2); - expect($.subscriptionCount("event2")).toBe(1); - }); + assertEquals($.subscriptionCount("event1"), 2); + assertEquals($.subscriptionCount("event2"), 1); }); }); |
