@bonsae/nrg 0.18.5 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server/index.cjs +86 -9
- package/server/resources/nrg-client.js +2020 -1987
- package/test/client/component/config.js +11 -0
- package/test/client/component/index.js +218 -235
- package/test/client/component/nrg.css +1 -0
- package/test/client/component/setup.js +1549 -140
- package/test/client/e2e/index.js +720 -369
- package/test/client/unit/index.js +204 -16
- package/test/client/unit/setup.js +209 -19
- package/test/server/unit/index.js +25 -4
- package/tsconfig/core/client.json +1 -1
- package/tsconfig/test/client/component.json +1 -1
- package/types/client.d.ts +98 -18
- package/types/server.d.ts +50 -12
- package/types/shims/brands.d.ts +32 -0
- package/types/shims/{form → client/form}/components/node-red-editor-input.vue.d.ts +1 -1
- package/types/shims/{form → client/form}/components/node-red-json-schema-form.vue.d.ts +21 -2
- package/types/shims/{form → client/form}/components/node-red-select-input.vue.d.ts +1 -0
- package/types/shims/{form → client/form}/components/node-red-typed-input.vue.d.ts +1 -0
- package/types/shims/client/types.d.ts +206 -0
- package/types/shims/components.d.ts +8 -8
- package/types/shims/constants.d.ts +4 -0
- package/types/shims/schema-options.d.ts +23 -10
- package/types/shims/typebox.d.ts +2 -2
- package/types/test-client-component.d.ts +170 -55
- package/types/test-client-e2e.d.ts +50 -0
- package/types/test-client-unit.d.ts +86 -22
- package/types/test-server-unit.d.ts +3 -1
- package/types/vite.d.ts +38 -9
- package/vite/index.js +732 -530
- /package/types/shims/{form → client/form}/components/node-red-config-input.vue.d.ts +0 -0
- /package/types/shims/{form → client/form}/components/node-red-input-label.vue.d.ts +0 -0
- /package/types/shims/{form → client/form}/components/node-red-input.vue.d.ts +0 -0
- /package/types/shims/{form → client/form}/components/node-red-toggle.vue.d.ts +0 -0
- /package/types/shims/{globals.d.ts → client/globals.d.ts} +0 -0
|
@@ -1,18 +1,67 @@
|
|
|
1
1
|
// src/test/client/mocks.ts
|
|
2
|
+
function createSettings() {
|
|
3
|
+
const settings = {
|
|
4
|
+
get(key) {
|
|
5
|
+
return settings[key];
|
|
6
|
+
},
|
|
7
|
+
set(key, value) {
|
|
8
|
+
settings[key] = value;
|
|
9
|
+
return value;
|
|
10
|
+
},
|
|
11
|
+
remove(key) {
|
|
12
|
+
const value = settings[key];
|
|
13
|
+
delete settings[key];
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
return settings;
|
|
18
|
+
}
|
|
19
|
+
function topicMatches(pattern, topic) {
|
|
20
|
+
if (pattern === topic) return true;
|
|
21
|
+
const p = pattern.split("/");
|
|
22
|
+
const t = topic.split("/");
|
|
23
|
+
for (let i = 0; i < p.length; i++) {
|
|
24
|
+
if (p[i] === "#") return true;
|
|
25
|
+
if (i >= t.length) return false;
|
|
26
|
+
if (p[i] !== "+" && p[i] !== t[i]) return false;
|
|
27
|
+
}
|
|
28
|
+
return p.length === t.length;
|
|
29
|
+
}
|
|
2
30
|
function createRED() {
|
|
3
|
-
|
|
31
|
+
const nodeStore = /* @__PURE__ */ new Map();
|
|
32
|
+
const typeRegistry = /* @__PURE__ */ new Map();
|
|
33
|
+
const links = [];
|
|
34
|
+
const eventListeners = {};
|
|
35
|
+
const commsSubscriptions = [];
|
|
36
|
+
let dirtyState = false;
|
|
37
|
+
let idCounter = 0;
|
|
38
|
+
const popoverInstance = () => {
|
|
39
|
+
const instance = {
|
|
40
|
+
element: null,
|
|
41
|
+
open: () => instance,
|
|
42
|
+
close: () => instance,
|
|
43
|
+
setContent: () => instance,
|
|
44
|
+
move: () => {
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return instance;
|
|
48
|
+
};
|
|
49
|
+
const red = {
|
|
4
50
|
_: (key) => key,
|
|
5
51
|
editor: {
|
|
6
52
|
createEditor(options) {
|
|
7
|
-
let currentValue = options
|
|
53
|
+
let currentValue = options?.value || "";
|
|
54
|
+
const sessionListeners = {};
|
|
8
55
|
const session = {
|
|
9
|
-
on(
|
|
56
|
+
on(event, cb) {
|
|
57
|
+
(sessionListeners[event] ??= []).push(cb);
|
|
10
58
|
}
|
|
11
59
|
};
|
|
12
60
|
return {
|
|
13
61
|
getValue: () => currentValue,
|
|
14
62
|
setValue: (val) => {
|
|
15
63
|
currentValue = val;
|
|
64
|
+
(sessionListeners["change"] ?? []).forEach((cb) => cb());
|
|
16
65
|
},
|
|
17
66
|
getSession: () => session,
|
|
18
67
|
focus: () => {
|
|
@@ -36,28 +85,133 @@ function createRED() {
|
|
|
36
85
|
}
|
|
37
86
|
},
|
|
38
87
|
popover: {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
88
|
+
create: () => popoverInstance(),
|
|
89
|
+
tooltip: () => {
|
|
90
|
+
const instance = {
|
|
91
|
+
element: null,
|
|
92
|
+
open: () => instance,
|
|
93
|
+
close: () => instance,
|
|
94
|
+
setContent: () => instance,
|
|
95
|
+
move: () => {
|
|
96
|
+
},
|
|
97
|
+
delete: () => {
|
|
98
|
+
},
|
|
99
|
+
setAction: () => {
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return instance;
|
|
103
|
+
}
|
|
42
104
|
},
|
|
43
105
|
nodes: {
|
|
44
|
-
registerType
|
|
106
|
+
registerType(type, definition) {
|
|
107
|
+
typeRegistry.set(type, definition);
|
|
108
|
+
},
|
|
109
|
+
getType(type) {
|
|
110
|
+
return typeRegistry.get(type) ?? null;
|
|
111
|
+
},
|
|
112
|
+
node(id) {
|
|
113
|
+
return nodeStore.get(id) ?? null;
|
|
114
|
+
},
|
|
115
|
+
add(node) {
|
|
116
|
+
nodeStore.set(node.id, node);
|
|
117
|
+
return node;
|
|
118
|
+
},
|
|
119
|
+
remove(id) {
|
|
120
|
+
const node = nodeStore.get(id);
|
|
121
|
+
nodeStore.delete(id);
|
|
122
|
+
return { links: [], nodes: node ? [node] : [] };
|
|
123
|
+
},
|
|
124
|
+
clear() {
|
|
125
|
+
nodeStore.clear();
|
|
126
|
+
},
|
|
127
|
+
// The mock keeps a single registry: eachNode and eachConfig iterate the
|
|
128
|
+
// same entries. Register whatever your component expects to find.
|
|
129
|
+
eachNode(callback) {
|
|
130
|
+
for (const node of nodeStore.values()) {
|
|
131
|
+
if (callback(node) === false) break;
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
eachConfig(callback) {
|
|
135
|
+
for (const node of nodeStore.values()) {
|
|
136
|
+
if (callback(node) === false) break;
|
|
137
|
+
}
|
|
45
138
|
},
|
|
46
|
-
|
|
47
|
-
|
|
139
|
+
filterNodes(filter) {
|
|
140
|
+
return [...nodeStore.values()].filter(
|
|
141
|
+
(n) => (filter.type === void 0 || n.type === filter.type) && (filter.z === void 0 || n.z === filter.z)
|
|
142
|
+
);
|
|
143
|
+
},
|
|
144
|
+
filterLinks(filter) {
|
|
145
|
+
return links.filter(
|
|
146
|
+
(l) => (filter.source === void 0 || l.source === filter.source || l.source?.id === filter.source?.id) && (filter.target === void 0 || l.target === filter.target || l.target?.id === filter.target?.id)
|
|
147
|
+
);
|
|
148
|
+
},
|
|
149
|
+
addLink(link) {
|
|
150
|
+
links.push(link);
|
|
151
|
+
},
|
|
152
|
+
dirty(state) {
|
|
153
|
+
if (state === void 0) return dirtyState;
|
|
154
|
+
dirtyState = state;
|
|
155
|
+
},
|
|
156
|
+
id() {
|
|
157
|
+
return (++idCounter).toString(16).padStart(16, "0");
|
|
158
|
+
}
|
|
48
159
|
},
|
|
49
160
|
events: {
|
|
50
|
-
on
|
|
161
|
+
on(event, listener) {
|
|
162
|
+
(eventListeners[event] ??= []).push(listener);
|
|
51
163
|
},
|
|
52
|
-
off
|
|
164
|
+
off(event, listener) {
|
|
165
|
+
if (!eventListeners[event]) return;
|
|
166
|
+
if (listener) {
|
|
167
|
+
eventListeners[event] = eventListeners[event].filter(
|
|
168
|
+
(l) => l !== listener
|
|
169
|
+
);
|
|
170
|
+
} else {
|
|
171
|
+
delete eventListeners[event];
|
|
172
|
+
}
|
|
53
173
|
},
|
|
54
|
-
emit
|
|
174
|
+
emit(event, ...args) {
|
|
175
|
+
[...eventListeners[event] ?? []].forEach((cb) => cb(...args));
|
|
55
176
|
}
|
|
56
177
|
},
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
178
|
+
comms: {
|
|
179
|
+
subscribe(topic, callback) {
|
|
180
|
+
commsSubscriptions.push({ topic, callback });
|
|
181
|
+
},
|
|
182
|
+
unsubscribe(topic, callback) {
|
|
183
|
+
const index = commsSubscriptions.findIndex(
|
|
184
|
+
(s) => s.topic === topic && s.callback === callback
|
|
185
|
+
);
|
|
186
|
+
if (index !== -1) commsSubscriptions.splice(index, 1);
|
|
187
|
+
},
|
|
188
|
+
publish(topic, msg) {
|
|
189
|
+
[...commsSubscriptions].filter((s) => topicMatches(s.topic, topic)).forEach((s) => s.callback(topic, msg));
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
settings: createSettings(),
|
|
193
|
+
notify: () => ({
|
|
194
|
+
update: () => {
|
|
195
|
+
},
|
|
196
|
+
close: () => {
|
|
197
|
+
}
|
|
198
|
+
})
|
|
60
199
|
};
|
|
200
|
+
Object.defineProperty(red, "__reset", {
|
|
201
|
+
enumerable: false,
|
|
202
|
+
value: () => {
|
|
203
|
+
nodeStore.clear();
|
|
204
|
+
typeRegistry.clear();
|
|
205
|
+
links.length = 0;
|
|
206
|
+
for (const key of Object.keys(eventListeners)) {
|
|
207
|
+
delete eventListeners[key];
|
|
208
|
+
}
|
|
209
|
+
commsSubscriptions.length = 0;
|
|
210
|
+
dirtyState = false;
|
|
211
|
+
red.settings = createSettings();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
return red;
|
|
61
215
|
}
|
|
62
216
|
function ensureState(el) {
|
|
63
217
|
if (el && !el.__jqState) {
|
|
@@ -75,7 +229,11 @@ function createJQ(el) {
|
|
|
75
229
|
length: el ? 1 : 0,
|
|
76
230
|
typedInput(action, value) {
|
|
77
231
|
if (typeof action === "object") {
|
|
78
|
-
state.typedInput = {
|
|
232
|
+
state.typedInput = {
|
|
233
|
+
value: "",
|
|
234
|
+
type: action.default || "",
|
|
235
|
+
types: action.types
|
|
236
|
+
};
|
|
79
237
|
return jq;
|
|
80
238
|
}
|
|
81
239
|
if (action === "value") {
|
|
@@ -93,6 +251,36 @@ function createJQ(el) {
|
|
|
93
251
|
}
|
|
94
252
|
return state.typedInput.type;
|
|
95
253
|
}
|
|
254
|
+
if (action === "types") {
|
|
255
|
+
state.typedInput.types = value;
|
|
256
|
+
return void 0;
|
|
257
|
+
}
|
|
258
|
+
if (action === "validate") {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
if (action === "disable") {
|
|
262
|
+
state.typedInput.disabled = value !== false;
|
|
263
|
+
return void 0;
|
|
264
|
+
}
|
|
265
|
+
if (action === "enable") {
|
|
266
|
+
state.typedInput.disabled = false;
|
|
267
|
+
return void 0;
|
|
268
|
+
}
|
|
269
|
+
if (action === "hide") {
|
|
270
|
+
state.typedInput.hidden = true;
|
|
271
|
+
return void 0;
|
|
272
|
+
}
|
|
273
|
+
if (action === "show") {
|
|
274
|
+
state.typedInput.hidden = false;
|
|
275
|
+
return void 0;
|
|
276
|
+
}
|
|
277
|
+
if (action === "width") {
|
|
278
|
+
state.typedInput.width = value;
|
|
279
|
+
return void 0;
|
|
280
|
+
}
|
|
281
|
+
if (action === "focus") {
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
96
284
|
return jq;
|
|
97
285
|
},
|
|
98
286
|
on(event, cb) {
|
|
@@ -2,20 +2,72 @@
|
|
|
2
2
|
import { beforeEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
// src/test/client/mocks.ts
|
|
5
|
+
function createSettings() {
|
|
6
|
+
const settings = {
|
|
7
|
+
get(key) {
|
|
8
|
+
return settings[key];
|
|
9
|
+
},
|
|
10
|
+
set(key, value) {
|
|
11
|
+
settings[key] = value;
|
|
12
|
+
return value;
|
|
13
|
+
},
|
|
14
|
+
remove(key) {
|
|
15
|
+
const value = settings[key];
|
|
16
|
+
delete settings[key];
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return settings;
|
|
21
|
+
}
|
|
22
|
+
function topicMatches(pattern, topic) {
|
|
23
|
+
if (pattern === topic) return true;
|
|
24
|
+
const p = pattern.split("/");
|
|
25
|
+
const t = topic.split("/");
|
|
26
|
+
for (let i = 0; i < p.length; i++) {
|
|
27
|
+
if (p[i] === "#") return true;
|
|
28
|
+
if (i >= t.length) return false;
|
|
29
|
+
if (p[i] !== "+" && p[i] !== t[i]) return false;
|
|
30
|
+
}
|
|
31
|
+
return p.length === t.length;
|
|
32
|
+
}
|
|
33
|
+
function resetRED(red) {
|
|
34
|
+
red.__reset?.();
|
|
35
|
+
}
|
|
5
36
|
function createRED() {
|
|
6
|
-
|
|
37
|
+
const nodeStore = /* @__PURE__ */ new Map();
|
|
38
|
+
const typeRegistry = /* @__PURE__ */ new Map();
|
|
39
|
+
const links = [];
|
|
40
|
+
const eventListeners = {};
|
|
41
|
+
const commsSubscriptions = [];
|
|
42
|
+
let dirtyState = false;
|
|
43
|
+
let idCounter = 0;
|
|
44
|
+
const popoverInstance = () => {
|
|
45
|
+
const instance = {
|
|
46
|
+
element: null,
|
|
47
|
+
open: () => instance,
|
|
48
|
+
close: () => instance,
|
|
49
|
+
setContent: () => instance,
|
|
50
|
+
move: () => {
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return instance;
|
|
54
|
+
};
|
|
55
|
+
const red = {
|
|
7
56
|
_: (key) => key,
|
|
8
57
|
editor: {
|
|
9
58
|
createEditor(options) {
|
|
10
|
-
let currentValue = options
|
|
59
|
+
let currentValue = options?.value || "";
|
|
60
|
+
const sessionListeners = {};
|
|
11
61
|
const session = {
|
|
12
|
-
on(
|
|
62
|
+
on(event, cb) {
|
|
63
|
+
(sessionListeners[event] ??= []).push(cb);
|
|
13
64
|
}
|
|
14
65
|
};
|
|
15
66
|
return {
|
|
16
67
|
getValue: () => currentValue,
|
|
17
68
|
setValue: (val) => {
|
|
18
69
|
currentValue = val;
|
|
70
|
+
(sessionListeners["change"] ?? []).forEach((cb) => cb());
|
|
19
71
|
},
|
|
20
72
|
getSession: () => session,
|
|
21
73
|
focus: () => {
|
|
@@ -39,28 +91,133 @@ function createRED() {
|
|
|
39
91
|
}
|
|
40
92
|
},
|
|
41
93
|
popover: {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
94
|
+
create: () => popoverInstance(),
|
|
95
|
+
tooltip: () => {
|
|
96
|
+
const instance = {
|
|
97
|
+
element: null,
|
|
98
|
+
open: () => instance,
|
|
99
|
+
close: () => instance,
|
|
100
|
+
setContent: () => instance,
|
|
101
|
+
move: () => {
|
|
102
|
+
},
|
|
103
|
+
delete: () => {
|
|
104
|
+
},
|
|
105
|
+
setAction: () => {
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return instance;
|
|
109
|
+
}
|
|
45
110
|
},
|
|
46
111
|
nodes: {
|
|
47
|
-
registerType
|
|
112
|
+
registerType(type, definition) {
|
|
113
|
+
typeRegistry.set(type, definition);
|
|
114
|
+
},
|
|
115
|
+
getType(type) {
|
|
116
|
+
return typeRegistry.get(type) ?? null;
|
|
117
|
+
},
|
|
118
|
+
node(id) {
|
|
119
|
+
return nodeStore.get(id) ?? null;
|
|
120
|
+
},
|
|
121
|
+
add(node) {
|
|
122
|
+
nodeStore.set(node.id, node);
|
|
123
|
+
return node;
|
|
124
|
+
},
|
|
125
|
+
remove(id) {
|
|
126
|
+
const node = nodeStore.get(id);
|
|
127
|
+
nodeStore.delete(id);
|
|
128
|
+
return { links: [], nodes: node ? [node] : [] };
|
|
129
|
+
},
|
|
130
|
+
clear() {
|
|
131
|
+
nodeStore.clear();
|
|
132
|
+
},
|
|
133
|
+
// The mock keeps a single registry: eachNode and eachConfig iterate the
|
|
134
|
+
// same entries. Register whatever your component expects to find.
|
|
135
|
+
eachNode(callback) {
|
|
136
|
+
for (const node of nodeStore.values()) {
|
|
137
|
+
if (callback(node) === false) break;
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
eachConfig(callback) {
|
|
141
|
+
for (const node of nodeStore.values()) {
|
|
142
|
+
if (callback(node) === false) break;
|
|
143
|
+
}
|
|
48
144
|
},
|
|
49
|
-
|
|
50
|
-
|
|
145
|
+
filterNodes(filter) {
|
|
146
|
+
return [...nodeStore.values()].filter(
|
|
147
|
+
(n) => (filter.type === void 0 || n.type === filter.type) && (filter.z === void 0 || n.z === filter.z)
|
|
148
|
+
);
|
|
149
|
+
},
|
|
150
|
+
filterLinks(filter) {
|
|
151
|
+
return links.filter(
|
|
152
|
+
(l) => (filter.source === void 0 || l.source === filter.source || l.source?.id === filter.source?.id) && (filter.target === void 0 || l.target === filter.target || l.target?.id === filter.target?.id)
|
|
153
|
+
);
|
|
154
|
+
},
|
|
155
|
+
addLink(link) {
|
|
156
|
+
links.push(link);
|
|
157
|
+
},
|
|
158
|
+
dirty(state) {
|
|
159
|
+
if (state === void 0) return dirtyState;
|
|
160
|
+
dirtyState = state;
|
|
161
|
+
},
|
|
162
|
+
id() {
|
|
163
|
+
return (++idCounter).toString(16).padStart(16, "0");
|
|
164
|
+
}
|
|
51
165
|
},
|
|
52
166
|
events: {
|
|
53
|
-
on
|
|
167
|
+
on(event, listener) {
|
|
168
|
+
(eventListeners[event] ??= []).push(listener);
|
|
54
169
|
},
|
|
55
|
-
off
|
|
170
|
+
off(event, listener) {
|
|
171
|
+
if (!eventListeners[event]) return;
|
|
172
|
+
if (listener) {
|
|
173
|
+
eventListeners[event] = eventListeners[event].filter(
|
|
174
|
+
(l) => l !== listener
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
delete eventListeners[event];
|
|
178
|
+
}
|
|
56
179
|
},
|
|
57
|
-
emit
|
|
180
|
+
emit(event, ...args) {
|
|
181
|
+
[...eventListeners[event] ?? []].forEach((cb) => cb(...args));
|
|
58
182
|
}
|
|
59
183
|
},
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
184
|
+
comms: {
|
|
185
|
+
subscribe(topic, callback) {
|
|
186
|
+
commsSubscriptions.push({ topic, callback });
|
|
187
|
+
},
|
|
188
|
+
unsubscribe(topic, callback) {
|
|
189
|
+
const index = commsSubscriptions.findIndex(
|
|
190
|
+
(s) => s.topic === topic && s.callback === callback
|
|
191
|
+
);
|
|
192
|
+
if (index !== -1) commsSubscriptions.splice(index, 1);
|
|
193
|
+
},
|
|
194
|
+
publish(topic, msg) {
|
|
195
|
+
[...commsSubscriptions].filter((s) => topicMatches(s.topic, topic)).forEach((s) => s.callback(topic, msg));
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
settings: createSettings(),
|
|
199
|
+
notify: () => ({
|
|
200
|
+
update: () => {
|
|
201
|
+
},
|
|
202
|
+
close: () => {
|
|
203
|
+
}
|
|
204
|
+
})
|
|
63
205
|
};
|
|
206
|
+
Object.defineProperty(red, "__reset", {
|
|
207
|
+
enumerable: false,
|
|
208
|
+
value: () => {
|
|
209
|
+
nodeStore.clear();
|
|
210
|
+
typeRegistry.clear();
|
|
211
|
+
links.length = 0;
|
|
212
|
+
for (const key of Object.keys(eventListeners)) {
|
|
213
|
+
delete eventListeners[key];
|
|
214
|
+
}
|
|
215
|
+
commsSubscriptions.length = 0;
|
|
216
|
+
dirtyState = false;
|
|
217
|
+
red.settings = createSettings();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
return red;
|
|
64
221
|
}
|
|
65
222
|
function ensureState(el) {
|
|
66
223
|
if (el && !el.__jqState) {
|
|
@@ -78,7 +235,11 @@ function createJQ(el) {
|
|
|
78
235
|
length: el ? 1 : 0,
|
|
79
236
|
typedInput(action, value) {
|
|
80
237
|
if (typeof action === "object") {
|
|
81
|
-
state.typedInput = {
|
|
238
|
+
state.typedInput = {
|
|
239
|
+
value: "",
|
|
240
|
+
type: action.default || "",
|
|
241
|
+
types: action.types
|
|
242
|
+
};
|
|
82
243
|
return jq;
|
|
83
244
|
}
|
|
84
245
|
if (action === "value") {
|
|
@@ -96,6 +257,36 @@ function createJQ(el) {
|
|
|
96
257
|
}
|
|
97
258
|
return state.typedInput.type;
|
|
98
259
|
}
|
|
260
|
+
if (action === "types") {
|
|
261
|
+
state.typedInput.types = value;
|
|
262
|
+
return void 0;
|
|
263
|
+
}
|
|
264
|
+
if (action === "validate") {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
if (action === "disable") {
|
|
268
|
+
state.typedInput.disabled = value !== false;
|
|
269
|
+
return void 0;
|
|
270
|
+
}
|
|
271
|
+
if (action === "enable") {
|
|
272
|
+
state.typedInput.disabled = false;
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
if (action === "hide") {
|
|
276
|
+
state.typedInput.hidden = true;
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
if (action === "show") {
|
|
280
|
+
state.typedInput.hidden = false;
|
|
281
|
+
return void 0;
|
|
282
|
+
}
|
|
283
|
+
if (action === "width") {
|
|
284
|
+
state.typedInput.width = value;
|
|
285
|
+
return void 0;
|
|
286
|
+
}
|
|
287
|
+
if (action === "focus") {
|
|
288
|
+
return void 0;
|
|
289
|
+
}
|
|
99
290
|
return jq;
|
|
100
291
|
},
|
|
101
292
|
on(event, cb) {
|
|
@@ -191,9 +382,8 @@ function createJQuery() {
|
|
|
191
382
|
}
|
|
192
383
|
|
|
193
384
|
// src/test/client/unit/setup.ts
|
|
194
|
-
var RED = createRED();
|
|
195
385
|
window.$ = createJQuery();
|
|
196
|
-
window.RED =
|
|
386
|
+
window.RED = createRED();
|
|
197
387
|
beforeEach(() => {
|
|
198
|
-
RED
|
|
388
|
+
resetRED(window.RED);
|
|
199
389
|
});
|
|
@@ -6,6 +6,7 @@ import { vi } from "vitest";
|
|
|
6
6
|
function createRED(options = {}) {
|
|
7
7
|
const { settings = {} } = options;
|
|
8
8
|
const nodes = {};
|
|
9
|
+
const credentials = {};
|
|
9
10
|
const red = {
|
|
10
11
|
log: {
|
|
11
12
|
info: vi.fn(),
|
|
@@ -31,7 +32,10 @@ function createRED(options = {}) {
|
|
|
31
32
|
getNode: vi.fn((id) => nodes[id]),
|
|
32
33
|
registerType: vi.fn(),
|
|
33
34
|
createNode: vi.fn(),
|
|
34
|
-
getCredentials: vi.fn(),
|
|
35
|
+
getCredentials: vi.fn((id) => credentials[id]),
|
|
36
|
+
addCredentials: vi.fn((id, creds) => {
|
|
37
|
+
credentials[id] = { ...credentials[id], ...creds };
|
|
38
|
+
}),
|
|
35
39
|
eachNode: vi.fn(),
|
|
36
40
|
getType: vi.fn(),
|
|
37
41
|
getNodeInfo: vi.fn(),
|
|
@@ -126,12 +130,16 @@ function createRED(options = {}) {
|
|
|
126
130
|
}
|
|
127
131
|
),
|
|
128
132
|
generateId: vi.fn(() => "mock-id"),
|
|
129
|
-
cloneMessage: vi.fn((msg) => (
|
|
133
|
+
cloneMessage: vi.fn((msg) => structuredClone(msg)),
|
|
130
134
|
ensureString: vi.fn((o) => String(o)),
|
|
131
135
|
ensureBuffer: vi.fn(),
|
|
132
136
|
compareObjects: vi.fn(),
|
|
133
|
-
getMessageProperty: vi.fn(
|
|
134
|
-
|
|
137
|
+
getMessageProperty: vi.fn(
|
|
138
|
+
(msg, prop) => getProperty(msg, prop)
|
|
139
|
+
),
|
|
140
|
+
setMessageProperty: vi.fn(
|
|
141
|
+
(msg, prop, value, createMissing) => setProperty(msg, prop, value, createMissing ?? false)
|
|
142
|
+
),
|
|
135
143
|
getObjectProperty: vi.fn(),
|
|
136
144
|
setObjectProperty: vi.fn(),
|
|
137
145
|
normalisePropertyExpression: vi.fn(),
|
|
@@ -156,6 +164,19 @@ function createRED(options = {}) {
|
|
|
156
164
|
function getProperty(obj, path) {
|
|
157
165
|
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
158
166
|
}
|
|
167
|
+
function setProperty(obj, path, value, createMissing) {
|
|
168
|
+
const keys = path.split(".");
|
|
169
|
+
let target = obj;
|
|
170
|
+
for (const key of keys.slice(0, -1)) {
|
|
171
|
+
if (target[key] == null || typeof target[key] !== "object") {
|
|
172
|
+
if (!createMissing) return false;
|
|
173
|
+
target[key] = {};
|
|
174
|
+
}
|
|
175
|
+
target = target[key];
|
|
176
|
+
}
|
|
177
|
+
target[keys[keys.length - 1]] = value;
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
159
180
|
function createContextStore() {
|
|
160
181
|
const store = {};
|
|
161
182
|
return {
|