doc-detective 1.0.1 → 1.0.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/README.md +1 -6
- package/package.json +2 -1
- package/sample/config.json +2 -0
- package/src/config.json +2 -0
- package/src/lib/analytics.js +1 -1
- package/src/lib/utils.js +136 -66
package/README.md
CHANGED
|
@@ -18,8 +18,6 @@ You can use Doc Detective as an [NPM package](#npm-package) or a standalone [CLI
|
|
|
18
18
|
|
|
19
19
|
Doc Detective integrates with Node projects as an NPM package. When using the NPM package, you must specify all options in the `run()` method's `config` argument, which is a JSON object with the same structure as [config.json](https://github.com/hawkeyexl/doc-detective/blob/master/sample/config.json).
|
|
20
20
|
|
|
21
|
-
0. Install prerequisites:
|
|
22
|
-
- [FFmpeg](https://ffmpeg.org/) (Only required if you want the [Start recording](#start-recording) action to output GIFs. Not required for MP4 output.)
|
|
23
21
|
1. In a terminal, navigate to your Node project, then install Doc Detective:
|
|
24
22
|
|
|
25
23
|
```bash
|
|
@@ -45,7 +43,6 @@ You can run Doc Detective as a standalone CLI tool. When running as a CLI tool,
|
|
|
45
43
|
0. Install prerequisites:
|
|
46
44
|
|
|
47
45
|
- [Node.js](https://nodejs.org/)
|
|
48
|
-
- [FFmpeg](https://ffmpeg.org/) (Only required if you want the [Start recording](#start-recording) action to output GIFs. Not required for MP4 output.)
|
|
49
46
|
|
|
50
47
|
1. In a terminal, clone the repo and install dependencies:
|
|
51
48
|
|
|
@@ -276,7 +273,7 @@ Format:
|
|
|
276
273
|
|
|
277
274
|
Start recording the current browser viewport. Must be followed by a `stopRecording` action. Supported extensions: .mp4, .gif
|
|
278
275
|
|
|
279
|
-
**Note:** `.gif` format is **not** recommended. Because of file format and encoding differences, `.gif` files tend to be ~6.5 times larger than `.mp4` files, and with lower visual fidelity. But if `.gif` is a hard requirement for you, it's here. Creating `.gif` files
|
|
276
|
+
**Note:** `.gif` format is **not** recommended. Because of file format and encoding differences, `.gif` files tend to be ~6.5 times larger than `.mp4` files, and with lower visual fidelity. But if `.gif` is a hard requirement for you, it's here. Creating `.gif` files also creates `.mp4` files of the recordings.
|
|
280
277
|
|
|
281
278
|
Format:
|
|
282
279
|
|
|
@@ -524,8 +521,6 @@ Analytics reporting is off by default. If you want to make extra sure that Doc D
|
|
|
524
521
|
## Potential future features
|
|
525
522
|
|
|
526
523
|
- Browser auto-detection and fallback.
|
|
527
|
-
- Improved default config experience.
|
|
528
|
-
- Environment variable overrides for config options.
|
|
529
524
|
- Docker image with bundled Chromium/Chrome/Firefox.
|
|
530
525
|
- New/upgraded test actions:
|
|
531
526
|
- New: Curl commands. (Support substitution/setting env vars. Only check for `200 OK`.)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doc-detective",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Unit test documentation (and record videos of those tests).",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"homepage": "https://github.com/hawkeyexl/doc-detective#readme",
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
27
28
|
"axios": "^0.27.2",
|
|
28
29
|
"dotenv": "^16.0.2",
|
|
29
30
|
"n-readlines": "^1.0.1",
|
package/sample/config.json
CHANGED
package/src/config.json
CHANGED
package/src/lib/analytics.js
CHANGED
package/src/lib/utils.js
CHANGED
|
@@ -50,6 +50,16 @@ function setArgs(args) {
|
|
|
50
50
|
description: "Path for a JSON file of test result output.",
|
|
51
51
|
type: "string",
|
|
52
52
|
})
|
|
53
|
+
.option("setup", {
|
|
54
|
+
description:
|
|
55
|
+
"Path to a file or directory to parse for tests to run before 'input' tests. Useful for preparing environments to perform tests.",
|
|
56
|
+
type: "string",
|
|
57
|
+
})
|
|
58
|
+
.option("cleanup", {
|
|
59
|
+
description:
|
|
60
|
+
"Path to a file or directory to parse for tests to run after 'input' tests. Useful for resetting environments after tests run.",
|
|
61
|
+
type: "string",
|
|
62
|
+
})
|
|
53
63
|
.option("recursive", {
|
|
54
64
|
alias: "r",
|
|
55
65
|
description:
|
|
@@ -122,7 +132,8 @@ function setArgs(args) {
|
|
|
122
132
|
function setLogLevel(config, argv) {
|
|
123
133
|
let logLevel = "";
|
|
124
134
|
let enums = ["debug", "info", "warning", "error", "silent"];
|
|
125
|
-
logLevel =
|
|
135
|
+
logLevel =
|
|
136
|
+
argv.logLevel || process.env.DOC_LOG_LEVEL || config.logLevel || "info";
|
|
126
137
|
logLevel = String(logLevel).toLowerCase();
|
|
127
138
|
if (enums.indexOf(logLevel) >= 0) {
|
|
128
139
|
config.logLevel = logLevel;
|
|
@@ -159,7 +170,7 @@ function selectConfig(config, argv) {
|
|
|
159
170
|
log(config, "debug", "Loaded config from function parameter.");
|
|
160
171
|
} else {
|
|
161
172
|
// Default
|
|
162
|
-
config = defaultConfig;
|
|
173
|
+
config = JSON.parse(JSON.stringify(defaultConfig));
|
|
163
174
|
setLogLevel(config, argv);
|
|
164
175
|
log(
|
|
165
176
|
config,
|
|
@@ -172,16 +183,18 @@ function selectConfig(config, argv) {
|
|
|
172
183
|
|
|
173
184
|
function setEnv(config, argv) {
|
|
174
185
|
config.env = argv.env || process.env.DOC_ENV_PATH || config.env;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
if (config.env) {
|
|
187
|
+
config.env = path.resolve(config.env);
|
|
188
|
+
if (fs.existsSync(config.env)) {
|
|
189
|
+
let envResult = setEnvs(config.env);
|
|
190
|
+
if (envResult.status === "PASS")
|
|
191
|
+
log(config, "debug", `Env file set: ${config.env}`);
|
|
192
|
+
if (envResult.status === "FAIL")
|
|
193
|
+
log(config, "warning", `File format issue. Can't load env file.`);
|
|
194
|
+
} else {
|
|
195
|
+
log(config, "warning", `Invalid file path. Can't load env file.`);
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
185
198
|
log(config, "debug", "No env file specified.");
|
|
186
199
|
}
|
|
187
200
|
return config;
|
|
@@ -189,9 +202,17 @@ function setEnv(config, argv) {
|
|
|
189
202
|
|
|
190
203
|
function setInput(config, argv) {
|
|
191
204
|
config.input = argv.input || process.env.DOC_INPUT_PATH || config.input;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
if (config.input) {
|
|
206
|
+
config.input = path.resolve(config.input);
|
|
207
|
+
if (fs.existsSync(config.input)) {
|
|
208
|
+
log(config, "debug", `Input path set: ${config.input}`);
|
|
209
|
+
} else {
|
|
210
|
+
log(
|
|
211
|
+
config,
|
|
212
|
+
"warning",
|
|
213
|
+
`Invalid input path. Reverted to default: ${config.input}`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
195
216
|
} else {
|
|
196
217
|
config.input = path.resolve(defaultConfig.input);
|
|
197
218
|
log(
|
|
@@ -210,6 +231,40 @@ function setOutput(config, argv) {
|
|
|
210
231
|
return config;
|
|
211
232
|
}
|
|
212
233
|
|
|
234
|
+
function setSetup(config, argv) {
|
|
235
|
+
config.setup = argv.setup || process.env.DOC_SETUP || config.setup;
|
|
236
|
+
if (config.setup === "") {
|
|
237
|
+
log(config, "debug", `No setup tests.`);
|
|
238
|
+
return config;
|
|
239
|
+
} else {
|
|
240
|
+
config.setup = path.resolve(config.setup);
|
|
241
|
+
if (fs.existsSync(config.setup)) {
|
|
242
|
+
log(config, "debug", `Setup tests path set: ${config.setup}`);
|
|
243
|
+
} else {
|
|
244
|
+
config.setup = defaultConfig.setup;
|
|
245
|
+
log(config, "warning", `Invalid setup tests path.`);
|
|
246
|
+
}
|
|
247
|
+
return config;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function setCleanup(config, argv) {
|
|
252
|
+
config.cleanup = argv.cleanup || process.env.DOC_CLEANUP || config.cleanup;
|
|
253
|
+
if (config.cleanup === "") {
|
|
254
|
+
log(config, "debug", `No cleanup tests.`);
|
|
255
|
+
return config;
|
|
256
|
+
} else {
|
|
257
|
+
config.cleanup = path.resolve(config.cleanup);
|
|
258
|
+
if (fs.existsSync(config.cleanup)) {
|
|
259
|
+
log(config, "debug", `Cleanup tests path set: ${config.cleanup}`);
|
|
260
|
+
} else {
|
|
261
|
+
config.cleanup = defaultConfig.cleanup;
|
|
262
|
+
log(config, "warning", `Invalid cleanup tests path.`);
|
|
263
|
+
}
|
|
264
|
+
return config;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
213
268
|
function setMediaDirectory(config, argv) {
|
|
214
269
|
config.mediaDirectory =
|
|
215
270
|
argv.mediaDir ||
|
|
@@ -320,24 +375,24 @@ function setBrowserPath(config, argv) {
|
|
|
320
375
|
argv.browserPath ||
|
|
321
376
|
process.env.DOC_BROWSER_PATH ||
|
|
322
377
|
config.browserOptions.path;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
378
|
+
if (config.browserOptions.path === "") {
|
|
379
|
+
log(config, "debug", `Browser set to default Chromium install.`);
|
|
380
|
+
return config;
|
|
381
|
+
} else {
|
|
382
|
+
config.browserOptions.path = path.resolve(config.browserOptions.path);
|
|
383
|
+
if (fs.existsSync(config.browserOptions.path)) {
|
|
384
|
+
log(config, "debug", `Browser path set: ${config.browserOptions.path}`);
|
|
326
385
|
} else {
|
|
327
|
-
config.browserOptions.path =
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
config,
|
|
334
|
-
"warning",
|
|
335
|
-
`Invalid browser path. Reverted to default Chromium install.`
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
return config;
|
|
386
|
+
config.browserOptions.path = defaultConfig.browserOptions.path;
|
|
387
|
+
log(
|
|
388
|
+
config,
|
|
389
|
+
"warning",
|
|
390
|
+
`Invalid browser path. Reverted to default Chromium install.`
|
|
391
|
+
);
|
|
339
392
|
}
|
|
393
|
+
return config;
|
|
340
394
|
}
|
|
395
|
+
}
|
|
341
396
|
|
|
342
397
|
function setBrowserHeight(config, argv) {
|
|
343
398
|
config.browserOptions.height =
|
|
@@ -467,8 +522,6 @@ function setAnalyticsServers(config, argv) {
|
|
|
467
522
|
}
|
|
468
523
|
|
|
469
524
|
function setConfig(config, argv) {
|
|
470
|
-
config = setLogLevel(config, argv);
|
|
471
|
-
|
|
472
525
|
config = selectConfig(config, argv);
|
|
473
526
|
|
|
474
527
|
config = setEnv(config, argv);
|
|
@@ -477,6 +530,10 @@ function setConfig(config, argv) {
|
|
|
477
530
|
|
|
478
531
|
config = setOutput(config, argv);
|
|
479
532
|
|
|
533
|
+
config = setSetup(config, argv);
|
|
534
|
+
|
|
535
|
+
config = setCleanup(config, argv);
|
|
536
|
+
|
|
480
537
|
config = setMediaDirectory(config, argv);
|
|
481
538
|
|
|
482
539
|
config = setRecursion(config, argv);
|
|
@@ -506,49 +563,59 @@ function setConfig(config, argv) {
|
|
|
506
563
|
function setFiles(config) {
|
|
507
564
|
let dirs = [];
|
|
508
565
|
let files = [];
|
|
566
|
+
let sequence = [];
|
|
509
567
|
|
|
510
568
|
// Validate input
|
|
511
|
-
const
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
569
|
+
const setup = config.setup;
|
|
570
|
+
if (setup) sequence.push(setup);
|
|
571
|
+
const input = config.input;
|
|
572
|
+
sequence.push(input);
|
|
573
|
+
const cleanup = config.cleanup;
|
|
574
|
+
if (cleanup) sequence.push(cleanup);
|
|
575
|
+
|
|
576
|
+
for (s = 0; s < sequence.length; s++) {
|
|
577
|
+
let isFile = fs.statSync(sequence[s]).isFile();
|
|
578
|
+
let isDir = fs.statSync(sequence[s]).isDirectory();
|
|
579
|
+
|
|
580
|
+
// Parse input
|
|
581
|
+
if (
|
|
582
|
+
// Is a file
|
|
583
|
+
isFile &&
|
|
584
|
+
// Isn't present in files array already
|
|
585
|
+
files.indexOf(sequence[s]) < 0 &&
|
|
586
|
+
// No extension filter or extension included in filter
|
|
587
|
+
(config.testExtensions === "" ||
|
|
588
|
+
config.testExtensions.includes(path.extname(sequence[s])))
|
|
589
|
+
) {
|
|
590
|
+
files.push(sequence[s]);
|
|
591
|
+
} else if (isDir) {
|
|
592
|
+
// Load files from directory
|
|
593
|
+
dirs = [];
|
|
594
|
+
dirs[0] = sequence[s];
|
|
595
|
+
for (let i = 0; i < dirs.length; i++) {
|
|
596
|
+
fs.readdirSync(dirs[i]).forEach((object) => {
|
|
597
|
+
let content = path.resolve(dirs[i] + "/" + object);
|
|
598
|
+
let isFile = fs.statSync(content).isFile();
|
|
599
|
+
let isDir = fs.statSync(content).isDirectory();
|
|
534
600
|
if (
|
|
535
|
-
//
|
|
536
|
-
|
|
537
|
-
|
|
601
|
+
// Is a file
|
|
602
|
+
isFile &&
|
|
603
|
+
// Isn't present in files array already
|
|
604
|
+
files.indexOf(s) < 0 &&
|
|
605
|
+
// No extension filter or extension included in filter
|
|
606
|
+
(config.testExtensions === "" ||
|
|
607
|
+
config.testExtensions.includes(path.extname(content)))
|
|
538
608
|
) {
|
|
539
609
|
files.push(content);
|
|
540
|
-
}
|
|
541
|
-
} else if (isDir) {
|
|
542
|
-
// is a directory
|
|
543
|
-
if (config.recursive) {
|
|
610
|
+
} else if (isDir && config.recursive) {
|
|
544
611
|
// recursive set to true
|
|
545
612
|
dirs.push(content);
|
|
546
613
|
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
614
|
+
});
|
|
615
|
+
}
|
|
549
616
|
}
|
|
550
|
-
return files;
|
|
551
617
|
}
|
|
618
|
+
return files;
|
|
552
619
|
}
|
|
553
620
|
|
|
554
621
|
// Parse files for tests
|
|
@@ -624,13 +691,16 @@ async function outputResults(config, results) {
|
|
|
624
691
|
}
|
|
625
692
|
|
|
626
693
|
async function convertToGif(config, input, fps, width) {
|
|
694
|
+
const ffmpegPath = require("@ffmpeg-installer/ffmpeg").path;
|
|
695
|
+
|
|
627
696
|
if (!fs.existsSync(input)) return { error: "Invalid input." };
|
|
628
697
|
let output = path.join(
|
|
629
698
|
path.parse(input).dir,
|
|
630
699
|
path.parse(input).name + ".gif"
|
|
631
700
|
);
|
|
632
701
|
if (!fps) fps = 15;
|
|
633
|
-
|
|
702
|
+
|
|
703
|
+
let command = `${ffmpegPath} -nostats -loglevel 0 -y -i ${input} -vf "fps=${fps},scale=${width}:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 ${output}`;
|
|
634
704
|
exec(command, (error, stdout, stderr) => {
|
|
635
705
|
if (error) {
|
|
636
706
|
log(config, "debug", error.message);
|