dazscript-framework 1.0.29 → 1.0.31
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 +60 -0
- package/dist/scripts/cli.js +44 -0
- package/dist/scripts/init.js +329 -0
- package/dist/scripts/integration.js +304 -0
- package/dist/scripts/launchers.js +7 -1
- package/package.json +2 -1
- package/src/helpers/progress-helper.test.ts +95 -0
- package/src/helpers/progress-helper.ts +89 -29
- package/src/helpers/script-helper.ts +6 -1
- package/src/scripts/init.test.ts +131 -0
- package/src/scripts/integration.test.ts +97 -0
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
- [Quick Start: A Simple Dialog](#quick-start-a-simple-dialog)
|
|
10
10
|
- [Documentation](#documentation)
|
|
11
11
|
- [Installation & Setup](#installation--setup)
|
|
12
|
+
- [Unit Tests](#unit-tests)
|
|
13
|
+
- [DAZ Studio Integration Tests](#daz-studio-integration-tests)
|
|
12
14
|
- [Project Configuration](#project-configuration)
|
|
13
15
|
- [The `action(...)` Entrypoint](#the-action-entrypoint)
|
|
14
16
|
- [Build Output: Launcher Shims](#build-output-launcher-shims)
|
|
@@ -55,6 +57,13 @@ npx dazscript init
|
|
|
55
57
|
|
|
56
58
|
Follow the prompt for your AppData author namespace (e.g. `YourName/my-project`). This creates `dazscript.config.ts`, `tsconfig.json`, and wires the `build`, `build:encrypted`, `build:release`, `watch`, `encrypt`, `icons`, and `installer` scripts into `package.json`.
|
|
57
59
|
|
|
60
|
+
To include optional test scaffolds, run one or both:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx dazscript init --unit-tests
|
|
64
|
+
npx dazscript init --integration-tests
|
|
65
|
+
```
|
|
66
|
+
|
|
58
67
|
### 3. Write the script
|
|
59
68
|
|
|
60
69
|
Create `src/hello-world.dsa.ts`:
|
|
@@ -166,6 +175,8 @@ Available `init` flags:
|
|
|
166
175
|
|
|
167
176
|
```bash
|
|
168
177
|
npx dazscript init --menu-path /MyScripts --scripts-path ./src --out-dir ./out --app-data-path YourName/my-project
|
|
178
|
+
npx dazscript init --unit-tests --app-data-path YourName/my-project
|
|
179
|
+
npx dazscript init --integration-tests --app-data-path YourName/my-project
|
|
169
180
|
```
|
|
170
181
|
|
|
171
182
|
| Flag | Description |
|
|
@@ -174,11 +185,43 @@ npx dazscript init --menu-path /MyScripts --scripts-path ./src --out-dir ./out -
|
|
|
174
185
|
| `--scripts-path` | Where the generator scans for runnable `.dsa.ts` entry files |
|
|
175
186
|
| `--out-dir` | Where `build` writes `.dsa` files and copies icons |
|
|
176
187
|
| `--app-data-path` | AppData namespace for launcher fallback (`Author/Product` format) |
|
|
188
|
+
| `--unit-tests` | Add Vitest config, sample unit test, unit-test docs, `test` scripts, and the `vitest` dev dependency |
|
|
189
|
+
| `--integration-tests` | Add a DAZ Studio headless integration-test fixture, env examples, ignore entries, and `test:integration` script |
|
|
177
190
|
|
|
178
191
|
Builds also accept `--log-level <trace|debug|info|warn|error|off>`. This sets the minimum runtime log level for the compiled scripts. When omitted, builds default to `debug`; use `warn` for release packages.
|
|
179
192
|
|
|
180
193
|
Use `--scripts-path ./src/scripts` when runnable files live under a subfolder; use `--scripts-path ./src` when they are at the source root.
|
|
181
194
|
|
|
195
|
+
### Unit tests
|
|
196
|
+
|
|
197
|
+
Projects can bootstrap fast Node-side TypeScript tests with:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npx dazscript init --unit-tests
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
This adds:
|
|
204
|
+
|
|
205
|
+
- `vitest.config.ts`
|
|
206
|
+
- `tsconfig.test.json`
|
|
207
|
+
- `test/unit/smoke.test.ts`
|
|
208
|
+
- `test/unit/README.md`
|
|
209
|
+
- `npm test`
|
|
210
|
+
- `npm run test:watch`
|
|
211
|
+
- `vitest` as a dev dependency
|
|
212
|
+
|
|
213
|
+
Use unit tests for pure TypeScript helpers, parsing, normalization, and code that does not need Daz Studio runtime objects.
|
|
214
|
+
|
|
215
|
+
### DAZ Studio integration tests
|
|
216
|
+
|
|
217
|
+
Projects can run real DAZ Studio smoke tests through the published CLI:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npm run test:integration
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
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
|
+
|
|
182
225
|
---
|
|
183
226
|
|
|
184
227
|
### Project Configuration
|
|
@@ -528,14 +571,29 @@ my-daz-scripts/
|
|
|
528
571
|
│ ├── my-dialog-model.ts # plain TypeScript — model or helper class
|
|
529
572
|
│ ├── my-dialog.ts
|
|
530
573
|
│ └── my-dialog-script.dsa.ts # runnable entry point
|
|
574
|
+
├── test/
|
|
575
|
+
│ ├── integration/
|
|
576
|
+
│ │ ├── fixtures/
|
|
577
|
+
│ │ │ └── my-daz-scripts-smoke.dsa.ts
|
|
578
|
+
│ │ ├── out/ # integration output, ignored by git
|
|
579
|
+
│ │ └── README.md
|
|
580
|
+
│ └── unit/
|
|
581
|
+
│ ├── smoke.test.ts
|
|
582
|
+
│ └── README.md
|
|
531
583
|
├── out/ # build output — launchers, bundles, icons
|
|
584
|
+
├── .env.integration.linux.example
|
|
585
|
+
├── .env.integration.windows.example
|
|
532
586
|
├── dazscript.config.ts
|
|
533
587
|
├── tsconfig.json
|
|
588
|
+
├── tsconfig.test.json
|
|
589
|
+
├── vitest.config.ts
|
|
534
590
|
└── package.json
|
|
535
591
|
```
|
|
536
592
|
|
|
537
593
|
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.
|
|
538
594
|
|
|
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`.
|
|
596
|
+
|
|
539
597
|
**Common commands**
|
|
540
598
|
|
|
541
599
|
| Command | What it does |
|
|
@@ -545,6 +603,8 @@ Files ending in `.dsa.ts` are treated as runnable entry points and compiled to `
|
|
|
545
603
|
| `npm run watch` | Recompile on every save |
|
|
546
604
|
| `npm run installer` | Generate the setup dialog |
|
|
547
605
|
| `npm run icons` | Copy icon assets to the output folder |
|
|
606
|
+
| `npm test` | Run fast Node/Vitest tests |
|
|
607
|
+
| `npm run test:integration` | Run a DAZ Studio headless integration fixture |
|
|
548
608
|
|
|
549
609
|
---
|
|
550
610
|
|
package/dist/scripts/cli.js
CHANGED
|
@@ -9,6 +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
13
|
|
|
13
14
|
function printHelp() {
|
|
14
15
|
console.log(`dazscript <command> [options]
|
|
@@ -20,6 +21,7 @@ Commands:
|
|
|
20
21
|
encrypt Encrypt built implementation bundles through Daz Studio
|
|
21
22
|
icons Copy png assets into the output directory
|
|
22
23
|
installer Generate Install.dsa.ts and Uninstall.dsa.ts
|
|
24
|
+
integration Run a DAZ Studio headless integration fixture
|
|
23
25
|
|
|
24
26
|
Options:
|
|
25
27
|
--menu-path <path> Default menu path. Default: /MyScripts
|
|
@@ -30,6 +32,11 @@ Options:
|
|
|
30
32
|
--daz-studio <path> Daz Studio executable for encrypt
|
|
31
33
|
--keep-source Keep source script.dsa files after encrypting
|
|
32
34
|
--timeout-ms <value> Daz Studio encrypt timeout. Default: 300000
|
|
35
|
+
--fixture <path> Integration fixture .dsa.ts file
|
|
36
|
+
--env-file <path> Integration env file. Default: .env.integration.local
|
|
37
|
+
--require-content Require DAZ_TEST_CONTENT_DUF for integration tests
|
|
38
|
+
--unit-tests Add Vitest unit-test scaffold during init
|
|
39
|
+
--integration-tests Add integration-test scaffold during init
|
|
33
40
|
--force Overwrite generated files
|
|
34
41
|
--help Show this message
|
|
35
42
|
`);
|
|
@@ -92,6 +99,16 @@ function parseOptions(args, defaults) {
|
|
|
92
99
|
continue;
|
|
93
100
|
}
|
|
94
101
|
|
|
102
|
+
if (arg === '--integration-tests') {
|
|
103
|
+
options.integrationTests = true;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (arg === '--unit-tests') {
|
|
108
|
+
options.unitTests = true;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
95
112
|
if (arg === '--menu-path') {
|
|
96
113
|
options.menuPath = args[index + 1];
|
|
97
114
|
index += 1;
|
|
@@ -139,6 +156,23 @@ function parseOptions(args, defaults) {
|
|
|
139
156
|
continue;
|
|
140
157
|
}
|
|
141
158
|
|
|
159
|
+
if (arg === '--fixture') {
|
|
160
|
+
options.fixture = args[index + 1];
|
|
161
|
+
index += 1;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (arg === '--env-file') {
|
|
166
|
+
options.envFile = args[index + 1];
|
|
167
|
+
index += 1;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (arg === '--require-content') {
|
|
172
|
+
options.requireContent = true;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
142
176
|
if (arg === '--file') {
|
|
143
177
|
options.file = args[index + 1];
|
|
144
178
|
index += 1;
|
|
@@ -191,6 +225,11 @@ async function main(argv) {
|
|
|
191
225
|
dazStudio: undefined,
|
|
192
226
|
keepSource: false,
|
|
193
227
|
timeoutMs: undefined,
|
|
228
|
+
fixture: undefined,
|
|
229
|
+
envFile: undefined,
|
|
230
|
+
requireContent: false,
|
|
231
|
+
unitTests: false,
|
|
232
|
+
integrationTests: false,
|
|
194
233
|
});
|
|
195
234
|
|
|
196
235
|
if (options.help) {
|
|
@@ -198,6 +237,11 @@ async function main(argv) {
|
|
|
198
237
|
return;
|
|
199
238
|
}
|
|
200
239
|
|
|
240
|
+
if (command === 'integration') {
|
|
241
|
+
await runIntegration(options, process.env, workdir);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
201
245
|
const commandOptions =
|
|
202
246
|
command === 'init'
|
|
203
247
|
? await resolveInitOptions(workdir, options)
|
package/dist/scripts/init.js
CHANGED
|
@@ -37,11 +37,28 @@ function writeFileIfNeeded(filePath, content, force) {
|
|
|
37
37
|
return false;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
40
41
|
fs.writeFileSync(filePath, content);
|
|
41
42
|
console.log(`write ${path.basename(filePath)}`);
|
|
42
43
|
return true;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
function ensureLine(filePath, line) {
|
|
47
|
+
const existing = fs.existsSync(filePath)
|
|
48
|
+
? fs.readFileSync(filePath, 'utf8')
|
|
49
|
+
: '';
|
|
50
|
+
const lines = existing.split(/\r?\n/).map((item) => item.trim()).filter(Boolean);
|
|
51
|
+
|
|
52
|
+
if (lines.includes(line)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const prefix = existing && !existing.endsWith('\n') ? '\n' : '';
|
|
57
|
+
fs.appendFileSync(filePath, `${prefix}${line}\n`);
|
|
58
|
+
console.log(`update ${path.basename(filePath)}`);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
function buildConfigContent(options) {
|
|
46
63
|
return `import { defineConfig } from 'dazscript-framework/config';
|
|
47
64
|
|
|
@@ -63,6 +80,13 @@ function toBundleName(projectName) {
|
|
|
63
80
|
.join(' ');
|
|
64
81
|
}
|
|
65
82
|
|
|
83
|
+
function toFixtureName(projectName) {
|
|
84
|
+
return projectName
|
|
85
|
+
.toLowerCase()
|
|
86
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
87
|
+
.replace(/^-+|-+$/g, '') || 'project';
|
|
88
|
+
}
|
|
89
|
+
|
|
66
90
|
function buildTsconfigContent() {
|
|
67
91
|
return `{
|
|
68
92
|
"extends": "./node_modules/dazscript-framework/tsconfig.json",
|
|
@@ -106,6 +130,299 @@ function updatePackageJson(workdir, options) {
|
|
|
106
130
|
console.log('update package.json');
|
|
107
131
|
}
|
|
108
132
|
|
|
133
|
+
function updatePackageJsonForIntegration(workdir, fixturePath) {
|
|
134
|
+
const packageJsonPath = path.join(workdir, 'package.json');
|
|
135
|
+
const packageJson = fs.existsSync(packageJsonPath)
|
|
136
|
+
? readJson(packageJsonPath)
|
|
137
|
+
: { private: true };
|
|
138
|
+
|
|
139
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
140
|
+
if (packageJson.scripts['test:integration']) {
|
|
141
|
+
console.log('skip package.json test:integration');
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
packageJson.scripts['test:integration'] = `dazscript integration --fixture ${fixturePath}`;
|
|
145
|
+
writeJson(packageJsonPath, packageJson);
|
|
146
|
+
console.log('update package.json');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function isNpmDefaultTestScript(scriptName, command) {
|
|
151
|
+
return scriptName === 'test' && command === 'echo "Error: no test specified" && exit 1';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function setPackageScript(packageJson, scriptName, command) {
|
|
155
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
156
|
+
const existingCommand = packageJson.scripts[scriptName];
|
|
157
|
+
if (existingCommand && !isNpmDefaultTestScript(scriptName, existingCommand)) {
|
|
158
|
+
console.log(`skip package.json ${scriptName}`);
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
packageJson.scripts[scriptName] = command;
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function setDevDependency(packageJson, dependencyName, version) {
|
|
167
|
+
packageJson.devDependencies = packageJson.devDependencies || {};
|
|
168
|
+
if (packageJson.devDependencies[dependencyName]) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
packageJson.devDependencies[dependencyName] = version;
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function updatePackageJsonForUnitTests(workdir) {
|
|
177
|
+
const packageJsonPath = path.join(workdir, 'package.json');
|
|
178
|
+
const packageJson = fs.existsSync(packageJsonPath)
|
|
179
|
+
? readJson(packageJsonPath)
|
|
180
|
+
: { private: true };
|
|
181
|
+
|
|
182
|
+
let changed = false;
|
|
183
|
+
changed = setPackageScript(packageJson, 'test', 'vitest run') || changed;
|
|
184
|
+
changed = setPackageScript(packageJson, 'test:watch', 'vitest') || changed;
|
|
185
|
+
changed = setDevDependency(packageJson, 'vitest', '^3.0.0') || changed;
|
|
186
|
+
|
|
187
|
+
if (changed) {
|
|
188
|
+
writeJson(packageJsonPath, packageJson);
|
|
189
|
+
console.log('update package.json');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function buildVitestConfigContent() {
|
|
194
|
+
return `import path from 'node:path'
|
|
195
|
+
import { defineConfig } from 'vitest/config'
|
|
196
|
+
|
|
197
|
+
export default defineConfig({
|
|
198
|
+
test: {
|
|
199
|
+
environment: 'node',
|
|
200
|
+
include: ['src/**/*.test.ts', 'test/unit/**/*.test.ts']
|
|
201
|
+
},
|
|
202
|
+
resolve: {
|
|
203
|
+
alias: {
|
|
204
|
+
'@dsf': path.resolve(__dirname, 'node_modules/dazscript-framework/src'),
|
|
205
|
+
'@dst': path.resolve(__dirname, 'node_modules/dazscript-types/src/types')
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function buildTestTsconfigContent() {
|
|
213
|
+
return `{
|
|
214
|
+
"extends": "./tsconfig.json",
|
|
215
|
+
"compilerOptions": {
|
|
216
|
+
"moduleResolution": "Node"
|
|
217
|
+
},
|
|
218
|
+
"include": ["src/**/*.test.ts", "test/unit/**/*.test.ts"],
|
|
219
|
+
"exclude": []
|
|
220
|
+
}
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function buildUnitTestContent() {
|
|
225
|
+
return `import { describe, expect, it } from 'vitest'
|
|
226
|
+
|
|
227
|
+
const toTitleCase = (value: string): string =>
|
|
228
|
+
value
|
|
229
|
+
.split(/[-_\\s]+/)
|
|
230
|
+
.filter(Boolean)
|
|
231
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
232
|
+
.join(' ')
|
|
233
|
+
|
|
234
|
+
describe('unit test scaffold', () => {
|
|
235
|
+
it('runs TypeScript tests with Vitest', () => {
|
|
236
|
+
expect(toTitleCase('hello-daz-script')).toBe('Hello Daz Script')
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function buildUnitTestReadmeContent() {
|
|
243
|
+
return `# Unit Tests
|
|
244
|
+
|
|
245
|
+
This project uses Vitest for fast Node-side unit tests.
|
|
246
|
+
|
|
247
|
+
Run once:
|
|
248
|
+
|
|
249
|
+
\`\`\`bash
|
|
250
|
+
npm test
|
|
251
|
+
\`\`\`
|
|
252
|
+
|
|
253
|
+
Watch mode:
|
|
254
|
+
|
|
255
|
+
\`\`\`bash
|
|
256
|
+
npm run test:watch
|
|
257
|
+
\`\`\`
|
|
258
|
+
|
|
259
|
+
Unit tests are useful for pure TypeScript helpers, parsing, normalization, and other logic that does not require Daz Studio runtime objects. Use DAZ Studio integration tests for helpers that must execute inside Daz Studio.
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function initUnitTests(workdir, options) {
|
|
264
|
+
writeFileIfNeeded(
|
|
265
|
+
path.join(workdir, 'vitest.config.ts'),
|
|
266
|
+
buildVitestConfigContent(),
|
|
267
|
+
options.force
|
|
268
|
+
);
|
|
269
|
+
writeFileIfNeeded(
|
|
270
|
+
path.join(workdir, 'tsconfig.test.json'),
|
|
271
|
+
buildTestTsconfigContent(),
|
|
272
|
+
options.force
|
|
273
|
+
);
|
|
274
|
+
writeFileIfNeeded(
|
|
275
|
+
path.join(workdir, 'test/unit/smoke.test.ts'),
|
|
276
|
+
buildUnitTestContent(),
|
|
277
|
+
options.force
|
|
278
|
+
);
|
|
279
|
+
writeFileIfNeeded(
|
|
280
|
+
path.join(workdir, 'test/unit/README.md'),
|
|
281
|
+
buildUnitTestReadmeContent(),
|
|
282
|
+
options.force
|
|
283
|
+
);
|
|
284
|
+
updatePackageJsonForUnitTests(workdir);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function buildIntegrationFixtureContent() {
|
|
288
|
+
return `import { action } from '@dsf/core/action'
|
|
289
|
+
import { saveToFile } from '@dsf/helpers/file-helper'
|
|
290
|
+
import { currentTime, frameToTime, getCurrentFrame, timeToFrame } from '@dsf/helpers/scene-helper'
|
|
291
|
+
import { getStringScriptArguments } from '@dsf/helpers/script-helper'
|
|
292
|
+
|
|
293
|
+
type IntegrationResult = {
|
|
294
|
+
ok: boolean
|
|
295
|
+
project: string
|
|
296
|
+
checks: Record<string, unknown>
|
|
297
|
+
failures: string[]
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const isNumber = (value: unknown): boolean => typeof value === 'number' && !isNaN(value as number)
|
|
301
|
+
|
|
302
|
+
action({ text: 'Integration Smoke Test', menuPath: false }, () => {
|
|
303
|
+
const args = getStringScriptArguments()
|
|
304
|
+
const resultPath = args.length > 0 ? args[0] : ''
|
|
305
|
+
const failures: string[] = []
|
|
306
|
+
const frame = getCurrentFrame()
|
|
307
|
+
const time = frameToTime(frame)
|
|
308
|
+
const current = currentTime()
|
|
309
|
+
const roundTripFrame = timeToFrame(time)
|
|
310
|
+
|
|
311
|
+
if (!resultPath) {
|
|
312
|
+
failures.push('missing result path argument')
|
|
313
|
+
}
|
|
314
|
+
if (!isNumber(frame)) {
|
|
315
|
+
failures.push('scene-helper getCurrentFrame did not return a number')
|
|
316
|
+
}
|
|
317
|
+
if (current === null || current === undefined) {
|
|
318
|
+
failures.push('scene-helper currentTime returned null or undefined')
|
|
319
|
+
}
|
|
320
|
+
if (roundTripFrame !== frame) {
|
|
321
|
+
failures.push(\`frame/time round trip failed: \${frame} -> \${time} -> \${roundTripFrame}\`)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const result: IntegrationResult = {
|
|
325
|
+
ok: failures.length === 0,
|
|
326
|
+
project: 'integration-smoke',
|
|
327
|
+
checks: {
|
|
328
|
+
frame,
|
|
329
|
+
time: String(time),
|
|
330
|
+
currentTime: String(current),
|
|
331
|
+
roundTripFrame
|
|
332
|
+
},
|
|
333
|
+
failures
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (resultPath) {
|
|
337
|
+
saveToFile(resultPath, JSON.stringify(result, null, 2))
|
|
338
|
+
}
|
|
339
|
+
})
|
|
340
|
+
`;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function buildIntegrationReadmeContent(fixturePath) {
|
|
344
|
+
return `# Integration Tests
|
|
345
|
+
|
|
346
|
+
This project uses the framework DAZ Studio headless integration harness.
|
|
347
|
+
|
|
348
|
+
Create a local env file from the example for your OS:
|
|
349
|
+
|
|
350
|
+
\`\`\`bash
|
|
351
|
+
cp .env.integration.linux.example .env.integration.local
|
|
352
|
+
\`\`\`
|
|
353
|
+
|
|
354
|
+
\`\`\`powershell
|
|
355
|
+
Copy-Item .env.integration.windows.example .env.integration.local
|
|
356
|
+
\`\`\`
|
|
357
|
+
|
|
358
|
+
Then run:
|
|
359
|
+
|
|
360
|
+
\`\`\`bash
|
|
361
|
+
npm run test:integration
|
|
362
|
+
\`\`\`
|
|
363
|
+
|
|
364
|
+
The default smoke fixture is figure-independent:
|
|
365
|
+
|
|
366
|
+
\`\`\`text
|
|
367
|
+
${fixturePath}
|
|
368
|
+
\`\`\`
|
|
369
|
+
|
|
370
|
+
Generated output is written to \`test/integration/out/\` and ignored by git.
|
|
371
|
+
`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function buildLinuxEnvExample() {
|
|
375
|
+
return `# Copy this file to .env.integration.local and edit paths for your machine.
|
|
376
|
+
# Shell environment variables override values in .env.integration.local.
|
|
377
|
+
# DAZ_STUDIO_EXE is required for all integration tests.
|
|
378
|
+
# DAZ_TEST_CONTENT_DUF is required only when the fixture or npm script uses --require-content.
|
|
379
|
+
|
|
380
|
+
WINEPREFIX=/home/your-user/.local/share/daz-wine/prefix
|
|
381
|
+
DAZ_STUDIO_EXE=/home/your-user/.local/share/daz-wine/prefix/drive_c/Program Files/DAZ 3D/DAZStudio4/DAZStudio.exe
|
|
382
|
+
# DAZ_TEST_CONTENT_DUF=/home/your-user/.local/share/daz-wine/prefix/drive_c/users/Public/Documents/My DAZ 3D Library/People/Genesis 9/Genesis 9.duf
|
|
383
|
+
DAZ_TEST_TIMEOUT_MS=300000
|
|
384
|
+
`;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function buildWindowsEnvExample() {
|
|
388
|
+
return `# Copy this file to .env.integration.local and edit paths for your machine.
|
|
389
|
+
# Shell environment variables override values in .env.integration.local.
|
|
390
|
+
# Forward slashes avoid escaping issues in env files.
|
|
391
|
+
# DAZ_STUDIO_EXE is required for all integration tests.
|
|
392
|
+
# DAZ_TEST_CONTENT_DUF is required only when the fixture or npm script uses --require-content.
|
|
393
|
+
|
|
394
|
+
DAZ_STUDIO_EXE=C:/Program Files/DAZ 3D/DAZStudio4/DAZStudio.exe
|
|
395
|
+
# DAZ_TEST_CONTENT_DUF=C:/Users/Public/Documents/My DAZ 3D Library/People/Genesis 9/Genesis 9.duf
|
|
396
|
+
DAZ_TEST_TIMEOUT_MS=300000
|
|
397
|
+
`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function initIntegrationTests(workdir, options) {
|
|
401
|
+
const fixtureBaseName = `${toFixtureName(path.basename(workdir))}-smoke.dsa.ts`;
|
|
402
|
+
const fixturePath = `./test/integration/fixtures/${fixtureBaseName}`;
|
|
403
|
+
const localFixturePath = path.join(workdir, fixturePath);
|
|
404
|
+
|
|
405
|
+
writeFileIfNeeded(localFixturePath, buildIntegrationFixtureContent(), options.force);
|
|
406
|
+
writeFileIfNeeded(
|
|
407
|
+
path.join(workdir, 'test/integration/README.md'),
|
|
408
|
+
buildIntegrationReadmeContent(fixturePath),
|
|
409
|
+
options.force
|
|
410
|
+
);
|
|
411
|
+
writeFileIfNeeded(
|
|
412
|
+
path.join(workdir, '.env.integration.linux.example'),
|
|
413
|
+
buildLinuxEnvExample(),
|
|
414
|
+
options.force
|
|
415
|
+
);
|
|
416
|
+
writeFileIfNeeded(
|
|
417
|
+
path.join(workdir, '.env.integration.windows.example'),
|
|
418
|
+
buildWindowsEnvExample(),
|
|
419
|
+
options.force
|
|
420
|
+
);
|
|
421
|
+
updatePackageJsonForIntegration(workdir, fixturePath);
|
|
422
|
+
ensureLine(path.join(workdir, '.gitignore'), 'test/integration/out/');
|
|
423
|
+
ensureLine(path.join(workdir, '.gitignore'), '.env.integration.local');
|
|
424
|
+
}
|
|
425
|
+
|
|
109
426
|
function initProject(workdir, rawOptions) {
|
|
110
427
|
const projectName = path.basename(workdir);
|
|
111
428
|
const options = {
|
|
@@ -115,6 +432,8 @@ function initProject(workdir, rawOptions) {
|
|
|
115
432
|
outDir: normalizePath(rawOptions.outDir, './out'),
|
|
116
433
|
appDataPath: normalizePath(rawOptions.appDataPath, `YourName/${projectName}`),
|
|
117
434
|
bundleName: toBundleName(projectName),
|
|
435
|
+
unitTests: Boolean(rawOptions.unitTests),
|
|
436
|
+
integrationTests: Boolean(rawOptions.integrationTests),
|
|
118
437
|
};
|
|
119
438
|
|
|
120
439
|
writeFileIfNeeded(
|
|
@@ -129,8 +448,18 @@ function initProject(workdir, rawOptions) {
|
|
|
129
448
|
);
|
|
130
449
|
|
|
131
450
|
updatePackageJson(workdir, options);
|
|
451
|
+
|
|
452
|
+
if (options.unitTests) {
|
|
453
|
+
initUnitTests(workdir, options);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (options.integrationTests) {
|
|
457
|
+
initIntegrationTests(workdir, options);
|
|
458
|
+
}
|
|
132
459
|
}
|
|
133
460
|
|
|
134
461
|
module.exports = {
|
|
462
|
+
initIntegrationTests,
|
|
463
|
+
initUnitTests,
|
|
135
464
|
initProject,
|
|
136
465
|
};
|