doc-detective 3.4.0-dev.2 → 3.4.0-dev.4
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/package.json +4 -3
- package/src/index.js +32 -11
- package/src/utils.js +202 -23
- package/test/resolvedTests.test.js +193 -0
- package/test/server/index.js +46 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doc-detective",
|
|
3
|
-
"version": "3.4.0-dev.
|
|
3
|
+
"version": "3.4.0-dev.4",
|
|
4
4
|
"description": "Treat doc content as testable assertions to validate doc accuracy and product UX.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"doc-detective": "src/index.js"
|
|
@@ -33,8 +33,9 @@
|
|
|
33
33
|
"homepage": "https://github.com/doc-detective/doc-detective#readme",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
36
|
-
"
|
|
37
|
-
"doc-detective-
|
|
36
|
+
"axios": "^1.12.2",
|
|
37
|
+
"doc-detective-common": "3.4.0-dev.1",
|
|
38
|
+
"doc-detective-core": "3.4.0-dev.2",
|
|
38
39
|
"yargs": "^17.7.2"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { runTests
|
|
4
|
-
const {
|
|
3
|
+
const { runTests } = require("doc-detective-core");
|
|
4
|
+
const {
|
|
5
|
+
setArgs,
|
|
6
|
+
setConfig,
|
|
7
|
+
outputResults,
|
|
8
|
+
setMeta,
|
|
9
|
+
getVersionData,
|
|
10
|
+
log,
|
|
11
|
+
getResolvedTestsFromEnv,
|
|
12
|
+
reportResults,
|
|
13
|
+
} = require("./utils");
|
|
5
14
|
const { argv } = require("node:process");
|
|
6
15
|
const path = require("path");
|
|
7
16
|
const fs = require("fs");
|
|
@@ -36,16 +45,28 @@ async function main(argv) {
|
|
|
36
45
|
// Set config
|
|
37
46
|
const config = await setConfig({ configPath: configPath, args: argv });
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
log(
|
|
49
|
+
`CLI:VERSION INFO:\n${JSON.stringify(getVersionData(), null, 2)}`,
|
|
50
|
+
"debug",
|
|
51
|
+
config
|
|
52
|
+
);
|
|
53
|
+
log(`CLI:CONFIG:\n${JSON.stringify(config, null, 2)}`, "debug", config);
|
|
54
|
+
|
|
55
|
+
// Check for DOC_DETECTIVE_API environment variable
|
|
56
|
+
let api = await getResolvedTestsFromEnv(config);
|
|
57
|
+
let resolvedTests = api?.resolvedTests || null;
|
|
58
|
+
let apiConfig = api?.apiConfig || null;
|
|
43
59
|
|
|
44
60
|
// Run tests
|
|
45
61
|
const output = config.output;
|
|
46
|
-
const results =
|
|
62
|
+
const results = resolvedTests
|
|
63
|
+
? await runTests(config, { resolvedTests })
|
|
64
|
+
: await runTests(config);
|
|
47
65
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
if (apiConfig) {
|
|
67
|
+
await reportResults({ apiConfig, results });
|
|
68
|
+
} else {
|
|
69
|
+
// Output results
|
|
70
|
+
await outputResults(config, output, results, { command: "runTests" });
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/utils.js
CHANGED
|
@@ -5,6 +5,7 @@ const path = require("path");
|
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const { spawn } = require("child_process");
|
|
7
7
|
const os = require("os");
|
|
8
|
+
const axios = require("axios");
|
|
8
9
|
|
|
9
10
|
exports.setArgs = setArgs;
|
|
10
11
|
exports.setConfig = setConfig;
|
|
@@ -12,6 +13,26 @@ exports.outputResults = outputResults;
|
|
|
12
13
|
exports.spawnCommand = spawnCommand;
|
|
13
14
|
exports.setMeta = setMeta;
|
|
14
15
|
exports.getVersionData = getVersionData;
|
|
16
|
+
exports.log = log;
|
|
17
|
+
exports.getResolvedTestsFromEnv = getResolvedTestsFromEnv;
|
|
18
|
+
exports.reportResults = reportResults;
|
|
19
|
+
|
|
20
|
+
// Log function that respects logLevel
|
|
21
|
+
function log(message, level = "info", config = {}) {
|
|
22
|
+
const logLevels = ["silent", "error", "warning", "info", "debug"];
|
|
23
|
+
const currentLevel = config.logLevel || "info";
|
|
24
|
+
const currentLevelIndex = logLevels.indexOf(currentLevel);
|
|
25
|
+
const messageLevelIndex = logLevels.indexOf(level);
|
|
26
|
+
|
|
27
|
+
// Only log if the message level is at or above the current log level
|
|
28
|
+
if (currentLevelIndex >= messageLevelIndex && messageLevelIndex > 0) {
|
|
29
|
+
if (level === "error") {
|
|
30
|
+
console.error(message);
|
|
31
|
+
} else {
|
|
32
|
+
console.log(message);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
15
36
|
|
|
16
37
|
// Define args
|
|
17
38
|
function setArgs(args) {
|
|
@@ -50,6 +71,116 @@ function setArgs(args) {
|
|
|
50
71
|
return argv;
|
|
51
72
|
}
|
|
52
73
|
|
|
74
|
+
// Get resolved tests from environment variable, if set
|
|
75
|
+
async function getResolvedTestsFromEnv(config = {}) {
|
|
76
|
+
if (!process.env.DOC_DETECTIVE_API) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let resolvedTests = null;
|
|
81
|
+
let apiConfig = null;
|
|
82
|
+
try {
|
|
83
|
+
// Parse the environment variable as JSON
|
|
84
|
+
apiConfig = JSON.parse(process.env.DOC_DETECTIVE_API);
|
|
85
|
+
|
|
86
|
+
// Validate the structure: { accountId, url, token, contextIds }
|
|
87
|
+
if (!apiConfig.accountId || !apiConfig.url || !apiConfig.token || !apiConfig.contextIds) {
|
|
88
|
+
log(
|
|
89
|
+
"Invalid DOC_DETECTIVE_API: must contain 'accountId', 'url', 'token', and 'contextIds' properties",
|
|
90
|
+
"error",
|
|
91
|
+
config
|
|
92
|
+
);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
log(`CLI:Fetching resolved tests from ${apiConfig.url}`, "debug", config);
|
|
97
|
+
|
|
98
|
+
// Make GET request to the specified URL with token in header
|
|
99
|
+
const response = await axios.get(apiConfig.url, {
|
|
100
|
+
headers: {
|
|
101
|
+
"x-runner-token": apiConfig.token,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// The response is the resolvedTests
|
|
106
|
+
resolvedTests = response.data;
|
|
107
|
+
|
|
108
|
+
// Validate against resolvedTests_v3 schema
|
|
109
|
+
const validation = validate({
|
|
110
|
+
schemaKey: "resolvedTests_v3",
|
|
111
|
+
object: resolvedTests,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!validation.valid) {
|
|
115
|
+
log(
|
|
116
|
+
"Invalid resolvedTests from API response. " + validation.errors,
|
|
117
|
+
"error",
|
|
118
|
+
config
|
|
119
|
+
);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Get config from environment variable for merging
|
|
124
|
+
const envConfig = await getConfigFromEnv();
|
|
125
|
+
if (envConfig) {
|
|
126
|
+
// Apply config overrides to resolvedTests.config
|
|
127
|
+
if (resolvedTests.config) {
|
|
128
|
+
resolvedTests.config = { ...resolvedTests.config, ...envConfig };
|
|
129
|
+
} else {
|
|
130
|
+
resolvedTests.config = envConfig;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
log(
|
|
135
|
+
`CLI:RESOLVED_TESTS:\n${JSON.stringify(resolvedTests, null, 2)}`,
|
|
136
|
+
"debug",
|
|
137
|
+
config
|
|
138
|
+
);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
log(
|
|
141
|
+
`Error fetching resolved tests from DOC_DETECTIVE_API: ${error.message}`,
|
|
142
|
+
"error",
|
|
143
|
+
config
|
|
144
|
+
);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
return { apiConfig, resolvedTests };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function getConfigFromEnv() {
|
|
151
|
+
if (!process.env.DOC_DETECTIVE_CONFIG) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let envConfig = null;
|
|
156
|
+
try {
|
|
157
|
+
// Parse the environment variable as JSON
|
|
158
|
+
envConfig = JSON.parse(process.env.DOC_DETECTIVE_CONFIG);
|
|
159
|
+
|
|
160
|
+
// Validate the environment variable config
|
|
161
|
+
const envValidation = validate({
|
|
162
|
+
schemaKey: "config_v3",
|
|
163
|
+
object: envConfig,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (!envValidation.valid) {
|
|
167
|
+
console.error(
|
|
168
|
+
"Invalid config from DOC_DETECTIVE_CONFIG environment variable.",
|
|
169
|
+
envValidation.errors
|
|
170
|
+
);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
log(`CLI:ENV_CONFIG:\n${JSON.stringify(envConfig, null, 2)}`, "debug", envConfig);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error(
|
|
177
|
+
`Error parsing DOC_DETECTIVE_CONFIG environment variable: ${error.message}`
|
|
178
|
+
);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
return envConfig;
|
|
182
|
+
}
|
|
183
|
+
|
|
53
184
|
// Override config values based on args and validate the config
|
|
54
185
|
async function setConfig({ configPath, args }) {
|
|
55
186
|
if (args.config && !configPath) {
|
|
@@ -68,28 +199,10 @@ async function setConfig({ configPath, args }) {
|
|
|
68
199
|
}
|
|
69
200
|
|
|
70
201
|
// Check for DOC_DETECTIVE_CONFIG environment variable
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// Validate the environment variable config
|
|
77
|
-
const envValidation = validate({
|
|
78
|
-
schemaKey: "config_v3",
|
|
79
|
-
object: envConfig,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
if (!envValidation.valid) {
|
|
83
|
-
console.error("Invalid config from DOC_DETECTIVE_CONFIG environment variable.", envValidation.errors);
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Merge with file config, preferring environment variable config (use raw envConfig, not validated with defaults)
|
|
88
|
-
config = { ...config, ...envConfig };
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.error(`Error parsing DOC_DETECTIVE_CONFIG environment variable: ${error.message}`);
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
202
|
+
const envConfig = await getConfigFromEnv();
|
|
203
|
+
if (envConfig) {
|
|
204
|
+
// Merge with file config, preferring environment variable config (use raw envConfig, not validated with defaults)
|
|
205
|
+
config = { ...config, ...envConfig };
|
|
93
206
|
}
|
|
94
207
|
|
|
95
208
|
// Validate config
|
|
@@ -613,6 +726,70 @@ function registerReporter(name, reporterFunction) {
|
|
|
613
726
|
// Export the registerReporter function
|
|
614
727
|
exports.registerReporter = registerReporter;
|
|
615
728
|
|
|
729
|
+
async function reportResults({ apiConfig, results }) {
|
|
730
|
+
// Transform results into the required format for the API
|
|
731
|
+
// Extract contexts from the nested structure and format them
|
|
732
|
+
const contexts = [];
|
|
733
|
+
|
|
734
|
+
if (results.specs) {
|
|
735
|
+
results.specs.forEach((spec) => {
|
|
736
|
+
if (spec.tests) {
|
|
737
|
+
spec.tests.forEach((test) => {
|
|
738
|
+
if (test.contexts) {
|
|
739
|
+
test.contexts.forEach((context) => {
|
|
740
|
+
// Extract or generate contextId
|
|
741
|
+
const contextId =
|
|
742
|
+
context.contextId ||
|
|
743
|
+
context.id ||
|
|
744
|
+
`${spec.specId}-${test.testId}-${
|
|
745
|
+
context.platform || "unknown"
|
|
746
|
+
}`;
|
|
747
|
+
|
|
748
|
+
// Convert result status to lowercase (PASS -> passed, FAIL -> failed, etc.)
|
|
749
|
+
let status;
|
|
750
|
+
if (context.result === "PASS") {
|
|
751
|
+
status = "passed";
|
|
752
|
+
} else if (context.result === "FAIL") {
|
|
753
|
+
status = "failed";
|
|
754
|
+
} else if (context.result === "WARNING") {
|
|
755
|
+
status = "warning";
|
|
756
|
+
} else if (context.result === "SKIPPED") {
|
|
757
|
+
status = "skipped";
|
|
758
|
+
} else {
|
|
759
|
+
status = "unknown";
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Build the context payload with the entire context object embedded
|
|
763
|
+
contexts.push({
|
|
764
|
+
contextId: contextId,
|
|
765
|
+
status: status,
|
|
766
|
+
result: context,
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// POST to the /contexts endpoint
|
|
776
|
+
try {
|
|
777
|
+
const url = `${apiConfig.url}/contexts`;
|
|
778
|
+
const payload = { contexts };
|
|
779
|
+
|
|
780
|
+
const response = await axios.post(url, payload, {
|
|
781
|
+
headers: {
|
|
782
|
+
"x-runner-token": apiConfig.token,
|
|
783
|
+
},
|
|
784
|
+
});
|
|
785
|
+
console.log("Results reported successfully:", response.data);
|
|
786
|
+
} catch (error) {
|
|
787
|
+
console.error(
|
|
788
|
+
`Error reporting results to ${apiConfig.url}/contexts: ${error.message}`
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
616
793
|
async function outputResults(config = {}, outputPath, results, options = {}) {
|
|
617
794
|
// Default to using both built-in reporters if none specified
|
|
618
795
|
const defaultReporters = ["terminal", "json"];
|
|
@@ -678,7 +855,9 @@ async function spawnCommand(cmd, args) {
|
|
|
678
855
|
}
|
|
679
856
|
}
|
|
680
857
|
|
|
681
|
-
const runCommand = spawn(cmd, args
|
|
858
|
+
const runCommand = spawn(cmd, args, {
|
|
859
|
+
env: process.env, // Explicitly pass environment variables
|
|
860
|
+
});
|
|
682
861
|
|
|
683
862
|
// Capture stdout
|
|
684
863
|
let stdout = "";
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
const { createServer } = require("./server");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { spawnCommand } = require("../src/utils");
|
|
4
|
+
const assert = require("assert").strict;
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const artifactPath = path.resolve(__dirname, "./artifacts");
|
|
7
|
+
const outputFile = path.resolve(`${artifactPath}/resolvedTestsResults.json`);
|
|
8
|
+
|
|
9
|
+
// Create a server with custom options
|
|
10
|
+
const server = createServer({
|
|
11
|
+
port: 8093,
|
|
12
|
+
staticDir: "./test/server/public",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Start the server before tests
|
|
16
|
+
before(async () => {
|
|
17
|
+
try {
|
|
18
|
+
await server.start();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(`Failed to start test server: ${error.message}`);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Stop the server after tests
|
|
26
|
+
after(async () => {
|
|
27
|
+
try {
|
|
28
|
+
await server.stop();
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error(`Failed to stop test server: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("DOC_DETECTIVE_API environment variable", function () {
|
|
35
|
+
// Set indefinite timeout
|
|
36
|
+
this.timeout(0);
|
|
37
|
+
|
|
38
|
+
it("Should fetch and run resolved tests from API", async () => {
|
|
39
|
+
const apiConfig = {
|
|
40
|
+
accountId: "test-account",
|
|
41
|
+
url: "http://localhost:8093/api/resolved-tests",
|
|
42
|
+
token: "test-token-123",
|
|
43
|
+
contextIds: "test-context",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Set environment variable
|
|
47
|
+
const originalEnv = process.env.DOC_DETECTIVE_API;
|
|
48
|
+
process.env.DOC_DETECTIVE_API = JSON.stringify(apiConfig);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const result = await spawnCommand(
|
|
52
|
+
`node ./src/index.js -o ${outputFile}`
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Wait until the file is written
|
|
56
|
+
let waitCount = 0;
|
|
57
|
+
while (!fs.existsSync(outputFile) && waitCount < 50) {
|
|
58
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
59
|
+
waitCount++;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (fs.existsSync(outputFile)) {
|
|
63
|
+
const testResult = require(outputFile);
|
|
64
|
+
console.log(
|
|
65
|
+
"API Result summary:",
|
|
66
|
+
JSON.stringify(testResult.summary, null, 2)
|
|
67
|
+
);
|
|
68
|
+
// Clean up the require cache
|
|
69
|
+
delete require.cache[require.resolve(outputFile)];
|
|
70
|
+
fs.unlinkSync(outputFile);
|
|
71
|
+
|
|
72
|
+
// Check that tests were run
|
|
73
|
+
assert.ok(testResult.summary);
|
|
74
|
+
assert.ok(testResult.specs);
|
|
75
|
+
}
|
|
76
|
+
} finally {
|
|
77
|
+
// Restore original env
|
|
78
|
+
if (originalEnv !== undefined) {
|
|
79
|
+
process.env.DOC_DETECTIVE_API = originalEnv;
|
|
80
|
+
} else {
|
|
81
|
+
delete process.env.DOC_DETECTIVE_API;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("Should reject API config without required fields", async () => {
|
|
87
|
+
const invalidApiConfig = {
|
|
88
|
+
accountId: "test-account",
|
|
89
|
+
// Missing url and token
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const originalEnv = process.env.DOC_DETECTIVE_API;
|
|
93
|
+
process.env.DOC_DETECTIVE_API = JSON.stringify(invalidApiConfig);
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const result = await spawnCommand(
|
|
97
|
+
`node ./src/index.js -o ${outputFile}`
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Should exit with non-zero code
|
|
101
|
+
assert.notEqual(result.exitCode, 0);
|
|
102
|
+
} finally {
|
|
103
|
+
// Restore original env
|
|
104
|
+
if (originalEnv !== undefined) {
|
|
105
|
+
process.env.DOC_DETECTIVE_API = originalEnv;
|
|
106
|
+
} else {
|
|
107
|
+
delete process.env.DOC_DETECTIVE_API;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("Should reject unauthorized API requests", async () => {
|
|
113
|
+
const apiConfigBadToken = {
|
|
114
|
+
accountId: "test-account",
|
|
115
|
+
url: "http://localhost:8093/api/resolved-tests",
|
|
116
|
+
token: "wrong-token",
|
|
117
|
+
contextIds: "test-context",
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const originalEnv = process.env.DOC_DETECTIVE_API;
|
|
121
|
+
process.env.DOC_DETECTIVE_API = JSON.stringify(apiConfigBadToken);
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const result = await spawnCommand(
|
|
125
|
+
`node ./src/index.js -o ${outputFile}`
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// Should exit with non-zero code due to 401 response
|
|
129
|
+
assert.notEqual(result.exitCode, 0);
|
|
130
|
+
} finally {
|
|
131
|
+
// Restore original env
|
|
132
|
+
if (originalEnv !== undefined) {
|
|
133
|
+
process.env.DOC_DETECTIVE_API = originalEnv;
|
|
134
|
+
} else {
|
|
135
|
+
delete process.env.DOC_DETECTIVE_API;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("Should apply config overrides from DOC_DETECTIVE_CONFIG to API-fetched tests", async () => {
|
|
141
|
+
const apiConfig = {
|
|
142
|
+
accountId: "test-account",
|
|
143
|
+
url: "http://localhost:8093/api/resolved-tests",
|
|
144
|
+
token: "test-token-123",
|
|
145
|
+
contextIds: "test-context",
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const configOverride = {
|
|
149
|
+
logLevel: "debug",
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const originalApiEnv = process.env.DOC_DETECTIVE_API;
|
|
153
|
+
const originalConfigEnv = process.env.DOC_DETECTIVE_CONFIG;
|
|
154
|
+
process.env.DOC_DETECTIVE_API = JSON.stringify(apiConfig);
|
|
155
|
+
process.env.DOC_DETECTIVE_CONFIG = JSON.stringify(configOverride);
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
await spawnCommand(
|
|
159
|
+
`node ./src/index.js -o ${outputFile}`
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Wait until the file is written
|
|
163
|
+
let waitCount = 0;
|
|
164
|
+
while (!fs.existsSync(outputFile) && waitCount < 50) {
|
|
165
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
166
|
+
waitCount++;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (fs.existsSync(outputFile)) {
|
|
170
|
+
const testResult = require(outputFile);
|
|
171
|
+
// Clean up the require cache
|
|
172
|
+
delete require.cache[require.resolve(outputFile)];
|
|
173
|
+
fs.unlinkSync(outputFile);
|
|
174
|
+
|
|
175
|
+
// Check that tests were run
|
|
176
|
+
assert.ok(testResult.summary);
|
|
177
|
+
assert.ok(testResult.specs);
|
|
178
|
+
}
|
|
179
|
+
} finally {
|
|
180
|
+
// Restore original env
|
|
181
|
+
if (originalApiEnv !== undefined) {
|
|
182
|
+
process.env.DOC_DETECTIVE_API = originalApiEnv;
|
|
183
|
+
} else {
|
|
184
|
+
delete process.env.DOC_DETECTIVE_API;
|
|
185
|
+
}
|
|
186
|
+
if (originalConfigEnv !== undefined) {
|
|
187
|
+
process.env.DOC_DETECTIVE_CONFIG = originalConfigEnv;
|
|
188
|
+
} else {
|
|
189
|
+
delete process.env.DOC_DETECTIVE_CONFIG;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
});
|
package/test/server/index.js
CHANGED
|
@@ -54,6 +54,52 @@ function createServer(options = {}) {
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
// Endpoint for testing DOC_DETECTIVE_API - returns resolved tests
|
|
58
|
+
app.get("/api/resolved-tests", (req, res) => {
|
|
59
|
+
try {
|
|
60
|
+
// Check for x-runner-token header
|
|
61
|
+
const token = req.headers['x-runner-token'];
|
|
62
|
+
|
|
63
|
+
if (!token || token !== 'test-token-123') {
|
|
64
|
+
return res.status(401).json({ error: "Unauthorized" });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Return a valid resolvedTests object
|
|
68
|
+
const resolvedTests = {
|
|
69
|
+
"resolvedTestsId": "api-resolved-tests-id",
|
|
70
|
+
"config": {
|
|
71
|
+
"logLevel": "info"
|
|
72
|
+
},
|
|
73
|
+
"specs": [
|
|
74
|
+
{
|
|
75
|
+
"specId": "api-spec",
|
|
76
|
+
"tests": [
|
|
77
|
+
{
|
|
78
|
+
"testId": "api-test",
|
|
79
|
+
"contexts": [
|
|
80
|
+
{
|
|
81
|
+
"contextId": "api-context",
|
|
82
|
+
"steps": [
|
|
83
|
+
{
|
|
84
|
+
"stepId": "step-1",
|
|
85
|
+
"checkLink": `http://localhost:${port}`
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
res.json(resolvedTests);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error("Error processing resolved tests request:", error);
|
|
99
|
+
res.status(500).json({ error: "Internal server error" });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
57
103
|
return {
|
|
58
104
|
/**
|
|
59
105
|
* Start the server
|