@bonsae/nrg 0.18.1 → 0.18.3
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/README.md +10 -2
- package/package.json +14 -2
- package/test/client/e2e/index.js +54 -6
- package/vite/index.js +58 -10
package/README.md
CHANGED
|
@@ -145,13 +145,21 @@ See the [consumer template](https://github.com/AllanOricil/node-red-vue-template
|
|
|
145
145
|
|
|
146
146
|
## Testing
|
|
147
147
|
|
|
148
|
-
NRG provides four test libraries and bundles
|
|
148
|
+
NRG provides four test libraries and bundles most test infrastructure as direct dependencies. Install `vitest` plus any optional peer dependencies you need:
|
|
149
149
|
|
|
150
150
|
```bash
|
|
151
151
|
pnpm add -D vitest
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
Optional peer dependencies:
|
|
155
|
+
|
|
156
|
+
| Package | When to install |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| `@vitest/browser-playwright` | Component tests (Playwright browser provider for Vitest) |
|
|
159
|
+
| `playwright` | Component tests or E2E tests (direct `import` in test files) |
|
|
160
|
+
| `vitest-browser-vue` | Component tests (`render` helper for Vue components) |
|
|
161
|
+
| `@vitest/coverage-v8` | Coverage with `--coverage` (V8 provider) |
|
|
162
|
+
| `@vitest/coverage-istanbul` | Coverage with `--coverage` (Istanbul provider) |
|
|
155
163
|
|
|
156
164
|
- `@bonsae/nrg/test/server/unit` — server-side unit tests
|
|
157
165
|
- `@bonsae/nrg/test/client/unit` — client-side unit tests (TypeScript logic)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bonsae/nrg",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"description": "NRG framework — build Node-RED nodes with Vue 3, TypeScript, and JSON Schema",
|
|
5
5
|
"author": "Allan Oricil <allanoricil@duck.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -81,7 +81,10 @@
|
|
|
81
81
|
"vitest": "^4.0.0",
|
|
82
82
|
"vue": "^3.5.14",
|
|
83
83
|
"@vitest/coverage-istanbul": "^4.0.0",
|
|
84
|
-
"@vitest/coverage-v8": "^4.0.0"
|
|
84
|
+
"@vitest/coverage-v8": "^4.0.0",
|
|
85
|
+
"@vitest/browser-playwright": "^4.0.0",
|
|
86
|
+
"playwright": "^1.50.0",
|
|
87
|
+
"vitest-browser-vue": "^2.0.0"
|
|
85
88
|
},
|
|
86
89
|
"peerDependenciesMeta": {
|
|
87
90
|
"@vitest/coverage-istanbul": {
|
|
@@ -89,6 +92,15 @@
|
|
|
89
92
|
},
|
|
90
93
|
"@vitest/coverage-v8": {
|
|
91
94
|
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"@vitest/browser-playwright": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"playwright": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"vitest-browser-vue": {
|
|
103
|
+
"optional": true
|
|
92
104
|
}
|
|
93
105
|
},
|
|
94
106
|
"dependencies": {
|
package/test/client/e2e/index.js
CHANGED
|
@@ -1995,7 +1995,7 @@ async function build2(clientBuildOptions, buildContext) {
|
|
|
1995
1995
|
}
|
|
1996
1996
|
|
|
1997
1997
|
// src/vite/node-red-launcher.ts
|
|
1998
|
-
import { spawn } from "child_process";
|
|
1998
|
+
import { spawn, execSync } from "child_process";
|
|
1999
1999
|
import getPort from "get-port";
|
|
2000
2000
|
import detect from "detect-port";
|
|
2001
2001
|
import { builtinModules as builtinModules2 } from "module";
|
|
@@ -2003,6 +2003,7 @@ import treeKill from "tree-kill";
|
|
|
2003
2003
|
import fs10 from "fs";
|
|
2004
2004
|
import os from "os";
|
|
2005
2005
|
import path10 from "path";
|
|
2006
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
2006
2007
|
import { build as esbuild } from "esbuild";
|
|
2007
2008
|
|
|
2008
2009
|
// src/vite/async-utils.ts
|
|
@@ -2114,7 +2115,7 @@ var NodeRedLauncher = class {
|
|
|
2114
2115
|
define: {
|
|
2115
2116
|
"import.meta.dirname": JSON.stringify(settingsDir),
|
|
2116
2117
|
"import.meta.filename": JSON.stringify(settingsFile),
|
|
2117
|
-
"import.meta.url": JSON.stringify(
|
|
2118
|
+
"import.meta.url": JSON.stringify(pathToFileURL3(settingsFile).href)
|
|
2118
2119
|
},
|
|
2119
2120
|
external: [...nodeBuiltins2, "node-red", "@node-red/*"]
|
|
2120
2121
|
});
|
|
@@ -2164,6 +2165,53 @@ module.exports = settings;
|
|
|
2164
2165
|
this.compiledRuntimeSettingsFilepath = finalRuntimeSettingsFilepath;
|
|
2165
2166
|
return finalRuntimeSettingsFilepath;
|
|
2166
2167
|
}
|
|
2168
|
+
resolveNodeRedEntryPoint() {
|
|
2169
|
+
const resolverScript = path10.join(
|
|
2170
|
+
os.tmpdir(),
|
|
2171
|
+
`nrg-resolve-node-red-${process.pid}.cjs`
|
|
2172
|
+
);
|
|
2173
|
+
fs10.writeFileSync(
|
|
2174
|
+
resolverScript,
|
|
2175
|
+
`const fs = require("fs");
|
|
2176
|
+
const path = require("path");
|
|
2177
|
+
const isWin = process.platform === "win32";
|
|
2178
|
+
const binName = isWin ? "node-red.cmd" : "node-red";
|
|
2179
|
+
const dirs = process.env.PATH.split(path.delimiter);
|
|
2180
|
+
for (const d of dirs) {
|
|
2181
|
+
const f = path.join(d, binName);
|
|
2182
|
+
if (fs.existsSync(f)) {
|
|
2183
|
+
if (isWin) {
|
|
2184
|
+
const nodeRedDir = path.resolve(d, "..", "node-red");
|
|
2185
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(nodeRedDir, "package.json"), "utf-8"));
|
|
2186
|
+
const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin["node-red"];
|
|
2187
|
+
process.stdout.write(path.resolve(nodeRedDir, bin));
|
|
2188
|
+
} else {
|
|
2189
|
+
process.stdout.write(fs.realpathSync(f));
|
|
2190
|
+
}
|
|
2191
|
+
break;
|
|
2192
|
+
}
|
|
2193
|
+
}`
|
|
2194
|
+
);
|
|
2195
|
+
try {
|
|
2196
|
+
const entryPoint = execSync(
|
|
2197
|
+
`npx --yes -p ${this.nodeRedCommand} -c "node ${resolverScript}"`,
|
|
2198
|
+
{ encoding: "utf-8", timeout: 12e4 }
|
|
2199
|
+
).trim();
|
|
2200
|
+
if (!entryPoint || !fs10.existsSync(entryPoint)) {
|
|
2201
|
+
throw new NodeRedStartError(
|
|
2202
|
+
new Error(
|
|
2203
|
+
`Could not resolve node-red entry point: ${entryPoint || "(empty)"}`
|
|
2204
|
+
)
|
|
2205
|
+
);
|
|
2206
|
+
}
|
|
2207
|
+
return entryPoint;
|
|
2208
|
+
} finally {
|
|
2209
|
+
try {
|
|
2210
|
+
fs10.unlinkSync(resolverScript);
|
|
2211
|
+
} catch {
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2167
2215
|
log(line) {
|
|
2168
2216
|
if (line.includes("Server now running at")) {
|
|
2169
2217
|
return;
|
|
@@ -2189,6 +2237,7 @@ module.exports = settings;
|
|
|
2189
2237
|
this.port = await getPort({ port: this.preferredPort });
|
|
2190
2238
|
}
|
|
2191
2239
|
}
|
|
2240
|
+
const nodeRedEntryPoint = this.resolveNodeRedEntryPoint();
|
|
2192
2241
|
const startProcess = () => {
|
|
2193
2242
|
return new Promise(async (resolve, reject) => {
|
|
2194
2243
|
try {
|
|
@@ -2197,11 +2246,10 @@ module.exports = settings;
|
|
|
2197
2246
|
this.bufferedLogs = [];
|
|
2198
2247
|
this.isReady = false;
|
|
2199
2248
|
this.process = spawn(
|
|
2200
|
-
|
|
2201
|
-
[
|
|
2249
|
+
process.execPath,
|
|
2250
|
+
[nodeRedEntryPoint, "-s", settingsPath, ...args],
|
|
2202
2251
|
{
|
|
2203
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
2204
|
-
shell: true
|
|
2252
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2205
2253
|
}
|
|
2206
2254
|
);
|
|
2207
2255
|
this.process.stdout?.on("data", (data) => {
|
package/vite/index.js
CHANGED
|
@@ -107,7 +107,7 @@ function mergeOptions(defaults, overrides) {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// src/vite/node-red-launcher.ts
|
|
110
|
-
import { spawn } from "child_process";
|
|
110
|
+
import { spawn, execSync } from "child_process";
|
|
111
111
|
import getPort from "get-port";
|
|
112
112
|
import detect from "detect-port";
|
|
113
113
|
import { builtinModules } from "module";
|
|
@@ -115,6 +115,7 @@ import treeKill from "tree-kill";
|
|
|
115
115
|
import fs2 from "fs";
|
|
116
116
|
import os from "os";
|
|
117
117
|
import path2 from "path";
|
|
118
|
+
import { pathToFileURL } from "url";
|
|
118
119
|
import { build as esbuild } from "esbuild";
|
|
119
120
|
|
|
120
121
|
// src/vite/async-utils.ts
|
|
@@ -332,7 +333,7 @@ var NodeRedLauncher = class {
|
|
|
332
333
|
define: {
|
|
333
334
|
"import.meta.dirname": JSON.stringify(settingsDir),
|
|
334
335
|
"import.meta.filename": JSON.stringify(settingsFile),
|
|
335
|
-
"import.meta.url": JSON.stringify(
|
|
336
|
+
"import.meta.url": JSON.stringify(pathToFileURL(settingsFile).href)
|
|
336
337
|
},
|
|
337
338
|
external: [...nodeBuiltins2, "node-red", "@node-red/*"]
|
|
338
339
|
});
|
|
@@ -382,6 +383,53 @@ module.exports = settings;
|
|
|
382
383
|
this.compiledRuntimeSettingsFilepath = finalRuntimeSettingsFilepath;
|
|
383
384
|
return finalRuntimeSettingsFilepath;
|
|
384
385
|
}
|
|
386
|
+
resolveNodeRedEntryPoint() {
|
|
387
|
+
const resolverScript = path2.join(
|
|
388
|
+
os.tmpdir(),
|
|
389
|
+
`nrg-resolve-node-red-${process.pid}.cjs`
|
|
390
|
+
);
|
|
391
|
+
fs2.writeFileSync(
|
|
392
|
+
resolverScript,
|
|
393
|
+
`const fs = require("fs");
|
|
394
|
+
const path = require("path");
|
|
395
|
+
const isWin = process.platform === "win32";
|
|
396
|
+
const binName = isWin ? "node-red.cmd" : "node-red";
|
|
397
|
+
const dirs = process.env.PATH.split(path.delimiter);
|
|
398
|
+
for (const d of dirs) {
|
|
399
|
+
const f = path.join(d, binName);
|
|
400
|
+
if (fs.existsSync(f)) {
|
|
401
|
+
if (isWin) {
|
|
402
|
+
const nodeRedDir = path.resolve(d, "..", "node-red");
|
|
403
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(nodeRedDir, "package.json"), "utf-8"));
|
|
404
|
+
const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin["node-red"];
|
|
405
|
+
process.stdout.write(path.resolve(nodeRedDir, bin));
|
|
406
|
+
} else {
|
|
407
|
+
process.stdout.write(fs.realpathSync(f));
|
|
408
|
+
}
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
}`
|
|
412
|
+
);
|
|
413
|
+
try {
|
|
414
|
+
const entryPoint = execSync(
|
|
415
|
+
`npx --yes -p ${this.nodeRedCommand} -c "node ${resolverScript}"`,
|
|
416
|
+
{ encoding: "utf-8", timeout: 12e4 }
|
|
417
|
+
).trim();
|
|
418
|
+
if (!entryPoint || !fs2.existsSync(entryPoint)) {
|
|
419
|
+
throw new NodeRedStartError(
|
|
420
|
+
new Error(
|
|
421
|
+
`Could not resolve node-red entry point: ${entryPoint || "(empty)"}`
|
|
422
|
+
)
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
return entryPoint;
|
|
426
|
+
} finally {
|
|
427
|
+
try {
|
|
428
|
+
fs2.unlinkSync(resolverScript);
|
|
429
|
+
} catch {
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
385
433
|
log(line) {
|
|
386
434
|
if (line.includes("Server now running at")) {
|
|
387
435
|
return;
|
|
@@ -407,6 +455,7 @@ module.exports = settings;
|
|
|
407
455
|
this.port = await getPort({ port: this.preferredPort });
|
|
408
456
|
}
|
|
409
457
|
}
|
|
458
|
+
const nodeRedEntryPoint = this.resolveNodeRedEntryPoint();
|
|
410
459
|
const startProcess = () => {
|
|
411
460
|
return new Promise(async (resolve, reject) => {
|
|
412
461
|
try {
|
|
@@ -415,11 +464,10 @@ module.exports = settings;
|
|
|
415
464
|
this.bufferedLogs = [];
|
|
416
465
|
this.isReady = false;
|
|
417
466
|
this.process = spawn(
|
|
418
|
-
|
|
419
|
-
[
|
|
467
|
+
process.execPath,
|
|
468
|
+
[nodeRedEntryPoint, "-s", settingsPath, ...args],
|
|
420
469
|
{
|
|
421
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
422
|
-
shell: true
|
|
470
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
423
471
|
}
|
|
424
472
|
);
|
|
425
473
|
this.process.stdout?.on("data", (data) => {
|
|
@@ -1262,7 +1310,7 @@ import path11 from "path";
|
|
|
1262
1310
|
// src/vite/client/plugins/help-generator.ts
|
|
1263
1311
|
import fs6 from "fs";
|
|
1264
1312
|
import path6 from "path";
|
|
1265
|
-
import { pathToFileURL } from "url";
|
|
1313
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1266
1314
|
import { createRequire } from "module";
|
|
1267
1315
|
|
|
1268
1316
|
// src/vite/client/plugins/help-i18n.ts
|
|
@@ -1700,7 +1748,7 @@ function helpGenerator(options) {
|
|
|
1700
1748
|
let packageFn;
|
|
1701
1749
|
try {
|
|
1702
1750
|
if (fs6.existsSync(esmPath)) {
|
|
1703
|
-
const fileUrl =
|
|
1751
|
+
const fileUrl = pathToFileURL2(esmPath).href + `?t=${Date.now()}`;
|
|
1704
1752
|
const mod = await import(fileUrl);
|
|
1705
1753
|
packageFn = mod?.default ?? mod;
|
|
1706
1754
|
} else if (fs6.existsSync(cjsPath)) {
|
|
@@ -2049,7 +2097,7 @@ function minifier() {
|
|
|
2049
2097
|
|
|
2050
2098
|
// src/vite/client/plugins/node-definitions-inliner.ts
|
|
2051
2099
|
import { createRequire as createRequire2 } from "module";
|
|
2052
|
-
import { pathToFileURL as
|
|
2100
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
2053
2101
|
import path9 from "path";
|
|
2054
2102
|
import fs9 from "fs";
|
|
2055
2103
|
import mime2 from "mime-types";
|
|
@@ -2105,7 +2153,7 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
|
|
|
2105
2153
|
const cjsEntryPath = path9.resolve(serverOutDir, "index.js");
|
|
2106
2154
|
let packageFn;
|
|
2107
2155
|
if (fs9.existsSync(esmEntryPath)) {
|
|
2108
|
-
const fileUrl =
|
|
2156
|
+
const fileUrl = pathToFileURL3(esmEntryPath).href + `?t=${Date.now()}`;
|
|
2109
2157
|
const mod = await import(fileUrl);
|
|
2110
2158
|
packageFn = mod?.default ?? mod;
|
|
2111
2159
|
} else if (fs9.existsSync(cjsEntryPath)) {
|