@domql/element 3.0.7 → 3.1.2
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/__tests__/inheritStateUpdates.test.js +1 -1
- package/__tests__/throughExecProps.test.js +12 -12
- package/__tests__/throughInitialDefine.test.js +16 -16
- package/__tests__/throughInitialExec.test.js +16 -16
- package/__tests__/throughUpdatedDefine.test.js +14 -14
- package/__tests__/update.test.js +11 -8
- package/create.js +1 -10
- package/dist/cjs/__tests__/checkIfOnUpdate.test.js +73 -0
- package/dist/cjs/__tests__/children.test.js +177 -0
- package/dist/cjs/__tests__/define.test.js +75 -0
- package/dist/cjs/__tests__/inheritStateUpdates.test.js +62 -0
- package/dist/cjs/__tests__/renderElement.test.js +138 -0
- package/dist/cjs/__tests__/resetElement.test.js +35 -0
- package/dist/cjs/__tests__/set.test.js +256 -0
- package/dist/cjs/__tests__/throughExecProps.test.js +62 -0
- package/dist/cjs/__tests__/throughInitialDefine.test.js +79 -0
- package/dist/cjs/__tests__/throughInitialExec.test.js +73 -0
- package/dist/cjs/__tests__/throughUpdatedDefine.test.js +69 -0
- package/dist/cjs/__tests__/throughUpdatedExec.test.js +84 -0
- package/dist/cjs/__tests__/tree.test.js +11 -0
- package/dist/cjs/__tests__/update.test.js +222 -0
- package/dist/cjs/create.js +2 -11
- package/dist/cjs/iterate.js +11 -11
- package/dist/cjs/update.js +3 -2
- package/dist/esm/__tests__/checkIfOnUpdate.test.js +73 -0
- package/dist/esm/__tests__/children.test.js +177 -0
- package/dist/esm/__tests__/define.test.js +53 -0
- package/dist/esm/__tests__/inheritStateUpdates.test.js +62 -0
- package/dist/esm/__tests__/renderElement.test.js +116 -0
- package/dist/esm/__tests__/resetElement.test.js +35 -0
- package/dist/esm/__tests__/set.test.js +256 -0
- package/dist/esm/__tests__/throughExecProps.test.js +62 -0
- package/dist/esm/__tests__/throughInitialDefine.test.js +79 -0
- package/dist/esm/__tests__/throughInitialExec.test.js +73 -0
- package/dist/esm/__tests__/throughUpdatedDefine.test.js +69 -0
- package/dist/esm/__tests__/throughUpdatedExec.test.js +84 -0
- package/dist/esm/__tests__/tree.test.js +11 -0
- package/dist/esm/__tests__/update.test.js +222 -0
- package/dist/esm/create.js +2 -11
- package/dist/esm/iterate.js +13 -12
- package/dist/esm/update.js +5 -4
- package/iterate.js +13 -12
- package/package.json +11 -12
- package/update.js +6 -4
- package/dist/cjs/utils/onlyResolveExtends.js +0 -85
- package/dist/esm/utils/onlyResolveExtends.js +0 -72
- package/utils/onlyResolveExtends.js +0 -128
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
var import_update = require("../update");
|
|
2
|
+
describe("update()", () => {
|
|
3
|
+
let element, params, opts;
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
element = {
|
|
6
|
+
__ref: {
|
|
7
|
+
__if: true,
|
|
8
|
+
__execProps: {},
|
|
9
|
+
__exec: {},
|
|
10
|
+
__defineCache: {},
|
|
11
|
+
__propsStack: [],
|
|
12
|
+
__props: [],
|
|
13
|
+
__state: "state"
|
|
14
|
+
},
|
|
15
|
+
state: "string",
|
|
16
|
+
props: {},
|
|
17
|
+
parent: {
|
|
18
|
+
props: {}
|
|
19
|
+
},
|
|
20
|
+
context: {},
|
|
21
|
+
define: {},
|
|
22
|
+
node: document.createElement("div"),
|
|
23
|
+
key: "testElement",
|
|
24
|
+
on: {},
|
|
25
|
+
update: import_update.update
|
|
26
|
+
};
|
|
27
|
+
opts = {
|
|
28
|
+
preventUpdate: [],
|
|
29
|
+
preventDefineUpdate: [],
|
|
30
|
+
preventBeforeStateUpdateListener: false,
|
|
31
|
+
preventListeners: false,
|
|
32
|
+
preventStateUpdateListener: false
|
|
33
|
+
};
|
|
34
|
+
params = {};
|
|
35
|
+
});
|
|
36
|
+
it("does not modify opts when params and opts are empty", async () => {
|
|
37
|
+
await element.update({}, opts);
|
|
38
|
+
expect(opts).toEqual({
|
|
39
|
+
calleeElement: false,
|
|
40
|
+
cleanExec: true,
|
|
41
|
+
currentSnapshot: false,
|
|
42
|
+
exclude: [],
|
|
43
|
+
preventRecursive: false,
|
|
44
|
+
stackChanges: false,
|
|
45
|
+
preventUpdate: [],
|
|
46
|
+
preventDefineUpdate: [],
|
|
47
|
+
preventBeforeStateUpdateListener: false,
|
|
48
|
+
preventListeners: false,
|
|
49
|
+
preventStateUpdateListener: false
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
it("initializes options with UPDATE_DEFAULT_OPTIONS when opts is empty", async () => {
|
|
53
|
+
await element.update({}, opts);
|
|
54
|
+
expect(opts.calleeElement).toBe(false);
|
|
55
|
+
expect(element.__ref).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
it("merges opts with UPDATE_DEFAULT_OPTIONS using deepMerge", async () => {
|
|
58
|
+
opts.customOption = true;
|
|
59
|
+
await element.update({}, opts);
|
|
60
|
+
expect(opts.customOption).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
it("converts string params to { text: params }", async () => {
|
|
63
|
+
await element.update("testString", opts);
|
|
64
|
+
expect(element.text).toBe("testString");
|
|
65
|
+
});
|
|
66
|
+
it("converts number params to { text: params }", async () => {
|
|
67
|
+
await element.update(123, opts);
|
|
68
|
+
expect(element.text).toBe(123);
|
|
69
|
+
});
|
|
70
|
+
it("returns early if preventInheritAtCurrentState matches element", async () => {
|
|
71
|
+
opts.preventInheritAtCurrentState = { __element: element };
|
|
72
|
+
await element.update({}, opts);
|
|
73
|
+
expect(element.__ref.__currentSnapshot).toBe(6);
|
|
74
|
+
});
|
|
75
|
+
it("initializes __ref if not present", async () => {
|
|
76
|
+
delete element.__ref;
|
|
77
|
+
await element.update({}, opts);
|
|
78
|
+
expect(element.__ref).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
it("merges options with UPDATE_DEFAULT_OPTIONS when exclude is missing", async () => {
|
|
81
|
+
await element.update({}, opts);
|
|
82
|
+
expect(opts.exclude).toBeDefined();
|
|
83
|
+
});
|
|
84
|
+
it("does not throw or modify opts when params is undefined", async () => {
|
|
85
|
+
await element.update(void 0, opts);
|
|
86
|
+
expect(opts).toEqual({
|
|
87
|
+
calleeElement: false,
|
|
88
|
+
cleanExec: true,
|
|
89
|
+
currentSnapshot: false,
|
|
90
|
+
exclude: [],
|
|
91
|
+
preventRecursive: false,
|
|
92
|
+
preventUpdate: [],
|
|
93
|
+
preventDefineUpdate: [],
|
|
94
|
+
stackChanges: false,
|
|
95
|
+
preventBeforeStateUpdateListener: false,
|
|
96
|
+
preventListeners: false,
|
|
97
|
+
preventStateUpdateListener: false
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it("does not throw when opts is undefined", async () => {
|
|
101
|
+
await element.update({}, void 0);
|
|
102
|
+
expect(element.__ref).toBeDefined();
|
|
103
|
+
});
|
|
104
|
+
it("does not throw when opts is null", async () => {
|
|
105
|
+
await element.update({}, null);
|
|
106
|
+
expect(element.__ref).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
it("does not modify the params object", async () => {
|
|
109
|
+
params = { key: "value" };
|
|
110
|
+
await element.update(params, opts);
|
|
111
|
+
expect(params).toEqual({ key: "value" });
|
|
112
|
+
});
|
|
113
|
+
it("does modify opts when params is an empty object", async () => {
|
|
114
|
+
await element.update({}, opts);
|
|
115
|
+
expect(opts).toEqual({
|
|
116
|
+
calleeElement: false,
|
|
117
|
+
cleanExec: true,
|
|
118
|
+
currentSnapshot: false,
|
|
119
|
+
exclude: [],
|
|
120
|
+
preventRecursive: false,
|
|
121
|
+
stackChanges: false,
|
|
122
|
+
preventUpdate: [],
|
|
123
|
+
preventDefineUpdate: [],
|
|
124
|
+
preventBeforeStateUpdateListener: false,
|
|
125
|
+
preventListeners: false,
|
|
126
|
+
preventStateUpdateListener: false
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
it("moves regular properties to element.props", async () => {
|
|
130
|
+
params = { props: { title: "Test", description: "Content" } };
|
|
131
|
+
await element.update(params, opts);
|
|
132
|
+
expect(element.props).toEqual({
|
|
133
|
+
title: "Test",
|
|
134
|
+
description: "Content"
|
|
135
|
+
});
|
|
136
|
+
expect(element.title).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
it("keeps element-rooted properties", async () => {
|
|
139
|
+
params = { Header: {}, Footer: {}, 0: "index" };
|
|
140
|
+
await element.update(params, opts);
|
|
141
|
+
expect(element.Header).toBeDefined();
|
|
142
|
+
expect(element.Footer).toBeDefined();
|
|
143
|
+
expect(element["0"]).toBe("index");
|
|
144
|
+
expect(element.props).toEqual({});
|
|
145
|
+
});
|
|
146
|
+
it("preserves built-in properties on element", async () => {
|
|
147
|
+
params = { props: { className: "container", hidden: true } };
|
|
148
|
+
await element.update(params, opts);
|
|
149
|
+
expect(element.props.className).toBe("container");
|
|
150
|
+
expect(element.props.hidden).toBe(true);
|
|
151
|
+
expect(element.props).toEqual({ className: "container", hidden: true });
|
|
152
|
+
});
|
|
153
|
+
it("moves element-like properties from props to root", async () => {
|
|
154
|
+
params = { props: { Header: {} } };
|
|
155
|
+
await element.update(params, opts);
|
|
156
|
+
expect(element.Header).toBeDefined();
|
|
157
|
+
expect(element.props.Header).toBeUndefined();
|
|
158
|
+
});
|
|
159
|
+
it("exits early when inheritStateUpdates returns false", async () => {
|
|
160
|
+
element.__ref.__stateBlocked = true;
|
|
161
|
+
await element.update({ props: { shouldChange: true } }, opts);
|
|
162
|
+
expect(element.props.shouldChange).toBe(true);
|
|
163
|
+
expect(element.__ref.__stateBlocked).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
it("exits early when checkIfOnUpdate fails", async () => {
|
|
166
|
+
element.parent.props.ifCondition = false;
|
|
167
|
+
await element.update({ state: { newState: true } }, opts);
|
|
168
|
+
expect(element.state.newState).toBe(true);
|
|
169
|
+
});
|
|
170
|
+
it("updates props from parent key match", async () => {
|
|
171
|
+
element.parent.props.testKey = { inherited: true };
|
|
172
|
+
await element.update({}, opts);
|
|
173
|
+
expect(element.props.inherited).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
it("updates props when functions exist in __props", async () => {
|
|
176
|
+
element.__ref.__props.push(() => "dynamic");
|
|
177
|
+
await element.update({}, opts);
|
|
178
|
+
expect(element.props).toEqual(expect.any(Object));
|
|
179
|
+
});
|
|
180
|
+
it("skips props update when preventPropsUpdate=true", async () => {
|
|
181
|
+
opts.preventPropsUpdate = true;
|
|
182
|
+
opts.preventUpdateAfter = true;
|
|
183
|
+
element.parent.props.testKey = { shouldExist: true };
|
|
184
|
+
await element.update({}, opts);
|
|
185
|
+
expect(element.props.shouldExist).toBeUndefined();
|
|
186
|
+
});
|
|
187
|
+
it("should not skips props update when preventPropsUpdate=false", async () => {
|
|
188
|
+
opts.preventPropsUpdate = false;
|
|
189
|
+
opts.lazyLoad = true;
|
|
190
|
+
opts.onEachUpdate = () => {
|
|
191
|
+
return true;
|
|
192
|
+
};
|
|
193
|
+
element.parent.props.testKey = { shouldExist: true };
|
|
194
|
+
element.__ref.__propsStack = [];
|
|
195
|
+
element.__ref.__if = true;
|
|
196
|
+
element.off = { text: "off" };
|
|
197
|
+
await element.update({}, opts);
|
|
198
|
+
expect(element.props.shouldExist).toBeUndefined();
|
|
199
|
+
});
|
|
200
|
+
it("should set preventUpdateAfterCount to 1 when is not a number", async () => {
|
|
201
|
+
opts.preventPropsUpdate = true;
|
|
202
|
+
opts.preventUpdateAfter = 2;
|
|
203
|
+
opts.preventUpdateAfterCount = void 0;
|
|
204
|
+
element.parent.props.testKey = { shouldExist: true };
|
|
205
|
+
await element.update({}, opts);
|
|
206
|
+
expect(element.props.shouldExist).toBeUndefined();
|
|
207
|
+
});
|
|
208
|
+
it("processes parent.childProps", async () => {
|
|
209
|
+
element.parent.props.childProps = { global: true };
|
|
210
|
+
await element.update({}, opts);
|
|
211
|
+
expect(element.props.global).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
it("processes function props", async () => {
|
|
214
|
+
await element.update({ props: { calc: () => 42 } }, opts);
|
|
215
|
+
expect(element.props.calc()).toBe(42);
|
|
216
|
+
});
|
|
217
|
+
it("returns element when beforeUpdate rejects", async () => {
|
|
218
|
+
element.on.beforeUpdate = () => false;
|
|
219
|
+
const result = await element.update({}, opts);
|
|
220
|
+
expect(result).toBe(element);
|
|
221
|
+
});
|
|
222
|
+
});
|
package/dist/cjs/create.js
CHANGED
|
@@ -40,7 +40,7 @@ const create = async (props, parentEl, passedKey, options = import_utils.OPTIONS
|
|
|
40
40
|
const { key, parent, __ref: ref } = element;
|
|
41
41
|
(0, import_utils.createRoot)(element, parent);
|
|
42
42
|
(0, import_utils.applyExtends)(element, parent, options);
|
|
43
|
-
|
|
43
|
+
import_utils.propertizeElement.call(element, element);
|
|
44
44
|
await (0, import_event.triggerEventOn)("start", element, options);
|
|
45
45
|
if (options.onlyResolveExtends) {
|
|
46
46
|
return onlyResolveExtends(element, parent, key, options);
|
|
@@ -87,7 +87,7 @@ const addElementIntoParentChildren = (element, parent) => {
|
|
|
87
87
|
};
|
|
88
88
|
const visitedElements = /* @__PURE__ */ new WeakMap();
|
|
89
89
|
const renderElement = async (element, parent, options, attachOptions) => {
|
|
90
|
-
var _a, _b, _c
|
|
90
|
+
var _a, _b, _c;
|
|
91
91
|
if (visitedElements.has(element)) {
|
|
92
92
|
if (ENV === "test" || ENV === "development") {
|
|
93
93
|
console.warn("Cyclic rendering detected:", element.__ref.path);
|
|
@@ -124,15 +124,6 @@ const renderElement = async (element, parent, options, attachOptions) => {
|
|
|
124
124
|
if ((_c = element.on) == null ? void 0 : _c.error) {
|
|
125
125
|
element.on.error(e, element, element.state, element.context, options);
|
|
126
126
|
}
|
|
127
|
-
if ((_d = element.props) == null ? void 0 : _d.onError) {
|
|
128
|
-
element.props.onError(
|
|
129
|
-
e,
|
|
130
|
-
element,
|
|
131
|
-
element.state,
|
|
132
|
-
element.context,
|
|
133
|
-
options
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
127
|
}
|
|
137
128
|
}
|
|
138
129
|
if (!ref.__if) {
|
package/dist/cjs/iterate.js
CHANGED
|
@@ -27,14 +27,14 @@ __export(iterate_exports, {
|
|
|
27
27
|
});
|
|
28
28
|
module.exports = __toCommonJS(iterate_exports);
|
|
29
29
|
var import_utils = require("@domql/utils");
|
|
30
|
-
const throughInitialExec = (element, exclude = {}) => {
|
|
30
|
+
const throughInitialExec = async (element, exclude = {}) => {
|
|
31
31
|
const { __ref: ref } = element;
|
|
32
32
|
for (const param in element) {
|
|
33
33
|
if (exclude[param]) continue;
|
|
34
34
|
const prop = element[param];
|
|
35
35
|
if ((0, import_utils.isFunction)(prop) && !(0, import_utils.isMethod)(param, element)) {
|
|
36
36
|
ref.__exec[param] = prop;
|
|
37
|
-
element[param] = prop(element, element.state, element.context);
|
|
37
|
+
element[param] = await prop(element, element.state, element.context);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
};
|
|
@@ -65,23 +65,23 @@ const throughUpdatedExec = (element, options = {}) => {
|
|
|
65
65
|
}
|
|
66
66
|
return changes;
|
|
67
67
|
};
|
|
68
|
-
const throughExecProps = (element) => {
|
|
68
|
+
const throughExecProps = async (element) => {
|
|
69
69
|
const { __ref: ref } = element;
|
|
70
70
|
const { props } = element;
|
|
71
71
|
for (const k in props) {
|
|
72
72
|
const isDefine = k.startsWith("is") || k.startsWith("has") || k.startsWith("use");
|
|
73
73
|
const cachedExecProp = ref.__execProps[k];
|
|
74
74
|
if ((0, import_utils.isFunction)(cachedExecProp)) {
|
|
75
|
-
props[k] = (0, import_utils.
|
|
75
|
+
props[k] = await (0, import_utils.execPromise)(cachedExecProp, element);
|
|
76
76
|
} else if (isDefine && (0, import_utils.isFunction)(props[k])) {
|
|
77
77
|
ref.__execProps[k] = props[k];
|
|
78
|
-
props[k] = (0, import_utils.
|
|
78
|
+
props[k] = await (0, import_utils.execPromise)(props[k], element);
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
};
|
|
82
82
|
const isPropertyInDefines = (key, element) => {
|
|
83
83
|
};
|
|
84
|
-
const throughInitialDefine = (element) => {
|
|
84
|
+
const throughInitialDefine = async (element) => {
|
|
85
85
|
const { define, context, __ref: ref } = element;
|
|
86
86
|
let defineObj = {};
|
|
87
87
|
const hasGlobalDefine = context && (0, import_utils.isObject)(context.define);
|
|
@@ -91,13 +91,13 @@ const throughInitialDefine = (element) => {
|
|
|
91
91
|
let elementProp = element[param];
|
|
92
92
|
if ((0, import_utils.isFunction)(elementProp) && !(0, import_utils.isMethod)(param, element)) {
|
|
93
93
|
ref.__exec[param] = elementProp;
|
|
94
|
-
const execParam2 = elementProp = (0, import_utils.
|
|
94
|
+
const execParam2 = elementProp = await (0, import_utils.execPromise)(elementProp, element);
|
|
95
95
|
if (execParam2) {
|
|
96
96
|
elementProp = element[param] = execParam2.parse ? execParam2.parse() : execParam2;
|
|
97
97
|
ref.__defineCache[param] = elementProp;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
const execParam = defineObj[param](
|
|
100
|
+
const execParam = await defineObj[param](
|
|
101
101
|
elementProp,
|
|
102
102
|
element,
|
|
103
103
|
element.state,
|
|
@@ -107,7 +107,7 @@ const throughInitialDefine = (element) => {
|
|
|
107
107
|
}
|
|
108
108
|
return element;
|
|
109
109
|
};
|
|
110
|
-
const throughUpdatedDefine = (element) => {
|
|
110
|
+
const throughUpdatedDefine = async (element) => {
|
|
111
111
|
const { context, define, __ref: ref } = element;
|
|
112
112
|
const changes = {};
|
|
113
113
|
let obj = {};
|
|
@@ -116,13 +116,13 @@ const throughUpdatedDefine = (element) => {
|
|
|
116
116
|
for (const param in obj) {
|
|
117
117
|
const execParam = ref.__exec[param];
|
|
118
118
|
if (execParam) {
|
|
119
|
-
ref.__defineCache[param] = execParam(
|
|
119
|
+
ref.__defineCache[param] = await execParam(
|
|
120
120
|
element,
|
|
121
121
|
element.state,
|
|
122
122
|
element.context
|
|
123
123
|
);
|
|
124
124
|
}
|
|
125
|
-
const cached = (0, import_utils.
|
|
125
|
+
const cached = await (0, import_utils.execPromise)(ref.__defineCache[param], element);
|
|
126
126
|
const newExecParam = typeof obj[param] === "function" ? obj[param](cached, element, element.state, element.context) : void 0;
|
|
127
127
|
if (newExecParam) element[param] = newExecParam;
|
|
128
128
|
}
|
package/dist/cjs/update.js
CHANGED
|
@@ -77,7 +77,7 @@ const update = async function(params = {}, opts) {
|
|
|
77
77
|
if ((0, import_utils.isString)(params) || (0, import_utils.isNumber)(params)) {
|
|
78
78
|
params = { text: params };
|
|
79
79
|
}
|
|
80
|
-
params = (
|
|
80
|
+
params = import_utils.propertizeUpdate.call(element, params);
|
|
81
81
|
const inheritState = await inheritStateUpdates(element, options);
|
|
82
82
|
if (inheritState === false) return;
|
|
83
83
|
const ifFails = await checkIfOnUpdate(element, parent, options);
|
|
@@ -89,10 +89,11 @@ const update = async function(params = {}, opts) {
|
|
|
89
89
|
if (props) (0, import_utils.updateProps)(props, element, parent);
|
|
90
90
|
}
|
|
91
91
|
if (!options.preventBeforeUpdateListener && !options.preventListeners) {
|
|
92
|
+
const simulate = { ...params, ...element };
|
|
92
93
|
const beforeUpdateReturns = await (0, import_event.triggerEventOnUpdate)(
|
|
93
94
|
"beforeUpdate",
|
|
94
95
|
params,
|
|
95
|
-
|
|
96
|
+
simulate,
|
|
96
97
|
options
|
|
97
98
|
);
|
|
98
99
|
if (beforeUpdateReturns === false) return element;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { update } from "../update";
|
|
2
|
+
describe("checkIfOnUpdate via update()", () => {
|
|
3
|
+
let element, parent, options;
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
parent = {
|
|
6
|
+
node: document.createElement("div"),
|
|
7
|
+
props: {},
|
|
8
|
+
state: {}
|
|
9
|
+
};
|
|
10
|
+
element = {
|
|
11
|
+
__ref: {
|
|
12
|
+
__if: void 0,
|
|
13
|
+
__state: null,
|
|
14
|
+
__hasRootState: false,
|
|
15
|
+
__execProps: {},
|
|
16
|
+
contentElementKey: "content"
|
|
17
|
+
},
|
|
18
|
+
parent,
|
|
19
|
+
props: {},
|
|
20
|
+
state: {
|
|
21
|
+
update: (el, st) => {
|
|
22
|
+
return st;
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
context: {
|
|
26
|
+
defaultExtends: {}
|
|
27
|
+
},
|
|
28
|
+
node: document.createElement("div"),
|
|
29
|
+
if: () => true,
|
|
30
|
+
previousElement: () => {
|
|
31
|
+
return {};
|
|
32
|
+
},
|
|
33
|
+
nextElement: () => {
|
|
34
|
+
return {};
|
|
35
|
+
},
|
|
36
|
+
removeContent: () => {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
options = {};
|
|
41
|
+
});
|
|
42
|
+
it("uses props.if when element.if missing", async () => {
|
|
43
|
+
delete element.if;
|
|
44
|
+
element.props.if = () => false;
|
|
45
|
+
await update.call(element, {}, options);
|
|
46
|
+
expect(element.node).toEqual(document.createElement("div"));
|
|
47
|
+
});
|
|
48
|
+
it("retains state when __hasRootState=true", async () => {
|
|
49
|
+
element.__ref.__hasRootState = true;
|
|
50
|
+
element.state.critical = true;
|
|
51
|
+
element.__ref.__if = false;
|
|
52
|
+
await update.call(element, {}, options);
|
|
53
|
+
expect(element.state.critical).toBe(true);
|
|
54
|
+
expect(element.state.preserved).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
it("processes nested content with parseDeep", async () => {
|
|
57
|
+
element.content = {
|
|
58
|
+
parseDeep: () => ({ parsed: true }),
|
|
59
|
+
existing: "data"
|
|
60
|
+
};
|
|
61
|
+
await update.call(element, {}, options);
|
|
62
|
+
expect(element.content.parsed).toBe(true);
|
|
63
|
+
expect(element.content.existing).toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
it("reattaches after previous sibling", async () => {
|
|
66
|
+
const prevNode = document.createElement("span");
|
|
67
|
+
parent.node.appendChild(prevNode);
|
|
68
|
+
await update.call(element, {}, options);
|
|
69
|
+
const newElement = parent.node.children[0];
|
|
70
|
+
expect(newElement).toEqual(document.createElement("span"));
|
|
71
|
+
expect(newElement.previousSibling).toBe(null);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { jest } from "@jest/globals";
|
|
2
|
+
import { setChildren } from "../children";
|
|
3
|
+
describe("children", () => {
|
|
4
|
+
let element, node;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
element = {
|
|
7
|
+
__ref: {},
|
|
8
|
+
state: {},
|
|
9
|
+
props: {},
|
|
10
|
+
call: jest.fn(),
|
|
11
|
+
removeContent: jest.fn(),
|
|
12
|
+
content: null
|
|
13
|
+
};
|
|
14
|
+
node = {};
|
|
15
|
+
});
|
|
16
|
+
it("handles null/undefined params", async () => {
|
|
17
|
+
const result = await setChildren(null, element, node);
|
|
18
|
+
expect(result).toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
it("handles direct string children", async () => {
|
|
21
|
+
const result = await setChildren("Hello World", element, node);
|
|
22
|
+
expect(result).toEqual({ tag: "fragment", 0: { text: "Hello World" } });
|
|
23
|
+
});
|
|
24
|
+
it("handles numeric children", async () => {
|
|
25
|
+
const result = await setChildren(42, element, node);
|
|
26
|
+
expect(result).toEqual({ tag: "fragment", 0: { text: 42 } });
|
|
27
|
+
});
|
|
28
|
+
it("handles array of primitive values with childrenAs prop", async () => {
|
|
29
|
+
const result = await setChildren(["one", "two"], element, node);
|
|
30
|
+
expect(result).toEqual({
|
|
31
|
+
tag: "fragment",
|
|
32
|
+
0: { text: "one" },
|
|
33
|
+
1: { text: "two" }
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
it("handles array of primitive values with childrenAs state", async () => {
|
|
37
|
+
element.props.childrenAs = "state";
|
|
38
|
+
const result = await setChildren(["one", "two"], element, node);
|
|
39
|
+
expect(result).toEqual({
|
|
40
|
+
tag: "fragment",
|
|
41
|
+
0: { state: { value: "one" } },
|
|
42
|
+
1: { state: { value: "two" } }
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
it("caches children and detects changes", async () => {
|
|
46
|
+
const children1 = [{ id: 1 }, { id: 2 }];
|
|
47
|
+
const children2 = [{ id: 1 }, { id: 2 }];
|
|
48
|
+
const children3 = [{ id: 1 }, { id: 3 }];
|
|
49
|
+
await setChildren(children1, element, node);
|
|
50
|
+
expect(element.__ref.__childrenCache).toEqual(children1);
|
|
51
|
+
expect(element.__ref.__noChildrenDifference).toBeUndefined();
|
|
52
|
+
await setChildren(children2, element, node);
|
|
53
|
+
expect(element.__ref.__noChildrenDifference).toBe(true);
|
|
54
|
+
await setChildren(children3, element, node);
|
|
55
|
+
expect(element.__ref.__noChildrenDifference).toBeUndefined();
|
|
56
|
+
expect(element.__ref.__childrenCache).toEqual(children3);
|
|
57
|
+
});
|
|
58
|
+
it("handles mixed React and normal components", async () => {
|
|
59
|
+
const mixedChildren = [
|
|
60
|
+
{ type: "div", text: "Normal" },
|
|
61
|
+
{ $$typeof: Symbol("react") },
|
|
62
|
+
{ type: "span", text: "Another" }
|
|
63
|
+
];
|
|
64
|
+
await setChildren(mixedChildren, element, node);
|
|
65
|
+
expect(element.call).toHaveBeenCalledWith(
|
|
66
|
+
"renderReact",
|
|
67
|
+
[mixedChildren[1]],
|
|
68
|
+
element
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
it("handles state-based children", async () => {
|
|
72
|
+
element.state = {
|
|
73
|
+
items: ["a", "b"],
|
|
74
|
+
parse: () => ["parsed a", "parsed b"]
|
|
75
|
+
};
|
|
76
|
+
const result = await setChildren("state", element, node);
|
|
77
|
+
expect(result).toEqual({
|
|
78
|
+
tag: "fragment",
|
|
79
|
+
0: { text: "parsed a" },
|
|
80
|
+
1: { text: "parsed b" }
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
it("handles async function parameters", async () => {
|
|
84
|
+
const asyncParam = async () => ["async1", "async2"];
|
|
85
|
+
const result = await setChildren(asyncParam, element, node);
|
|
86
|
+
expect(result).toEqual({
|
|
87
|
+
tag: "fragment",
|
|
88
|
+
0: { text: "async1" },
|
|
89
|
+
1: { text: "async2" }
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
it("handles nested object structures", async () => {
|
|
93
|
+
const nestedChildren = {
|
|
94
|
+
header: { text: "Title" },
|
|
95
|
+
content: {
|
|
96
|
+
nested: { text: "Content" }
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const result = await setChildren(nestedChildren, element, node);
|
|
100
|
+
expect(result).toEqual({
|
|
101
|
+
tag: "fragment",
|
|
102
|
+
0: { text: "Title" },
|
|
103
|
+
1: { nested: { text: "Content" } }
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
it("handles empty arrays and objects", async () => {
|
|
107
|
+
let result = await setChildren([], element, node);
|
|
108
|
+
expect(result).toEqual({
|
|
109
|
+
tag: "fragment"
|
|
110
|
+
});
|
|
111
|
+
result = await setChildren({}, element, node);
|
|
112
|
+
expect(result).toEqual({
|
|
113
|
+
tag: "fragment"
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
it("handles falsy values in arrays", async () => {
|
|
117
|
+
const result = await setChildren(
|
|
118
|
+
[null, void 0, false, 0, ""],
|
|
119
|
+
element,
|
|
120
|
+
node
|
|
121
|
+
);
|
|
122
|
+
expect(result).toEqual({
|
|
123
|
+
tag: "fragment",
|
|
124
|
+
3: { text: 0 },
|
|
125
|
+
4: { text: "" }
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
it("handles React components with falsy values in array", async () => {
|
|
129
|
+
const mixedChildren = [
|
|
130
|
+
null,
|
|
131
|
+
{ $$typeof: Symbol("react") },
|
|
132
|
+
void 0,
|
|
133
|
+
{ $$typeof: Symbol("react") },
|
|
134
|
+
false
|
|
135
|
+
];
|
|
136
|
+
await setChildren(mixedChildren, element, node);
|
|
137
|
+
expect(element.call).toHaveBeenCalledWith(
|
|
138
|
+
"renderReact",
|
|
139
|
+
[mixedChildren[1], mixedChildren[3]],
|
|
140
|
+
element
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
it("handles nested state parsing", async () => {
|
|
144
|
+
element.state = {
|
|
145
|
+
nested: {
|
|
146
|
+
items: ["c", "d"]
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
element.state.nested.__proto__.parse = () => ["parsed c", "parsed d"];
|
|
150
|
+
const result = await setChildren("nested", element, node);
|
|
151
|
+
expect(result).toEqual({
|
|
152
|
+
tag: "fragment",
|
|
153
|
+
0: { state: ["c", "d"] }
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
it("handles mixed state and regular objects", async () => {
|
|
157
|
+
element.state = {
|
|
158
|
+
header: { parse: () => "Header" },
|
|
159
|
+
footer: { parse: () => "Footer" }
|
|
160
|
+
};
|
|
161
|
+
const result = await setChildren(
|
|
162
|
+
{
|
|
163
|
+
header: "header",
|
|
164
|
+
content: { text: "Content" },
|
|
165
|
+
footer: "footer"
|
|
166
|
+
},
|
|
167
|
+
element,
|
|
168
|
+
node
|
|
169
|
+
);
|
|
170
|
+
expect(result).toEqual({
|
|
171
|
+
tag: "fragment",
|
|
172
|
+
0: { text: "header" },
|
|
173
|
+
1: { text: "Content" },
|
|
174
|
+
2: { text: "footer" }
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import define from "../define";
|
|
2
|
+
import { REGISTRY } from "../mixins";
|
|
3
|
+
describe("default function (registry updater)", () => {
|
|
4
|
+
let originalRegistry;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
originalRegistry = { ...REGISTRY };
|
|
7
|
+
});
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
Object.keys(REGISTRY).forEach((key) => {
|
|
10
|
+
REGISTRY[key] = originalRegistry[key];
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
it("should add new params to REGISTRY when overwrite is true", () => {
|
|
14
|
+
const params = { newKey: "newValue", anotherKey: "anotherValue" };
|
|
15
|
+
const options = { overwrite: true };
|
|
16
|
+
define(params, options);
|
|
17
|
+
expect(REGISTRY.newKey).toBe("newValue");
|
|
18
|
+
expect(REGISTRY.anotherKey).toBe("anotherValue");
|
|
19
|
+
});
|
|
20
|
+
it("should not modify REGISTRY when trying to overwrite existing keys without overwrite option", () => {
|
|
21
|
+
const params = { attr: "newValue", text: "newText" };
|
|
22
|
+
try {
|
|
23
|
+
define(params);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
}
|
|
26
|
+
expect(REGISTRY.attr).toBe(originalRegistry.attr);
|
|
27
|
+
expect(REGISTRY.text).toBe(originalRegistry.text);
|
|
28
|
+
});
|
|
29
|
+
it("should overwrite existing keys when overwrite is true", () => {
|
|
30
|
+
const params = { attr: "newValue", text: "newText" };
|
|
31
|
+
const options = { overwrite: true };
|
|
32
|
+
define(params, options);
|
|
33
|
+
expect(REGISTRY.attr).toBe("newValue");
|
|
34
|
+
expect(REGISTRY.text).toBe("newText");
|
|
35
|
+
});
|
|
36
|
+
it("should handle empty params object without errors", () => {
|
|
37
|
+
const params = {};
|
|
38
|
+
const options = { overwrite: true };
|
|
39
|
+
expect(() => define(params, options)).not.toThrow();
|
|
40
|
+
expect(REGISTRY).toEqual(originalRegistry);
|
|
41
|
+
});
|
|
42
|
+
it("should handle empty options object without errors", () => {
|
|
43
|
+
const params = { newKey: "newValue" };
|
|
44
|
+
expect(() => define(params, {})).not.toThrow();
|
|
45
|
+
expect(REGISTRY.newKey).toBe("newValue");
|
|
46
|
+
});
|
|
47
|
+
it("should not add new keys when params is empty", () => {
|
|
48
|
+
const params = {};
|
|
49
|
+
const options = { overwrite: true };
|
|
50
|
+
define(params, options);
|
|
51
|
+
expect(REGISTRY).toEqual(originalRegistry);
|
|
52
|
+
});
|
|
53
|
+
});
|