ivue 1.5.8 → 2.0.0

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.
@@ -0,0 +1,182 @@
1
+ import { reactive, ref } from 'vue';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { Reactive } from '../Reactive';
4
+ import { Kernel } from '../kernel';
5
+
6
+ describe('Reactive adversarial boundaries', () => {
7
+ it('richer cleanup composes as an ordinary method calling $stopEffects', () => {
8
+ const observed: number[] = [];
9
+ let closed = 0;
10
+
11
+ class $Store {
12
+ get count() {
13
+ return ref(0);
14
+ }
15
+
16
+ // the composition pattern: no reserved names, no auto-calls —
17
+ // the class's own dispose() does its work, then resets the engine
18
+ dispose() {
19
+ this.closeSocket();
20
+ (this as any).$stopEffects();
21
+ }
22
+
23
+ closeSocket() {
24
+ closed++;
25
+ }
26
+ }
27
+
28
+ const Store = Reactive($Store);
29
+ const store: any = new Store();
30
+ const originalCount = store.count;
31
+ store.$watch(
32
+ () => store.count.value,
33
+ (count: number) => observed.push(count),
34
+ { flush: 'sync' },
35
+ );
36
+
37
+ originalCount.value = 1;
38
+ expect(observed).toEqual([1]);
39
+
40
+ store.dispose();
41
+
42
+ expect(closed).toBe(1);
43
+ originalCount.value = 2;
44
+ expect(observed).toEqual([1]); // watcher dead
45
+ expect(store.count).not.toBe(originalCount); // cells reset
46
+ });
47
+
48
+ it('teardown clears only engine cache keys — consumer symbols survive', () => {
49
+ const consumerSymbol = Symbol('consumer-metadata');
50
+
51
+ class $Parent {
52
+ get inherited() {
53
+ return ref('parent');
54
+ }
55
+ }
56
+
57
+ class $Child extends $Parent {
58
+ get own() {
59
+ return ref('child');
60
+ }
61
+
62
+ grow() {
63
+ return this.own.value;
64
+ }
65
+ }
66
+
67
+ const Child = Reactive($Child);
68
+ const child: any = new Child();
69
+
70
+ // materialize cells on BOTH prototype layers + a bound method
71
+ const inheritedCell = child.inherited;
72
+ const ownCell = child.own;
73
+ const boundGrow = child.grow;
74
+ // a symbol the engine did NOT create — foreign metadata on the instance
75
+ child[consumerSymbol] = 'must survive';
76
+
77
+ child.$stopEffects();
78
+
79
+ // engine cells across the whole chain are gone: fresh identities
80
+ expect(child.inherited).not.toBe(inheritedCell);
81
+ expect(child.own).not.toBe(ownCell);
82
+ expect(child.grow).not.toBe(boundGrow);
83
+ // the consumer's symbol is untouched
84
+ expect(child[consumerSymbol]).toBe('must survive');
85
+ });
86
+
87
+ it('can allocate a fresh watcher scope after teardown', () => {
88
+ class $Store {
89
+ get count() {
90
+ return ref(0);
91
+ }
92
+ }
93
+
94
+ const Store = Reactive($Store);
95
+ const store: any = new Store();
96
+ const firstObserved = vi.fn();
97
+ store.$watch(() => store.count.value, firstObserved, { flush: 'sync' });
98
+ store.count.value = 1;
99
+ store.$stopEffects();
100
+
101
+ const secondObserved = vi.fn();
102
+ store.$watch(() => store.count.value, secondObserved, { flush: 'sync' });
103
+ store.count.value = 2;
104
+
105
+ expect(firstObserved).toHaveBeenCalledTimes(1);
106
+ expect(secondObserved).toHaveBeenCalledTimes(1);
107
+ });
108
+
109
+ it('does not poison a lazy ref cache when its factory throws once', () => {
110
+ let attempts = 0;
111
+
112
+ class $Store {
113
+ get state() {
114
+ attempts++;
115
+ if (attempts === 1) throw new Error('dependency is not ready');
116
+ return ref(7);
117
+ }
118
+ }
119
+
120
+ const Store = Reactive($Store);
121
+ const store = new Store();
122
+
123
+ expect(() => store.state).toThrow('dependency is not ready');
124
+ const recovered = store.state;
125
+ expect(recovered.value).toBe(7);
126
+ expect(store.state).toBe(recovered);
127
+ expect(attempts).toBe(2);
128
+ });
129
+
130
+ it('caches an undefined $-singleton result instead of rerunning it', () => {
131
+ const factory = vi.fn(() => undefined);
132
+
133
+ class $Store {
134
+ get $optionalService() {
135
+ return factory();
136
+ }
137
+ }
138
+
139
+ const Store = Reactive($Store);
140
+ const store = new Store();
141
+
142
+ expect(store.$optionalService).toBeUndefined();
143
+ expect(store.$optionalService).toBeUndefined();
144
+ expect(factory).toHaveBeenCalledTimes(1);
145
+ });
146
+
147
+ it('tears down the raw instance when invoked through a Vue proxy', () => {
148
+ const observed = vi.fn();
149
+
150
+ class $Store {
151
+ get count() {
152
+ return ref(0);
153
+ }
154
+ }
155
+
156
+ const Store = Reactive($Store);
157
+ const rawStore: any = new Store();
158
+ const proxiedStore: any = reactive(rawStore);
159
+ const originalCount = rawStore.count;
160
+ proxiedStore.$watch(() => rawStore.count.value, observed, { flush: 'sync' });
161
+
162
+ originalCount.value = 1;
163
+ proxiedStore.$stopEffects();
164
+ originalCount.value = 2;
165
+
166
+ expect(observed).toHaveBeenCalledTimes(1);
167
+ expect(rawStore.count).not.toBe(originalCount);
168
+ });
169
+ });
170
+
171
+ describe('Kernel adversarial values', () => {
172
+ it('preserves stored falsy values instead of taking the fallback', () => {
173
+ const kernel = new Kernel();
174
+ kernel.set('zero', 0);
175
+ kernel.set('false', false);
176
+ kernel.set('empty', '');
177
+
178
+ expect(kernel.get('zero', 1)).toBe(0);
179
+ expect(kernel.get('false', true)).toBe(false);
180
+ expect(kernel.get('empty', 'fallback')).toBe('');
181
+ });
182
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Coverage completion for the package entry and Kernel container.
3
+ */
4
+ import { describe, expect, it } from 'vitest';
5
+ import * as packageEntry from '../index';
6
+ import { Kernel, kernel } from '../kernel';
7
+
8
+ describe('package entry (index.ts)', () => {
9
+ it('re-exports the engine surface', () => {
10
+ expect(typeof packageEntry.Reactive).toBe('function');
11
+ });
12
+ });
13
+
14
+ describe('Kernel', () => {
15
+ it('sets, gets, falls back, clears', () => {
16
+ const container = new Kernel();
17
+ container.set('answer', 42);
18
+ expect(container.get('answer', 0)).toBe(42);
19
+ expect(container.get('missing', 'fallback')).toBe('fallback');
20
+ container.clear();
21
+ expect(container.get('answer', 0)).toBe(0);
22
+ expect(kernel).toBeInstanceOf(Kernel);
23
+ });
24
+ });