@testsmith/api-spector 0.0.4 → 0.0.5
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/LICENSE +674 -0
- package/out/main/chunks/{script-runner-DIevRMmJ.js → script-runner-CmdLWmKN.js} +70 -1
- package/out/main/index.js +8 -1
- package/out/main/runner.js +3 -1
- package/out/preload/index.js +3 -1
- package/out/renderer/assets/{index-BbhJgjM1.js → index-KbYng3S3.js} +422 -90
- package/out/renderer/assets/{index-C1Q1TfC-.css → index-f4ppKNTS.css} +17 -5
- package/out/renderer/index.html +2 -2
- package/package.json +5 -3
|
@@ -27,6 +27,8 @@ const crypto = require("crypto");
|
|
|
27
27
|
const vm = require("vm");
|
|
28
28
|
const dayjs = require("dayjs");
|
|
29
29
|
const tv4 = require("tv4");
|
|
30
|
+
const jsonpathPlus = require("jsonpath-plus");
|
|
31
|
+
const xmldom = require("@xmldom/xmldom");
|
|
30
32
|
function _interopNamespaceDefault(e) {
|
|
31
33
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
32
34
|
if (e) {
|
|
@@ -173,6 +175,43 @@ async function buildEnvVars(environment) {
|
|
|
173
175
|
function mergeVars(envVars, collectionVars, globals2, localVars = {}) {
|
|
174
176
|
return { ...globals2, ...collectionVars, ...envVars, ...localVars };
|
|
175
177
|
}
|
|
178
|
+
function xmlFindAll(node, tag, nth) {
|
|
179
|
+
const results = [];
|
|
180
|
+
const siblings = Array.from(node.childNodes).filter((c) => c.nodeType === 1 && c.tagName === tag);
|
|
181
|
+
if (siblings[nth]) results.push(siblings[nth]);
|
|
182
|
+
for (const child of Array.from(node.childNodes)) {
|
|
183
|
+
if (child.nodeType === 1) results.push(...xmlFindAll(child, tag, nth));
|
|
184
|
+
}
|
|
185
|
+
return results;
|
|
186
|
+
}
|
|
187
|
+
function xmlQuerySelector(root, selector) {
|
|
188
|
+
const parts = selector.trim().split(/\s*>\s*/);
|
|
189
|
+
const m0 = parts[0].match(/^([A-Za-z0-9_:.-]+?)(?::nth-of-type\((\d+)\))?$/);
|
|
190
|
+
if (!m0) return null;
|
|
191
|
+
let candidates = xmlFindAll(root, m0[1], m0[2] ? parseInt(m0[2]) - 1 : 0);
|
|
192
|
+
for (let i = 1; i < parts.length; i++) {
|
|
193
|
+
const m = parts[i].match(/^([A-Za-z0-9_:.-]+?)(?::nth-of-type\((\d+)\))?$/);
|
|
194
|
+
if (!m) return null;
|
|
195
|
+
const tag = m[1];
|
|
196
|
+
const idx = m[2] ? parseInt(m[2]) - 1 : 0;
|
|
197
|
+
const next = [];
|
|
198
|
+
for (const node of candidates) {
|
|
199
|
+
const children = Array.from(node.childNodes).filter((c) => c.nodeType === 1 && c.tagName === tag);
|
|
200
|
+
if (children[idx]) next.push(children[idx]);
|
|
201
|
+
}
|
|
202
|
+
candidates = next;
|
|
203
|
+
}
|
|
204
|
+
return candidates[0] ?? null;
|
|
205
|
+
}
|
|
206
|
+
function makeSandboxDOMParser() {
|
|
207
|
+
return {
|
|
208
|
+
parseFromString(str, mime) {
|
|
209
|
+
const doc = new xmldom.DOMParser().parseFromString(str, mime);
|
|
210
|
+
doc.querySelector = (sel) => xmlQuerySelector(doc, sel);
|
|
211
|
+
return doc;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
176
215
|
let _fakerCache = null;
|
|
177
216
|
async function getFaker() {
|
|
178
217
|
if (!_fakerCache) _fakerCache = await import("@faker-js/faker");
|
|
@@ -280,6 +319,28 @@ function makeAsserter(value, negated = false) {
|
|
|
280
319
|
asserter.gte = asserter.least;
|
|
281
320
|
asserter.lt = asserter.below;
|
|
282
321
|
asserter.lte = asserter.most;
|
|
322
|
+
asserter.oneOf = (list) => {
|
|
323
|
+
doAssert(
|
|
324
|
+
list.includes(value),
|
|
325
|
+
`Expected ${JSON.stringify(value)} to ${negated ? "not " : ""}be one of ${JSON.stringify(list)}`
|
|
326
|
+
);
|
|
327
|
+
return asserter;
|
|
328
|
+
};
|
|
329
|
+
asserter.lengthOf = (n) => {
|
|
330
|
+
const len = value.length;
|
|
331
|
+
doAssert(
|
|
332
|
+
len === n,
|
|
333
|
+
`Expected length ${len} to ${negated ? "not " : ""}equal ${n}`
|
|
334
|
+
);
|
|
335
|
+
return asserter;
|
|
336
|
+
};
|
|
337
|
+
asserter.match = (re) => {
|
|
338
|
+
doAssert(
|
|
339
|
+
re.test(String(value)),
|
|
340
|
+
`Expected "${value}" to ${negated ? "not " : ""}match ${re}`
|
|
341
|
+
);
|
|
342
|
+
return asserter;
|
|
343
|
+
};
|
|
283
344
|
return asserter;
|
|
284
345
|
}
|
|
285
346
|
class AssertionError extends Error {
|
|
@@ -330,7 +391,9 @@ function buildAt(ctx, testResults, consoleOutput) {
|
|
|
330
391
|
}
|
|
331
392
|
},
|
|
332
393
|
// Expect / assertions
|
|
333
|
-
expect: (value) => makeAsserter(value, false)
|
|
394
|
+
expect: (value) => makeAsserter(value, false),
|
|
395
|
+
// JSONPath query: sp.jsonPath(data, '$.store.book[?(@.price < 10)].title')
|
|
396
|
+
jsonPath: (data, expr) => jsonpathPlus.JSONPath({ path: expr, json: data })
|
|
334
397
|
};
|
|
335
398
|
if (ctx.response) {
|
|
336
399
|
const resp = ctx.response;
|
|
@@ -350,6 +413,11 @@ function buildAt(ctx, testResults, consoleOutput) {
|
|
|
350
413
|
return parsedJson;
|
|
351
414
|
},
|
|
352
415
|
text: () => resp.body,
|
|
416
|
+
xmlText: (selector) => {
|
|
417
|
+
const doc = new xmldom.DOMParser().parseFromString(resp.body, "text/xml");
|
|
418
|
+
const node = xmlQuerySelector(doc, selector);
|
|
419
|
+
return node ? String(node.textContent ?? "").trim() : null;
|
|
420
|
+
},
|
|
353
421
|
to: {
|
|
354
422
|
have: {
|
|
355
423
|
status: (code) => {
|
|
@@ -385,6 +453,7 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
|
|
|
385
453
|
};
|
|
386
454
|
const sandbox = {
|
|
387
455
|
sp,
|
|
456
|
+
DOMParser: makeSandboxDOMParser,
|
|
388
457
|
dayjs,
|
|
389
458
|
faker,
|
|
390
459
|
tv4,
|
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 scriptRunner = require("./chunks/script-runner-
|
|
28
|
+
const scriptRunner = require("./chunks/script-runner-CmdLWmKN.js");
|
|
29
29
|
const undici = require("undici");
|
|
30
30
|
const crypto = require("crypto");
|
|
31
31
|
const uuid = require("uuid");
|
|
@@ -39,6 +39,8 @@ const Ajv = require("ajv");
|
|
|
39
39
|
require("vm");
|
|
40
40
|
require("dayjs");
|
|
41
41
|
require("tv4");
|
|
42
|
+
require("jsonpath-plus");
|
|
43
|
+
require("@xmldom/xmldom");
|
|
42
44
|
const LAST_WS_FILE = path.join(electron.app.getPath("userData"), "last-workspace.json");
|
|
43
45
|
async function saveLastWorkspacePath(wsPath) {
|
|
44
46
|
await promises.writeFile(LAST_WS_FILE, JSON.stringify({ path: wsPath }), "utf8");
|
|
@@ -3970,6 +3972,11 @@ function createWindow() {
|
|
|
3970
3972
|
win.show();
|
|
3971
3973
|
}, 1200);
|
|
3972
3974
|
});
|
|
3975
|
+
if (process.platform === "win32") {
|
|
3976
|
+
const version = electron.app.getVersion();
|
|
3977
|
+
win.setTitle(`api Spector${version ? ` v${version}` : ""}`);
|
|
3978
|
+
win.webContents.on("page-title-updated", (e) => e.preventDefault());
|
|
3979
|
+
}
|
|
3973
3980
|
win.webContents.on("before-input-event", (_e, input) => {
|
|
3974
3981
|
if (input.type !== "keyDown") return;
|
|
3975
3982
|
const devToolsShortcut = input.key === "F12" || input.key === "I" && input.shift && (input.meta || input.control);
|
package/out/main/runner.js
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
const promises = require("fs/promises");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const undici = require("undici");
|
|
6
|
-
const scriptRunner = require("./chunks/script-runner-
|
|
6
|
+
const scriptRunner = require("./chunks/script-runner-CmdLWmKN.js");
|
|
7
7
|
require("crypto");
|
|
8
8
|
require("vm");
|
|
9
9
|
require("dayjs");
|
|
10
10
|
require("tv4");
|
|
11
|
+
require("jsonpath-plus");
|
|
12
|
+
require("@xmldom/xmldom");
|
|
11
13
|
function buildJsonReport(results, summary, meta = {}) {
|
|
12
14
|
return JSON.stringify({
|
|
13
15
|
timestamp: meta.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
package/out/preload/index.js
CHANGED
|
@@ -78,6 +78,8 @@ const api = {
|
|
|
78
78
|
generateDocs: (payload) => electron.ipcRenderer.invoke("docs:generate", payload),
|
|
79
79
|
// ─── Contract testing ─────────────────────────────────────────────────────
|
|
80
80
|
runContracts: (payload) => electron.ipcRenderer.invoke("contract:run", payload),
|
|
81
|
-
inferContractSchema: (jsonBody) => electron.ipcRenderer.invoke("contract:inferSchema", jsonBody)
|
|
81
|
+
inferContractSchema: (jsonBody) => electron.ipcRenderer.invoke("contract:inferSchema", jsonBody),
|
|
82
|
+
// ─── Platform ─────────────────────────────────────────────────────────────
|
|
83
|
+
platform: process.platform
|
|
82
84
|
};
|
|
83
85
|
electron.contextBridge.exposeInMainWorld("electron", api);
|