|
1 | 1 | import { createRoot } from "solid-js"; |
2 | | -import { describe, expect, it } from "vitest"; |
| 2 | +import { describe, expect, it, vi } from "vitest"; |
3 | 3 | import { createEvent } from "../../src/ts/hooks/createEvent"; |
4 | 4 |
|
5 | 5 | describe("createEvent", () => { |
6 | | - it("initial value is 0", () => { |
7 | | - createRoot((dispose) => { |
8 | | - const [event] = createEvent(); |
9 | | - expect(event()).toBe(0); |
10 | | - dispose(); |
11 | | - }); |
| 6 | + it("dispatch notifies subscribers", () => { |
| 7 | + const event = createEvent<string>(); |
| 8 | + const fn = vi.fn(); |
| 9 | + event.subscribe(fn); |
| 10 | + event.dispatch("hello"); |
| 11 | + expect(fn).toHaveBeenCalledWith("hello"); |
12 | 12 | }); |
13 | 13 |
|
14 | | - it("dispatch increments the value by 1", () => { |
15 | | - createRoot((dispose) => { |
16 | | - const [event, dispatch] = createEvent(); |
17 | | - dispatch(); |
18 | | - expect(event()).toBe(1); |
19 | | - dispose(); |
20 | | - }); |
| 14 | + it("dispatch notifies multiple subscribers", () => { |
| 15 | + const event = createEvent<number>(); |
| 16 | + const fn1 = vi.fn(); |
| 17 | + const fn2 = vi.fn(); |
| 18 | + event.subscribe(fn1); |
| 19 | + event.subscribe(fn2); |
| 20 | + event.dispatch(42); |
| 21 | + expect(fn1).toHaveBeenCalledWith(42); |
| 22 | + expect(fn2).toHaveBeenCalledWith(42); |
21 | 23 | }); |
22 | 24 |
|
23 | | - it("each dispatch increments independently", () => { |
24 | | - createRoot((dispose) => { |
25 | | - const [event, dispatch] = createEvent(); |
26 | | - dispatch(); |
27 | | - dispatch(); |
28 | | - dispatch(); |
29 | | - expect(event()).toBe(3); |
30 | | - dispose(); |
31 | | - }); |
| 25 | + it("dispatch with no type arg requires no arguments", () => { |
| 26 | + const event = createEvent(); |
| 27 | + const fn = vi.fn(); |
| 28 | + event.subscribe(fn); |
| 29 | + event.dispatch(); |
| 30 | + expect(fn).toHaveBeenCalledTimes(1); |
| 31 | + }); |
| 32 | + |
| 33 | + it("subscribe returns an unsubscribe function", () => { |
| 34 | + const event = createEvent<string>(); |
| 35 | + const fn = vi.fn(); |
| 36 | + const unsub = event.subscribe(fn); |
| 37 | + event.dispatch("a"); |
| 38 | + unsub(); |
| 39 | + event.dispatch("b"); |
| 40 | + expect(fn).toHaveBeenCalledTimes(1); |
| 41 | + expect(fn).toHaveBeenCalledWith("a"); |
32 | 42 | }); |
33 | 43 |
|
34 | 44 | it("two independent events do not share state", () => { |
| 45 | + const eventA = createEvent<string>(); |
| 46 | + const eventB = createEvent<string>(); |
| 47 | + const fnA = vi.fn(); |
| 48 | + const fnB = vi.fn(); |
| 49 | + eventA.subscribe(fnA); |
| 50 | + eventB.subscribe(fnB); |
| 51 | + eventA.dispatch("a"); |
| 52 | + expect(fnA).toHaveBeenCalledWith("a"); |
| 53 | + expect(fnB).not.toHaveBeenCalled(); |
| 54 | + }); |
| 55 | + |
| 56 | + it("useListener auto-unsubscribes on dispose", () => { |
| 57 | + const event = createEvent<string>(); |
| 58 | + const fn = vi.fn(); |
35 | 59 | createRoot((dispose) => { |
36 | | - const [eventA, dispatchA] = createEvent(); |
37 | | - const [eventB, dispatchB] = createEvent(); |
38 | | - dispatchA(); |
39 | | - dispatchA(); |
40 | | - dispatchB(); |
41 | | - expect(eventA()).toBe(2); |
42 | | - expect(eventB()).toBe(1); |
| 60 | + event.useListener(fn); |
| 61 | + event.dispatch("inside"); |
43 | 62 | dispose(); |
44 | 63 | }); |
| 64 | + event.dispatch("outside"); |
| 65 | + expect(fn).toHaveBeenCalledTimes(1); |
| 66 | + expect(fn).toHaveBeenCalledWith("inside"); |
| 67 | + }); |
| 68 | + |
| 69 | + it("subscriber errors do not prevent other subscribers from running", () => { |
| 70 | + const event = createEvent<string>(); |
| 71 | + const fn1 = vi.fn(() => { |
| 72 | + throw new Error("oops"); |
| 73 | + }); |
| 74 | + const fn2 = vi.fn(); |
| 75 | + event.subscribe(fn1); |
| 76 | + event.subscribe(fn2); |
| 77 | + event.dispatch("test"); |
| 78 | + expect(fn1).toHaveBeenCalled(); |
| 79 | + expect(fn2).toHaveBeenCalled(); |
45 | 80 | }); |
46 | 81 | }); |
0 commit comments