signalium 0.2.8 → 0.3.1

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 (161) hide show
  1. package/.turbo/turbo-build.log +12 -0
  2. package/CHANGELOG.md +12 -0
  3. package/dist/cjs/config.d.ts +14 -5
  4. package/dist/cjs/config.d.ts.map +1 -1
  5. package/dist/cjs/config.js +23 -14
  6. package/dist/cjs/config.js.map +1 -1
  7. package/dist/cjs/debug.d.ts +3 -0
  8. package/dist/cjs/debug.d.ts.map +1 -0
  9. package/dist/cjs/debug.js +16 -0
  10. package/dist/cjs/debug.js.map +1 -0
  11. package/dist/cjs/hooks.d.ts +45 -0
  12. package/dist/cjs/hooks.d.ts.map +1 -0
  13. package/dist/cjs/hooks.js +263 -0
  14. package/dist/cjs/hooks.js.map +1 -0
  15. package/dist/cjs/index.d.ts +5 -3
  16. package/dist/cjs/index.d.ts.map +1 -1
  17. package/dist/cjs/index.js +21 -8
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/react/context.d.ts +4 -0
  20. package/dist/cjs/react/context.d.ts.map +1 -0
  21. package/dist/cjs/react/context.js +10 -0
  22. package/dist/cjs/react/context.js.map +1 -0
  23. package/dist/cjs/react/index.d.ts +5 -0
  24. package/dist/cjs/react/index.d.ts.map +1 -0
  25. package/dist/cjs/react/index.js +12 -0
  26. package/dist/cjs/react/index.js.map +1 -0
  27. package/dist/cjs/react/provider.d.ts +7 -0
  28. package/dist/cjs/react/provider.d.ts.map +1 -0
  29. package/dist/cjs/react/provider.js +13 -0
  30. package/dist/cjs/react/provider.js.map +1 -0
  31. package/dist/cjs/react/setup.d.ts +2 -0
  32. package/dist/cjs/react/setup.d.ts.map +1 -0
  33. package/dist/cjs/react/setup.js +13 -0
  34. package/dist/cjs/react/setup.js.map +1 -0
  35. package/dist/cjs/react/signal-value.d.ts +2 -0
  36. package/dist/cjs/react/signal-value.d.ts.map +1 -0
  37. package/dist/cjs/react/signal-value.js +35 -0
  38. package/dist/cjs/react/signal-value.js.map +1 -0
  39. package/dist/cjs/react/state.d.ts +3 -0
  40. package/dist/cjs/react/state.d.ts.map +1 -0
  41. package/dist/cjs/react/state.js +13 -0
  42. package/dist/cjs/react/state.js.map +1 -0
  43. package/dist/cjs/scheduling.d.ts +5 -0
  44. package/dist/cjs/scheduling.d.ts.map +1 -1
  45. package/dist/cjs/scheduling.js +59 -5
  46. package/dist/cjs/scheduling.js.map +1 -1
  47. package/dist/cjs/signals.d.ts +28 -68
  48. package/dist/cjs/signals.d.ts.map +1 -1
  49. package/dist/cjs/signals.js +223 -76
  50. package/dist/cjs/signals.js.map +1 -1
  51. package/dist/cjs/trace.d.ts +127 -0
  52. package/dist/cjs/trace.d.ts.map +1 -0
  53. package/dist/cjs/trace.js +319 -0
  54. package/dist/cjs/trace.js.map +1 -0
  55. package/dist/cjs/types.d.ts +66 -0
  56. package/dist/cjs/types.d.ts.map +1 -0
  57. package/dist/cjs/types.js +3 -0
  58. package/dist/cjs/types.js.map +1 -0
  59. package/dist/cjs/utils.d.ts +4 -0
  60. package/dist/cjs/utils.d.ts.map +1 -0
  61. package/dist/cjs/utils.js +80 -0
  62. package/dist/cjs/utils.js.map +1 -0
  63. package/dist/esm/config.d.ts +14 -5
  64. package/dist/esm/config.d.ts.map +1 -1
  65. package/dist/esm/config.js +19 -11
  66. package/dist/esm/config.js.map +1 -1
  67. package/dist/esm/debug.d.ts +3 -0
  68. package/dist/esm/debug.d.ts.map +1 -0
  69. package/dist/esm/debug.js +3 -0
  70. package/dist/esm/debug.js.map +1 -0
  71. package/dist/esm/hooks.d.ts +45 -0
  72. package/dist/esm/hooks.d.ts.map +1 -0
  73. package/dist/esm/hooks.js +246 -0
  74. package/dist/esm/hooks.js.map +1 -0
  75. package/dist/esm/index.d.ts +5 -3
  76. package/dist/esm/index.d.ts.map +1 -1
  77. package/dist/esm/index.js +4 -2
  78. package/dist/esm/index.js.map +1 -1
  79. package/dist/esm/react/context.d.ts +4 -0
  80. package/dist/esm/react/context.d.ts.map +1 -0
  81. package/dist/esm/react/context.js +6 -0
  82. package/dist/esm/react/context.js.map +1 -0
  83. package/dist/esm/react/index.d.ts +5 -0
  84. package/dist/esm/react/index.d.ts.map +1 -0
  85. package/dist/esm/react/index.js +5 -0
  86. package/dist/esm/react/index.js.map +1 -0
  87. package/dist/esm/react/provider.d.ts +7 -0
  88. package/dist/esm/react/provider.d.ts.map +1 -0
  89. package/dist/esm/react/provider.js +10 -0
  90. package/dist/esm/react/provider.js.map +1 -0
  91. package/dist/esm/react/setup.d.ts +2 -0
  92. package/dist/esm/react/setup.d.ts.map +1 -0
  93. package/dist/esm/react/setup.js +10 -0
  94. package/dist/esm/react/setup.js.map +1 -0
  95. package/dist/esm/react/signal-value.d.ts +2 -0
  96. package/dist/esm/react/signal-value.d.ts.map +1 -0
  97. package/dist/esm/react/signal-value.js +32 -0
  98. package/dist/esm/react/signal-value.js.map +1 -0
  99. package/dist/esm/react/state.d.ts +3 -0
  100. package/dist/esm/react/state.d.ts.map +1 -0
  101. package/dist/esm/react/state.js +10 -0
  102. package/dist/esm/react/state.js.map +1 -0
  103. package/dist/esm/scheduling.d.ts +5 -0
  104. package/dist/esm/scheduling.d.ts.map +1 -1
  105. package/dist/esm/scheduling.js +51 -1
  106. package/dist/esm/scheduling.js.map +1 -1
  107. package/dist/esm/signals.d.ts +28 -68
  108. package/dist/esm/signals.d.ts.map +1 -1
  109. package/dist/esm/signals.js +215 -72
  110. package/dist/esm/signals.js.map +1 -1
  111. package/dist/esm/trace.d.ts +127 -0
  112. package/dist/esm/trace.d.ts.map +1 -0
  113. package/dist/esm/trace.js +311 -0
  114. package/dist/esm/trace.js.map +1 -0
  115. package/dist/esm/types.d.ts +66 -0
  116. package/dist/esm/types.d.ts.map +1 -0
  117. package/dist/esm/types.js +2 -0
  118. package/dist/esm/types.js.map +1 -0
  119. package/dist/esm/utils.d.ts +4 -0
  120. package/dist/esm/utils.d.ts.map +1 -0
  121. package/dist/esm/utils.js +75 -0
  122. package/dist/esm/utils.js.map +1 -0
  123. package/package.json +43 -2
  124. package/src/__tests__/hooks/async-computed.test.ts +190 -0
  125. package/src/__tests__/hooks/async-task.test.ts +227 -0
  126. package/src/__tests__/hooks/computed.test.ts +126 -0
  127. package/src/__tests__/hooks/context.test.ts +527 -0
  128. package/src/__tests__/hooks/nesting.test.ts +303 -0
  129. package/src/__tests__/hooks/params-and-state.test.ts +168 -0
  130. package/src/__tests__/hooks/subscription.test.ts +97 -0
  131. package/src/__tests__/signals/async.test.ts +416 -0
  132. package/src/__tests__/signals/basic.test.ts +399 -0
  133. package/src/__tests__/signals/subscription.test.ts +632 -0
  134. package/src/__tests__/signals/watcher.test.ts +253 -0
  135. package/src/__tests__/utils/async.ts +6 -0
  136. package/src/__tests__/utils/builders.ts +22 -0
  137. package/src/__tests__/utils/instrumented-hooks.ts +309 -0
  138. package/src/__tests__/utils/instrumented-signals.ts +281 -0
  139. package/src/__tests__/utils/permute.ts +74 -0
  140. package/src/config.ts +32 -17
  141. package/src/debug.ts +14 -0
  142. package/src/hooks.ts +433 -0
  143. package/src/index.ts +28 -3
  144. package/src/react/__tests__/react.test.tsx +227 -0
  145. package/src/react/context.ts +8 -0
  146. package/src/react/index.ts +4 -0
  147. package/src/react/provider.tsx +18 -0
  148. package/src/react/setup.ts +10 -0
  149. package/src/react/signal-value.ts +49 -0
  150. package/src/react/state.ts +13 -0
  151. package/src/scheduling.ts +69 -1
  152. package/src/signals.ts +328 -169
  153. package/src/trace.ts +449 -0
  154. package/src/types.ts +86 -0
  155. package/src/utils.ts +83 -0
  156. package/tsconfig.json +2 -1
  157. package/vitest.workspace.ts +24 -0
  158. package/src/__tests__/async.test.ts +0 -426
  159. package/src/__tests__/basic.test.ts +0 -378
  160. package/src/__tests__/subscription.test.ts +0 -645
  161. package/src/__tests__/utils/instrumented.ts +0 -326
