doc-detective 2.9.3-dev.0 → 2.10.1
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/.github/FUNDING.yml +14 -14
- package/.github/dependabot.yml +11 -11
- package/.github/workflows/docker-image.yml +19 -19
- package/.github/workflows/electron-publish.yml +17 -17
- package/.github/workflows/npm-publish.yml +67 -67
- package/.github/workflows/npm-test.yaml +48 -48
- package/CONTRIBUTIONS.md +27 -27
- package/LICENSE +20 -20
- package/README.md +117 -117
- package/dev/dev.spec.json +62 -62
- package/dev/index.js +5 -5
- package/package.json +44 -43
- package/samples/config.json +89 -89
- package/samples/doc-content-inline-tests.md +27 -27
- package/samples/doc-content.md +8 -8
- package/samples/tests.spec.json +70 -70
- package/samples/variables.env +4 -4
- package/src/index.js +43 -43
- package/src/utils.js +156 -156
- package/test/artifacts/cleanup.spec.json +19 -0
- package/test/artifacts/config.json +43 -43
- package/test/artifacts/doc-content.md +17 -17
- package/test/artifacts/runShell.spec.json +29 -0
- package/test/artifacts/setup.spec.json +18 -0
- package/test/artifacts/test.spec.json +60 -58
- package/test/runCoverage.test.js +18 -18
- package/test/runTests.test.js +22 -22
- package/test/test-config.json +9 -9
- package/test/test-results.json +124 -124
- package/test/utils.test.js +204 -204
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
# Doc Detective documentation overview
|
|
2
|
-
|
|
3
|
-
[comment]: # (test start {"id":"search-kittens", "detectSteps":false})
|
|
4
|
-
|
|
5
|
-
[Doc Detective documentation](http://doc-detective.com) is split into a few key sections:
|
|
6
|
-
|
|
7
|
-
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com"})
|
|
8
|
-
|
|
9
|
-
- The landing page discusses what Doc Detective is, what it does, and who might find it useful.
|
|
10
|
-
- [Get started](https://doc-detective.com/get-started.html) covers how to quickly get up and running with Doc Detective.
|
|
11
|
-
|
|
12
|
-
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/get-started.html"})
|
|
13
|
-
|
|
14
|
-
- The [references](https://doc-detective.com/reference/) detail the various JSON objects that Doc Detective expects for [configs](https://doc-detective.com/reference/schemas/config.html), [test specifications](https://doc-detective.com/reference/schemas/specification.html), [tests](https://doc-detective.com/reference/schemas/test), actions, and more. Open [typeKeys](https://doc-detective.com/reference/schemas/typeKeys.html)--or any other schema--and you'll find three sections: **Description**, **Fields**, and **Examples**.
|
|
15
|
-
|
|
16
|
-
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/"})
|
|
17
|
-
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/schemas/config.html"})
|
|
18
|
-
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/schemas/specification.html"})
|
|
19
|
-
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/schemas/test.html"})
|
|
20
|
-
[comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/reference/schemas/typeKeys.html"})
|
|
21
|
-
[comment]: # (step {"action":"find", "selector":"h2#description", "matchText":"Description"})
|
|
22
|
-
[comment]: # (step {"action":"find", "selector":"h2#fields", "matchText":"Fields"})
|
|
23
|
-
[comment]: # (step {"action":"find", "selector":"h2#examples", "matchText":"Examples"})
|
|
24
|
-
|
|
25
|
-

|
|
26
|
-
[comment]: # (step {"action":"saveScreenshot", "path":"reference.png", "directory":"samples", "maxVariation":5, "overwrite":"byVariation"})
|
|
27
|
-
|
|
1
|
+
# Doc Detective documentation overview
|
|
2
|
+
|
|
3
|
+
[comment]: # (test start {"id":"search-kittens", "detectSteps":false})
|
|
4
|
+
|
|
5
|
+
[Doc Detective documentation](http://doc-detective.com) is split into a few key sections:
|
|
6
|
+
|
|
7
|
+
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com"})
|
|
8
|
+
|
|
9
|
+
- The landing page discusses what Doc Detective is, what it does, and who might find it useful.
|
|
10
|
+
- [Get started](https://doc-detective.com/get-started.html) covers how to quickly get up and running with Doc Detective.
|
|
11
|
+
|
|
12
|
+
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/get-started.html"})
|
|
13
|
+
|
|
14
|
+
- The [references](https://doc-detective.com/reference/) detail the various JSON objects that Doc Detective expects for [configs](https://doc-detective.com/reference/schemas/config.html), [test specifications](https://doc-detective.com/reference/schemas/specification.html), [tests](https://doc-detective.com/reference/schemas/test), actions, and more. Open [typeKeys](https://doc-detective.com/reference/schemas/typeKeys.html)--or any other schema--and you'll find three sections: **Description**, **Fields**, and **Examples**.
|
|
15
|
+
|
|
16
|
+
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/"})
|
|
17
|
+
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/schemas/config.html"})
|
|
18
|
+
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/schemas/specification.html"})
|
|
19
|
+
[comment]: # (step {"action":"checkLink", "url":"https://doc-detective.com/reference/schemas/test.html"})
|
|
20
|
+
[comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/reference/schemas/typeKeys.html"})
|
|
21
|
+
[comment]: # (step {"action":"find", "selector":"h2#description", "matchText":"Description"})
|
|
22
|
+
[comment]: # (step {"action":"find", "selector":"h2#fields", "matchText":"Fields"})
|
|
23
|
+
[comment]: # (step {"action":"find", "selector":"h2#examples", "matchText":"Examples"})
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
[comment]: # (step {"action":"saveScreenshot", "path":"reference.png", "directory":"samples", "maxVariation":5, "overwrite":"byVariation"})
|
|
27
|
+
|
|
28
28
|
[comment]: # (test end)
|
package/samples/doc-content.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# Doc Detective documentation overview
|
|
2
|
-
|
|
3
|
-
[Doc Detective documentation](https://doc-detective.com) is split into a few key sections:
|
|
4
|
-
|
|
5
|
-
- The landing page discusses what Doc Detective is, what it does, and who might find it useful.
|
|
6
|
-
- [Get started](https://doc-detective.com/get-started.html) covers how to quickly get up and running with Doc Detective.
|
|
7
|
-
- The [references](https://doc-detective.com/reference/) detail the various JSON objects that Doc Detective expects for [configs](https://doc-detective.com/reference/schemas/config.html), [test specifications](https://doc-detective.com/reference/schemas/specification.html), [tests](https://doc-detective.com/reference/schemas/test), actions, and more. Open [typeKeys](https://doc-detective.com/reference/schemas/typeKeys.html)--or any other schema--and you'll find three sections: **Description**, **Fields**, and **Examples**.
|
|
8
|
-
|
|
1
|
+
# Doc Detective documentation overview
|
|
2
|
+
|
|
3
|
+
[Doc Detective documentation](https://doc-detective.com) is split into a few key sections:
|
|
4
|
+
|
|
5
|
+
- The landing page discusses what Doc Detective is, what it does, and who might find it useful.
|
|
6
|
+
- [Get started](https://doc-detective.com/get-started.html) covers how to quickly get up and running with Doc Detective.
|
|
7
|
+
- The [references](https://doc-detective.com/reference/) detail the various JSON objects that Doc Detective expects for [configs](https://doc-detective.com/reference/schemas/config.html), [test specifications](https://doc-detective.com/reference/schemas/specification.html), [tests](https://doc-detective.com/reference/schemas/test), actions, and more. Open [typeKeys](https://doc-detective.com/reference/schemas/typeKeys.html)--or any other schema--and you'll find three sections: **Description**, **Fields**, and **Examples**.
|
|
8
|
+
|
|
9
9
|

|
package/samples/tests.spec.json
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "Do all the things! - Spec",
|
|
3
|
-
"contexts": [
|
|
4
|
-
{
|
|
5
|
-
"app": {
|
|
6
|
-
"name": "firefox"
|
|
7
|
-
},
|
|
8
|
-
"platforms": ["windows", "mac", "linux"]
|
|
9
|
-
}
|
|
10
|
-
],
|
|
11
|
-
"tests": [
|
|
12
|
-
{
|
|
13
|
-
"id": "Do all the things! - Test",
|
|
14
|
-
"description": "This test includes nearly every property across all actions.",
|
|
15
|
-
"steps": [
|
|
16
|
-
{
|
|
17
|
-
"action": "setVariables",
|
|
18
|
-
"path": ".env"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"action": "runShell",
|
|
22
|
-
"command": "echo",
|
|
23
|
-
"args": ["$USER"]
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"action": "checkLink",
|
|
27
|
-
"url": "https://www.duckduckgo.com"
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
"action": "httpRequest",
|
|
31
|
-
"url": "https://reqres.in/api/users",
|
|
32
|
-
"method": "post",
|
|
33
|
-
"requestData": {
|
|
34
|
-
"name": "morpheus",
|
|
35
|
-
"job": "leader"
|
|
36
|
-
},
|
|
37
|
-
"responseData": {
|
|
38
|
-
"name": "morpheus",
|
|
39
|
-
"job": "leader"
|
|
40
|
-
},
|
|
41
|
-
"statusCodes": [200, 201]
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"action": "goTo",
|
|
45
|
-
"url": "https://www.google.com"
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
"action": "find",
|
|
49
|
-
"selector": "[title=Search]",
|
|
50
|
-
"timeout": 10000,
|
|
51
|
-
"moveTo": true,
|
|
52
|
-
"click": true,
|
|
53
|
-
"typeKeys": {
|
|
54
|
-
"keys": ["shorthair cat", "$ENTER$"]
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"action": "wait"
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
"action": "saveScreenshot",
|
|
62
|
-
"path": "screenshot.png",
|
|
63
|
-
"directory": "samples",
|
|
64
|
-
"maxVariation": 5,
|
|
65
|
-
"overwrite": "byVariation"
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"id": "Do all the things! - Spec",
|
|
3
|
+
"contexts": [
|
|
4
|
+
{
|
|
5
|
+
"app": {
|
|
6
|
+
"name": "firefox"
|
|
7
|
+
},
|
|
8
|
+
"platforms": ["windows", "mac", "linux"]
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"tests": [
|
|
12
|
+
{
|
|
13
|
+
"id": "Do all the things! - Test",
|
|
14
|
+
"description": "This test includes nearly every property across all actions.",
|
|
15
|
+
"steps": [
|
|
16
|
+
{
|
|
17
|
+
"action": "setVariables",
|
|
18
|
+
"path": ".env"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"action": "runShell",
|
|
22
|
+
"command": "echo",
|
|
23
|
+
"args": ["$USER"]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"action": "checkLink",
|
|
27
|
+
"url": "https://www.duckduckgo.com"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"action": "httpRequest",
|
|
31
|
+
"url": "https://reqres.in/api/users",
|
|
32
|
+
"method": "post",
|
|
33
|
+
"requestData": {
|
|
34
|
+
"name": "morpheus",
|
|
35
|
+
"job": "leader"
|
|
36
|
+
},
|
|
37
|
+
"responseData": {
|
|
38
|
+
"name": "morpheus",
|
|
39
|
+
"job": "leader"
|
|
40
|
+
},
|
|
41
|
+
"statusCodes": [200, 201]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"action": "goTo",
|
|
45
|
+
"url": "https://www.google.com"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"action": "find",
|
|
49
|
+
"selector": "[title=Search]",
|
|
50
|
+
"timeout": 10000,
|
|
51
|
+
"moveTo": true,
|
|
52
|
+
"click": true,
|
|
53
|
+
"typeKeys": {
|
|
54
|
+
"keys": ["shorthair cat", "$ENTER$"]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"action": "wait"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"action": "saveScreenshot",
|
|
62
|
+
"path": "screenshot.png",
|
|
63
|
+
"directory": "samples",
|
|
64
|
+
"maxVariation": 5,
|
|
65
|
+
"overwrite": "byVariation"
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
package/samples/variables.env
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
USERNAME=foo
|
|
2
|
-
PASSWORD=bar
|
|
3
|
-
SHORTHAIR_CAT_SEARCH=american shorthair cats
|
|
4
|
-
URL=www.google.com
|
|
1
|
+
USERNAME=foo
|
|
2
|
+
PASSWORD=bar
|
|
3
|
+
SHORTHAIR_CAT_SEARCH=american shorthair cats
|
|
4
|
+
URL=www.google.com
|
|
5
5
|
TEXT=I'm Feeling Lucky
|
package/src/index.js
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { runTests, runCoverage } = require("doc-detective-core");
|
|
4
|
-
const { setArgs, setConfig, outputResults } = require("./utils");
|
|
5
|
-
const { argv } = require("node:process");
|
|
6
|
-
const path = require("path");
|
|
7
|
-
|
|
8
|
-
main(argv);
|
|
9
|
-
|
|
10
|
-
// Run tests
|
|
11
|
-
async function main(argv) {
|
|
12
|
-
// Find index of `doc-detective` or `run` in argv
|
|
13
|
-
let index = argv.indexOf("doc-detective");
|
|
14
|
-
if (index === -1) {
|
|
15
|
-
index = argv.findIndex((arg) => arg.endsWith("index.js"));
|
|
16
|
-
}
|
|
17
|
-
// `command` is the next argument after `doc-detective` or `src/index.js`
|
|
18
|
-
const command = argv[index + 1];
|
|
19
|
-
// Set args and config
|
|
20
|
-
argv = setArgs(argv);
|
|
21
|
-
const config = setConfig({}, argv);
|
|
22
|
-
// Run command
|
|
23
|
-
let results = {};
|
|
24
|
-
let outputDir;
|
|
25
|
-
let outputReportType;
|
|
26
|
-
if (command === "runCoverage") {
|
|
27
|
-
outputDir = config?.runCoverage?.output || config.output;
|
|
28
|
-
outputReportType = "coverageResults";
|
|
29
|
-
results = await runCoverage(config);
|
|
30
|
-
} else if (command === "runTests") {
|
|
31
|
-
outputDir = config?.runTests?.output || config.output;
|
|
32
|
-
outputReportType = "testResults";
|
|
33
|
-
results = await runTests(config);
|
|
34
|
-
} else {
|
|
35
|
-
throw new Error(`Command ${command} not found`);
|
|
36
|
-
}
|
|
37
|
-
// Output results
|
|
38
|
-
const outputPath = path.resolve(
|
|
39
|
-
outputDir,
|
|
40
|
-
`${outputReportType}-${Date.now()}.json`
|
|
41
|
-
);
|
|
42
|
-
await outputResults(config, outputPath, results);
|
|
43
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { runTests, runCoverage } = require("doc-detective-core");
|
|
4
|
+
const { setArgs, setConfig, outputResults } = require("./utils");
|
|
5
|
+
const { argv } = require("node:process");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
|
|
8
|
+
main(argv);
|
|
9
|
+
|
|
10
|
+
// Run tests
|
|
11
|
+
async function main(argv) {
|
|
12
|
+
// Find index of `doc-detective` or `run` in argv
|
|
13
|
+
let index = argv.indexOf("doc-detective");
|
|
14
|
+
if (index === -1) {
|
|
15
|
+
index = argv.findIndex((arg) => arg.endsWith("index.js"));
|
|
16
|
+
}
|
|
17
|
+
// `command` is the next argument after `doc-detective` or `src/index.js`
|
|
18
|
+
const command = argv[index + 1];
|
|
19
|
+
// Set args and config
|
|
20
|
+
argv = setArgs(argv);
|
|
21
|
+
const config = setConfig({}, argv);
|
|
22
|
+
// Run command
|
|
23
|
+
let results = {};
|
|
24
|
+
let outputDir;
|
|
25
|
+
let outputReportType;
|
|
26
|
+
if (command === "runCoverage") {
|
|
27
|
+
outputDir = config?.runCoverage?.output || config.output;
|
|
28
|
+
outputReportType = "coverageResults";
|
|
29
|
+
results = await runCoverage(config);
|
|
30
|
+
} else if (command === "runTests") {
|
|
31
|
+
outputDir = config?.runTests?.output || config.output;
|
|
32
|
+
outputReportType = "testResults";
|
|
33
|
+
results = await runTests(config);
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error(`Command ${command} not found`);
|
|
36
|
+
}
|
|
37
|
+
// Output results
|
|
38
|
+
const outputPath = path.resolve(
|
|
39
|
+
outputDir,
|
|
40
|
+
`${outputReportType}-${Date.now()}.json`
|
|
41
|
+
);
|
|
42
|
+
await outputResults(config, outputPath, results);
|
|
43
|
+
}
|
package/src/utils.js
CHANGED
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
const yargs = require("yargs/yargs");
|
|
2
|
-
const { hideBin } = require("yargs/helpers");
|
|
3
|
-
const { validate } = require("doc-detective-common");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const fs = require("fs");
|
|
6
|
-
const { spawn } = require("child_process");
|
|
7
|
-
|
|
8
|
-
exports.setArgs = setArgs;
|
|
9
|
-
exports.setConfig = setConfig;
|
|
10
|
-
exports.outputResults = outputResults;
|
|
11
|
-
exports.spawnCommand = spawnCommand;
|
|
12
|
-
|
|
13
|
-
// Define args
|
|
14
|
-
function setArgs(args) {
|
|
15
|
-
if (!args) return {};
|
|
16
|
-
let argv = yargs(hideBin(args))
|
|
17
|
-
.option("config", {
|
|
18
|
-
alias: "c",
|
|
19
|
-
description: "Path to a `config.json` file.",
|
|
20
|
-
type: "string",
|
|
21
|
-
})
|
|
22
|
-
.option("input", {
|
|
23
|
-
alias: "i",
|
|
24
|
-
description:
|
|
25
|
-
"Path to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.",
|
|
26
|
-
type: "string",
|
|
27
|
-
})
|
|
28
|
-
.option("output", {
|
|
29
|
-
alias: "o",
|
|
30
|
-
description:
|
|
31
|
-
"Path of the directory in which to store the output of Doc Detective commands.",
|
|
32
|
-
type: "string",
|
|
33
|
-
})
|
|
34
|
-
.option("setup", {
|
|
35
|
-
description:
|
|
36
|
-
"Path to test specifications to perform before those specified by `input`. Useful for setting up testing environments.",
|
|
37
|
-
type: "string",
|
|
38
|
-
})
|
|
39
|
-
.option("cleanup", {
|
|
40
|
-
description:
|
|
41
|
-
"Path to test specifications to perform after those specified by input. Useful for cleaning up testing environments.",
|
|
42
|
-
type: "string",
|
|
43
|
-
})
|
|
44
|
-
.option("recursive", {
|
|
45
|
-
alias: "r",
|
|
46
|
-
description:
|
|
47
|
-
"Boolean. If true searches input, setup, and cleanup paths recursively for test specificaions and source files. Defaults to `true`.",
|
|
48
|
-
type: "string",
|
|
49
|
-
})
|
|
50
|
-
.option("logLevel", {
|
|
51
|
-
alias: "l",
|
|
52
|
-
description:
|
|
53
|
-
"Detail level of logging events. Accepted values: silent, error, warning, info (default), debug",
|
|
54
|
-
type: "string",
|
|
55
|
-
})
|
|
56
|
-
.help()
|
|
57
|
-
.alias("help", "h").argv;
|
|
58
|
-
|
|
59
|
-
return argv;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Override config values based on args
|
|
63
|
-
function setConfig(config, args) {
|
|
64
|
-
// If no args, return config
|
|
65
|
-
if (!args) return config;
|
|
66
|
-
|
|
67
|
-
// Load config from file
|
|
68
|
-
if (args.config) {
|
|
69
|
-
const configPath = path.resolve(args.config);
|
|
70
|
-
configContent = require(configPath);
|
|
71
|
-
// Validate config
|
|
72
|
-
const validation = validate("config_v2", configContent);
|
|
73
|
-
if (validation.valid) {
|
|
74
|
-
config = configContent;
|
|
75
|
-
} else {
|
|
76
|
-
// Output validation errors
|
|
77
|
-
console.error("Invalid config file:");
|
|
78
|
-
validation.errors.forEach((error) => {
|
|
79
|
-
console.error(error);
|
|
80
|
-
});
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Override config values
|
|
86
|
-
if (args.input) config.input = args.input;
|
|
87
|
-
if (args.output) config.output = args.output;
|
|
88
|
-
if (args.recursive) config.recursive = args.recursive;
|
|
89
|
-
if (args.logLevel) config.logLevel = args.logLevel;
|
|
90
|
-
if ((args.setup || args.cleanup || args.input || args.output ) && !config.runTests) config.runTests = {};
|
|
91
|
-
if (args.input) config.runTests.input = args.input;
|
|
92
|
-
if (args.output) config.runTests.output = args.output;
|
|
93
|
-
if (args.setup) config.runTests.setup = args.setup;
|
|
94
|
-
if (args.cleanup) config.runTests.cleanup = args.cleanup;
|
|
95
|
-
|
|
96
|
-
// Validate config
|
|
97
|
-
const validation = validate("config_v2", config);
|
|
98
|
-
if (!validation.valid) {
|
|
99
|
-
// Output validation errors
|
|
100
|
-
console.error("Invalid config.");
|
|
101
|
-
validation.errors.forEach((error) => {
|
|
102
|
-
console.error(error);
|
|
103
|
-
});
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return config;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function outputResults(config, path, results) {
|
|
111
|
-
let data = JSON.stringify(results, null, 2);
|
|
112
|
-
fs.writeFile(path, data, (err) => {
|
|
113
|
-
if (err) throw err;
|
|
114
|
-
});
|
|
115
|
-
console.log(`See results at ${path}`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Perform a native command in the current working directory.
|
|
119
|
-
async function spawnCommand(cmd, args) {
|
|
120
|
-
// Split command into command and arguments
|
|
121
|
-
if (cmd.includes(" ")) {
|
|
122
|
-
const cmdArray = cmd.split(" ");
|
|
123
|
-
cmd = cmdArray[0];
|
|
124
|
-
cmdArgs = cmdArray.slice(1);
|
|
125
|
-
// Add arguments to args array
|
|
126
|
-
if (args) {
|
|
127
|
-
args = cmdArgs.concat(args);
|
|
128
|
-
} else {
|
|
129
|
-
args = cmdArgs;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const runCommand = spawn(cmd, args);
|
|
134
|
-
|
|
135
|
-
// Capture stdout
|
|
136
|
-
let stdout = "";
|
|
137
|
-
for await (const chunk of runCommand.stdout) {
|
|
138
|
-
stdout += chunk;
|
|
139
|
-
}
|
|
140
|
-
// Remove trailing newline
|
|
141
|
-
stdout = stdout.replace(/\n$/, "");
|
|
142
|
-
|
|
143
|
-
// Capture stderr
|
|
144
|
-
let stderr = "";
|
|
145
|
-
for await (const chunk of runCommand.stderr) {
|
|
146
|
-
stderr += chunk;
|
|
147
|
-
}
|
|
148
|
-
// Remove trailing newline
|
|
149
|
-
stderr = stderr.replace(/\n$/, "");
|
|
150
|
-
|
|
151
|
-
// Capture exit code
|
|
152
|
-
const exitCode = await new Promise((resolve, reject) => {
|
|
153
|
-
runCommand.on("close", resolve);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
return { stdout, stderr, exitCode };
|
|
1
|
+
const yargs = require("yargs/yargs");
|
|
2
|
+
const { hideBin } = require("yargs/helpers");
|
|
3
|
+
const { validate } = require("doc-detective-common");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const { spawn } = require("child_process");
|
|
7
|
+
|
|
8
|
+
exports.setArgs = setArgs;
|
|
9
|
+
exports.setConfig = setConfig;
|
|
10
|
+
exports.outputResults = outputResults;
|
|
11
|
+
exports.spawnCommand = spawnCommand;
|
|
12
|
+
|
|
13
|
+
// Define args
|
|
14
|
+
function setArgs(args) {
|
|
15
|
+
if (!args) return {};
|
|
16
|
+
let argv = yargs(hideBin(args))
|
|
17
|
+
.option("config", {
|
|
18
|
+
alias: "c",
|
|
19
|
+
description: "Path to a `config.json` file.",
|
|
20
|
+
type: "string",
|
|
21
|
+
})
|
|
22
|
+
.option("input", {
|
|
23
|
+
alias: "i",
|
|
24
|
+
description:
|
|
25
|
+
"Path to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.",
|
|
26
|
+
type: "string",
|
|
27
|
+
})
|
|
28
|
+
.option("output", {
|
|
29
|
+
alias: "o",
|
|
30
|
+
description:
|
|
31
|
+
"Path of the directory in which to store the output of Doc Detective commands.",
|
|
32
|
+
type: "string",
|
|
33
|
+
})
|
|
34
|
+
.option("setup", {
|
|
35
|
+
description:
|
|
36
|
+
"Path to test specifications to perform before those specified by `input`. Useful for setting up testing environments.",
|
|
37
|
+
type: "string",
|
|
38
|
+
})
|
|
39
|
+
.option("cleanup", {
|
|
40
|
+
description:
|
|
41
|
+
"Path to test specifications to perform after those specified by input. Useful for cleaning up testing environments.",
|
|
42
|
+
type: "string",
|
|
43
|
+
})
|
|
44
|
+
.option("recursive", {
|
|
45
|
+
alias: "r",
|
|
46
|
+
description:
|
|
47
|
+
"Boolean. If true searches input, setup, and cleanup paths recursively for test specificaions and source files. Defaults to `true`.",
|
|
48
|
+
type: "string",
|
|
49
|
+
})
|
|
50
|
+
.option("logLevel", {
|
|
51
|
+
alias: "l",
|
|
52
|
+
description:
|
|
53
|
+
"Detail level of logging events. Accepted values: silent, error, warning, info (default), debug",
|
|
54
|
+
type: "string",
|
|
55
|
+
})
|
|
56
|
+
.help()
|
|
57
|
+
.alias("help", "h").argv;
|
|
58
|
+
|
|
59
|
+
return argv;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Override config values based on args
|
|
63
|
+
function setConfig(config, args) {
|
|
64
|
+
// If no args, return config
|
|
65
|
+
if (!args) return config;
|
|
66
|
+
|
|
67
|
+
// Load config from file
|
|
68
|
+
if (args.config) {
|
|
69
|
+
const configPath = path.resolve(args.config);
|
|
70
|
+
configContent = require(configPath);
|
|
71
|
+
// Validate config
|
|
72
|
+
const validation = validate("config_v2", configContent);
|
|
73
|
+
if (validation.valid) {
|
|
74
|
+
config = configContent;
|
|
75
|
+
} else {
|
|
76
|
+
// Output validation errors
|
|
77
|
+
console.error("Invalid config file:");
|
|
78
|
+
validation.errors.forEach((error) => {
|
|
79
|
+
console.error(error);
|
|
80
|
+
});
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Override config values
|
|
86
|
+
if (args.input) config.input = args.input;
|
|
87
|
+
if (args.output) config.output = args.output;
|
|
88
|
+
if (args.recursive) config.recursive = args.recursive;
|
|
89
|
+
if (args.logLevel) config.logLevel = args.logLevel;
|
|
90
|
+
if ((args.setup || args.cleanup || args.input || args.output ) && !config.runTests) config.runTests = {};
|
|
91
|
+
if (args.input) config.runTests.input = args.input;
|
|
92
|
+
if (args.output) config.runTests.output = args.output;
|
|
93
|
+
if (args.setup) config.runTests.setup = args.setup;
|
|
94
|
+
if (args.cleanup) config.runTests.cleanup = args.cleanup;
|
|
95
|
+
|
|
96
|
+
// Validate config
|
|
97
|
+
const validation = validate("config_v2", config);
|
|
98
|
+
if (!validation.valid) {
|
|
99
|
+
// Output validation errors
|
|
100
|
+
console.error("Invalid config.");
|
|
101
|
+
validation.errors.forEach((error) => {
|
|
102
|
+
console.error(error);
|
|
103
|
+
});
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return config;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function outputResults(config, path, results) {
|
|
111
|
+
let data = JSON.stringify(results, null, 2);
|
|
112
|
+
fs.writeFile(path, data, (err) => {
|
|
113
|
+
if (err) throw err;
|
|
114
|
+
});
|
|
115
|
+
console.log(`See results at ${path}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Perform a native command in the current working directory.
|
|
119
|
+
async function spawnCommand(cmd, args) {
|
|
120
|
+
// Split command into command and arguments
|
|
121
|
+
if (cmd.includes(" ")) {
|
|
122
|
+
const cmdArray = cmd.split(" ");
|
|
123
|
+
cmd = cmdArray[0];
|
|
124
|
+
cmdArgs = cmdArray.slice(1);
|
|
125
|
+
// Add arguments to args array
|
|
126
|
+
if (args) {
|
|
127
|
+
args = cmdArgs.concat(args);
|
|
128
|
+
} else {
|
|
129
|
+
args = cmdArgs;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const runCommand = spawn(cmd, args);
|
|
134
|
+
|
|
135
|
+
// Capture stdout
|
|
136
|
+
let stdout = "";
|
|
137
|
+
for await (const chunk of runCommand.stdout) {
|
|
138
|
+
stdout += chunk;
|
|
139
|
+
}
|
|
140
|
+
// Remove trailing newline
|
|
141
|
+
stdout = stdout.replace(/\n$/, "");
|
|
142
|
+
|
|
143
|
+
// Capture stderr
|
|
144
|
+
let stderr = "";
|
|
145
|
+
for await (const chunk of runCommand.stderr) {
|
|
146
|
+
stderr += chunk;
|
|
147
|
+
}
|
|
148
|
+
// Remove trailing newline
|
|
149
|
+
stderr = stderr.replace(/\n$/, "");
|
|
150
|
+
|
|
151
|
+
// Capture exit code
|
|
152
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
153
|
+
runCommand.on("close", resolve);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return { stdout, stderr, exitCode };
|
|
157
157
|
}
|