dazscript-framework 1.0.32 → 1.0.33
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 +20 -1
- package/dist/scripts/cli.js +17 -4
- package/dist/scripts/init.js +139 -0
- package/dist/scripts/integration.js +61 -8
- package/package.json +1 -1
- package/src/scripts/init.test.ts +43 -1
- package/src/scripts/integration.test.ts +42 -0
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
- [Installation & Setup](#installation--setup)
|
|
12
12
|
- [Unit Tests](#unit-tests)
|
|
13
13
|
- [DAZ Studio Integration Tests](#daz-studio-integration-tests)
|
|
14
|
+
- [DAZ Studio Headless Probes](#daz-studio-headless-probes)
|
|
14
15
|
- [Project Configuration](#project-configuration)
|
|
15
16
|
- [The `action(...)` Entrypoint](#the-action-entrypoint)
|
|
16
17
|
- [Build Output: Launcher Shims](#build-output-launcher-shims)
|
|
@@ -62,6 +63,7 @@ To include optional test scaffolds, run one or both:
|
|
|
62
63
|
```bash
|
|
63
64
|
npx dazscript init --unit-tests
|
|
64
65
|
npx dazscript init --integration-tests
|
|
66
|
+
npx dazscript init --probes
|
|
65
67
|
```
|
|
66
68
|
|
|
67
69
|
### 3. Write the script
|
|
@@ -177,6 +179,7 @@ Available `init` flags:
|
|
|
177
179
|
npx dazscript init --menu-path /MyScripts --scripts-path ./src --out-dir ./out --app-data-path YourName/my-project
|
|
178
180
|
npx dazscript init --unit-tests --app-data-path YourName/my-project
|
|
179
181
|
npx dazscript init --integration-tests --app-data-path YourName/my-project
|
|
182
|
+
npx dazscript init --probes --app-data-path YourName/my-project
|
|
180
183
|
```
|
|
181
184
|
|
|
182
185
|
| Flag | Description |
|
|
@@ -222,6 +225,22 @@ npm run test:integration
|
|
|
222
225
|
|
|
223
226
|
The generated script calls `dazscript integration --fixture ./test/integration/fixtures/<project>-smoke.dsa.ts`. Configure local machine paths in an ignored `.env.integration.local`; `DAZ_STUDIO_EXE` is always required, and `DAZ_TEST_CONTENT_DUF` is required only for tests that use `--require-content`. See `test/integration/README.md` in this repository for maintainer and consuming-project details.
|
|
224
227
|
|
|
228
|
+
### DAZ Studio headless probes
|
|
229
|
+
|
|
230
|
+
Projects can bootstrap non-asserting DAZ Studio probes with:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
npx dazscript init --probes
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Run a probe with:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
npm run probe
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Probes use the same headless DAZ build and launch infrastructure as integration tests, but they do not require `ok: true` assertions. A probe succeeds when DAZ completes and writes readable JSON. Use `dazscript probe` for exploratory runtime observations such as available globals, installed plugins, scene state, signal behavior, or content loading details.
|
|
243
|
+
|
|
225
244
|
---
|
|
226
245
|
|
|
227
246
|
### Project Configuration
|
|
@@ -592,7 +611,7 @@ my-daz-scripts/
|
|
|
592
611
|
|
|
593
612
|
Files ending in `.dsa.ts` are treated as runnable entry points and compiled to `.dsa`. Plain `.ts` files are modules — imported by entry points but not compiled independently.
|
|
594
613
|
|
|
595
|
-
The `test/unit/` files are generated only when you run `dazscript init --unit-tests`. The `test/integration/` files and env examples are generated only when you run `dazscript init --integration-tests`.
|
|
614
|
+
The `test/unit/` files are generated only when you run `dazscript init --unit-tests`. The `test/integration/` files and env examples are generated only when you run `dazscript init --integration-tests`. The `probes/` files and probe env examples are generated only when you run `dazscript init --probes`.
|
|
596
615
|
|
|
597
616
|
**Common commands**
|
|
598
617
|
|
package/dist/scripts/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ const { copyIcons } = require('./icons');
|
|
|
9
9
|
const { runEncrypt } = require('./encrypt');
|
|
10
10
|
const { generateInstallerFiles } = require('./install-generator');
|
|
11
11
|
const { initProject } = require('./init');
|
|
12
|
-
const { runIntegration } = require('./integration');
|
|
12
|
+
const { runIntegration, runProbe } = require('./integration');
|
|
13
13
|
|
|
14
14
|
function printHelp() {
|
|
15
15
|
console.log(`dazscript <command> [options]
|
|
@@ -22,6 +22,7 @@ Commands:
|
|
|
22
22
|
icons Copy png assets into the output directory
|
|
23
23
|
installer Generate Install.dsa.ts and Uninstall.dsa.ts
|
|
24
24
|
integration Run a DAZ Studio headless integration fixture
|
|
25
|
+
probe Run a non-asserting DAZ Studio headless probe fixture
|
|
25
26
|
|
|
26
27
|
Options:
|
|
27
28
|
--menu-path <path> Default menu path. Default: /MyScripts
|
|
@@ -32,11 +33,12 @@ Options:
|
|
|
32
33
|
--daz-studio <path> Daz Studio executable for encrypt
|
|
33
34
|
--keep-source Keep source script.dsa files after encrypting
|
|
34
35
|
--timeout-ms <value> Daz Studio encrypt timeout. Default: 300000
|
|
35
|
-
--fixture <path> Integration fixture .dsa.ts file
|
|
36
|
-
--env-file <path> Integration env file.
|
|
37
|
-
--require-content Require DAZ_TEST_CONTENT_DUF for integration tests
|
|
36
|
+
--fixture <path> Integration or probe fixture .dsa.ts file
|
|
37
|
+
--env-file <path> Integration/probe env file. Defaults: .env.integration.local or .env.probe.local
|
|
38
|
+
--require-content Require DAZ_TEST_CONTENT_DUF for integration tests or probes
|
|
38
39
|
--unit-tests Add Vitest unit-test scaffold during init
|
|
39
40
|
--integration-tests Add integration-test scaffold during init
|
|
41
|
+
--probes Add DAZ headless probe scaffold during init
|
|
40
42
|
--force Overwrite generated files
|
|
41
43
|
--help Show this message
|
|
42
44
|
`);
|
|
@@ -109,6 +111,11 @@ function parseOptions(args, defaults) {
|
|
|
109
111
|
continue;
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
if (arg === '--probes') {
|
|
115
|
+
options.probes = true;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
112
119
|
if (arg === '--menu-path') {
|
|
113
120
|
options.menuPath = args[index + 1];
|
|
114
121
|
index += 1;
|
|
@@ -230,6 +237,7 @@ async function main(argv) {
|
|
|
230
237
|
requireContent: false,
|
|
231
238
|
unitTests: false,
|
|
232
239
|
integrationTests: false,
|
|
240
|
+
probes: false,
|
|
233
241
|
});
|
|
234
242
|
|
|
235
243
|
if (options.help) {
|
|
@@ -242,6 +250,11 @@ async function main(argv) {
|
|
|
242
250
|
return;
|
|
243
251
|
}
|
|
244
252
|
|
|
253
|
+
if (command === 'probe') {
|
|
254
|
+
await runProbe(options, process.env, workdir);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
245
258
|
const commandOptions =
|
|
246
259
|
command === 'init'
|
|
247
260
|
? await resolveInitOptions(workdir, options)
|
package/dist/scripts/init.js
CHANGED
|
@@ -147,6 +147,23 @@ function updatePackageJsonForIntegration(workdir, fixturePath) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
function updatePackageJsonForProbe(workdir, fixturePath) {
|
|
151
|
+
const packageJsonPath = path.join(workdir, 'package.json');
|
|
152
|
+
const packageJson = fs.existsSync(packageJsonPath)
|
|
153
|
+
? readJson(packageJsonPath)
|
|
154
|
+
: { private: true };
|
|
155
|
+
|
|
156
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
157
|
+
if (packageJson.scripts.probe) {
|
|
158
|
+
console.log('skip package.json probe');
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
packageJson.scripts.probe = `dazscript probe --fixture ${fixturePath}`;
|
|
162
|
+
writeJson(packageJsonPath, packageJson);
|
|
163
|
+
console.log('update package.json');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
150
167
|
function isNpmDefaultTestScript(scriptName, command) {
|
|
151
168
|
return scriptName === 'test' && command === 'echo "Error: no test specified" && exit 1';
|
|
152
169
|
}
|
|
@@ -423,6 +440,122 @@ function initIntegrationTests(workdir, options) {
|
|
|
423
440
|
ensureLine(path.join(workdir, '.gitignore'), '.env.integration.local');
|
|
424
441
|
}
|
|
425
442
|
|
|
443
|
+
function buildProbeFixtureContent() {
|
|
444
|
+
return `import { action } from '@dsf/core/action'
|
|
445
|
+
import { saveToFile } from '@dsf/helpers/file-helper'
|
|
446
|
+
import { getStringScriptArguments } from '@dsf/helpers/script-helper'
|
|
447
|
+
|
|
448
|
+
type ProbeResult = {
|
|
449
|
+
kind: string
|
|
450
|
+
status: string
|
|
451
|
+
observations: Record<string, unknown>
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const countSceneNodes = (): number => {
|
|
455
|
+
return Scene.getNumNodes()
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
action({ text: 'Scene Probe', menuPath: false }, () => {
|
|
459
|
+
const args = getStringScriptArguments()
|
|
460
|
+
const resultPath = args.length > 0 ? args[0] : ''
|
|
461
|
+
const result: ProbeResult = {
|
|
462
|
+
kind: 'daz-headless-probe',
|
|
463
|
+
status: 'observed',
|
|
464
|
+
observations: {
|
|
465
|
+
graphicsMode: App.getGraphicsMode(),
|
|
466
|
+
interfaceAvailable: !!App.getInterface(),
|
|
467
|
+
nodeCount: countSceneNodes(),
|
|
468
|
+
time: String(Scene.getTime()),
|
|
469
|
+
frame: Scene.getFrame()
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (resultPath) {
|
|
474
|
+
saveToFile(resultPath, JSON.stringify(result, null, 2))
|
|
475
|
+
}
|
|
476
|
+
})
|
|
477
|
+
`;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function buildProbeReadmeContent(fixturePath) {
|
|
481
|
+
return `# DAZ Headless Probes
|
|
482
|
+
|
|
483
|
+
Probes are non-asserting DAZ Studio headless scripts for runtime exploration. They are useful for AI-agent investigations where the desired output is structured observations, not pass/fail test assertions.
|
|
484
|
+
|
|
485
|
+
Create a local env file:
|
|
486
|
+
|
|
487
|
+
\`\`\`bash
|
|
488
|
+
cp .env.probe.linux.example .env.probe.local
|
|
489
|
+
\`\`\`
|
|
490
|
+
|
|
491
|
+
\`\`\`powershell
|
|
492
|
+
Copy-Item .env.probe.windows.example .env.probe.local
|
|
493
|
+
\`\`\`
|
|
494
|
+
|
|
495
|
+
Then run:
|
|
496
|
+
|
|
497
|
+
\`\`\`bash
|
|
498
|
+
npm run probe
|
|
499
|
+
\`\`\`
|
|
500
|
+
|
|
501
|
+
The default scene probe is:
|
|
502
|
+
|
|
503
|
+
\`\`\`text
|
|
504
|
+
${fixturePath}
|
|
505
|
+
\`\`\`
|
|
506
|
+
|
|
507
|
+
Generated output is written to \`probes/out/\` and ignored by git.
|
|
508
|
+
`;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function buildProbeLinuxEnvExample() {
|
|
512
|
+
return `# Copy this file to .env.probe.local and edit paths for your machine.
|
|
513
|
+
# Shell environment variables override values in .env.probe.local.
|
|
514
|
+
# DAZ_STUDIO_EXE is required for probes.
|
|
515
|
+
|
|
516
|
+
WINEPREFIX=/home/your-user/.local/share/daz-wine/prefix
|
|
517
|
+
DAZ_STUDIO_EXE=/home/your-user/.local/share/daz-wine/prefix/drive_c/Program Files/DAZ 3D/DAZStudio4/DAZStudio.exe
|
|
518
|
+
DAZ_PROBE_TIMEOUT_MS=300000
|
|
519
|
+
`;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function buildProbeWindowsEnvExample() {
|
|
523
|
+
return `# Copy this file to .env.probe.local and edit paths for your machine.
|
|
524
|
+
# Shell environment variables override values in .env.probe.local.
|
|
525
|
+
# Forward slashes avoid escaping issues in env files.
|
|
526
|
+
# DAZ_STUDIO_EXE is required for probes.
|
|
527
|
+
|
|
528
|
+
DAZ_STUDIO_EXE=C:/Program Files/DAZ 3D/DAZStudio4/DAZStudio.exe
|
|
529
|
+
DAZ_PROBE_TIMEOUT_MS=300000
|
|
530
|
+
`;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function initProbes(workdir, options) {
|
|
534
|
+
const fixtureBaseName = `${toFixtureName(path.basename(workdir))}-scene.dsa.ts`;
|
|
535
|
+
const fixturePath = `./probes/fixtures/${fixtureBaseName}`;
|
|
536
|
+
const localFixturePath = path.join(workdir, fixturePath);
|
|
537
|
+
|
|
538
|
+
writeFileIfNeeded(localFixturePath, buildProbeFixtureContent(), options.force);
|
|
539
|
+
writeFileIfNeeded(
|
|
540
|
+
path.join(workdir, 'probes/README.md'),
|
|
541
|
+
buildProbeReadmeContent(fixturePath),
|
|
542
|
+
options.force
|
|
543
|
+
);
|
|
544
|
+
writeFileIfNeeded(
|
|
545
|
+
path.join(workdir, '.env.probe.linux.example'),
|
|
546
|
+
buildProbeLinuxEnvExample(),
|
|
547
|
+
options.force
|
|
548
|
+
);
|
|
549
|
+
writeFileIfNeeded(
|
|
550
|
+
path.join(workdir, '.env.probe.windows.example'),
|
|
551
|
+
buildProbeWindowsEnvExample(),
|
|
552
|
+
options.force
|
|
553
|
+
);
|
|
554
|
+
updatePackageJsonForProbe(workdir, fixturePath);
|
|
555
|
+
ensureLine(path.join(workdir, '.gitignore'), 'probes/out/');
|
|
556
|
+
ensureLine(path.join(workdir, '.gitignore'), '.env.probe.local');
|
|
557
|
+
}
|
|
558
|
+
|
|
426
559
|
function initProject(workdir, rawOptions) {
|
|
427
560
|
const projectName = path.basename(workdir);
|
|
428
561
|
const options = {
|
|
@@ -434,6 +567,7 @@ function initProject(workdir, rawOptions) {
|
|
|
434
567
|
bundleName: toBundleName(projectName),
|
|
435
568
|
unitTests: Boolean(rawOptions.unitTests),
|
|
436
569
|
integrationTests: Boolean(rawOptions.integrationTests),
|
|
570
|
+
probes: Boolean(rawOptions.probes),
|
|
437
571
|
};
|
|
438
572
|
|
|
439
573
|
writeFileIfNeeded(
|
|
@@ -456,10 +590,15 @@ function initProject(workdir, rawOptions) {
|
|
|
456
590
|
if (options.integrationTests) {
|
|
457
591
|
initIntegrationTests(workdir, options);
|
|
458
592
|
}
|
|
593
|
+
|
|
594
|
+
if (options.probes) {
|
|
595
|
+
initProbes(workdir, options);
|
|
596
|
+
}
|
|
459
597
|
}
|
|
460
598
|
|
|
461
599
|
module.exports = {
|
|
462
600
|
initIntegrationTests,
|
|
601
|
+
initProbes,
|
|
463
602
|
initUnitTests,
|
|
464
603
|
initProject,
|
|
465
604
|
};
|
|
@@ -71,10 +71,10 @@ function assertRequiredFile(label, filePath, allowDazPath) {
|
|
|
71
71
|
return resolvedPath;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
function
|
|
74
|
+
function resolveHeadlessOptions(cwd, rawOptions, env, defaults) {
|
|
75
75
|
const options = rawOptions || {};
|
|
76
76
|
const projectRoot = path.resolve(cwd || process.cwd());
|
|
77
|
-
const envFile = path.resolve(projectRoot, options.envFile ||
|
|
77
|
+
const envFile = path.resolve(projectRoot, options.envFile || defaults.envFile);
|
|
78
78
|
const fixturePath = options.fixture
|
|
79
79
|
? path.resolve(projectRoot, options.fixture)
|
|
80
80
|
: '';
|
|
@@ -100,12 +100,12 @@ function resolveIntegrationOptions(cwd, rawOptions, env) {
|
|
|
100
100
|
throw new Error(`DAZ_TEST_CONTENT_DUF does not exist: ${path.resolve(rawContentPath)}`);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
const timeoutMs = Number(options.timeoutMs || env.DAZ_TEST_TIMEOUT_MS || defaultTimeoutMs);
|
|
103
|
+
const timeoutMs = Number(options.timeoutMs || env[defaults.timeoutEnv] || env.DAZ_TEST_TIMEOUT_MS || defaultTimeoutMs);
|
|
104
104
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
105
|
-
throw new Error(`invalid timeout: ${options.timeoutMs || env.DAZ_TEST_TIMEOUT_MS}`);
|
|
105
|
+
throw new Error(`invalid timeout: ${options.timeoutMs || env[defaults.timeoutEnv] || env.DAZ_TEST_TIMEOUT_MS}`);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const outDir = path.resolve(projectRoot, options.outDir ||
|
|
108
|
+
const outDir = path.resolve(projectRoot, options.outDir || defaults.outDir);
|
|
109
109
|
const fixtureName = path.basename(fixturePath).replace(/\.dsa\.ts$/i, '').replace(/\.ts$/i, '');
|
|
110
110
|
const fixtureRoot = path.join(outDir, 'fixture');
|
|
111
111
|
const resultPath = path.join(fixtureRoot, 'result.json');
|
|
@@ -124,12 +124,35 @@ function resolveIntegrationOptions(cwd, rawOptions, env) {
|
|
|
124
124
|
contentPath: rawContentPath ? normalizeForDaz(rawContentPath) : '',
|
|
125
125
|
requireContent: Boolean(options.requireContent),
|
|
126
126
|
timeoutMs,
|
|
127
|
-
appDataPath: options.appDataPath ||
|
|
128
|
-
bundleName: options.bundleName ||
|
|
127
|
+
appDataPath: options.appDataPath || defaults.appDataPath,
|
|
128
|
+
bundleName: options.bundleName || defaults.bundleName,
|
|
129
|
+
commandName: defaults.commandName,
|
|
129
130
|
env,
|
|
130
131
|
};
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
function resolveIntegrationOptions(cwd, rawOptions, env) {
|
|
135
|
+
return resolveHeadlessOptions(cwd, rawOptions, env, {
|
|
136
|
+
commandName: 'integration',
|
|
137
|
+
envFile: '.env.integration.local',
|
|
138
|
+
timeoutEnv: 'DAZ_TEST_TIMEOUT_MS',
|
|
139
|
+
outDir: './test/integration/out',
|
|
140
|
+
appDataPath: 'DazScriptFramework/integration-tests',
|
|
141
|
+
bundleName: 'Integration Test Fixture',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function resolveProbeOptions(cwd, rawOptions, env) {
|
|
146
|
+
return resolveHeadlessOptions(cwd, rawOptions, env, {
|
|
147
|
+
commandName: 'probe',
|
|
148
|
+
envFile: '.env.probe.local',
|
|
149
|
+
timeoutEnv: 'DAZ_PROBE_TIMEOUT_MS',
|
|
150
|
+
outDir: './probes/out',
|
|
151
|
+
appDataPath: 'DazScriptFramework/probes',
|
|
152
|
+
bundleName: 'Probe Fixture',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
133
156
|
function run(command, args, options) {
|
|
134
157
|
const result = spawnSync(command, args, {
|
|
135
158
|
cwd: options.cwd,
|
|
@@ -306,7 +329,7 @@ function runDazFixture(options) {
|
|
|
306
329
|
const command = useWine ? 'wine' : options.dazStudioExe;
|
|
307
330
|
const commandArgs = useWine ? [options.dazStudioExe].concat(dazArgs) : dazArgs;
|
|
308
331
|
|
|
309
|
-
console.log(`[dazscript integration] launching DAZ: ${useWine ? `${command} ${options.dazStudioExe}` : command}`);
|
|
332
|
+
console.log(`[dazscript ${options.commandName || 'integration'}] launching DAZ: ${useWine ? `${command} ${options.dazStudioExe}` : command}`);
|
|
310
333
|
run(command, commandArgs, {
|
|
311
334
|
cwd: options.fixtureRoot,
|
|
312
335
|
env: options.env,
|
|
@@ -335,6 +358,19 @@ function readIntegrationResult(resultPath) {
|
|
|
335
358
|
return result;
|
|
336
359
|
}
|
|
337
360
|
|
|
361
|
+
function readProbeResult(resultPath) {
|
|
362
|
+
if (!fs.existsSync(resultPath)) {
|
|
363
|
+
throw new Error(`DAZ did not write result JSON: ${resultPath}`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
return JSON.parse(fs.readFileSync(resultPath, 'utf8'));
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
throw new Error(`could not parse result JSON: ${error}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
338
374
|
async function runIntegration(rawOptions, injectedEnv, cwd) {
|
|
339
375
|
const env = { ...(injectedEnv || process.env) };
|
|
340
376
|
const projectRoot = path.resolve(cwd || process.cwd());
|
|
@@ -349,14 +385,31 @@ async function runIntegration(rawOptions, injectedEnv, cwd) {
|
|
|
349
385
|
return result;
|
|
350
386
|
}
|
|
351
387
|
|
|
388
|
+
async function runProbe(rawOptions, injectedEnv, cwd) {
|
|
389
|
+
const env = { ...(injectedEnv || process.env) };
|
|
390
|
+
const projectRoot = path.resolve(cwd || process.cwd());
|
|
391
|
+
const envFile = path.resolve(projectRoot, (rawOptions && rawOptions.envFile) || '.env.probe.local');
|
|
392
|
+
loadEnvFile(envFile, env);
|
|
393
|
+
|
|
394
|
+
const options = resolveProbeOptions(projectRoot, rawOptions, env);
|
|
395
|
+
buildFixtureProject(options);
|
|
396
|
+
runDazFixture(options);
|
|
397
|
+
const result = readProbeResult(options.resultPath);
|
|
398
|
+
console.log(`[dazscript probe] result: ${options.resultPath}`);
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
|
|
352
402
|
module.exports = {
|
|
353
403
|
loadEnvFile,
|
|
354
404
|
normalizeForDaz,
|
|
355
405
|
getNpmInvocation,
|
|
356
406
|
getFixtureBuildDependencies,
|
|
357
407
|
readIntegrationResult,
|
|
408
|
+
readProbeResult,
|
|
358
409
|
resolveIntegrationOptions,
|
|
410
|
+
resolveProbeOptions,
|
|
359
411
|
buildFixtureProject,
|
|
360
412
|
runDazFixture,
|
|
361
413
|
runIntegration,
|
|
414
|
+
runProbe,
|
|
362
415
|
};
|
package/package.json
CHANGED
package/src/scripts/init.test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import os from 'node:os'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
5
5
|
|
|
6
|
-
const { initIntegrationTests, initUnitTests } = require('../../dist/scripts/init')
|
|
6
|
+
const { initIntegrationTests, initProbes, initUnitTests } = require('../../dist/scripts/init')
|
|
7
7
|
|
|
8
8
|
const tempDirs: string[] = []
|
|
9
9
|
|
|
@@ -74,6 +74,48 @@ describe('init integration tests', () => {
|
|
|
74
74
|
})
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
+
describe('init probes', () => {
|
|
78
|
+
it('creates the probe fixture, docs, env examples, npm script, and ignore entries', () => {
|
|
79
|
+
const projectDir = makeProject('probe-test')
|
|
80
|
+
const fixtureBaseName = toFixtureName(projectDir)
|
|
81
|
+
|
|
82
|
+
initProbes(projectDir, { force: false })
|
|
83
|
+
|
|
84
|
+
const fixturePath = path.join(projectDir, `probes/fixtures/${fixtureBaseName}-scene.dsa.ts`)
|
|
85
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(projectDir, 'package.json'), 'utf8'))
|
|
86
|
+
const gitignore = fs.readFileSync(path.join(projectDir, '.gitignore'), 'utf8')
|
|
87
|
+
|
|
88
|
+
expect(fs.existsSync(fixturePath)).toBe(true)
|
|
89
|
+
expect(fs.existsSync(path.join(projectDir, 'probes/README.md'))).toBe(true)
|
|
90
|
+
expect(fs.existsSync(path.join(projectDir, '.env.probe.linux.example'))).toBe(true)
|
|
91
|
+
expect(fs.existsSync(path.join(projectDir, '.env.probe.windows.example'))).toBe(true)
|
|
92
|
+
expect(packageJson.scripts.probe).toBe(
|
|
93
|
+
`dazscript probe --fixture ./probes/fixtures/${fixtureBaseName}-scene.dsa.ts`
|
|
94
|
+
)
|
|
95
|
+
expect(gitignore).toContain('probes/out/')
|
|
96
|
+
expect(gitignore).toContain('.env.probe.local')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('does not replace an existing probe script or duplicate ignore entries', () => {
|
|
100
|
+
const projectDir = makeProject('existing-probe')
|
|
101
|
+
const packageJsonPath = path.join(projectDir, 'package.json')
|
|
102
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
103
|
+
packageJson.scripts.probe = 'custom probe'
|
|
104
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
105
|
+
fs.writeFileSync(path.join(projectDir, '.gitignore'), 'probes/out/\n')
|
|
106
|
+
|
|
107
|
+
initProbes(projectDir, { force: false })
|
|
108
|
+
initProbes(projectDir, { force: false })
|
|
109
|
+
|
|
110
|
+
const updatedPackageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
111
|
+
const gitignore = fs.readFileSync(path.join(projectDir, '.gitignore'), 'utf8')
|
|
112
|
+
|
|
113
|
+
expect(updatedPackageJson.scripts.probe).toBe('custom probe')
|
|
114
|
+
expect(gitignore.match(/probes\/out\//g)?.length).toBe(1)
|
|
115
|
+
expect(gitignore.match(/\.env\.probe\.local/g)?.length).toBe(1)
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
77
119
|
describe('init unit tests', () => {
|
|
78
120
|
it('creates Vitest config, sample test, docs, npm scripts, and dev dependency', () => {
|
|
79
121
|
const projectDir = makeProject('unit-test')
|
|
@@ -8,7 +8,9 @@ const {
|
|
|
8
8
|
getFixtureBuildDependencies,
|
|
9
9
|
getNpmInvocation,
|
|
10
10
|
readIntegrationResult,
|
|
11
|
+
readProbeResult,
|
|
11
12
|
resolveIntegrationOptions,
|
|
13
|
+
resolveProbeOptions,
|
|
12
14
|
} = require('../../dist/scripts/integration')
|
|
13
15
|
|
|
14
16
|
const tempDirs: string[] = []
|
|
@@ -80,6 +82,28 @@ describe('integration option resolution', () => {
|
|
|
80
82
|
})
|
|
81
83
|
})
|
|
82
84
|
|
|
85
|
+
describe('probe option resolution', () => {
|
|
86
|
+
it('uses probe-specific env and output defaults', () => {
|
|
87
|
+
const projectDir = makeProject()
|
|
88
|
+
fs.mkdirSync(path.join(projectDir, 'probes/fixtures'), { recursive: true })
|
|
89
|
+
fs.writeFileSync(path.join(projectDir, 'probes/fixtures/scene.dsa.ts'), 'action({}, function() {})\n')
|
|
90
|
+
|
|
91
|
+
const options = resolveProbeOptions(projectDir, {
|
|
92
|
+
fixture: './probes/fixtures/scene.dsa.ts',
|
|
93
|
+
}, {
|
|
94
|
+
DAZ_STUDIO_EXE: path.join(projectDir, 'DAZStudio.exe'),
|
|
95
|
+
DAZ_PROBE_TIMEOUT_MS: '123456',
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
expect(options.envFile).toBe(path.join(projectDir, '.env.probe.local'))
|
|
99
|
+
expect(options.outDir).toBe(path.join(projectDir, 'probes/out'))
|
|
100
|
+
expect(options.fixtureRoot).toBe(path.join(projectDir, 'probes/out/fixture'))
|
|
101
|
+
expect(options.resultPath).toBe(path.join(projectDir, 'probes/out/fixture/result.json'))
|
|
102
|
+
expect(options.timeoutMs).toBe(123456)
|
|
103
|
+
expect(options.commandName).toBe('probe')
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
83
107
|
describe('integration command resolution', () => {
|
|
84
108
|
it('uses node plus npm-cli on Windows so child_process can spawn without a shell', () => {
|
|
85
109
|
const invocation = getNpmInvocation(['--version'], 'win32')
|
|
@@ -125,3 +149,21 @@ describe('integration result reader', () => {
|
|
|
125
149
|
expect(() => readIntegrationResult(resultPath)).toThrow(/bad frame/)
|
|
126
150
|
})
|
|
127
151
|
})
|
|
152
|
+
|
|
153
|
+
describe('probe result reader', () => {
|
|
154
|
+
it('accepts arbitrary readable probe JSON without ok assertions', () => {
|
|
155
|
+
const projectDir = makeProject()
|
|
156
|
+
const resultPath = path.join(projectDir, 'result.json')
|
|
157
|
+
fs.writeFileSync(resultPath, JSON.stringify({
|
|
158
|
+
kind: 'daz-headless-probe',
|
|
159
|
+
status: 'inconclusive',
|
|
160
|
+
observations: { interfaceAvailable: false }
|
|
161
|
+
}))
|
|
162
|
+
|
|
163
|
+
expect(readProbeResult(resultPath)).toEqual({
|
|
164
|
+
kind: 'daz-headless-probe',
|
|
165
|
+
status: 'inconclusive',
|
|
166
|
+
observations: { interfaceAvailable: false }
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
})
|