@@ -0,0 +1,632 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import {
3
+ createStateSignal,
4
+ createComputedSignal,
5
+ createSubscriptionSignal,
6
+ createWatcherSignal,
7
+ } from '../utils/instrumented-signals.js';
8
+ import { nextTick } from '../utils/async.js';
9
+
10
+ describe('Subscription Signal functionality', () => {
11
+ describe('subscribe', () => {
12
+ test('Subscribes when first accessed when watched', async () => {
13
+ const s = createSubscriptionSignal(() => {}, { initValue: 123 });
14
+
15
+ const w = createWatcherSignal(() => {
16
+ s.get();
17
+ });
18
+
19
+ expect(s).toHaveSignalValueAndCounts(123, {
20
+ subscribe: 0,
21
+ });
22
+
23
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
24
+
25
+ await nextTick();
26
+
27
+ expect(s).toHaveSignalValueAndCounts(123, {
28
+ subscribe: 0,
29
+ });
30
+
31
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
32
+
33
+ w.addListener(() => {
34
+ // do something;
35
+ });
36
+
37
+ await nextTick();
38
+
39
+ expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
40
+
41
+ expect(s).toHaveSignalValueAndCounts(123, {
42
+ subscribe: 1,
43
+ });
44
+ });
45
+
46
+ test('Subscribes if nested', async () => {
47
+ const s = createSubscriptionSignal(() => {}, { initValue: 123 });
48
+
49
+ const c = createComputedSignal(() => {
50
+ s.get();
51
+ });
52
+
53
+ const w = createWatcherSignal(() => {
54
+ c.get();
55
+ });
56
+
57
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
58
+ expect(s).toHaveSignalValueAndCounts(123, {
59
+ subscribe: 0,
60
+ });
61
+
62
+ await nextTick();
63
+
64
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
65
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
66
+
67
+ w.addListener(() => {
68
+ // do something;
69
+ });
70
+
71
+ await nextTick();
72
+
73
+ expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
74
+ expect(c).toHaveSignalCounts({ get: 1, compute: 1 });
75
+ expect(s).toHaveSignalValueAndCounts(123, {
76
+ subscribe: 1,
77
+ });
78
+ });
79
+
80
+ test('Subscribes when dynamically connected to a watcher', async () => {
81
+ const a = createStateSignal(false);
82
+
83
+ const s = createSubscriptionSignal(() => {}, { initValue: 123 });
84
+
85
+ const w = createWatcherSignal(() => {
86
+ return a.get() ? s.get() : 0;
87
+ });
88
+
89
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
90
+ expect(s).toHaveSignalValueAndCounts(123, {
91
+ subscribe: 0,
92
+ });
93
+
94
+ await nextTick();
95
+
96
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
97
+ expect(s).toHaveSignalValueAndCounts(123, {
98
+ subscribe: 0,
99
+ });
100
+
101
+ w.addListener(() => {
102
+ // do something;
103
+ });
104
+
105
+ await nextTick();
106
+
107
+ expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
108
+ expect(s).toHaveSignalValueAndCounts(123, {
109
+ subscribe: 0,
110
+ });
111
+
112
+ a.set(true);
113
+
114
+ await nextTick();
115
+
116
+ expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
117
+ expect(s).toHaveSignalValueAndCounts(123, {
118
+ subscribe: 1,
119
+ });
120
+ });
121
+
122
+ test('Subscribes when dynamically used by a connected computed', async () => {
123
+ const a = createStateSignal(false);
124
+
125
+ const s = createSubscriptionSignal(() => {}, { initValue: 123 });
126
+
127
+ const c = createComputedSignal(() => {
128
+ return a.get() ? s.get() : 0;
129
+ });
130
+
131
+ const w = createWatcherSignal(() => {
132
+ return c.get();
133
+ });
134
+
135
+ w.addListener(() => {
136
+ // do something;
137
+ });
138
+
139
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
140
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
141
+ expect(s).toHaveSignalValueAndCounts(123, {
142
+ subscribe: 0,
143
+ });
144
+
145
+ await nextTick();
146
+
147
+ expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
148
+ expect(c).toHaveSignalCounts({ get: 1, compute: 1 });
149
+ expect(s).toHaveSignalValueAndCounts(123, {
150
+ subscribe: 0,
151
+ });
152
+
153
+ a.set(true);
154
+
155
+ await nextTick();
156
+
157
+ expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
158
+ expect(c).toHaveSignalCounts({ get: 2, compute: 2 });
159
+ expect(s).toHaveSignalValueAndCounts(123, {
160
+ subscribe: 1,
161
+ });
162
+ });
163
+
164
+ test('Subscribes when parent is connected and uncached', async () => {
165
+ const a = createStateSignal(false);
166
+
167
+ const s = createSubscriptionSignal(() => {}, { initValue: 123 });
168
+
169
+ const c = createComputedSignal(() => {
170
+ return s.get();
171
+ });
172
+
173
+ const w = createWatcherSignal(() => {
174
+ return a.get() ? c.get() : 0;
175
+ });
176
+
177
+ w.addListener(() => {
178
+ // do something;
179
+ });
180
+
181
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
182
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
183
+ expect(s).toHaveSignalValueAndCounts(123, {
184
+ subscribe: 0,
185
+ });
186
+
187
+ await nextTick();
188
+
189
+ expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
190
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
191
+ expect(s).toHaveSignalValueAndCounts(123, {
192
+ subscribe: 0,
193
+ });
194
+
195
+ a.set(true);
196
+
197
+ await nextTick();
198
+
199
+ expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
200
+ expect(c).toHaveSignalCounts({ get: 1, compute: 1 });
201
+ expect(s).toHaveSignalValueAndCounts(123, {
202
+ subscribe: 1,
203
+ });
204
+ });
205
+
206
+ test('Subscribes when parent is connected and dirty', async () => {
207
+ const a = createStateSignal(false);
208
+
209
+ const s = createSubscriptionSignal(() => {}, { initValue: 123 });
210
+
211
+ const c = createComputedSignal(() => {
212
+ return a.get() ? s.get() : 0;
213
+ });
214
+
215
+ const w = createWatcherSignal(() => {
216
+ return a.get() ? c.get() : 0;
217
+ });
218
+
219
+ w.addListener(() => {
220
+ // do something;
221
+ });
222
+
223
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
224
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
225
+ expect(s).toHaveSignalValueAndCounts(123, {
226
+ subscribe: 0,
227
+ });
228
+
229
+ await nextTick();
230
+
231
+ expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
232
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
233
+ expect(s).toHaveSignalValueAndCounts(123, {
234
+ subscribe: 0,
235
+ });
236
+
237
+ a.set(true);
238
+
239
+ await nextTick();
240
+
241
+ expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
242
+ expect(c).toHaveSignalCounts({ get: 1, compute: 1 });
243
+ expect(s).toHaveSignalValueAndCounts(123, {
244
+ subscribe: 1,
245
+ });
246
+ });
247
+
248
+ test('Subscribes when parent is connected and cached', async () => {
249
+ const a = createStateSignal(false);
250
+
251
+ const s = createSubscriptionSignal(() => {}, { initValue: 123 });
252
+
253
+ const c = createComputedSignal(() => {
254
+ return s.get();
255
+ });
256
+
257
+ const w = createWatcherSignal(() => {
258
+ return a.get() ? c.get() : 0;
259
+ });
260
+
261
+ w.addListener(() => {
262
+ // do something;
263
+ });
264
+
265
+ expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
266
+ expect(c).toHaveSignalCounts({ get: 0, compute: 0 });
267
+ expect(s).toHaveSignalValueAndCounts(123, {
268
+ subscribe: 0,
269
+ });
270
+
271
+ await nextTick();
272
+
273
+ c.get();
274
+
275
+ expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
276
+ expect(c).toHaveSignalCounts({ get: 1, compute: 1 });
277
+ expect(s).toHaveSignalValueAndCounts(123, {
278
+ subscribe: 0,
279
+ });
280
+
281
+ a.set(true);
282
+
283
+ await nextTick();
284
+
285
+ expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
286
+ expect(c).toHaveSignalValueAndCounts(123, { get: 3, compute: 1 });
287
+ expect(s).toHaveSignalValueAndCounts(123, {
288
+ subscribe: 1,
289
+ });
290
+ });
291
+
292
+ test('Can set value during initial subscribe and value is used', async () => {
293
+ const s = createSubscriptionSignal(
294
+ (get, set) => {
295
+ set(456);
296
+ },
297
+ { initValue: 123 },
298
+ );
299
+
300
+ const w = createWatcherSignal(() => {
301
+ return s.get();
302
+ });
303
+
304
+ w.addListener(() => {
305
+ // do something;
306
+ });
307
+
308
+ expect(s).toHaveSignalValueAndCounts(123, {
309
+ subscribe: 0,
310
+ });
311
+
312
+ await nextTick();
313
+
314
+ expect(s).toHaveSignalValueAndCounts(456, {
315
+ subscribe: 1,
316
+ });
317
+ });
318
+
319
+ test('Can set value during resubscribe and value is used', async () => {
320
+ const s = createSubscriptionSignal(
321
+ (get, set) => {
322
+ set(get()! + 1);
323
+ },
324
+ { initValue: 123 },
325
+ );
326
+
327
+ let value;
328
+
329
+ const w = createWatcherSignal(() => {
330
+ value = s.get();
331
+ });
332
+
333
+ const unsub = w.addListener(() => {
334
+ // do something;
335
+ });
336
+
337
+ await nextTick();
338
+
339
+ expect(value).toBe(124);
340
+ expect(s).toHaveSignalValueAndCounts(124, {
341
+ subscribe: 1,
342
+ unsubscribe: 0,
343
+ });
344
+
345
+ unsub();
346
+
347
+ await nextTick();
348
+
349
+ expect(value).toBe(124);
350
+ expect(s).toHaveSignalValueAndCounts(124, {
351
+ subscribe: 1,
352
+ unsubscribe: 1,
353
+ });
354
+
355
+ w.addListener(() => {
356
+ // do something;
357
+ });
358
+
359
+ await nextTick();
360
+
361
+ expect(value).toBe(125);
362
+ expect(s).toHaveSignalValueAndCounts(125, {
363
+ subscribe: 2,
364
+ unsubscribe: 1,
365
+ });
366
+ });
367
+
368
+ test('Can set value during resubscribe and cached parents are dirtied', async () => {
369
+ const s = createSubscriptionSignal(
370
+ (get, set) => {
371
+ set((get() ?? 0) + 1);
372
+ },
373
+ { initValue: 123 },
374
+ );
375
+
376
+ const c = createComputedSignal(() => {
377
+ return s.get() + 1;
378
+ });
379
+
380
+ let value;
381
+
382
+ const w = createWatcherSignal(() => {
383
+ value = c.get();
384
+ });
385
+
386
+ const unsub = w.addListener(() => {
387
+ // do something;
388
+ });
389
+
390
+ await nextTick();
391
+
392
+ expect(value).toBe(125);
393
+ expect(s).toHaveSignalValueAndCounts(124, {
394
+ subscribe: 1,
395
+ unsubscribe: 0,
396
+ });
397
+
398
+ unsub();
399
+
400
+ await nextTick();
401
+
402
+ expect(value).toBe(125);
403
+ expect(s).toHaveSignalValueAndCounts(124, {
404
+ subscribe: 1,
405
+ unsubscribe: 1,
406
+ });
407
+
408
+ w.addListener(() => {
409
+ // do something;
410
+ });
411
+
412
+ await nextTick();
413
+
414
+ expect(value).toBe(126);
415
+ expect(s).toHaveSignalValueAndCounts(125, {
416
+ subscribe: 2,
417
+ });
418
+ });
419
+
420
+ test('Update can set value during eager pull and updated value is used by parent', async () => {
421
+ // ...
422
+ });
423
+
424
+ test('Update can set value and trigger a dirty for parent that happens in the same flush', async () => {
425
+ // ...
426
+ });
427
+
428
+ test('Update can trigger an dirty for a parent that has already flushed this time around (secondary flush, edge case)', async () => {
429
+ // ...
430
+ });
431
+ });
432
+
433
+ describe('unsubscribe', async () => {
434
+ test('It unsubscribes when all watchers are disconnected', async () => {
435
+ const s = createSubscriptionSignal(
436
+ (get, set) => {
437
+ return {
438
+ unsubscribe() {
439
+ // ...
440
+ },
441
+ };
442
+ },
443
+ { initValue: 123 },
444
+ );
445
+
446
+ let value;
447
+
448
+ let w = createWatcherSignal(() => {
449
+ value = s.get();
450
+ });
451
+
452
+ let w2 = createWatcherSignal(() => {
453
+ s.get();
454
+ });
455
+
456
+ const unsub1 = w.addListener(() => {
457
+ // do something;
458
+ });
459
+
460
+ const unsub2 = w2.addListener(() => {
461
+ // do something;
462
+ });
463
+
464
+ await nextTick();
465
+
466
+ expect(value).toBe(123);
467
+ expect(s).toHaveSignalValueAndCounts(123, {
468
+ subscribe: 1,
469
+ unsubscribe: 0,
470
+ });
471
+
472
+ unsub1();
473
+ unsub2();
474
+
475
+ await nextTick();
476
+
477
+ expect(value).toBe(123);
478
+ expect(s).toHaveSignalValueAndCounts(123, {
479
+ subscribe: 1,
480
+ unsubscribe: 1,
481
+ });
482
+ });
483
+
484
+ test('It unsubscribes when all watchers are disconnected at different times', async () => {
485
+ const s = createSubscriptionSignal(
486
+ (get, set) => {
487
+ return {
488
+ unsubscribe() {
489
+ // ...
490
+ },
491
+ };
492
+ },
493
+ { initValue: 123 },
494
+ );
495
+
496
+ let value;
497
+
498
+ let w = createWatcherSignal(() => {
499
+ value = s.get();
500
+ });
501
+
502
+ const unsub1 = w.addListener(() => {
503
+ // do something;
504
+ });
505
+
506
+ await nextTick();
507
+
508
+ expect(value).toBe(123);
509
+ expect(s).toHaveSignalValueAndCounts(123, {
510
+ subscribe: 1,
511
+ unsubscribe: 0,
512
+ });
513
+
514
+ let w2 = createWatcherSignal(() => {
515
+ s.get();
516
+ });
517
+
518
+ const unsub2 = w2.addListener(() => {
519
+ // do something;
520
+ });
521
+
522
+ await nextTick();
523
+
524
+ expect(value).toBe(123);
525
+ expect(s).toHaveSignalValueAndCounts(123, {
526
+ subscribe: 1,
527
+ unsubscribe: 0,
528
+ });
529
+
530
+ await nextTick();
531
+
532
+ expect(value).toBe(123);
533
+ expect(s).toHaveSignalValueAndCounts(123, {
534
+ subscribe: 1,
535
+ unsubscribe: 0,
536
+ });
537
+
538
+ unsub1();
539
+
540
+ await nextTick();
541
+
542
+ expect(value).toBe(123);
543
+ expect(s).toHaveSignalValueAndCounts(123, {
544
+ subscribe: 1,
545
+ unsubscribe: 0,
546
+ });
547
+
548
+ unsub2();
549
+
550
+ await nextTick();
551
+
552
+ expect(value).toBe(123);
553
+ expect(s).toHaveSignalValueAndCounts(123, {
554
+ subscribe: 1,
555
+ unsubscribe: 1,
556
+ });
557
+ });
558
+
559
+ test('It stays subscribed when all watchers are disconnected and new ones are connected in the same flush', async () => {
560
+ const s = createSubscriptionSignal(
561
+ (get, set) => {
562
+ return {
563
+ unsubscribe() {
564
+ // ...
565
+ },
566
+ };
567
+ },
568
+ { initValue: 123 },
569
+ );
570
+
571
+ let value;
572
+
573
+ let w = createWatcherSignal(() => {
574
+ value = s.get();
575
+ });
576
+
577
+ let w2 = createWatcherSignal(() => {
578
+ s.get();
579
+ });
580
+
581
+ let unsub1 = w.addListener(() => {
582
+ // do something;
583
+ });
584
+
585
+ await nextTick();
586
+
587
+ expect(value).toBe(123);
588
+ expect(s).toHaveSignalValueAndCounts(123, {
589
+ subscribe: 1,
590
+ unsubscribe: 0,
591
+ });
592
+
593
+ unsub1();
594
+
595
+ let unsub2 = w2.addListener(() => {
596
+ // do something;
597
+ });
598
+
599
+ await nextTick();
600
+
601
+ expect(value).toBe(123);
602
+ expect(s).toHaveSignalValueAndCounts(123, {
603
+ subscribe: 1,
604
+ unsubscribe: 0,
605
+ });
606
+
607
+ unsub1 = w.addListener(() => {
608
+ // do something;
609
+ });
610
+
611
+ unsub2();
612
+
613
+ await nextTick();
614
+
615
+ expect(value).toBe(123);
616
+ expect(s).toHaveSignalValueAndCounts(123, {
617
+ subscribe: 1,
618
+ unsubscribe: 0,
619
+ });
620
+
621
+ unsub1();
622
+
623
+ await nextTick();
624
+
625
+ expect(value).toBe(123);
626
+ expect(s).toHaveSignalValueAndCounts(123, {
627
+ subscribe: 1,
628
+ unsubscribe: 1,
629
+ });
630
+ });
631
+ });
632
+ });