@testsmith/api-spector 0.1.1 → 0.1.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.
|
@@ -208,6 +208,13 @@ async function buildEnvVars(environment) {
|
|
|
208
208
|
} catch {
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
+
if (vars[v.key] === void 0 && process.env[v.key] !== void 0) {
|
|
212
|
+
vars[v.key] = process.env[v.key];
|
|
213
|
+
}
|
|
214
|
+
} else if (v.secret) {
|
|
215
|
+
if (process.env[v.key] !== void 0) {
|
|
216
|
+
vars[v.key] = process.env[v.key];
|
|
217
|
+
}
|
|
211
218
|
} else {
|
|
212
219
|
vars[v.key] = v.value;
|
|
213
220
|
}
|
package/out/main/index.js
CHANGED
|
@@ -25,7 +25,7 @@ const electron = require("electron");
|
|
|
25
25
|
const path = require("path");
|
|
26
26
|
const fs = require("fs");
|
|
27
27
|
const promises = require("fs/promises");
|
|
28
|
-
const requestHandler = require("./chunks/request-handler-
|
|
28
|
+
const requestHandler = require("./chunks/request-handler-CvqESn11.js");
|
|
29
29
|
const uuid = require("uuid");
|
|
30
30
|
const jsYaml = require("js-yaml");
|
|
31
31
|
const undici = require("undici");
|
package/out/main/runner.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const promises = require("fs/promises");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const undici = require("undici");
|
|
6
|
-
const requestHandler = require("./chunks/request-handler-
|
|
6
|
+
const requestHandler = require("./chunks/request-handler-CvqESn11.js");
|
|
7
7
|
require("crypto");
|
|
8
8
|
require("dayjs");
|
|
9
9
|
require("vm");
|
|
@@ -35,6 +35,177 @@ function buildJsonReport(results, summary, meta = {}) {
|
|
|
35
35
|
}))
|
|
36
36
|
}, null, 2);
|
|
37
37
|
}
|
|
38
|
+
function buildHtmlReport(results, summary, meta = {}) {
|
|
39
|
+
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
40
|
+
function prettyJson(s) {
|
|
41
|
+
try {
|
|
42
|
+
return esc(JSON.stringify(JSON.parse(s), null, 2));
|
|
43
|
+
} catch {
|
|
44
|
+
return esc(s);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function headersTable(h) {
|
|
48
|
+
const rows = Object.entries(h).map(
|
|
49
|
+
([k, v]) => `<tr><td class="hk">${esc(k)}</td><td class="hv">${esc(v)}</td></tr>`
|
|
50
|
+
).join("");
|
|
51
|
+
return rows ? `<table class="htable"><tbody>${rows}</tbody></table>` : '<span class="muted">none</span>';
|
|
52
|
+
}
|
|
53
|
+
const ts = meta.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
54
|
+
const collection = meta.collection ?? "API Tests";
|
|
55
|
+
const env = meta.environment ?? "—";
|
|
56
|
+
const passRate = summary.total > 0 ? Math.round(summary.passed / summary.total * 100) : 0;
|
|
57
|
+
const cards = results.map((r, idx) => {
|
|
58
|
+
const statusCls = r.status === "passed" ? "badge-pass" : r.status === "failed" ? "badge-fail" : "badge-err";
|
|
59
|
+
const httpCls = r.httpStatus && r.httpStatus < 300 ? "http-ok" : r.httpStatus && r.httpStatus < 400 ? "http-redir" : "http-err";
|
|
60
|
+
const dur = r.durationMs != null ? `${r.durationMs} ms` : "—";
|
|
61
|
+
const label = r.iterationLabel ? ` <span class="muted">#${esc(r.iterationLabel)}</span>` : "";
|
|
62
|
+
const testRows = (r.testResults ?? []).map(
|
|
63
|
+
(t) => `<div class="test-row ${t.passed ? "test-pass" : "test-fail"}">
|
|
64
|
+
<span class="dot">${t.passed ? "✓" : "✗"}</span> ${esc(t.name)}
|
|
65
|
+
${!t.passed ? `<div class="test-err">${esc(t.error ?? "")}</div>` : ""}
|
|
66
|
+
</div>`
|
|
67
|
+
).join("");
|
|
68
|
+
const errRows = [
|
|
69
|
+
r.error ? `<div class="err-row">⚠ ${esc(r.error)}</div>` : "",
|
|
70
|
+
r.preScriptError ? `<div class="err-row">⚠ Pre-script: ${esc(r.preScriptError)}</div>` : "",
|
|
71
|
+
r.postScriptError ? `<div class="err-row">⚠ Post-script: ${esc(r.postScriptError)}</div>` : ""
|
|
72
|
+
].filter(Boolean).join("");
|
|
73
|
+
const consoleHtml = (r.consoleOutput ?? []).length ? `<div class="section-label">Console</div>
|
|
74
|
+
<div class="code-block">${(r.consoleOutput ?? []).map((l) => `<div>${esc(l)}</div>`).join("")}</div>` : "";
|
|
75
|
+
const reqHeaders = r.sentRequest?.headers ?? {};
|
|
76
|
+
const reqBody = r.sentRequest?.body;
|
|
77
|
+
const reqHtml = `
|
|
78
|
+
<div class="panel-label">Request</div>
|
|
79
|
+
<div class="panel req-panel">
|
|
80
|
+
<div class="req-line"><span class="method-badge">${esc(r.method)}</span> <span class="mono">${esc(r.resolvedUrl ?? "")}</span></div>
|
|
81
|
+
<div class="section-label">Headers</div>
|
|
82
|
+
${headersTable(reqHeaders)}
|
|
83
|
+
${reqBody ? `<div class="section-label">Body</div><pre class="code-block">${prettyJson(reqBody)}</pre>` : ""}
|
|
84
|
+
</div>`;
|
|
85
|
+
const resp = r.receivedResponse;
|
|
86
|
+
const respHtml = resp ? `
|
|
87
|
+
<div class="panel-label">Response</div>
|
|
88
|
+
<div class="panel resp-panel">
|
|
89
|
+
<div class="resp-status ${httpCls}">${resp.status} ${esc(resp.statusText)}</div>
|
|
90
|
+
<div class="section-label">Headers</div>
|
|
91
|
+
${headersTable(resp.headers)}
|
|
92
|
+
${resp.body ? `<div class="section-label">Body</div><pre class="code-block">${prettyJson(resp.body)}</pre>` : ""}
|
|
93
|
+
</div>` : "";
|
|
94
|
+
return `
|
|
95
|
+
<div class="card" id="r${idx}">
|
|
96
|
+
<div class="card-header" onclick="toggle(${idx})">
|
|
97
|
+
<span class="chevron" id="ch${idx}">▶</span>
|
|
98
|
+
<span class="badge ${statusCls}">${r.status}</span>
|
|
99
|
+
<span class="method mono">${esc(r.method)}</span>
|
|
100
|
+
<span class="card-name">${esc(r.name)}${label}</span>
|
|
101
|
+
<span class="card-url muted">${esc(r.resolvedUrl ?? "")}</span>
|
|
102
|
+
<span class="dur muted">${dur}</span>
|
|
103
|
+
${r.httpStatus ? `<span class="http-badge ${httpCls}">${r.httpStatus}</span>` : ""}
|
|
104
|
+
</div>
|
|
105
|
+
<div class="card-body" id="cb${idx}" style="display:none">
|
|
106
|
+
${errRows}
|
|
107
|
+
${testRows ? `<div class="section-label">Tests</div><div class="tests-wrap">${testRows}</div>` : ""}
|
|
108
|
+
${consoleHtml}
|
|
109
|
+
<div class="req-resp-grid">
|
|
110
|
+
${reqHtml}
|
|
111
|
+
${respHtml}
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>`;
|
|
115
|
+
}).join("\n");
|
|
116
|
+
return `<!DOCTYPE html>
|
|
117
|
+
<html lang="en">
|
|
118
|
+
<head>
|
|
119
|
+
<meta charset="UTF-8">
|
|
120
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
121
|
+
<title>${esc(collection)} — Test Results</title>
|
|
122
|
+
<style>
|
|
123
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
124
|
+
body { font-family: system-ui, sans-serif; background: #0f1117; color: #c9d1d9; font-size: 13px; line-height: 1.5; }
|
|
125
|
+
.wrap { max-width: 1200px; margin: 0 auto; padding: 32px 24px; }
|
|
126
|
+
h1 { font-size: 20px; font-weight: 600; color: #e6edf3; margin-bottom: 4px; }
|
|
127
|
+
.meta-line { color: #8b949e; font-size: 11px; margin-bottom: 24px; }
|
|
128
|
+
.summary { display: flex; gap: 12px; margin-bottom: 28px; flex-wrap: wrap; }
|
|
129
|
+
.stat { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 12px 20px; min-width: 90px; }
|
|
130
|
+
.stat-val { font-size: 22px; font-weight: 700; color: #e6edf3; }
|
|
131
|
+
.stat-lbl { font-size: 11px; color: #8b949e; margin-top: 2px; }
|
|
132
|
+
.stat-pass .stat-val { color: #3fb950; }
|
|
133
|
+
.stat-fail .stat-val { color: #f85149; }
|
|
134
|
+
.stat-err .stat-val { color: #d29922; }
|
|
135
|
+
/* Cards */
|
|
136
|
+
.card { border: 1px solid #21262d; border-radius: 8px; margin-bottom: 8px; overflow: hidden; }
|
|
137
|
+
.card-header { display: flex; align-items: baseline; gap: 8px; padding: 10px 14px; cursor: pointer; user-select: none; }
|
|
138
|
+
.card-header:hover { background: #161b22; }
|
|
139
|
+
.chevron { font-size: 10px; color: #8b949e; min-width: 10px; transition: transform .15s; }
|
|
140
|
+
.card-name { font-weight: 500; color: #e6edf3; white-space: nowrap; }
|
|
141
|
+
.card-url { font-family: monospace; font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
|
|
142
|
+
.card-body { padding: 12px 14px; border-top: 1px solid #21262d; display: flex; flex-direction: column; gap: 10px; }
|
|
143
|
+
/* Badges */
|
|
144
|
+
.badge { display: inline-block; padding: 1px 7px; border-radius: 10px; font-size: 11px; font-weight: 600; white-space: nowrap; }
|
|
145
|
+
.badge-pass { background: #0d3a1e; color: #3fb950; }
|
|
146
|
+
.badge-fail { background: #3d1014; color: #f85149; }
|
|
147
|
+
.badge-err { background: #3d2a00; color: #d29922; }
|
|
148
|
+
.method { font-family: monospace; font-size: 11px; font-weight: 700; color: #79c0ff; white-space: nowrap; }
|
|
149
|
+
.method-badge { display: inline-block; font-family: monospace; font-size: 11px; font-weight: 700; color: #79c0ff; min-width: 52px; }
|
|
150
|
+
.http-badge { font-family: monospace; font-size: 11px; font-weight: 600; white-space: nowrap; }
|
|
151
|
+
.http-ok { color: #3fb950; }
|
|
152
|
+
.http-redir { color: #79c0ff; }
|
|
153
|
+
.http-err { color: #f85149; }
|
|
154
|
+
.dur { font-family: monospace; font-size: 11px; white-space: nowrap; }
|
|
155
|
+
.muted { color: #8b949e; }
|
|
156
|
+
.mono { font-family: monospace; font-size: 12px; }
|
|
157
|
+
/* Request / Response */
|
|
158
|
+
.req-resp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
|
159
|
+
@media (max-width: 700px) { .req-resp-grid { grid-template-columns: 1fr; } }
|
|
160
|
+
.panel-label { font-size: 11px; font-weight: 600; color: #8b949e; text-transform: uppercase; letter-spacing: .05em; margin-bottom: 6px; }
|
|
161
|
+
.panel { background: #0d1117; border: 1px solid #21262d; border-radius: 6px; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
|
|
162
|
+
.req-line { font-family: monospace; font-size: 12px; color: #c9d1d9; word-break: break-all; }
|
|
163
|
+
.resp-status { font-family: monospace; font-size: 13px; font-weight: 700; }
|
|
164
|
+
.section-label { font-size: 10px; font-weight: 600; color: #8b949e; text-transform: uppercase; letter-spacing: .04em; margin-top: 2px; }
|
|
165
|
+
.htable { width: 100%; border-collapse: collapse; }
|
|
166
|
+
.htable td { font-family: monospace; font-size: 11px; padding: 1px 0; vertical-align: top; }
|
|
167
|
+
.hk { color: #79c0ff; padding-right: 12px; white-space: nowrap; }
|
|
168
|
+
.hv { color: #c9d1d9; word-break: break-all; }
|
|
169
|
+
.code-block { font-family: monospace; font-size: 11px; color: #c9d1d9; background: #0d1117; border: 1px solid #21262d; border-radius: 4px; padding: 8px; white-space: pre-wrap; word-break: break-all; max-height: 300px; overflow-y: auto; }
|
|
170
|
+
/* Tests */
|
|
171
|
+
.section-label { font-size: 11px; font-weight: 600; color: #8b949e; }
|
|
172
|
+
.tests-wrap { display: flex; flex-direction: column; gap: 2px; }
|
|
173
|
+
.test-row { font-size: 12px; display: flex; flex-wrap: wrap; gap: 4px; }
|
|
174
|
+
.test-pass { color: #3fb950; }
|
|
175
|
+
.test-fail { color: #f85149; }
|
|
176
|
+
.test-err { color: #8b949e; padding-left: 16px; width: 100%; font-family: monospace; font-size: 11px; }
|
|
177
|
+
.dot { font-weight: 700; }
|
|
178
|
+
/* Console */
|
|
179
|
+
.err-row { color: #f85149; font-size: 12px; }
|
|
180
|
+
</style>
|
|
181
|
+
</head>
|
|
182
|
+
<body>
|
|
183
|
+
<div class="wrap">
|
|
184
|
+
<h1>${esc(collection)}</h1>
|
|
185
|
+
<div class="meta-line">Environment: ${esc(env)} · ${esc(ts)}</div>
|
|
186
|
+
<div class="summary">
|
|
187
|
+
<div class="stat"><div class="stat-val">${summary.total}</div><div class="stat-lbl">Total</div></div>
|
|
188
|
+
<div class="stat stat-pass"><div class="stat-val">${summary.passed}</div><div class="stat-lbl">Passed</div></div>
|
|
189
|
+
<div class="stat stat-fail"><div class="stat-val">${summary.failed}</div><div class="stat-lbl">Failed</div></div>
|
|
190
|
+
<div class="stat stat-err"><div class="stat-val">${summary.errors}</div><div class="stat-lbl">Errors</div></div>
|
|
191
|
+
<div class="stat"><div class="stat-val">${passRate}%</div><div class="stat-lbl">Pass rate</div></div>
|
|
192
|
+
<div class="stat"><div class="stat-val">${summary.durationMs} ms</div><div class="stat-lbl">Duration</div></div>
|
|
193
|
+
</div>
|
|
194
|
+
<div class="cards">${cards}</div>
|
|
195
|
+
</div>
|
|
196
|
+
<script>
|
|
197
|
+
function toggle(i) {
|
|
198
|
+
const body = document.getElementById('cb' + i)
|
|
199
|
+
const ch = document.getElementById('ch' + i)
|
|
200
|
+
const open = body.style.display !== 'none'
|
|
201
|
+
body.style.display = open ? 'none' : 'block'
|
|
202
|
+
ch.style.transform = open ? '' : 'rotate(90deg)'
|
|
203
|
+
}
|
|
204
|
+
<\/script>
|
|
205
|
+
</body>
|
|
206
|
+
</html>
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
38
209
|
function buildJUnitReport(results, summary, meta = {}) {
|
|
39
210
|
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
40
211
|
const suiteName = esc(meta.collection ?? "API Tests");
|
|
@@ -267,8 +438,24 @@ async function executeRequest(req, collectionVars, envVars, globals, verbose, tl
|
|
|
267
438
|
if (verbose && r.consoleOutput.length) r.consoleOutput.forEach((l) => console.log(color(` [post] ${l}`, C.gray)));
|
|
268
439
|
}
|
|
269
440
|
const allPassed = testResults.every((t) => t.passed);
|
|
270
|
-
const
|
|
271
|
-
|
|
441
|
+
const httpOk = fetchResp.status < 400;
|
|
442
|
+
const status = postScriptError ? "error" : testResults.length > 0 ? allPassed ? "passed" : "failed" : httpOk ? "passed" : "failed";
|
|
443
|
+
const reqHeaders = {};
|
|
444
|
+
headers.forEach((v, k) => {
|
|
445
|
+
reqHeaders[k] = v;
|
|
446
|
+
});
|
|
447
|
+
return {
|
|
448
|
+
...base,
|
|
449
|
+
status,
|
|
450
|
+
httpStatus: fetchResp.status,
|
|
451
|
+
durationMs,
|
|
452
|
+
testResults,
|
|
453
|
+
consoleOutput,
|
|
454
|
+
preScriptError,
|
|
455
|
+
postScriptError,
|
|
456
|
+
sentRequest: { headers: reqHeaders, body },
|
|
457
|
+
receivedResponse: response
|
|
458
|
+
};
|
|
272
459
|
} catch (err) {
|
|
273
460
|
return {
|
|
274
461
|
...base,
|
|
@@ -298,7 +485,7 @@ async function main() {
|
|
|
298
485
|
const args = parseArgs(process.argv.slice(2));
|
|
299
486
|
if (args.help) {
|
|
300
487
|
console.log(
|
|
301
|
-
"\nUsage:\n api-spector run --workspace <path> [--
|
|
488
|
+
"\nUsage:\n api-spector run --workspace <path> [--environment <name>] [--tags <a,b>]\n [--collection <name>] [--output <path>] [--format json|junit]\n [--verbose] [--bail]\n"
|
|
302
489
|
);
|
|
303
490
|
process.exit(0);
|
|
304
491
|
}
|
|
@@ -308,13 +495,14 @@ async function main() {
|
|
|
308
495
|
process.exit(1);
|
|
309
496
|
}
|
|
310
497
|
const filterTags = args.tags ? args.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
311
|
-
const envName = args.env;
|
|
498
|
+
const envName = args.environment ?? args.env;
|
|
312
499
|
const colName = args.collection;
|
|
313
500
|
const verbose = Boolean(args.verbose);
|
|
314
501
|
const bail = Boolean(args.bail);
|
|
315
502
|
const outputPath = args.output;
|
|
316
|
-
const inferredFormat = outputPath
|
|
317
|
-
const
|
|
503
|
+
const inferredFormat = outputPath ? path.extname(outputPath).toLowerCase() === ".xml" ? "junit" : path.extname(outputPath).toLowerCase() === ".html" ? "html" : "json" : "json";
|
|
504
|
+
const explicitFormat = args.format?.toLowerCase();
|
|
505
|
+
const outputFormat = explicitFormat === "junit" || explicitFormat === "html" ? explicitFormat : inferredFormat;
|
|
318
506
|
let workspace, wsDir;
|
|
319
507
|
try {
|
|
320
508
|
;
|
|
@@ -336,6 +524,26 @@ async function main() {
|
|
|
336
524
|
console.log(color(` Environment: ${env?.name ?? "(none)"}`, C.gray));
|
|
337
525
|
if (filterTags.length) console.log(color(` Tags: ${filterTags.join(", ")}`, C.gray));
|
|
338
526
|
console.log("");
|
|
527
|
+
const envVarsSnapshot = await requestHandler.buildEnvVars(env);
|
|
528
|
+
const secretValuesToMask = (env?.variables ?? []).filter((v) => v.secret && v.enabled).map((v) => envVarsSnapshot[v.key]).filter((v) => typeof v === "string" && v.length > 0);
|
|
529
|
+
function redact(s) {
|
|
530
|
+
let out = s;
|
|
531
|
+
for (const secret of secretValuesToMask) out = out.split(secret).join("***");
|
|
532
|
+
return out;
|
|
533
|
+
}
|
|
534
|
+
function maskResult(r) {
|
|
535
|
+
return {
|
|
536
|
+
...r,
|
|
537
|
+
sentRequest: r.sentRequest ? {
|
|
538
|
+
headers: Object.fromEntries(Object.entries(r.sentRequest.headers).map(([k, v]) => [k, redact(v)])),
|
|
539
|
+
body: r.sentRequest.body != null ? redact(r.sentRequest.body) : void 0
|
|
540
|
+
} : void 0,
|
|
541
|
+
receivedResponse: r.receivedResponse ? {
|
|
542
|
+
...r.receivedResponse,
|
|
543
|
+
body: redact(r.receivedResponse.body)
|
|
544
|
+
} : void 0
|
|
545
|
+
};
|
|
546
|
+
}
|
|
339
547
|
const summary = { total: 0, passed: 0, failed: 0, errors: 0, durationMs: 0 };
|
|
340
548
|
const allResults = [];
|
|
341
549
|
const totalStart = Date.now();
|
|
@@ -378,7 +586,8 @@ async function main() {
|
|
|
378
586
|
`);
|
|
379
587
|
if (outputPath) {
|
|
380
588
|
const meta = { workspace: wsPath, environment: env?.name ?? null, collection: firstColName, timestamp };
|
|
381
|
-
const
|
|
589
|
+
const maskedResults = allResults.map(maskResult);
|
|
590
|
+
const report = outputFormat === "junit" ? buildJUnitReport(maskedResults, summary, meta) : outputFormat === "html" ? buildHtmlReport(maskedResults, summary, meta) : buildJsonReport(maskedResults, summary, meta);
|
|
382
591
|
await promises.writeFile(path.resolve(outputPath), report, "utf8");
|
|
383
592
|
console.log(color(` Report written: ${outputPath} (${outputFormat})
|
|
384
593
|
`, C.gray));
|
|
@@ -55100,12 +55100,13 @@ function generateCiContent(platform, envName, tags2, secretVars) {
|
|
|
55100
55100
|
"api-spector run --workspace .",
|
|
55101
55101
|
envName ? `--environment "${envName}"` : "",
|
|
55102
55102
|
tags2 ? `--tags "${tags2}"` : "",
|
|
55103
|
-
"--output results.
|
|
55103
|
+
"--output results.html"
|
|
55104
55104
|
].filter(Boolean).join(" ");
|
|
55105
|
+
const allSecretVars = secretVars.length ? ["API_SPECTOR_MASTER_KEY", ...secretVars] : [];
|
|
55105
55106
|
if (platform === "github") {
|
|
55106
|
-
const secretHint =
|
|
55107
|
-
` +
|
|
55108
|
-
const envBlock =
|
|
55107
|
+
const secretHint = allSecretVars.length ? ` # ⚠ Add these secrets in: Settings → Secrets and variables → Actions
|
|
55108
|
+
` + allSecretVars.map((v) => ` # ${v}`).join("\n") + "\n" : "";
|
|
55109
|
+
const envBlock = allSecretVars.length ? "\n env:\n" + allSecretVars.map((v) => ` ${v}: \${{ secrets.${v} }}`).join("\n") : "";
|
|
55109
55110
|
return `name: API Tests
|
|
55110
55111
|
|
|
55111
55112
|
on:
|
|
@@ -55129,13 +55130,13 @@ ${secretHint} - name: Run API tests
|
|
|
55129
55130
|
uses: actions/upload-artifact@v4
|
|
55130
55131
|
with:
|
|
55131
55132
|
name: api-test-results
|
|
55132
|
-
path: results.
|
|
55133
|
+
path: results.html
|
|
55133
55134
|
`;
|
|
55134
55135
|
}
|
|
55135
55136
|
if (platform === "gitlab") {
|
|
55136
|
-
const secretHint =
|
|
55137
|
-
` +
|
|
55138
|
-
const envBlock =
|
|
55137
|
+
const secretHint = allSecretVars.length ? ` # ⚠ Add these in: Settings → CI/CD → Variables
|
|
55138
|
+
` + allSecretVars.map((v) => ` # ${v}`).join("\n") + "\n" : "";
|
|
55139
|
+
const envBlock = allSecretVars.length ? "\n variables:\n" + allSecretVars.map((v) => ` ${v}: $${v}`).join("\n") : "";
|
|
55139
55140
|
return `api-tests:
|
|
55140
55141
|
image: node:${NODE_LTS}
|
|
55141
55142
|
stage: test
|
|
@@ -55146,14 +55147,14 @@ ${secretHint} script:
|
|
|
55146
55147
|
artifacts:
|
|
55147
55148
|
when: always
|
|
55148
55149
|
paths:
|
|
55149
|
-
- results.
|
|
55150
|
+
- results.html
|
|
55150
55151
|
expire_in: 30 days
|
|
55151
55152
|
`;
|
|
55152
55153
|
}
|
|
55153
55154
|
if (platform === "azure") {
|
|
55154
|
-
const secretHint =
|
|
55155
|
-
` +
|
|
55156
|
-
const envBlock =
|
|
55155
|
+
const secretHint = allSecretVars.length ? ` # ⚠ Add these in: Pipelines → Library → Variable groups (mark as secret)
|
|
55156
|
+
` + allSecretVars.map((v) => ` # ${v}`).join("\n") + "\n" : "";
|
|
55157
|
+
const envBlock = allSecretVars.length ? "\n env:\n" + allSecretVars.map((v) => ` ${v}: $(${v})`).join("\n") : "";
|
|
55157
55158
|
return `trigger:
|
|
55158
55159
|
- main
|
|
55159
55160
|
|
|
@@ -55169,7 +55170,7 @@ steps:
|
|
|
55169
55170
|
displayName: 'Install api Spector'
|
|
55170
55171
|
${secretHint} - script: ${runCmd}
|
|
55171
55172
|
displayName: 'Run API tests'${envBlock}
|
|
55172
|
-
- publish: results.
|
|
55173
|
+
- publish: results.html
|
|
55173
55174
|
artifact: api-test-results
|
|
55174
55175
|
displayName: 'Upload test results'
|
|
55175
55176
|
condition: always()
|
|
@@ -55638,7 +55639,7 @@ function App() {
|
|
|
55638
55639
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
|
|
55639
55640
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
|
|
55640
55641
|
"v",
|
|
55641
|
-
"0.1.
|
|
55642
|
+
"0.1.2"
|
|
55642
55643
|
] })
|
|
55643
55644
|
] }) }),
|
|
55644
55645
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Toolbar, { onOpenDocs: () => setDocsModalOpen(true) }),
|
package/out/renderer/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta charset="UTF-8" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>api Spector</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-BXpiAoKF.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="./assets/index-QI8AWMd3.css">
|
|
10
10
|
</head>
|
|
11
11
|
|