vestjs-runtime 1.7.0 → 2.0.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 (136) hide show
  1. package/IsolateSerializer/package.json +12 -8
  2. package/README.md +3 -1
  3. package/dist/IsolateKeys-B21aPuBk.mjs +23 -0
  4. package/dist/IsolateKeys-B21aPuBk.mjs.map +1 -0
  5. package/dist/IsolateKeys-CCvALpZC.cjs +35 -0
  6. package/dist/IsolateKeys-CCvALpZC.cjs.map +1 -0
  7. package/dist/IsolateSerializer-B1hE3gmT.mjs +1004 -0
  8. package/dist/IsolateSerializer-B1hE3gmT.mjs.map +1 -0
  9. package/dist/IsolateSerializer-pbEf5gB2.cjs +1121 -0
  10. package/dist/IsolateSerializer-pbEf5gB2.cjs.map +1 -0
  11. package/dist/chunk-CLMFDpHK.mjs +18 -0
  12. package/dist/exports/IsolateSerializer.cjs +4 -0
  13. package/dist/exports/IsolateSerializer.mjs +4 -0
  14. package/dist/exports/test-utils.cjs +21 -0
  15. package/dist/exports/test-utils.cjs.map +1 -0
  16. package/dist/exports/test-utils.mjs +21 -0
  17. package/dist/exports/test-utils.mjs.map +1 -0
  18. package/dist/vestjs-runtime.cjs +153 -0
  19. package/dist/vestjs-runtime.cjs.map +1 -0
  20. package/dist/vestjs-runtime.mjs +117 -0
  21. package/dist/vestjs-runtime.mjs.map +1 -0
  22. package/docs/IsolateRegistry.docs.md +146 -0
  23. package/docs/Isolates.md +97 -0
  24. package/package.json +43 -88
  25. package/src/Bus.ts +46 -0
  26. package/src/Isolate/Isolate.ts +163 -0
  27. package/src/Isolate/IsolateFocused.ts +93 -0
  28. package/src/Isolate/IsolateIndexer.ts +42 -0
  29. package/src/Isolate/IsolateInspector.ts +93 -0
  30. package/src/Isolate/IsolateKeys.ts +18 -0
  31. package/src/Isolate/IsolateMutator.ts +165 -0
  32. package/src/Isolate/IsolateRegistry.ts +176 -0
  33. package/src/Isolate/IsolateReorderable.ts +11 -0
  34. package/src/Isolate/IsolateSelectors.ts +25 -0
  35. package/src/Isolate/IsolateStateMachine.ts +30 -0
  36. package/src/Isolate/IsolateStatus.ts +8 -0
  37. package/src/Isolate/IsolateTransient.ts +27 -0
  38. package/src/Isolate/IsolateTypes.ts +33 -0
  39. package/src/Isolate/__tests__/Isolate.test.ts +123 -0
  40. package/src/Isolate/__tests__/IsolateFocused.test.ts +199 -0
  41. package/src/Isolate/__tests__/IsolateInspector.test.ts +136 -0
  42. package/src/Isolate/__tests__/IsolateMutator.test.ts +164 -0
  43. package/src/Isolate/__tests__/IsolatePropagation.test.ts +170 -0
  44. package/src/Isolate/__tests__/IsolateReorderable.test.ts +111 -0
  45. package/src/Isolate/__tests__/IsolateSelectors.test.ts +72 -0
  46. package/src/Isolate/__tests__/IsolateStatus.test.ts +44 -0
  47. package/src/Isolate/__tests__/IsolateTransient.test.ts +58 -0
  48. package/src/Isolate/__tests__/__snapshots__/asyncIsolate.test.ts.snap +71 -0
  49. package/src/Isolate/__tests__/asyncIsolate.test.ts +85 -0
  50. package/src/IsolateWalker.ts +359 -0
  51. package/src/Orchestrator/RuntimeStates.ts +4 -0
  52. package/src/Reconciler.ts +178 -0
  53. package/src/RuntimeEvents.ts +9 -0
  54. package/src/VestRuntime.ts +421 -0
  55. package/src/__tests__/Bus.test.ts +57 -0
  56. package/src/__tests__/IsolateWalker.iterative.test.ts +77 -0
  57. package/src/__tests__/IsolateWalker.test.ts +418 -0
  58. package/src/__tests__/Reconciler.test.ts +193 -0
  59. package/src/__tests__/Reconciler.transient.test.ts +166 -0
  60. package/src/__tests__/VestRuntime.test.ts +212 -0
  61. package/src/__tests__/VestRuntimeStateMachine.test.ts +36 -0
  62. package/src/__tests__/vestjs-runtime.test.ts +19 -0
  63. package/src/errors/ErrorStrings.ts +6 -0
  64. package/src/exports/IsolateSerializer.ts +131 -0
  65. package/src/exports/__tests__/IsolateSerializer.test.ts +334 -0
  66. package/src/exports/__tests__/IsolateSerializer.transient.test.ts +101 -0
  67. package/src/exports/__tests__/__snapshots__/IsolateSerializer.test.ts.snap +5 -0
  68. package/src/exports/test-utils.ts +17 -0
  69. package/src/vestjs-runtime.ts +28 -0
  70. package/test-utils/package.json +12 -8
  71. package/types/Isolate-DChR7h5K.d.mts +58 -0
  72. package/types/Isolate-DChR7h5K.d.mts.map +1 -0
  73. package/types/Isolate-HYIh82M8.d.cts +58 -0
  74. package/types/Isolate-HYIh82M8.d.cts.map +1 -0
  75. package/types/IsolateSerializer-BCg01Px5.d.mts +13 -0
  76. package/types/IsolateSerializer-BCg01Px5.d.mts.map +1 -0
  77. package/types/IsolateSerializer-CQpP6A4m.d.cts +13 -0
  78. package/types/IsolateSerializer-CQpP6A4m.d.cts.map +1 -0
  79. package/types/exports/IsolateSerializer.d.cts +3 -0
  80. package/types/exports/IsolateSerializer.d.mts +3 -0
  81. package/types/exports/test-utils.d.cts +7 -0
  82. package/types/exports/test-utils.d.cts.map +1 -0
  83. package/types/exports/test-utils.d.mts +7 -0
  84. package/types/exports/test-utils.d.mts.map +1 -0
  85. package/types/vestjs-runtime.d.cts +372 -0
  86. package/types/vestjs-runtime.d.cts.map +1 -0
  87. package/types/vestjs-runtime.d.mts +370 -0
  88. package/types/vestjs-runtime.d.mts.map +1 -0
  89. package/types/vestjs-runtime.d.ts +351 -257
  90. package/vitest.config.ts +9 -17
  91. package/dist/cjs/IsolateSerializer.development.js +0 -135
  92. package/dist/cjs/IsolateSerializer.development.js.map +0 -1
  93. package/dist/cjs/IsolateSerializer.js +0 -6
  94. package/dist/cjs/IsolateSerializer.production.js +0 -2
  95. package/dist/cjs/IsolateSerializer.production.js.map +0 -1
  96. package/dist/cjs/package.json +0 -1
  97. package/dist/cjs/test-utils.development.js +0 -61
  98. package/dist/cjs/test-utils.development.js.map +0 -1
  99. package/dist/cjs/test-utils.js +0 -6
  100. package/dist/cjs/test-utils.production.js +0 -2
  101. package/dist/cjs/test-utils.production.js.map +0 -1
  102. package/dist/cjs/vestjs-runtime.development.js +0 -686
  103. package/dist/cjs/vestjs-runtime.development.js.map +0 -1
  104. package/dist/cjs/vestjs-runtime.js +0 -6
  105. package/dist/cjs/vestjs-runtime.production.js +0 -2
  106. package/dist/cjs/vestjs-runtime.production.js.map +0 -1
  107. package/dist/es/IsolateSerializer.development.js +0 -133
  108. package/dist/es/IsolateSerializer.development.js.map +0 -1
  109. package/dist/es/IsolateSerializer.production.js +0 -2
  110. package/dist/es/IsolateSerializer.production.js.map +0 -1
  111. package/dist/es/package.json +0 -1
  112. package/dist/es/test-utils.development.js +0 -59
  113. package/dist/es/test-utils.development.js.map +0 -1
  114. package/dist/es/test-utils.production.js +0 -2
  115. package/dist/es/test-utils.production.js.map +0 -1
  116. package/dist/es/vestjs-runtime.development.js +0 -675
  117. package/dist/es/vestjs-runtime.development.js.map +0 -1
  118. package/dist/es/vestjs-runtime.production.js +0 -2
  119. package/dist/es/vestjs-runtime.production.js.map +0 -1
  120. package/dist/umd/IsolateSerializer.development.js +0 -138
  121. package/dist/umd/IsolateSerializer.development.js.map +0 -1
  122. package/dist/umd/IsolateSerializer.production.js +0 -2
  123. package/dist/umd/IsolateSerializer.production.js.map +0 -1
  124. package/dist/umd/test-utils.development.js +0 -67
  125. package/dist/umd/test-utils.development.js.map +0 -1
  126. package/dist/umd/test-utils.production.js +0 -2
  127. package/dist/umd/test-utils.production.js.map +0 -1
  128. package/dist/umd/vestjs-runtime.development.js +0 -688
  129. package/dist/umd/vestjs-runtime.development.js.map +0 -1
  130. package/dist/umd/vestjs-runtime.production.js +0 -2
  131. package/dist/umd/vestjs-runtime.production.js.map +0 -1
  132. package/types/IsolateSerializer.d.ts +0 -42
  133. package/types/IsolateSerializer.d.ts.map +0 -1
  134. package/types/test-utils.d.ts +0 -37
  135. package/types/test-utils.d.ts.map +0 -1
  136. package/types/vestjs-runtime.d.ts.map +0 -1
