rask-ui 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/dist/vdom/AbstractVNode.d.ts +24 -2
  2. package/dist/vdom/AbstractVNode.d.ts.map +1 -1
  3. package/dist/vdom/AbstractVNode.js +153 -13
  4. package/dist/vdom/ComponentVNode.d.ts +2 -2
  5. package/dist/vdom/ComponentVNode.d.ts.map +1 -1
  6. package/dist/vdom/ComponentVNode.js +11 -13
  7. package/dist/vdom/ElementVNode.d.ts +2 -8
  8. package/dist/vdom/ElementVNode.d.ts.map +1 -1
  9. package/dist/vdom/ElementVNode.js +15 -32
  10. package/dist/vdom/FragmentVNode.d.ts +2 -2
  11. package/dist/vdom/FragmentVNode.d.ts.map +1 -1
  12. package/dist/vdom/FragmentVNode.js +12 -3
  13. package/dist/vdom/RootVNode.d.ts +2 -2
  14. package/dist/vdom/RootVNode.d.ts.map +1 -1
  15. package/dist/vdom/RootVNode.js +7 -5
  16. package/package.json +1 -1
  17. package/dist/component.d.ts +0 -38
  18. package/dist/component.d.ts.map +0 -1
  19. package/dist/component.js +0 -130
  20. package/dist/context.d.ts +0 -5
  21. package/dist/context.d.ts.map +0 -1
  22. package/dist/context.js +0 -29
  23. package/dist/createAsync.test.d.ts +0 -2
  24. package/dist/createAsync.test.d.ts.map +0 -1
  25. package/dist/createAsync.test.js +0 -110
  26. package/dist/createAsyncState.d.ts +0 -16
  27. package/dist/createAsyncState.d.ts.map +0 -1
  28. package/dist/createAsyncState.js +0 -24
  29. package/dist/createContext.test.d.ts +0 -2
  30. package/dist/createContext.test.d.ts.map +0 -1
  31. package/dist/createContext.test.js +0 -136
  32. package/dist/createMutation.test.d.ts +0 -2
  33. package/dist/createMutation.test.d.ts.map +0 -1
  34. package/dist/createMutation.test.js +0 -168
  35. package/dist/createQuery.test.d.ts +0 -2
  36. package/dist/createQuery.test.d.ts.map +0 -1
  37. package/dist/createQuery.test.js +0 -156
  38. package/dist/createRef.test.d.ts +0 -2
  39. package/dist/createRef.test.d.ts.map +0 -1
  40. package/dist/createRef.test.js +0 -80
  41. package/dist/createState.test.d.ts +0 -2
  42. package/dist/createState.test.d.ts.map +0 -1
  43. package/dist/createState.test.js +0 -111
  44. package/dist/createView.test.d.ts +0 -2
  45. package/dist/createView.test.d.ts.map +0 -1
  46. package/dist/createView.test.js +0 -203
  47. package/dist/error.test.d.ts +0 -2
  48. package/dist/error.test.d.ts.map +0 -1
  49. package/dist/error.test.js +0 -144
  50. package/dist/integration.test.d.ts +0 -2
  51. package/dist/integration.test.d.ts.map +0 -1
  52. package/dist/integration.test.js +0 -155
  53. package/dist/jsx.d.ts.map +0 -1
  54. package/dist/jsx.js +0 -42
  55. package/dist/observation.test.d.ts +0 -2
  56. package/dist/observation.test.d.ts.map +0 -1
  57. package/dist/observation.test.js +0 -113
  58. package/dist/render-test.d.ts +0 -2
  59. package/dist/render-test.d.ts.map +0 -1
  60. package/dist/render-test.js +0 -21
  61. package/dist/render.d.ts +0 -7
  62. package/dist/render.d.ts.map +0 -1
  63. package/dist/render.js +0 -77
  64. package/dist/suspense.d.ts +0 -25
  65. package/dist/suspense.d.ts.map +0 -1
  66. package/dist/suspense.js +0 -97
  67. package/dist/tests/class.test.d.ts +0 -2
  68. package/dist/tests/class.test.d.ts.map +0 -1
  69. package/dist/tests/class.test.js +0 -185
  70. package/dist/tests/complex-rendering.test.d.ts +0 -2
  71. package/dist/tests/complex-rendering.test.d.ts.map +0 -1
  72. package/dist/tests/complex-rendering.test.js +0 -400
  73. package/dist/tests/component.cleanup.test.d.ts +0 -2
  74. package/dist/tests/component.cleanup.test.d.ts.map +0 -1
  75. package/dist/tests/component.cleanup.test.js +0 -325
  76. package/dist/tests/component.counter.test.d.ts +0 -2
  77. package/dist/tests/component.counter.test.d.ts.map +0 -1
  78. package/dist/tests/component.counter.test.js +0 -124
  79. package/dist/tests/component.interaction.test.d.ts +0 -2
  80. package/dist/tests/component.interaction.test.d.ts.map +0 -1
  81. package/dist/tests/component.interaction.test.js +0 -73
  82. package/dist/tests/component.props.test.d.ts +0 -2
  83. package/dist/tests/component.props.test.d.ts.map +0 -1
  84. package/dist/tests/component.props.test.js +0 -334
  85. package/dist/tests/component.return-types.test.d.ts +0 -2
  86. package/dist/tests/component.return-types.test.d.ts.map +0 -1
  87. package/dist/tests/component.return-types.test.js +0 -357
  88. package/dist/tests/component.state.test.d.ts +0 -2
  89. package/dist/tests/component.state.test.d.ts.map +0 -1
  90. package/dist/tests/component.state.test.js +0 -135
  91. package/dist/tests/component.test.d.ts +0 -2
  92. package/dist/tests/component.test.d.ts.map +0 -1
  93. package/dist/tests/component.test.js +0 -63
  94. package/dist/tests/createAsync.test.d.ts +0 -2
  95. package/dist/tests/createAsync.test.d.ts.map +0 -1
  96. package/dist/tests/createAsync.test.js +0 -110
  97. package/dist/tests/createContext.test.d.ts +0 -2
  98. package/dist/tests/createContext.test.d.ts.map +0 -1
  99. package/dist/tests/createContext.test.js +0 -141
  100. package/dist/tests/createMutation.test.d.ts +0 -2
  101. package/dist/tests/createMutation.test.d.ts.map +0 -1
  102. package/dist/tests/createMutation.test.js +0 -168
  103. package/dist/tests/createQuery.test.d.ts +0 -2
  104. package/dist/tests/createQuery.test.d.ts.map +0 -1
  105. package/dist/tests/createQuery.test.js +0 -156
  106. package/dist/tests/createRef.test.d.ts +0 -2
  107. package/dist/tests/createRef.test.d.ts.map +0 -1
  108. package/dist/tests/createRef.test.js +0 -84
  109. package/dist/tests/createState.test.d.ts +0 -2
  110. package/dist/tests/createState.test.d.ts.map +0 -1
  111. package/dist/tests/createState.test.js +0 -103
  112. package/dist/tests/createView.test.d.ts +0 -2
  113. package/dist/tests/createView.test.d.ts.map +0 -1
  114. package/dist/tests/createView.test.js +0 -203
  115. package/dist/tests/edge-cases.test.d.ts +0 -2
  116. package/dist/tests/edge-cases.test.d.ts.map +0 -1
  117. package/dist/tests/edge-cases.test.js +0 -637
  118. package/dist/tests/error-no-boundary.test.d.ts +0 -2
  119. package/dist/tests/error-no-boundary.test.d.ts.map +0 -1
  120. package/dist/tests/error-no-boundary.test.js +0 -174
  121. package/dist/tests/error.test.d.ts +0 -2
  122. package/dist/tests/error.test.d.ts.map +0 -1
  123. package/dist/tests/error.test.js +0 -199
  124. package/dist/tests/fragment.test.d.ts +0 -2
  125. package/dist/tests/fragment.test.d.ts.map +0 -1
  126. package/dist/tests/fragment.test.js +0 -618
  127. package/dist/tests/integration.test.d.ts +0 -2
  128. package/dist/tests/integration.test.d.ts.map +0 -1
  129. package/dist/tests/integration.test.js +0 -192
  130. package/dist/tests/keys.test.d.ts +0 -2
  131. package/dist/tests/keys.test.d.ts.map +0 -1
  132. package/dist/tests/keys.test.js +0 -293
  133. package/dist/tests/mount.test.d.ts +0 -2
  134. package/dist/tests/mount.test.d.ts.map +0 -1
  135. package/dist/tests/mount.test.js +0 -91
  136. package/dist/tests/observation.test.d.ts +0 -2
  137. package/dist/tests/observation.test.d.ts.map +0 -1
  138. package/dist/tests/observation.test.js +0 -113
  139. package/dist/tests/patch.test.d.ts +0 -2
  140. package/dist/tests/patch.test.d.ts.map +0 -1
  141. package/dist/tests/patch.test.js +0 -498
  142. package/dist/tests/patchChildren.test.d.ts +0 -2
  143. package/dist/tests/patchChildren.test.d.ts.map +0 -1
  144. package/dist/tests/patchChildren.test.js +0 -387
  145. package/dist/tests/primitives.test.d.ts +0 -2
  146. package/dist/tests/primitives.test.d.ts.map +0 -1
  147. package/dist/tests/primitives.test.js +0 -132
  148. package/dist/vdom/class.test.d.ts +0 -2
  149. package/dist/vdom/class.test.d.ts.map +0 -1
  150. package/dist/vdom/class.test.js +0 -143
  151. package/dist/vdom/complex-rendering.test.d.ts +0 -2
  152. package/dist/vdom/complex-rendering.test.d.ts.map +0 -1
  153. package/dist/vdom/complex-rendering.test.js +0 -400
  154. package/dist/vdom/component.cleanup.test.d.ts +0 -2
  155. package/dist/vdom/component.cleanup.test.d.ts.map +0 -1
  156. package/dist/vdom/component.cleanup.test.js +0 -323
  157. package/dist/vdom/component.counter.test.d.ts +0 -2
  158. package/dist/vdom/component.counter.test.d.ts.map +0 -1
  159. package/dist/vdom/component.counter.test.js +0 -124
  160. package/dist/vdom/component.interaction.test.d.ts +0 -2
  161. package/dist/vdom/component.interaction.test.d.ts.map +0 -1
  162. package/dist/vdom/component.interaction.test.js +0 -73
  163. package/dist/vdom/component.props.test.d.ts +0 -2
  164. package/dist/vdom/component.props.test.d.ts.map +0 -1
  165. package/dist/vdom/component.props.test.js +0 -88
  166. package/dist/vdom/component.return-types.test.d.ts +0 -2
  167. package/dist/vdom/component.return-types.test.d.ts.map +0 -1
  168. package/dist/vdom/component.return-types.test.js +0 -357
  169. package/dist/vdom/component.state.test.d.ts +0 -2
  170. package/dist/vdom/component.state.test.d.ts.map +0 -1
  171. package/dist/vdom/component.state.test.js +0 -129
  172. package/dist/vdom/component.test.d.ts +0 -2
  173. package/dist/vdom/component.test.d.ts.map +0 -1
  174. package/dist/vdom/component.test.js +0 -63
  175. package/dist/vdom/edge-cases.test.d.ts +0 -2
  176. package/dist/vdom/edge-cases.test.d.ts.map +0 -1
  177. package/dist/vdom/edge-cases.test.js +0 -637
  178. package/dist/vdom/fragment.test.d.ts +0 -2
  179. package/dist/vdom/fragment.test.d.ts.map +0 -1
  180. package/dist/vdom/fragment.test.js +0 -618
  181. package/dist/vdom/keys.test.d.ts +0 -2
  182. package/dist/vdom/keys.test.d.ts.map +0 -1
  183. package/dist/vdom/keys.test.js +0 -293
  184. package/dist/vdom/mount.test.d.ts +0 -2
  185. package/dist/vdom/mount.test.d.ts.map +0 -1
  186. package/dist/vdom/mount.test.js +0 -91
  187. package/dist/vdom/patch.test.d.ts +0 -2
  188. package/dist/vdom/patch.test.d.ts.map +0 -1
  189. package/dist/vdom/patch.test.js +0 -498
  190. package/dist/vdom/patchChildren.test.d.ts +0 -2
  191. package/dist/vdom/patchChildren.test.d.ts.map +0 -1
  192. package/dist/vdom/patchChildren.test.js +0 -392
  193. package/dist/vdom/primitives.test.d.ts +0 -2
  194. package/dist/vdom/primitives.test.d.ts.map +0 -1
  195. package/dist/vdom/primitives.test.js +0 -132
