@ryupold/vode 1.8.10 → 1.8.11
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.
- package/.github/workflows/publish.yml +5 -0
- package/.github/workflows/tests.yml +1 -0
- package/README.md +36 -2
- package/dist/vode.cjs.min.js +1 -1
- package/dist/vode.d.ts +1 -1
- package/dist/vode.es5.min.js +1 -1
- package/dist/vode.js +5 -5
- package/dist/vode.min.js +1 -1
- package/dist/vode.min.mjs +1 -1
- package/dist/vode.mjs +5 -5
- package/dist/vode.tests.mjs +331 -159
- package/log.txt +1 -0
- package/package.json +1 -1
- package/src/vode.ts +8 -8
- package/test/helper.ts +19 -11
- package/test/mocks.ts +26 -14
- package/test/tests-mount-unmount.ts +219 -142
- package/test/tests-patch-advanced.ts +108 -2
package/dist/vode.mjs
CHANGED
|
@@ -28,7 +28,7 @@ function app(container, state, dom, ...initialPatches) {
|
|
|
28
28
|
_vode.stats.liveEffectCount++;
|
|
29
29
|
try {
|
|
30
30
|
const resolvedPatch = await action;
|
|
31
|
-
patchableState.patch(resolvedPatch, isAnimated);
|
|
31
|
+
await patchableState.patch(resolvedPatch, isAnimated);
|
|
32
32
|
} finally {
|
|
33
33
|
_vode.stats.liveEffectCount--;
|
|
34
34
|
}
|
|
@@ -41,13 +41,13 @@ function app(container, state, dom, ...initialPatches) {
|
|
|
41
41
|
while (v.done === false) {
|
|
42
42
|
_vode.stats.liveEffectCount++;
|
|
43
43
|
try {
|
|
44
|
-
patchableState.patch(v.value, isAnimated);
|
|
44
|
+
await patchableState.patch(v.value, isAnimated);
|
|
45
45
|
v = await generator.next();
|
|
46
46
|
} finally {
|
|
47
47
|
_vode.stats.liveEffectCount--;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
patchableState.patch(v.value, isAnimated);
|
|
50
|
+
await patchableState.patch(v.value, isAnimated);
|
|
51
51
|
} finally {
|
|
52
52
|
_vode.stats.liveEffectCount--;
|
|
53
53
|
}
|
|
@@ -63,9 +63,9 @@ function app(container, state, dom, ...initialPatches) {
|
|
|
63
63
|
if (!action || typeof action !== "object") return;
|
|
64
64
|
_vode.stats.patchCount++;
|
|
65
65
|
if (action?.next) {
|
|
66
|
-
generatorPatch(action, isAnimated);
|
|
66
|
+
return generatorPatch(action, isAnimated);
|
|
67
67
|
} else if (action.then) {
|
|
68
|
-
promisePatch(action, isAnimated);
|
|
68
|
+
return promisePatch(action, isAnimated);
|
|
69
69
|
} else if (Array.isArray(action)) {
|
|
70
70
|
if (action.length > 0) {
|
|
71
71
|
for (const p of action) {
|
package/dist/vode.tests.mjs
CHANGED
|
@@ -28,7 +28,7 @@ function app(container, state, dom, ...initialPatches) {
|
|
|
28
28
|
_vode.stats.liveEffectCount++;
|
|
29
29
|
try {
|
|
30
30
|
const resolvedPatch = await action;
|
|
31
|
-
patchableState.patch(resolvedPatch, isAnimated);
|
|
31
|
+
await patchableState.patch(resolvedPatch, isAnimated);
|
|
32
32
|
} finally {
|
|
33
33
|
_vode.stats.liveEffectCount--;
|
|
34
34
|
}
|
|
@@ -41,13 +41,13 @@ function app(container, state, dom, ...initialPatches) {
|
|
|
41
41
|
while (v.done === false) {
|
|
42
42
|
_vode.stats.liveEffectCount++;
|
|
43
43
|
try {
|
|
44
|
-
patchableState.patch(v.value, isAnimated);
|
|
44
|
+
await patchableState.patch(v.value, isAnimated);
|
|
45
45
|
v = await generator.next();
|
|
46
46
|
} finally {
|
|
47
47
|
_vode.stats.liveEffectCount--;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
patchableState.patch(v.value, isAnimated);
|
|
50
|
+
await patchableState.patch(v.value, isAnimated);
|
|
51
51
|
} finally {
|
|
52
52
|
_vode.stats.liveEffectCount--;
|
|
53
53
|
}
|
|
@@ -63,9 +63,9 @@ function app(container, state, dom, ...initialPatches) {
|
|
|
63
63
|
if (!action || typeof action !== "object") return;
|
|
64
64
|
_vode.stats.patchCount++;
|
|
65
65
|
if (action?.next) {
|
|
66
|
-
generatorPatch(action, isAnimated);
|
|
66
|
+
return generatorPatch(action, isAnimated);
|
|
67
67
|
} else if (action.then) {
|
|
68
|
-
promisePatch(action, isAnimated);
|
|
68
|
+
return promisePatch(action, isAnimated);
|
|
69
69
|
} else if (Array.isArray(action)) {
|
|
70
70
|
if (action.length > 0) {
|
|
71
71
|
for (const p of action) {
|
|
@@ -1206,19 +1206,25 @@ ${other}${failSuffix}`);
|
|
|
1206
1206
|
waitTimeMs
|
|
1207
1207
|
);
|
|
1208
1208
|
}
|
|
1209
|
-
toSucceed() {
|
|
1209
|
+
toSucceed(failMessage) {
|
|
1210
|
+
const failSuffix = failMessage ? `
|
|
1211
|
+
|
|
1212
|
+
${failMessage}` : "";
|
|
1210
1213
|
if (typeof this.what !== "function") {
|
|
1211
1214
|
throw new ExpectationError(this, `expected a function
|
|
1212
1215
|
|
|
1213
|
-
but it is a ${typeof this.what}`);
|
|
1216
|
+
but it is a ${typeof this.what}${failSuffix}`);
|
|
1214
1217
|
}
|
|
1215
1218
|
return this.what();
|
|
1216
1219
|
}
|
|
1217
|
-
toFail() {
|
|
1220
|
+
toFail(failMessage) {
|
|
1221
|
+
const failSuffix = failMessage ? `
|
|
1222
|
+
|
|
1223
|
+
${failMessage}` : "";
|
|
1218
1224
|
if (typeof this.what !== "function") {
|
|
1219
1225
|
throw new ExpectationError(this, `expected a function
|
|
1220
1226
|
|
|
1221
|
-
but it is a ${typeof this.what}`);
|
|
1227
|
+
but it is a ${typeof this.what}${failSuffix}`);
|
|
1222
1228
|
}
|
|
1223
1229
|
let r;
|
|
1224
1230
|
try {
|
|
@@ -1230,25 +1236,34 @@ but it is a ${typeof this.what}`);
|
|
|
1230
1236
|
|
|
1231
1237
|
but it succeeded with a result of type ${typeof r}
|
|
1232
1238
|
|
|
1233
|
-
${r}`);
|
|
1239
|
+
${r}${failSuffix}`);
|
|
1234
1240
|
}
|
|
1235
|
-
toSucceedAsync(waitTime = 100) {
|
|
1241
|
+
toSucceedAsync(failMessage, waitTime = 100) {
|
|
1242
|
+
const failSuffix = failMessage ? `
|
|
1243
|
+
|
|
1244
|
+
${failMessage}` : "";
|
|
1236
1245
|
if (typeof this.what !== "function") {
|
|
1237
1246
|
throw new ExpectationError(this, `expected a function
|
|
1238
1247
|
|
|
1239
|
-
but it is a ${typeof this.what}`);
|
|
1248
|
+
but it is a ${typeof this.what}${failSuffix}`);
|
|
1240
1249
|
}
|
|
1241
1250
|
return retry(() => this.what(), waitTime);
|
|
1242
1251
|
}
|
|
1243
|
-
async toFailAsync() {
|
|
1252
|
+
async toFailAsync(failMessage) {
|
|
1253
|
+
const failSuffix = failMessage ? `
|
|
1254
|
+
|
|
1255
|
+
${failMessage}` : "";
|
|
1244
1256
|
if (typeof this.what !== "function") {
|
|
1245
1257
|
throw new ExpectationError(this, `expected a function
|
|
1246
1258
|
|
|
1247
|
-
but it is a ${typeof this.what}`);
|
|
1259
|
+
but it is a ${typeof this.what}${failSuffix}`);
|
|
1248
1260
|
}
|
|
1249
1261
|
let r;
|
|
1250
1262
|
try {
|
|
1251
|
-
|
|
1263
|
+
if (typeof this.what === "function")
|
|
1264
|
+
r = await this.what();
|
|
1265
|
+
else
|
|
1266
|
+
r = await this.what;
|
|
1252
1267
|
} catch (err) {
|
|
1253
1268
|
return err;
|
|
1254
1269
|
}
|
|
@@ -1256,7 +1271,7 @@ but it is a ${typeof this.what}`);
|
|
|
1256
1271
|
|
|
1257
1272
|
but it succeeded with a result of type ${typeof r}
|
|
1258
1273
|
|
|
1259
|
-
${r}`);
|
|
1274
|
+
${r}${failSuffix}`);
|
|
1260
1275
|
}
|
|
1261
1276
|
async toMatch(v, state, failMessage, waitTimeMs = 100) {
|
|
1262
1277
|
return await retry(
|
|
@@ -2942,6 +2957,103 @@ var tests_mount_unmount_default = {
|
|
|
2942
2957
|
patch({ show: true });
|
|
2943
2958
|
await expect(mounts).toEqual(["mount span"]);
|
|
2944
2959
|
},
|
|
2960
|
+
"onMount(): with catched component, replacement vode's onMount fires when error occurs": async () => {
|
|
2961
|
+
const container = setup();
|
|
2962
|
+
const mounts = [];
|
|
2963
|
+
const broken = () => {
|
|
2964
|
+
throw new Error("boom");
|
|
2965
|
+
};
|
|
2966
|
+
app(
|
|
2967
|
+
container,
|
|
2968
|
+
{},
|
|
2969
|
+
() => [
|
|
2970
|
+
DIV,
|
|
2971
|
+
{
|
|
2972
|
+
catch: [
|
|
2973
|
+
SECTION,
|
|
2974
|
+
{
|
|
2975
|
+
onMount: (s, ele) => {
|
|
2976
|
+
mounts.push("mount fallback");
|
|
2977
|
+
}
|
|
2978
|
+
},
|
|
2979
|
+
"fallback"
|
|
2980
|
+
]
|
|
2981
|
+
},
|
|
2982
|
+
broken
|
|
2983
|
+
]
|
|
2984
|
+
);
|
|
2985
|
+
await expect(mounts).toEqual(["mount fallback"]);
|
|
2986
|
+
},
|
|
2987
|
+
"onMount(): with catched component, returned vode's onMount fires and receives error": async () => {
|
|
2988
|
+
const container = setup();
|
|
2989
|
+
const mounts = [];
|
|
2990
|
+
const caughtErrors = [];
|
|
2991
|
+
const broken = () => {
|
|
2992
|
+
throw new Error("boom");
|
|
2993
|
+
};
|
|
2994
|
+
app(
|
|
2995
|
+
container,
|
|
2996
|
+
{},
|
|
2997
|
+
() => [
|
|
2998
|
+
DIV,
|
|
2999
|
+
{
|
|
3000
|
+
catch: (s, err) => {
|
|
3001
|
+
caughtErrors.push(err.message);
|
|
3002
|
+
return [
|
|
3003
|
+
SECTION,
|
|
3004
|
+
{
|
|
3005
|
+
onMount: (s2, ele) => {
|
|
3006
|
+
mounts.push("mount fallback");
|
|
3007
|
+
}
|
|
3008
|
+
},
|
|
3009
|
+
"fallback"
|
|
3010
|
+
];
|
|
3011
|
+
}
|
|
3012
|
+
},
|
|
3013
|
+
broken
|
|
3014
|
+
]
|
|
3015
|
+
);
|
|
3016
|
+
await expect(mounts).toEqual(["mount fallback"]);
|
|
3017
|
+
await expect(caughtErrors).toEqual(["boom"]);
|
|
3018
|
+
},
|
|
3019
|
+
"onMount(): with catched component, original element's onMount does NOT fire when error caused replacement": async () => {
|
|
3020
|
+
const container = setup();
|
|
3021
|
+
const logs = [];
|
|
3022
|
+
const broken = () => {
|
|
3023
|
+
throw new Error("boom");
|
|
3024
|
+
};
|
|
3025
|
+
app(
|
|
3026
|
+
container,
|
|
3027
|
+
{},
|
|
3028
|
+
() => [
|
|
3029
|
+
DIV,
|
|
3030
|
+
{
|
|
3031
|
+
catch: [
|
|
3032
|
+
ARTICLE,
|
|
3033
|
+
{
|
|
3034
|
+
onMount: (s, ele) => {
|
|
3035
|
+
logs.push("mount fallback");
|
|
3036
|
+
}
|
|
3037
|
+
},
|
|
3038
|
+
"fallback"
|
|
3039
|
+
]
|
|
3040
|
+
},
|
|
3041
|
+
[
|
|
3042
|
+
SECTION,
|
|
3043
|
+
{
|
|
3044
|
+
onMount: (s, ele) => {
|
|
3045
|
+
logs.push("mount original section");
|
|
3046
|
+
},
|
|
3047
|
+
onUnmount: (s, ele) => {
|
|
3048
|
+
logs.push("unmount original section");
|
|
3049
|
+
}
|
|
3050
|
+
},
|
|
3051
|
+
broken
|
|
3052
|
+
]
|
|
3053
|
+
]
|
|
3054
|
+
);
|
|
3055
|
+
await expect(logs).toEqual(["mount fallback"]);
|
|
3056
|
+
},
|
|
2945
3057
|
"onUnmount(): called when node is removed from the DOM": async () => {
|
|
2946
3058
|
const container = setup();
|
|
2947
3059
|
const unmounts = [];
|
|
@@ -3725,121 +3837,6 @@ var tests_mount_unmount_default = {
|
|
|
3725
3837
|
patch({ expanded: true, showB: false });
|
|
3726
3838
|
await expect(fired).toEqual(["unmount B"]);
|
|
3727
3839
|
},
|
|
3728
|
-
"onMount() + onUnmount: symmetry of calls": async () => {
|
|
3729
|
-
const container = setup();
|
|
3730
|
-
const state = createState({
|
|
3731
|
-
startTime: 0,
|
|
3732
|
-
inputReady: false,
|
|
3733
|
-
showInput: true,
|
|
3734
|
-
showTimer: true
|
|
3735
|
-
});
|
|
3736
|
-
const logs = [];
|
|
3737
|
-
const patch = app(
|
|
3738
|
-
container,
|
|
3739
|
-
state,
|
|
3740
|
-
(s) => {
|
|
3741
|
-
return [
|
|
3742
|
-
DIV,
|
|
3743
|
-
s.showInput && [INPUT, {
|
|
3744
|
-
type: "text",
|
|
3745
|
-
placeholder: "Auto-focused on mount",
|
|
3746
|
-
onMount: (s2, ele) => {
|
|
3747
|
-
logs.push("Input mounted");
|
|
3748
|
-
return { inputReady: true };
|
|
3749
|
-
},
|
|
3750
|
-
onUnmount: (s2, ele) => {
|
|
3751
|
-
logs.push("Input removed");
|
|
3752
|
-
return { inputReady: false };
|
|
3753
|
-
}
|
|
3754
|
-
}],
|
|
3755
|
-
s.showTimer && [P, {
|
|
3756
|
-
onMount: (s2, ele) => {
|
|
3757
|
-
logs.push("Timer started");
|
|
3758
|
-
return { startTime: Date.now() };
|
|
3759
|
-
},
|
|
3760
|
-
onUnmount: (s2, ele) => {
|
|
3761
|
-
logs.push("Timer removed");
|
|
3762
|
-
}
|
|
3763
|
-
}, "Mount/unmount lifecycle demo"]
|
|
3764
|
-
];
|
|
3765
|
-
}
|
|
3766
|
-
);
|
|
3767
|
-
await expect(state.inputReady).toEqual(true);
|
|
3768
|
-
await expect(state.startTime != 0).toEqual(true);
|
|
3769
|
-
patch({ showInput: false });
|
|
3770
|
-
await expect(
|
|
3771
|
-
async () => await expect(state.inputReady).toEqual(false, "expected: inputReady == false")
|
|
3772
|
-
).toSucceedAsync();
|
|
3773
|
-
patch({ showTimer: false });
|
|
3774
|
-
await expect(
|
|
3775
|
-
async () => await expect(container._vode.stats.syncRenderCount >= 4).toEqual(true)
|
|
3776
|
-
).toSucceedAsync();
|
|
3777
|
-
await expect(logs).toEqual([
|
|
3778
|
-
"Input mounted",
|
|
3779
|
-
"Timer started",
|
|
3780
|
-
"Input removed",
|
|
3781
|
-
"Timer removed"
|
|
3782
|
-
]);
|
|
3783
|
-
},
|
|
3784
|
-
"onMount(): with catched component, replacement vode's onMount fires when error occurs": async () => {
|
|
3785
|
-
const container = setup();
|
|
3786
|
-
const mounts = [];
|
|
3787
|
-
const broken = () => {
|
|
3788
|
-
throw new Error("boom");
|
|
3789
|
-
};
|
|
3790
|
-
app(
|
|
3791
|
-
container,
|
|
3792
|
-
{},
|
|
3793
|
-
() => [
|
|
3794
|
-
DIV,
|
|
3795
|
-
{
|
|
3796
|
-
catch: [
|
|
3797
|
-
SECTION,
|
|
3798
|
-
{
|
|
3799
|
-
onMount: (s, ele) => {
|
|
3800
|
-
mounts.push("mount fallback");
|
|
3801
|
-
}
|
|
3802
|
-
},
|
|
3803
|
-
"fallback"
|
|
3804
|
-
]
|
|
3805
|
-
},
|
|
3806
|
-
broken
|
|
3807
|
-
]
|
|
3808
|
-
);
|
|
3809
|
-
await expect(mounts).toEqual(["mount fallback"]);
|
|
3810
|
-
},
|
|
3811
|
-
"onMount(): with catched component, returned vode's onMount fires and receives error": async () => {
|
|
3812
|
-
const container = setup();
|
|
3813
|
-
const mounts = [];
|
|
3814
|
-
const caughtErrors = [];
|
|
3815
|
-
const broken = () => {
|
|
3816
|
-
throw new Error("boom");
|
|
3817
|
-
};
|
|
3818
|
-
app(
|
|
3819
|
-
container,
|
|
3820
|
-
{},
|
|
3821
|
-
() => [
|
|
3822
|
-
DIV,
|
|
3823
|
-
{
|
|
3824
|
-
catch: (s, err) => {
|
|
3825
|
-
caughtErrors.push(err.message);
|
|
3826
|
-
return [
|
|
3827
|
-
SECTION,
|
|
3828
|
-
{
|
|
3829
|
-
onMount: (s2, ele) => {
|
|
3830
|
-
mounts.push("mount fallback");
|
|
3831
|
-
}
|
|
3832
|
-
},
|
|
3833
|
-
"fallback"
|
|
3834
|
-
];
|
|
3835
|
-
}
|
|
3836
|
-
},
|
|
3837
|
-
broken
|
|
3838
|
-
]
|
|
3839
|
-
);
|
|
3840
|
-
await expect(mounts).toEqual(["mount fallback"]);
|
|
3841
|
-
await expect(caughtErrors).toEqual(["boom"]);
|
|
3842
|
-
},
|
|
3843
3840
|
"onUnmount(): with catched component, replacement vode's onUnmount fires when removed": async () => {
|
|
3844
3841
|
const container = setup();
|
|
3845
3842
|
const unmounts = [];
|
|
@@ -3923,7 +3920,7 @@ var tests_mount_unmount_default = {
|
|
|
3923
3920
|
patch({ show: false });
|
|
3924
3921
|
await expect(unmounts).toEqual(["unmount span", "unmount p", "unmount article"]);
|
|
3925
3922
|
},
|
|
3926
|
-
"onMount()
|
|
3923
|
+
"onMount() + onUnmount(): with catched component, full lifecycle symmetry of catch replacement": async () => {
|
|
3927
3924
|
const container = setup();
|
|
3928
3925
|
const logs = [];
|
|
3929
3926
|
const state = createState({ show: true });
|
|
@@ -3959,43 +3956,134 @@ var tests_mount_unmount_default = {
|
|
|
3959
3956
|
patch({ show: false });
|
|
3960
3957
|
await expect(logs).toEqual(["mount article", "unmount article"]);
|
|
3961
3958
|
},
|
|
3962
|
-
"onMount()
|
|
3959
|
+
"onMount() + onUnmount: symmetry of calls": async () => {
|
|
3963
3960
|
const container = setup();
|
|
3961
|
+
const state = createState({
|
|
3962
|
+
startTime: 0,
|
|
3963
|
+
inputReady: false,
|
|
3964
|
+
showInput: true,
|
|
3965
|
+
showTimer: true
|
|
3966
|
+
});
|
|
3964
3967
|
const logs = [];
|
|
3965
|
-
const
|
|
3966
|
-
throw new Error("boom");
|
|
3967
|
-
};
|
|
3968
|
-
app(
|
|
3968
|
+
const patch = app(
|
|
3969
3969
|
container,
|
|
3970
|
-
|
|
3971
|
-
() =>
|
|
3970
|
+
state,
|
|
3971
|
+
(s) => {
|
|
3972
|
+
return [
|
|
3973
|
+
DIV,
|
|
3974
|
+
s.showInput && [INPUT, {
|
|
3975
|
+
type: "text",
|
|
3976
|
+
placeholder: "Auto-focused on mount",
|
|
3977
|
+
onMount: (s2, ele) => {
|
|
3978
|
+
logs.push("Input mounted");
|
|
3979
|
+
return { inputReady: true };
|
|
3980
|
+
},
|
|
3981
|
+
onUnmount: (s2, ele) => {
|
|
3982
|
+
logs.push("Input removed");
|
|
3983
|
+
return { inputReady: false };
|
|
3984
|
+
}
|
|
3985
|
+
}],
|
|
3986
|
+
s.showTimer && [P, {
|
|
3987
|
+
onMount: (s2, ele) => {
|
|
3988
|
+
logs.push("Timer started");
|
|
3989
|
+
return { startTime: Date.now() };
|
|
3990
|
+
},
|
|
3991
|
+
onUnmount: (s2, ele) => {
|
|
3992
|
+
logs.push("Timer removed");
|
|
3993
|
+
}
|
|
3994
|
+
}, "Mount/unmount lifecycle demo"]
|
|
3995
|
+
];
|
|
3996
|
+
}
|
|
3997
|
+
);
|
|
3998
|
+
await expect(state.inputReady).toEqual(true);
|
|
3999
|
+
await expect(state.startTime != 0).toEqual(true);
|
|
4000
|
+
patch({ showInput: false });
|
|
4001
|
+
await expect(
|
|
4002
|
+
async () => await expect(state.inputReady).toEqual(false, "expected: inputReady == false")
|
|
4003
|
+
).toSucceedAsync();
|
|
4004
|
+
patch({ showTimer: false });
|
|
4005
|
+
await expect(
|
|
4006
|
+
async () => await expect(container._vode.stats.syncRenderCount >= 4).toEqual(true)
|
|
4007
|
+
).toSucceedAsync();
|
|
4008
|
+
await expect(logs).toEqual([
|
|
4009
|
+
"Input mounted",
|
|
4010
|
+
"Timer started",
|
|
4011
|
+
"Input removed",
|
|
4012
|
+
"Timer removed"
|
|
4013
|
+
]);
|
|
4014
|
+
},
|
|
4015
|
+
"onMount() + onUnmount(): Not called when DOM does not require element creation or removal (same TAGs)": async () => {
|
|
4016
|
+
const container = setup();
|
|
4017
|
+
const logs = [];
|
|
4018
|
+
const Comp = (name) => () => [
|
|
4019
|
+
ARTICLE,
|
|
4020
|
+
[
|
|
3972
4021
|
DIV,
|
|
3973
4022
|
{
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
{
|
|
3977
|
-
onMount: (s, ele) => {
|
|
3978
|
-
logs.push("mount fallback");
|
|
3979
|
-
}
|
|
3980
|
-
},
|
|
3981
|
-
"fallback"
|
|
3982
|
-
]
|
|
4023
|
+
onMount: () => logs.push("mount " + name),
|
|
4024
|
+
onUnmount: () => logs.push("unmount " + name)
|
|
3983
4025
|
},
|
|
4026
|
+
"Component " + name
|
|
4027
|
+
]
|
|
4028
|
+
];
|
|
4029
|
+
const state = createState({ showB: false, showD: false });
|
|
4030
|
+
app(container, state, (s) => [
|
|
4031
|
+
DIV,
|
|
4032
|
+
// this way they both "share a slot"
|
|
4033
|
+
s.showB ? Comp("B") : Comp("A"),
|
|
4034
|
+
// this way each component occupies its own "slot"
|
|
4035
|
+
!s.showD && Comp("C"),
|
|
4036
|
+
s.showD && Comp("D")
|
|
4037
|
+
]);
|
|
4038
|
+
await expect(container).toMatch(
|
|
4039
|
+
[
|
|
4040
|
+
DIV,
|
|
3984
4041
|
[
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
logs.push("unmount original section");
|
|
3992
|
-
}
|
|
3993
|
-
},
|
|
3994
|
-
broken
|
|
4042
|
+
ARTICLE,
|
|
4043
|
+
[DIV, "Component A"]
|
|
4044
|
+
],
|
|
4045
|
+
[
|
|
4046
|
+
ARTICLE,
|
|
4047
|
+
[DIV, "Component C"]
|
|
3995
4048
|
]
|
|
3996
4049
|
]
|
|
3997
4050
|
);
|
|
3998
|
-
await expect(logs).toEqual(["mount
|
|
4051
|
+
await expect(logs).toEqual(["mount A", "mount C"]);
|
|
4052
|
+
state.patch({ showB: true });
|
|
4053
|
+
await expect(container).toMatch(
|
|
4054
|
+
[
|
|
4055
|
+
DIV,
|
|
4056
|
+
[
|
|
4057
|
+
ARTICLE,
|
|
4058
|
+
[DIV, "Component B"]
|
|
4059
|
+
],
|
|
4060
|
+
[
|
|
4061
|
+
ARTICLE,
|
|
4062
|
+
[DIV, "Component C"]
|
|
4063
|
+
]
|
|
4064
|
+
]
|
|
4065
|
+
);
|
|
4066
|
+
await expect(logs).toEqual(["mount A", "mount C"]);
|
|
4067
|
+
state.patch({ showD: true });
|
|
4068
|
+
await expect(container).toMatch(
|
|
4069
|
+
[
|
|
4070
|
+
DIV,
|
|
4071
|
+
[
|
|
4072
|
+
ARTICLE,
|
|
4073
|
+
[DIV, "Component B"]
|
|
4074
|
+
],
|
|
4075
|
+
[
|
|
4076
|
+
ARTICLE,
|
|
4077
|
+
[DIV, "Component D"]
|
|
4078
|
+
]
|
|
4079
|
+
]
|
|
4080
|
+
);
|
|
4081
|
+
await expect(logs).toEqual([
|
|
4082
|
+
"mount A",
|
|
4083
|
+
"mount C",
|
|
4084
|
+
"unmount C",
|
|
4085
|
+
"mount D"
|
|
4086
|
+
]);
|
|
3999
4087
|
}
|
|
4000
4088
|
};
|
|
4001
4089
|
|
|
@@ -5189,8 +5277,11 @@ var tests_patch_advanced_default = {
|
|
|
5189
5277
|
app(container, state, (s) => [DIV, s.phase, String(s.value)]);
|
|
5190
5278
|
await expect(state.phase).toEqual("start");
|
|
5191
5279
|
state.patch((async function* () {
|
|
5280
|
+
await expect(container._vode.stats.syncRenderPatchCount).toEqual(0);
|
|
5192
5281
|
yield { phase: "working", value: 10 };
|
|
5282
|
+
await expect(container._vode.stats.syncRenderPatchCount).toEqual(1);
|
|
5193
5283
|
yield { phase: "almost", value: 20 };
|
|
5284
|
+
await expect(container._vode.stats.syncRenderPatchCount).toEqual(2);
|
|
5194
5285
|
return { phase: "done", value: 30 };
|
|
5195
5286
|
})());
|
|
5196
5287
|
await new Promise((r) => setTimeout(r, 0));
|
|
@@ -5223,6 +5314,87 @@ var tests_patch_advanced_default = {
|
|
|
5223
5314
|
await delay(10);
|
|
5224
5315
|
await expect(state.x).toEqual(10);
|
|
5225
5316
|
await expect(state.y).toEqual(20);
|
|
5317
|
+
},
|
|
5318
|
+
"patch(): returns Promise for generator functions, can be awaited": async () => {
|
|
5319
|
+
const container = setup4();
|
|
5320
|
+
const state = createState({ count: 0 });
|
|
5321
|
+
app(container, state, (s) => [DIV, String(s.count)]);
|
|
5322
|
+
await expect(container._vode.stats.patchCount).toEqual(0);
|
|
5323
|
+
const result = state.patch(function* () {
|
|
5324
|
+
yield { count: 1 };
|
|
5325
|
+
return { count: 2 };
|
|
5326
|
+
});
|
|
5327
|
+
await expect(container._vode.stats.patchCount).toEqual(1);
|
|
5328
|
+
expect(result).toBeA("object");
|
|
5329
|
+
await expect(result instanceof Promise).toEqual(true);
|
|
5330
|
+
await result;
|
|
5331
|
+
await expect(container._vode.stats.patchCount).toEqual(3);
|
|
5332
|
+
await expect(state.count).toEqual(2);
|
|
5333
|
+
await expect(container).toMatch([DIV, "2"]);
|
|
5334
|
+
},
|
|
5335
|
+
"patch(): returns Promise for Promise patches, can be awaited": async () => {
|
|
5336
|
+
const container = setup4();
|
|
5337
|
+
const state = createState({ msg: "before" });
|
|
5338
|
+
app(container, state, (s) => [DIV, s.msg]);
|
|
5339
|
+
const result = state.patch(Promise.resolve({ msg: "after" }));
|
|
5340
|
+
expect(result).toBeA("object");
|
|
5341
|
+
await expect(result instanceof Promise).toEqual(true);
|
|
5342
|
+
await result;
|
|
5343
|
+
await expect(state.msg).toEqual("after");
|
|
5344
|
+
await expect(container).toMatch([DIV, "after"]);
|
|
5345
|
+
},
|
|
5346
|
+
"patch(): returns void for object patches": async () => {
|
|
5347
|
+
const container = setup4();
|
|
5348
|
+
const state = createState({ x: 1 });
|
|
5349
|
+
app(container, state, (s) => [DIV, String(s.x)]);
|
|
5350
|
+
const result = state.patch({ x: 2 });
|
|
5351
|
+
expect(result).toBeA("undefined");
|
|
5352
|
+
await expect(state.x).toEqual(2);
|
|
5353
|
+
await expect(container).toMatch([DIV, "2"]);
|
|
5354
|
+
},
|
|
5355
|
+
"patch(): forward promise error when one happens during patch": async () => {
|
|
5356
|
+
const container = setup4();
|
|
5357
|
+
const state = createState({ msg: "before" });
|
|
5358
|
+
app(container, state, (s) => [DIV, s.msg]);
|
|
5359
|
+
const mockPromise = Promise.withResolvers();
|
|
5360
|
+
const promisePatchResult = state.patch(mockPromise.promise);
|
|
5361
|
+
mockPromise.reject(new Error("promise error"));
|
|
5362
|
+
let err = await expect(() => promisePatchResult).toFailAsync("promise (1) error expected");
|
|
5363
|
+
expect(err.message).toEqual("promise error");
|
|
5364
|
+
err = await expect(() => state.patch(async () => {
|
|
5365
|
+
await delay(1);
|
|
5366
|
+
throw new Error("promise error");
|
|
5367
|
+
})).toFailAsync("promise (2) error expected");
|
|
5368
|
+
expect(err.message).toEqual("promise error");
|
|
5369
|
+
},
|
|
5370
|
+
"patch(): forward generator error when one happens during patch": async () => {
|
|
5371
|
+
const container = setup4();
|
|
5372
|
+
const state = createState({ msg: "before" });
|
|
5373
|
+
app(container, state, (s) => [DIV, s.msg]);
|
|
5374
|
+
const err = await expect(
|
|
5375
|
+
() => state.patch(
|
|
5376
|
+
async function* () {
|
|
5377
|
+
yield {};
|
|
5378
|
+
await delay(1);
|
|
5379
|
+
yield {};
|
|
5380
|
+
throw new Error("generator error");
|
|
5381
|
+
}
|
|
5382
|
+
)
|
|
5383
|
+
).toFailAsync("generator error expected");
|
|
5384
|
+
expect(err.message).toEqual("generator error");
|
|
5385
|
+
},
|
|
5386
|
+
"patch(): forward error when one happens during patch": async () => {
|
|
5387
|
+
const container = setup4();
|
|
5388
|
+
const state = createState({ msg: "before" });
|
|
5389
|
+
app(container, state, (s) => [DIV, s.msg]);
|
|
5390
|
+
const err = await expect(
|
|
5391
|
+
() => state.patch(
|
|
5392
|
+
() => {
|
|
5393
|
+
throw new Error("void error");
|
|
5394
|
+
}
|
|
5395
|
+
)
|
|
5396
|
+
).toFailAsync("void error expected");
|
|
5397
|
+
expect(err.message).toEqual("void error");
|
|
5226
5398
|
}
|
|
5227
5399
|
};
|
|
5228
5400
|
|
package/log.txt
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npm warn gitignore-fallback No .npmignore file found, using .gitignore for file exclusion. Consider creating a .npmignore file to explicitly control published files.
|