@@ -0,0 +1,170 @@
1
+ import {
2
+ Isolate,
3
+ IsolateStatus,
4
+ TIsolate,
5
+ VestRuntime,
6
+ IsolateMutator,
7
+ } from 'vestjs-runtime';
8
+ import wait from 'wait';
9
+ import { describe, it, expect, vi } from 'vitest';
10
+
11
+ function mockRunTime(fn: () => void) {
12
+ // We mock a minimal runtime context for the test
13
+ const ref = {
14
+ historyNode: null,
15
+ runtimeNode: null,
16
+ runtimeRoot: null,
17
+ };
18
+ return VestRuntime.Run(VestRuntime.createRef(ref as any, vi.fn()), fn);
19
+ }
20
+
21
+ describe('Isolate Status Propagation (HAS_PENDING)', () => {
22
+ it('Should set all ancestors to HAS_PENDING when a child is async', async () => {
23
+ let root!: TIsolate;
24
+ let parent!: TIsolate;
25
+ let child!: TIsolate;
26
+ let resolveChild!: (value?: unknown) => void;
27
+
28
+ mockRunTime(() => {
29
+ root = Isolate.create('Root', () => {
30
+ parent = Isolate.create('Parent', () => {
31
+ child = Isolate.create(
32
+ 'Child',
33
+ () =>
34
+ new Promise(r => {
35
+ resolveChild = r;
36
+ }),
37
+ );
38
+ });
39
+ });
40
+ });
41
+
42
+ expect(child.status).toBe(IsolateStatus.PENDING);
43
+ expect(parent.status).toBe(IsolateStatus.HAS_PENDING);
44
+ expect(root.status).toBe(IsolateStatus.HAS_PENDING);
45
+
46
+ // This part tests the 'bubbleUpDone' logic (Phase 2 implementation)
47
+ resolveChild();
48
+ await wait(1); // Wait for microtask queue
49
+ await wait(1); // Ensure all callbacks are resolved
50
+
51
+ expect(child.status).toBe(IsolateStatus.DONE);
52
+ expect(parent.status).toBe(IsolateStatus.DONE);
53
+ expect(root.status).toBe(IsolateStatus.DONE);
54
+ });
55
+ it('Should remain HAS_PENDING if a sibling is still pending', async () => {
56
+ let root!: TIsolate;
57
+ let parent!: TIsolate;
58
+ let child1!: TIsolate;
59
+ let child2!: TIsolate;
60
+ let resolve1!: (value?: unknown) => void;
61
+ let resolve2!: (value?: unknown) => void;
62
+
63
+ mockRunTime(() => {
64
+ root = Isolate.create('Root', () => {
65
+ parent = Isolate.create('Parent', () => {
66
+ child1 = Isolate.create(
67
+ 'Child1',
68
+ () =>
69
+ new Promise(r => {
70
+ resolve1 = r;
71
+ }),
72
+ );
73
+ child2 = Isolate.create(
74
+ 'Child2',
75
+ () =>
76
+ new Promise(r => {
77
+ resolve2 = r;
78
+ }),
79
+ );
80
+ });
81
+ });
82
+ });
83
+
84
+ expect(child1.status).toBe(IsolateStatus.PENDING);
85
+ expect(child2.status).toBe(IsolateStatus.PENDING);
86
+ expect(parent.status).toBe(IsolateStatus.HAS_PENDING);
87
+ expect(root.status).toBe(IsolateStatus.HAS_PENDING);
88
+
89
+ // Resolve first child
90
+ resolve1();
91
+ await wait(1); // Wait for microtask queue
92
+ await wait(1); // Ensure callbacks
93
+
94
+ // Parent should still be HAS_PENDING because Child2 is pending
95
+ expect(child1.status).toBe(IsolateStatus.DONE);
96
+ expect(child2.status).toBe(IsolateStatus.PENDING);
97
+ expect(parent.status).toBe(IsolateStatus.HAS_PENDING);
98
+ expect(root.status).toBe(IsolateStatus.HAS_PENDING);
99
+
100
+ // Resolve second child
101
+ resolve2();
102
+ await wait(1); // Wait for microtask queue
103
+ await wait(1);
104
+
105
+ // Parent and root should now transition to DONE
106
+ expect(child2.status).toBe(IsolateStatus.DONE);
107
+ expect(parent.status).toBe(IsolateStatus.DONE);
108
+ expect(root.status).toBe(IsolateStatus.DONE);
109
+ });
110
+
111
+ it('Should remain HAS_PENDING if an indirect descendant is pending', async () => {
112
+ let parent!: TIsolate;
113
+ let nestedParent!: TIsolate;
114
+ let leaf!: TIsolate;
115
+ let resolveLeaf!: (value?: unknown) => void;
116
+
117
+ mockRunTime(() => {
118
+ parent = Isolate.create('Parent', () => {
119
+ nestedParent = Isolate.create('NestedParent', () => {
120
+ leaf = Isolate.create(
121
+ 'Leaf',
122
+ () =>
123
+ new Promise(r => {
124
+ resolveLeaf = r;
125
+ }),
126
+ );
127
+ });
128
+ });
129
+ });
130
+
131
+ expect(leaf.status).toBe(IsolateStatus.PENDING);
132
+ expect(nestedParent.status).toBe(IsolateStatus.HAS_PENDING);
133
+ expect(parent.status).toBe(IsolateStatus.HAS_PENDING);
134
+
135
+ // Resolve leaf
136
+ resolveLeaf();
137
+ await wait(1); // Wait for microtask queue
138
+ await wait(1);
139
+
140
+ // All should transition to DONE
141
+ expect(leaf.status).toBe(IsolateStatus.DONE);
142
+ expect(nestedParent.status).toBe(IsolateStatus.DONE);
143
+ expect(parent.status).toBe(IsolateStatus.DONE);
144
+ });
145
+
146
+ it('Should prevent manual setDone transition if children are active', async () => {
147
+ let parent!: TIsolate;
148
+ let child!: TIsolate;
149
+
150
+ mockRunTime(() => {
151
+ parent = Isolate.create('Parent', () => {
152
+ child = Isolate.create(
153
+ 'Child',
154
+ () => new Promise(() => {}), // Never resolves
155
+ );
156
+ });
157
+ });
158
+
159
+ expect(child.status).toBe(IsolateStatus.PENDING);
160
+ expect(parent.status).toBe(IsolateStatus.HAS_PENDING);
161
+
162
+ // Try to force setDone on parent
163
+ mockRunTime(() => {
164
+ IsolateMutator.setDone(parent);
165
+ });
166
+
167
+ // Should still be HAS_PENDING
168
+ expect(parent.status).toBe(IsolateStatus.HAS_PENDING);
169
+ });
170
+ });
@@ -0,0 +1,111 @@
1
+ import { CB } from 'vest-utils';
2
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
3
+
4
+ import { IsolateReorderable } from '../IsolateReorderable';
5
+ import { IsolateInspector } from '../IsolateInspector';
6
+ import { IsolateKeys } from '../IsolateKeys';
7
+ import { VestRuntime, IReconciler, Isolate } from '../../vestjs-runtime';
8
+
9
+ describe('IsolateReorderable', () => {
10
+ let stateRef: any;
11
+ // Mock reconciler to test reordering enforcement
12
+ const testReconciler = vi.fn((currentNode: any, historyNode: any) => {
13
+ // Simple check: if keys don't match, verify if reorder is allowed
14
+ if (currentNode.key !== historyNode.key) {
15
+ if (!IsolateInspector.canReorder(currentNode)) {
16
+ throw new Error('Reorder violation');
17
+ }
18
+ }
19
+ return currentNode;
20
+ });
21
+
22
+ beforeEach(() => {
23
+ testReconciler.mockClear();
24
+ stateRef = VestRuntime.createRef(
25
+ testReconciler as unknown as IReconciler,
26
+ v => v,
27
+ );
28
+ });
29
+
30
+ function withRunTime<T>(fn: CB<T>) {
31
+ return VestRuntime.Run(stateRef, () => {
32
+ return fn();
33
+ });
34
+ }
35
+
36
+ it('Should return an isolate with allowReorder set to true', () => {
37
+ const isolate = withRunTime(() => IsolateReorderable(() => {}));
38
+ expect(isolate[IsolateKeys.AllowReorder]).toBe(true);
39
+ });
40
+
41
+ it('Should set the type to "Reorderable" by default', () => {
42
+ const isolate = withRunTime(() => IsolateReorderable(() => {}));
43
+ expect(isolate[IsolateKeys.Type]).toBe('Reorderable');
44
+ });
45
+
46
+ it('Should allow overriding the type', () => {
47
+ const isolate = withRunTime(() =>
48
+ IsolateReorderable(() => {}, 'CustomType'),
49
+ );
50
+ expect(isolate[IsolateKeys.Type]).toBe('CustomType');
51
+ });
52
+
53
+ it('Should set the payload', () => {
54
+ const payload = { foo: 'bar' };
55
+ const isolate = withRunTime(() =>
56
+ IsolateReorderable(() => {}, 'Type', payload),
57
+ );
58
+ expect(isolate[IsolateKeys.Data]).toMatchObject(payload);
59
+ });
60
+
61
+ it('Should run the callback', () => {
62
+ const spy = vi.fn();
63
+ withRunTime(() => IsolateReorderable(spy));
64
+ expect(spy).toHaveBeenCalled();
65
+ });
66
+
67
+ describe('Reordering', () => {
68
+ describe('When the isolate is reorderable', () => {
69
+ it('Should allow reordering', () => {
70
+ withRunTime(() => {
71
+ IsolateReorderable(() => {
72
+ Isolate.create('Child', () => {}, {}, 'A');
73
+ Isolate.create('Child', () => {}, {}, 'B');
74
+ });
75
+ });
76
+
77
+ expect(() => {
78
+ withRunTime(() => {
79
+ IsolateReorderable(() => {
80
+ // Swapped order
81
+ Isolate.create('Child', () => {}, {}, 'B');
82
+ Isolate.create('Child', () => {}, {}, 'A');
83
+ });
84
+ });
85
+ }).not.toThrow();
86
+ });
87
+ });
88
+
89
+ describe('Sanity (Failure case)', () => {
90
+ it('Should NOT allow reordering when parent is not Reorderable', () => {
91
+ withRunTime(() => {
92
+ // Standard Isolate does not allow reordering
93
+ Isolate.create('Parent', () => {
94
+ Isolate.create('Child', () => {}, {}, 'A');
95
+ Isolate.create('Child', () => {}, {}, 'B');
96
+ });
97
+ });
98
+
99
+ expect(() => {
100
+ withRunTime(() => {
101
+ Isolate.create('Parent', () => {
102
+ // Swapped order
103
+ Isolate.create('Child', () => {}, {}, 'B');
104
+ Isolate.create('Child', () => {}, {}, 'A');
105
+ });
106
+ });
107
+ }).toThrow('Reorder violation');
108
+ });
109
+ });
110
+ });
111
+ });
@@ -0,0 +1,72 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ isIsolateType,
4
+ isSameIsolateType,
5
+ isSameIsolateIdentity,
6
+ } from '../IsolateSelectors';
7
+ import { IsolateKeys } from '../IsolateKeys';
8
+
9
+ describe('IsolateSelectors', () => {
10
+ const type = 'TEST_TYPE';
11
+ const otherType = 'OTHER_TYPE';
12
+
13
+ const isolate1 = { [IsolateKeys.Type]: type, key: 'key1' };
14
+ const isolate2 = { [IsolateKeys.Type]: type, key: 'key1' };
15
+ const isolate3 = { [IsolateKeys.Type]: type, key: 'key2' };
16
+ const isolate4 = { [IsolateKeys.Type]: otherType, key: 'key1' };
17
+ const nullIsolate = null;
18
+ const undefinedIsolate = undefined;
19
+
20
+ describe('isIsolateType', () => {
21
+ it('should return true if type matches', () => {
22
+ // @ts-ignore
23
+ expect(isIsolateType(isolate1, type)).toBe(true);
24
+ });
25
+
26
+ it('should return false if type matches', () => {
27
+ // @ts-ignore
28
+ expect(isIsolateType(isolate1, otherType)).toBe(false);
29
+ });
30
+
31
+ it('should return false if node is null/undefined', () => {
32
+ // @ts-ignore
33
+ expect(isIsolateType(nullIsolate, type)).toBe(false);
34
+ // @ts-ignore
35
+ expect(isIsolateType(undefinedIsolate, type)).toBe(false);
36
+ });
37
+ });
38
+
39
+ describe('isSameIsolateType', () => {
40
+ it('should return true if type matches', () => {
41
+ // @ts-ignore
42
+ expect(isSameIsolateType(isolate1, isolate2)).toBe(true);
43
+ });
44
+
45
+ it('should return false if type matches', () => {
46
+ // @ts-ignore
47
+ expect(isSameIsolateType(isolate1, isolate4)).toBe(false);
48
+ });
49
+ });
50
+
51
+ describe('isSameIsolateIdentity', () => {
52
+ it('should return true if strictly equal', () => {
53
+ // @ts-ignore
54
+ expect(isSameIsolateIdentity(isolate1, isolate1)).toBe(true);
55
+ });
56
+
57
+ it('should return true if type and key match', () => {
58
+ // @ts-ignore
59
+ expect(isSameIsolateIdentity(isolate1, isolate2)).toBe(true);
60
+ });
61
+
62
+ it('should return false if keys differ', () => {
63
+ // @ts-ignore
64
+ expect(isSameIsolateIdentity(isolate1, isolate3)).toBe(false);
65
+ });
66
+
67
+ it('should return false if types differ', () => {
68
+ // @ts-ignore
69
+ expect(isSameIsolateIdentity(isolate1, isolate4)).toBe(false);
70
+ });
71
+ });
72
+ });
@@ -0,0 +1,44 @@
1
+ import { Isolate, IsolateStatus, TIsolate, VestRuntime } from 'vestjs-runtime';
2
+ import { describe, it, expect } from 'vitest';
3
+
4
+ describe('Isolate Status Transitions', () => {
5
+ it('Should initialize with INITIAL status', () => {
6
+ VestRuntime.Run(VestRuntime.createRef({} as any, {} as any), () => {
7
+ Isolate.create('Test', isolate => {
8
+ expect(isolate.status).toBe(IsolateStatus.INITIAL);
9
+ });
10
+ });
11
+ });
12
+
13
+ it('Should transition to DONE for sync callbacks', () => {
14
+ VestRuntime.Run(VestRuntime.createRef({} as any, {} as any), () => {
15
+ const isolate = Isolate.create('Test', () => {});
16
+ expect(isolate.status).toBe(IsolateStatus.DONE);
17
+ });
18
+ });
19
+
20
+ it('Should transition to PENDING then DONE for async callbacks', async () => {
21
+ let resolve: (_value?: unknown) => void = () => {};
22
+ const promise = new Promise(r => (resolve = r));
23
+ const isolate = await new Promise<TIsolate>(done => {
24
+ VestRuntime.Run(VestRuntime.createRef({} as any, {} as any), () => {
25
+ const createdIsolate = Isolate.create('AsyncTest', async () => {
26
+ await promise;
27
+ });
28
+ done(createdIsolate);
29
+ });
30
+ });
31
+
32
+ // Since Isolate.create runs the callback, for async it returns the isolate
33
+ // which should be PENDING state before the promise resolves
34
+ expect(isolate.status).toBe(IsolateStatus.PENDING);
35
+
36
+ resolve();
37
+ await promise;
38
+
39
+ // Wait for microtasks
40
+ await new Promise(process.nextTick);
41
+
42
+ expect(isolate.status).toBe(IsolateStatus.DONE);
43
+ });
44
+ });
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CB } from 'vest-utils';
3
+
4
+ import { IReconciler } from '../../Reconciler';
5
+ import { IsolateTransient } from '../IsolateTransient';
6
+ import * as VestRuntime from '../../VestRuntime';
7
+ import { IsolateKeys } from '../IsolateKeys';
8
+ import { Isolate } from '../Isolate';
9
+
10
+ describe('IsolateTransient', () => {
11
+ function withRunTime<T>(fn: CB<T>) {
12
+ return VestRuntime.Run(
13
+ VestRuntime.createRef((() => null) as unknown as IReconciler, v => v),
14
+ () => fn(),
15
+ );
16
+ }
17
+
18
+ it('should create an isolate with transient flag set to true', () => {
19
+ let node: any;
20
+ withRunTime(() => {
21
+ Isolate.create('Root', () => {
22
+ node = IsolateTransient(() => {});
23
+ });
24
+ });
25
+ expect(node[IsolateKeys.Transient]).toBe(true);
26
+ });
27
+
28
+ it('should use default type "Transient" when no type is provided', () => {
29
+ let node: any;
30
+ withRunTime(() => {
31
+ Isolate.create('Root', () => {
32
+ node = IsolateTransient(() => {});
33
+ });
34
+ });
35
+ expect(node[IsolateKeys.Type]).toBe('Transient');
36
+ });
37
+
38
+ it('should accept a custom type', () => {
39
+ let node: any;
40
+ withRunTime(() => {
41
+ Isolate.create('Root', () => {
42
+ node = IsolateTransient(() => {}, 'Debounce');
43
+ });
44
+ });
45
+ expect(node[IsolateKeys.Type]).toBe('Debounce');
46
+ });
47
+
48
+ it('should merge custom payload with transient flag', () => {
49
+ let node: any;
50
+ withRunTime(() => {
51
+ Isolate.create('Root', () => {
52
+ node = IsolateTransient(() => {}, 'Custom', { myData: 42 });
53
+ });
54
+ });
55
+ expect(node[IsolateKeys.Transient]).toBe(true);
56
+ expect(node[IsolateKeys.Data]).toEqual({ myData: 42 });
57
+ });
58
+ });
@@ -0,0 +1,71 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`AsyncIsolate > It should resolve async isolate into the parent 2`] = `
4
+ IsolateInstance {
5
+ "$type": "URoot",
6
+ "abortController": null,
7
+ "allowReorder": undefined,
8
+ "children": [
9
+ IsolateInstance {
10
+ "$type": "UChild_1",
11
+ "abortController": null,
12
+ "allowReorder": undefined,
13
+ "children": [
14
+ IsolateInstance {
15
+ "$type": "UGrandChild_1",
16
+ "abortController": null,
17
+ "allowReorder": undefined,
18
+ "children": null,
19
+ "data": {},
20
+ "key": null,
21
+ "keys": null,
22
+ "output": undefined,
23
+ "parent": [Circular],
24
+ "status": "DONE",
25
+ "transient": undefined,
26
+ },
27
+ IsolateInstance {
28
+ "$type": "UGrandChild_2",
29
+ "abortController": null,
30
+ "allowReorder": undefined,
31
+ "children": null,
32
+ "data": {},
33
+ "key": null,
34
+ "keys": null,
35
+ "output": undefined,
36
+ "parent": [Circular],
37
+ "status": "DONE",
38
+ "transient": undefined,
39
+ },
40
+ IsolateInstance {
41
+ "$type": "UGrandChild_3",
42
+ "abortController": null,
43
+ "allowReorder": undefined,
44
+ "children": null,
45
+ "data": {},
46
+ "key": null,
47
+ "keys": null,
48
+ "output": undefined,
49
+ "parent": [Circular],
50
+ "status": "DONE",
51
+ "transient": undefined,
52
+ },
53
+ ],
54
+ "data": {},
55
+ "key": null,
56
+ "keys": null,
57
+ "output": undefined,
58
+ "parent": [Circular],
59
+ "status": "DONE",
60
+ "transient": undefined,
61
+ },
62
+ ],
63
+ "data": {},
64
+ "key": null,
65
+ "keys": null,
66
+ "output": Promise {},
67
+ "parent": null,
68
+ "status": "DONE",
69
+ "transient": undefined,
70
+ }
71
+ `;
@@ -0,0 +1,85 @@
1
+ import { useBus } from '../../Bus';
2
+ import { Isolate, TIsolate } from '../Isolate';
3
+ import { CB } from 'vest-utils';
4
+ import { describe, vi, it, expect, test } from 'vitest';
5
+ import wait from 'wait';
6
+
7
+ import { VestRuntime, IReconciler } from '../../vestjs-runtime';
8
+
9
+ describe('AsyncIsolate', () => {
10
+ test('It should resolve async isolate into the parent', async () => {
11
+ let root = {} as TIsolate;
12
+ withRunTime(() => {
13
+ // Create root isolate from which all others will be created
14
+ root = Isolate.create('URoot', genChildren);
15
+ });
16
+ expect(root).toMatchInlineSnapshot(`
17
+ IsolateInstance {
18
+ "$type": "URoot",
19
+ "abortController": null,
20
+ "allowReorder": undefined,
21
+ "children": null,
22
+ "data": {},
23
+ "key": null,
24
+ "keys": null,
25
+ "output": Promise {},
26
+ "parent": null,
27
+ "status": "PENDING",
28
+ "transient": undefined,
29
+ }
30
+ `);
31
+ await wait(10);
32
+ expect(root?.children?.[0]?.$type).toBe('UChild_1');
33
+ expect(root?.children?.[0].parent).toBe(root);
34
+ expect(root?.children?.[0]?.children?.[0]?.$type).toBe('UGrandChild_1');
35
+ expect(root?.children?.[0]?.children?.[0].parent).toBe(root?.children?.[0]);
36
+ expect(root?.children?.[0]?.children?.[1]?.$type).toBe('UGrandChild_2');
37
+ expect(root?.children?.[0]?.children?.[1].parent).toBe(root?.children?.[0]);
38
+ expect(root?.children?.[0]?.children?.[2]?.$type).toBe('UGrandChild_3');
39
+ expect(root?.children?.[0]?.children?.[2].parent).toBe(root?.children?.[0]);
40
+ expect(root).toMatchSnapshot();
41
+ });
42
+
43
+ it('Should emit an event when an async isolate is done running', async () => {
44
+ const cb = vi.fn();
45
+ let child = {} as TIsolate;
46
+ withRunTime(() => {
47
+ // Create root isolate from which all others will be created
48
+ Isolate.create('URoot', () => {
49
+ const bus = useBus();
50
+ bus.on('ISOLATE_DONE', cb);
51
+
52
+ expect(cb).not.toHaveBeenCalled();
53
+ child = Isolate.create('UChild_1', async () => {
54
+ await wait(10);
55
+ });
56
+ expect(cb).not.toHaveBeenCalled();
57
+ });
58
+ });
59
+ expect(cb).not.toHaveBeenCalledWith(child);
60
+ await wait(10);
61
+ expect(cb).toHaveBeenCalledWith(child);
62
+ });
63
+ });
64
+
65
+ function withRunTime<T>(fn: CB<T>) {
66
+ return VestRuntime.Run(
67
+ VestRuntime.createRef({} as IReconciler, v => v),
68
+ () => {
69
+ return fn();
70
+ },
71
+ );
72
+ }
73
+
74
+ async function genChildren() {
75
+ await wait(10);
76
+ // Create first child isolate
77
+ return withRunTime(() =>
78
+ Isolate.create('UChild_1', () => {
79
+ // Create three grandchildren
80
+ Isolate.create('UGrandChild_1', () => {});
81
+ Isolate.create('UGrandChild_2', () => {});
82
+ Isolate.create('UGrandChild_3', () => {});
83
+ }),
84
+ );
85
+ }