@@ -1,156 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { createQuery } from './createQuery';
3
- describe('createQuery', () => {
4
- it('should start in pending state and fetch immediately', async () => {
5
- const fetcher = vi.fn(() => Promise.resolve('data'));
6
- const query = createQuery(fetcher);
7
- expect(query.isPending).toBe(true);
8
- expect(query.data).toBeNull();
9
- expect(query.error).toBeNull();
10
- expect(fetcher).toHaveBeenCalledTimes(1);
11
- await new Promise((resolve) => setTimeout(resolve, 10));
12
- expect(query.isPending).toBe(false);
13
- expect(query.data).toBe('data');
14
- });
15
- it('should resolve to data state on success', async () => {
16
- const fetcher = () => Promise.resolve({ id: 1, name: 'Test' });
17
- const query = createQuery(fetcher);
18
- await new Promise((resolve) => setTimeout(resolve, 10));
19
- expect(query.isPending).toBe(false);
20
- expect(query.data).toEqual({ id: 1, name: 'Test' });
21
- expect(query.error).toBeNull();
22
- });
23
- it('should resolve to error state on failure', async () => {
24
- const fetcher = () => Promise.reject(new Error('Network error'));
25
- const query = createQuery(fetcher);
26
- await new Promise((resolve) => setTimeout(resolve, 10));
27
- expect(query.isPending).toBe(false);
28
- expect(query.data).toBeNull();
29
- expect(query.error).toContain('Network error');
30
- });
31
- it('should allow manual refetch', async () => {
32
- const fetcher = vi.fn(() => Promise.resolve('data'));
33
- const query = createQuery(fetcher);
34
- await new Promise((resolve) => setTimeout(resolve, 10));
35
- expect(fetcher).toHaveBeenCalledTimes(1);
36
- query.fetch();
37
- expect(query.isPending).toBe(true);
38
- await new Promise((resolve) => setTimeout(resolve, 10));
39
- expect(fetcher).toHaveBeenCalledTimes(2);
40
- expect(query.isPending).toBe(false);
41
- });
42
- it('should retain old data during refetch by default', async () => {
43
- const fetcher = vi
44
- .fn()
45
- .mockResolvedValueOnce('data1')
46
- .mockResolvedValueOnce('data2');
47
- const query = createQuery(fetcher);
48
- await new Promise((resolve) => setTimeout(resolve, 10));
49
- expect(query.data).toBe('data1');
50
- query.fetch();
51
- expect(query.isPending).toBe(true);
52
- expect(query.data).toBe('data1'); // Old data retained
53
- await new Promise((resolve) => setTimeout(resolve, 10));
54
- expect(query.data).toBe('data2');
55
- });
56
- it('should clear old data when force refetch is used', async () => {
57
- const fetcher = vi
58
- .fn()
59
- .mockResolvedValueOnce('data1')
60
- .mockResolvedValueOnce('data2');
61
- const query = createQuery(fetcher);
62
- await new Promise((resolve) => setTimeout(resolve, 10));
63
- expect(query.data).toBe('data1');
64
- query.fetch(true); // Force refresh
65
- expect(query.isPending).toBe(true);
66
- expect(query.data).toBeNull(); // Old data cleared
67
- await new Promise((resolve) => setTimeout(resolve, 10));
68
- expect(query.data).toBe('data2');
69
- });
70
- it('should cancel previous request on new fetch', async () => {
71
- let resolveFirst;
72
- let resolveSecond;
73
- const firstPromise = new Promise((resolve) => {
74
- resolveFirst = resolve;
75
- });
76
- const secondPromise = new Promise((resolve) => {
77
- resolveSecond = resolve;
78
- });
79
- const fetcher = vi
80
- .fn()
81
- .mockReturnValueOnce(firstPromise)
82
- .mockReturnValueOnce(secondPromise);
83
- const query = createQuery(fetcher);
84
- expect(query.isPending).toBe(true);
85
- // Trigger second fetch before first completes
86
- query.fetch();
87
- // Resolve first (should be ignored due to cancellation)
88
- resolveFirst('first');
89
- await new Promise((resolve) => setTimeout(resolve, 10));
90
- expect(query.data).toBeNull(); // First result ignored
91
- // Resolve second
92
- resolveSecond('second');
93
- await new Promise((resolve) => setTimeout(resolve, 10));
94
- expect(query.data).toBe('second');
95
- });
96
- it('should handle rapid successive fetches', async () => {
97
- let counter = 0;
98
- const fetcher = vi.fn(() => Promise.resolve(`data-${++counter}`));
99
- const query = createQuery(fetcher);
100
- await new Promise((resolve) => setTimeout(resolve, 10));
101
- // Rapid fetches
102
- query.fetch();
103
- query.fetch();
104
- query.fetch();
105
- await new Promise((resolve) => setTimeout(resolve, 20));
106
- // Only the last fetch should matter
107
- expect(fetcher).toHaveBeenCalledTimes(4); // Initial + 3 fetches
108
- expect(query.data).toBe('data-4');
109
- });
110
- it('should cancel on error and allow refetch', async () => {
111
- const fetcher = vi
112
- .fn()
113
- .mockRejectedValueOnce(new Error('First error'))
114
- .mockResolvedValueOnce('success');
115
- const query = createQuery(fetcher);
116
- await new Promise((resolve) => setTimeout(resolve, 10));
117
- expect(query.error).toContain('First error');
118
- expect(query.data).toBeNull();
119
- query.fetch();
120
- await new Promise((resolve) => setTimeout(resolve, 10));
121
- expect(query.error).toBeNull();
122
- expect(query.data).toBe('success');
123
- });
124
- it('should handle AbortController cancellation correctly', async () => {
125
- const abortedPromise = new Promise((_, reject) => {
126
- const error = new Error('Aborted');
127
- error.name = 'AbortError';
128
- setTimeout(() => reject(error), 5);
129
- });
130
- const successPromise = Promise.resolve('success');
131
- const fetcher = vi
132
- .fn()
133
- .mockReturnValueOnce(abortedPromise)
134
- .mockReturnValueOnce(successPromise);
135
- const query = createQuery(fetcher);
136
- // Immediately trigger second fetch to abort first
137
- query.fetch();
138
- await new Promise((resolve) => setTimeout(resolve, 20));
139
- expect(query.data).toBe('success');
140
- expect(query.error).toBeNull();
141
- });
142
- it('should expose reactive getters', async () => {
143
- const fetcher = () => Promise.resolve('data');
144
- const query = createQuery(fetcher);
145
- // Access getters
146
- const pending1 = query.isPending;
147
- const data1 = query.data;
148
- const error1 = query.error;
149
- expect(pending1).toBe(true);
150
- expect(data1).toBeNull();
151
- expect(error1).toBeNull();
152
- await new Promise((resolve) => setTimeout(resolve, 10));
153
- expect(query.isPending).toBe(false);
154
- expect(query.data).toBe('data');
155
- });
156
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=createRef.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createRef.test.d.ts","sourceRoot":"","sources":["../src/createRef.test.tsx"],"names":[],"mappings":""}
@@ -1,80 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "./jsx-runtime";
2
- import { describe, it, expect } from "vitest";
3
- import { createRef } from "./createRef";
4
- import { render } from "./vdom";
5
- describe("createRef", () => {
6
- it("should create a ref with null initial value", () => {
7
- const ref = createRef();
8
- expect(ref.current).toBeNull();
9
- });
10
- it("should be callable as a function", () => {
11
- const ref = createRef();
12
- expect(typeof ref).toBe("function");
13
- });
14
- it("should update current when called with a node", () => {
15
- const ref = createRef();
16
- const element = document.createElement("div");
17
- ref(element);
18
- expect(ref.current).toBe(element);
19
- });
20
- it("should update current when called with null", () => {
21
- const ref = createRef();
22
- const element = document.createElement("div");
23
- ref(element);
24
- expect(ref.current).toBe(element);
25
- ref(null);
26
- expect(ref.current).toBeNull();
27
- });
28
- it("should work with JSX ref attribute", async () => {
29
- const ref = createRef();
30
- function TestComponent() {
31
- return () => _jsx("div", { ref: ref, children: "Hello" });
32
- }
33
- const container = document.createElement("div");
34
- document.body.appendChild(container);
35
- const vnode = render(_jsx(TestComponent, {}), container);
36
- await new Promise((resolve) => setTimeout(resolve, 0));
37
- expect(ref.current).not.toBeNull();
38
- expect(ref.current?.tagName).toBe("DIV");
39
- expect(ref.current?.textContent).toBe("Hello");
40
- document.body.removeChild(vnode.elm);
41
- });
42
- it("should handle multiple ref updates", () => {
43
- const ref = createRef();
44
- const div = document.createElement("div");
45
- const span = document.createElement("span");
46
- ref(div);
47
- expect(ref.current).toBe(div);
48
- ref(span);
49
- expect(ref.current).toBe(span);
50
- ref(null);
51
- expect(ref.current).toBeNull();
52
- });
53
- it("should work with different element types", async () => {
54
- const inputRef = createRef();
55
- const buttonRef = createRef();
56
- function TestComponent() {
57
- return () => (_jsxs("div", { children: [_jsx("input", { ref: inputRef, type: "text" }), _jsx("button", { ref: buttonRef, children: "Click" })] }));
58
- }
59
- const container = document.createElement("div");
60
- document.body.appendChild(container);
61
- const vnode = render(_jsx(TestComponent, {}), container);
62
- await new Promise((resolve) => setTimeout(resolve, 0));
63
- expect(inputRef.current?.tagName).toBe("INPUT");
64
- expect(buttonRef.current?.tagName).toBe("BUTTON");
65
- document.body.removeChild(vnode.elm);
66
- });
67
- it("should allow accessing DOM properties", async () => {
68
- const ref = createRef();
69
- function TestComponent() {
70
- return () => _jsx("input", { ref: ref, type: "text", value: "test" });
71
- }
72
- const container = document.createElement("div");
73
- document.body.appendChild(container);
74
- const vnode = render(_jsx(TestComponent, {}), container);
75
- await new Promise((resolve) => setTimeout(resolve, 0));
76
- expect(ref.current?.value).toBe("test");
77
- expect(ref.current?.type).toBe("text");
78
- document.body.removeChild(vnode.elm);
79
- });
80
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=createState.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createState.test.d.ts","sourceRoot":"","sources":["../src/createState.test.ts"],"names":[],"mappings":""}
@@ -1,111 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { createState } from './createState';
3
- import { Observer } from './observation';
4
- describe('createState', () => {
5
- it('should create a reactive proxy from an object', () => {
6
- const state = createState({ count: 0 });
7
- expect(state.count).toBe(0);
8
- });
9
- it('should allow mutations', () => {
10
- const state = createState({ count: 0 });
11
- state.count = 5;
12
- expect(state.count).toBe(5);
13
- });
14
- it('should return the same proxy for the same object', () => {
15
- const obj = { count: 0 };
16
- const proxy1 = createState(obj);
17
- const proxy2 = createState(obj);
18
- expect(proxy1).toBe(proxy2);
19
- });
20
- it('should create nested proxies for nested objects', () => {
21
- const state = createState({ user: { name: 'Alice', age: 30 } });
22
- state.user.name = 'Bob';
23
- expect(state.user.name).toBe('Bob');
24
- });
25
- it('should handle arrays reactively', () => {
26
- const state = createState({ items: [1, 2, 3] });
27
- state.items.push(4);
28
- expect(state.items).toEqual([1, 2, 3, 4]);
29
- });
30
- it('should track property access in observers', () => {
31
- const state = createState({ count: 0 });
32
- let renderCount = 0;
33
- const observer = new Observer(() => {
34
- renderCount++;
35
- });
36
- const dispose = observer.observe();
37
- state.count; // Access property to track it
38
- dispose();
39
- expect(renderCount).toBe(0);
40
- // Mutate after observation setup
41
- const dispose2 = observer.observe();
42
- const value = state.count; // Track
43
- dispose2(); // Stop observing, subscriptions are now active
44
- state.count = 1;
45
- // Wait for microtask
46
- return new Promise((resolve) => {
47
- queueMicrotask(() => {
48
- expect(renderCount).toBeGreaterThan(0);
49
- resolve(undefined);
50
- });
51
- });
52
- });
53
- it('should handle property deletion', () => {
54
- const state = createState({ count: 0, temp: 'value' });
55
- delete state.temp;
56
- expect(state.temp).toBeUndefined();
57
- expect('temp' in state).toBe(false);
58
- });
59
- it('should not create proxies for functions', () => {
60
- const fn = () => 'hello';
61
- const state = createState({ method: fn });
62
- expect(state.method).toBe(fn);
63
- expect(state.method()).toBe('hello');
64
- });
65
- it('should handle symbol properties', () => {
66
- const sym = Symbol('test');
67
- const state = createState({ [sym]: 'value' });
68
- expect(state[sym]).toBe('value');
69
- });
70
- it('should notify observers only on actual changes', () => {
71
- const state = createState({ count: 0 });
72
- let notifyCount = 0;
73
- const observer = new Observer(() => {
74
- notifyCount++;
75
- });
76
- const dispose = observer.observe();
77
- state.count; // Track
78
- dispose();
79
- state.count = 0; // Same value - should still notify per current implementation
80
- state.count = 0;
81
- return new Promise((resolve) => {
82
- queueMicrotask(() => {
83
- // The implementation notifies even for same value, except for optimization cases
84
- observer.dispose();
85
- resolve(undefined);
86
- });
87
- });
88
- });
89
- it('should handle deeply nested objects', () => {
90
- const state = createState({
91
- level1: {
92
- level2: {
93
- level3: {
94
- value: 'deep',
95
- },
96
- },
97
- },
98
- });
99
- state.level1.level2.level3.value = 'modified';
100
- expect(state.level1.level2.level3.value).toBe('modified');
101
- });
102
- it('should handle array mutations correctly', () => {
103
- const state = createState({ items: [1, 2, 3] });
104
- state.items.pop();
105
- expect(state.items).toEqual([1, 2]);
106
- state.items.unshift(0);
107
- expect(state.items).toEqual([0, 1, 2]);
108
- state.items.splice(1, 1, 99);
109
- expect(state.items).toEqual([0, 99, 2]);
110
- });
111
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=createView.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createView.test.d.ts","sourceRoot":"","sources":["../src/createView.test.ts"],"names":[],"mappings":""}
@@ -1,203 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { createView } from './createView';
3
- import { createState } from './createState';
4
- import { Observer } from './observation';
5
- describe('createView', () => {
6
- it('should merge two plain objects', () => {
7
- const a = { x: 1, y: 2 };
8
- const b = { z: 3 };
9
- const view = createView(a, b);
10
- expect(view.x).toBe(1);
11
- expect(view.y).toBe(2);
12
- expect(view.z).toBe(3);
13
- });
14
- it('should allow later arguments to override earlier ones', () => {
15
- const a = { x: 1, y: 2 };
16
- const b = { y: 3, z: 4 };
17
- const view = createView(a, b);
18
- expect(view.x).toBe(1);
19
- expect(view.y).toBe(3); // b.y overrides a.y
20
- expect(view.z).toBe(4);
21
- });
22
- it('should maintain reactivity with reactive objects', async () => {
23
- const state = createState({ count: 0 });
24
- const view = createView(state);
25
- let renderCount = 0;
26
- let lastValue = 0;
27
- const observer = new Observer(() => {
28
- renderCount++;
29
- });
30
- const dispose = observer.observe();
31
- lastValue = view.count; // Track the property
32
- dispose();
33
- expect(renderCount).toBe(0);
34
- state.count = 5;
35
- // Wait for microtask to process notification
36
- await new Promise((resolve) => {
37
- queueMicrotask(() => {
38
- expect(renderCount).toBe(1);
39
- lastValue = view.count;
40
- expect(lastValue).toBe(5);
41
- resolve(undefined);
42
- });
43
- });
44
- });
45
- it('should merge reactive and plain objects while maintaining reactivity', () => {
46
- const state = createState({ count: 0 });
47
- const helpers = {
48
- increment() {
49
- state.count++;
50
- },
51
- decrement() {
52
- state.count--;
53
- },
54
- };
55
- const view = createView(state, helpers);
56
- expect(view.count).toBe(0);
57
- expect(typeof view.increment).toBe('function');
58
- expect(typeof view.decrement).toBe('function');
59
- view.increment();
60
- expect(view.count).toBe(1);
61
- view.decrement();
62
- expect(view.count).toBe(0);
63
- });
64
- it('should merge multiple reactive objects', () => {
65
- const state1 = createState({ count: 0 });
66
- const state2 = createState({ name: 'Alice' });
67
- const state3 = createState({ age: 25 });
68
- const view = createView(state1, state2, state3);
69
- expect(view.count).toBe(0);
70
- expect(view.name).toBe('Alice');
71
- expect(view.age).toBe(25);
72
- state1.count = 10;
73
- state2.name = 'Bob';
74
- state3.age = 30;
75
- expect(view.count).toBe(10);
76
- expect(view.name).toBe('Bob');
77
- expect(view.age).toBe(30);
78
- });
79
- it('should reflect changes in source objects', () => {
80
- const source = { x: 1 };
81
- const view = createView(source);
82
- expect(view.x).toBe(1);
83
- source.x = 2;
84
- expect(view.x).toBe(2);
85
- });
86
- it('should handle property override order correctly', () => {
87
- const a = { x: 1, y: 2, z: 3 };
88
- const b = { y: 20 };
89
- const c = { z: 30 };
90
- const view = createView(a, b, c);
91
- expect(view.x).toBe(1); // From a
92
- expect(view.y).toBe(20); // From b (overrides a)
93
- expect(view.z).toBe(30); // From c (overrides a)
94
- });
95
- it('should only include enumerable properties', () => {
96
- const obj = { x: 1 };
97
- Object.defineProperty(obj, 'hidden', {
98
- value: 42,
99
- enumerable: false,
100
- });
101
- const view = createView(obj);
102
- expect(view.x).toBe(1);
103
- expect(view.hidden).toBeUndefined();
104
- });
105
- it('should handle symbol keys', () => {
106
- const sym = Symbol('test');
107
- const obj = { x: 1, [sym]: 'symbol value' };
108
- const view = createView(obj);
109
- expect(view.x).toBe(1);
110
- expect(view[sym]).toBe('symbol value');
111
- });
112
- it('should track dependencies for each property independently', async () => {
113
- const state = createState({ count: 0, name: 'Alice' });
114
- const view = createView(state);
115
- let countRenderCount = 0;
116
- let nameRenderCount = 0;
117
- // Observer that only accesses count
118
- const countObserver = new Observer(() => {
119
- countRenderCount++;
120
- });
121
- const dispose1 = countObserver.observe();
122
- view.count; // Track count
123
- dispose1();
124
- expect(countRenderCount).toBe(0);
125
- // Change count - should trigger
126
- state.count = 1;
127
- await new Promise((resolve) => {
128
- queueMicrotask(() => {
129
- expect(countRenderCount).toBe(1);
130
- resolve(undefined);
131
- });
132
- });
133
- // Change name - should NOT trigger (not tracked)
134
- state.name = 'Bob';
135
- await new Promise((resolve) => {
136
- queueMicrotask(() => {
137
- expect(countRenderCount).toBe(1); // Still 1
138
- resolve(undefined);
139
- });
140
- });
141
- // Now track name with a different observer
142
- const nameObserver = new Observer(() => {
143
- nameRenderCount++;
144
- });
145
- const dispose2 = nameObserver.observe();
146
- view.name; // Track name
147
- dispose2();
148
- expect(nameRenderCount).toBe(0);
149
- // Change name - should trigger name observer
150
- state.name = 'Charlie';
151
- await new Promise((resolve) => {
152
- queueMicrotask(() => {
153
- expect(nameRenderCount).toBe(1);
154
- resolve(undefined);
155
- });
156
- });
157
- });
158
- it('should return the same value type as source', () => {
159
- const obj = { nums: [1, 2, 3], nested: { x: 1 } };
160
- const view = createView(obj);
161
- expect(Array.isArray(view.nums)).toBe(true);
162
- expect(view.nums).toEqual([1, 2, 3]);
163
- expect(typeof view.nested).toBe('object');
164
- expect(view.nested.x).toBe(1);
165
- });
166
- it('should handle empty merge', () => {
167
- const view = createView({});
168
- expect(Object.keys(view).length).toBe(0);
169
- });
170
- it('should merge single object', () => {
171
- const obj = { x: 1, y: 2 };
172
- const view = createView(obj);
173
- expect(view.x).toBe(1);
174
- expect(view.y).toBe(2);
175
- });
176
- it('should maintain function context', () => {
177
- const state = createState({ count: 0 });
178
- const methods = {
179
- increment() {
180
- state.count++;
181
- },
182
- };
183
- const view = createView(state, methods);
184
- expect(view.count).toBe(0);
185
- view.increment();
186
- expect(view.count).toBe(1);
187
- expect(state.count).toBe(1);
188
- });
189
- it('should work with reactive state and computed-like patterns', () => {
190
- const state = createState({ firstName: 'John', lastName: 'Doe' });
191
- const computed = {
192
- get fullName() {
193
- return `${state.firstName} ${state.lastName}`;
194
- },
195
- };
196
- const view = createView(state, computed);
197
- expect(view.firstName).toBe('John');
198
- expect(view.lastName).toBe('Doe');
199
- expect(view.fullName).toBe('John Doe');
200
- state.firstName = 'Jane';
201
- expect(view.fullName).toBe('Jane Doe');
202
- });
203
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=error.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error.test.d.ts","sourceRoot":"","sources":["../src/error.test.tsx"],"names":[],"mappings":""}