@testsmith/api-spector 0.7.7 → 0.7.8

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.
Files changed (31) hide show
  1. package/bin/cli.js +4 -0
  2. package/out/main/chunks/{broker-client-Df4PpJqB.js → broker-client-BYpWeOWT.js} +4 -1
  3. package/out/main/chunks/{flow-engine-BVzjz4lJ.js → flow-engine-BxwjEy37.js} +66 -1
  4. package/out/main/chunks/{handle-Bz0C56Eq.js → handle-Crv1i9hb.js} +60 -0
  5. package/out/main/chunks/{import-BhGBiW7j.js → import-DTcZMRNu.js} +2 -2
  6. package/out/main/chunks/perf-report-ChaO3K0w.js +124 -0
  7. package/out/main/chunks/perf-run-uZBqnG3S.js +578 -0
  8. package/out/main/chunks/{request-collection-KGPuvN7o.js → request-collection-gkOYlWml.js} +68 -11
  9. package/out/main/chunks/{request-exec-B-F0K-pN.js → request-exec-Cv2jkrO1.js} +439 -12
  10. package/out/main/chunks/run-concurrent-468tH0AX.js +26 -0
  11. package/out/main/chunks/{soap-handler-DqIPcIQL.js → soap-handler-Brr7BPWO.js} +2 -2
  12. package/out/main/contract.js +6 -3
  13. package/out/main/flow.js +8 -5
  14. package/out/main/index.js +1338 -179
  15. package/out/main/lib.js +6 -3
  16. package/out/main/perf-worker.js +45 -0
  17. package/out/main/perf.js +253 -0
  18. package/out/main/runner.js +181 -7
  19. package/out/main/socketio.js +172 -0
  20. package/out/main/wsdl.js +3 -3
  21. package/out/preload/index.js +123 -0
  22. package/out/renderer/assets/{GraphQLEditor-BXpdmpn6.js → GraphQLEditor-Dv2K4wdd.js} +59 -14
  23. package/out/renderer/assets/{SoapEditor-De6WlP6E.js → SoapEditor-Cnz3M4Dz.js} +3 -3
  24. package/out/renderer/assets/ajv-CJPwFjiP.js +6718 -0
  25. package/out/renderer/assets/{codemirror-F6m3Hm1M.js → codemirror-CdIFBPs2.js} +1214 -1207
  26. package/out/renderer/assets/{index-Gcd_t6pX.js → index-CtCdFiRx.js} +15213 -12165
  27. package/out/renderer/assets/index-DkhdKzQJ.css +627 -0
  28. package/out/renderer/index.html +4 -4
  29. package/package.json +12 -6
  30. package/out/renderer/assets/ajv-2MAg6kGF.js +0 -6153
  31. package/out/renderer/assets/index-CYArpqm5.css +0 -627
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  const undici = require("undici");
25
25
  const promises$1 = require("fs/promises");
26
26
  const nodeTls = require("tls");
27
- const handle = require("./handle-Bz0C56Eq.js");
27
+ const handle = require("./handle-Crv1i9hb.js");
28
28
  const fs = require("node:fs");
29
29
  const os = require("node:os");
30
30
  const path = require("node:path");
@@ -35,6 +35,9 @@ const vm = require("node:vm");
35
35
  const tv4 = require("tv4");
36
36
  const jsonpathPlus = require("jsonpath-plus");
37
37
  const xmldom = require("@xmldom/xmldom");
38
+ const mqtt = require("mqtt");
39
+ const WebSocket = require("ws");
40
+ const socket_ioClient = require("socket.io-client");
38
41
  const http = require("node:http");
39
42
  const Ajv = require("ajv");
40
43
  function _interopNamespaceDefault(e) {
@@ -905,9 +908,9 @@ async function buildEnvVars(environment) {
905
908
  }
906
909
  return vars;
907
910
  }
908
- function mergeVars(envVars, collectionVars, globals2, localVars = {}, dynamicVars = {}) {
911
+ function mergeVars(envVars, collectionVars, globals2, localVars = {}, dynamicVars = {}, folderVars = {}) {
909
912
  const out = {};
910
- for (const src of [dynamicVars, globals2, collectionVars, envVars, localVars]) {
913
+ for (const src of [dynamicVars, globals2, collectionVars, folderVars, envVars, localVars]) {
911
914
  for (const [k, v] of Object.entries(src ?? {})) {
912
915
  if (v == null) continue;
913
916
  out[k] = v;
@@ -1091,6 +1094,7 @@ class AssertionError extends Error {
1091
1094
  }
1092
1095
  function buildAt(ctx, testResults, consoleOutput) {
1093
1096
  const { envVars, collectionVars, globals: globals2, localVars, piiMaskPatterns = [] } = ctx;
1097
+ const folderVars = ctx.folderVars ?? {};
1094
1098
  const isSensitiveKey = (key) => piiMaskPatterns.some((p) => key.toLowerCase().includes(p.toLowerCase()));
1095
1099
  function makeVarScope(store, scopeName) {
1096
1100
  return {
@@ -1113,9 +1117,10 @@ function buildAt(ctx, testResults, consoleOutput) {
1113
1117
  variables: makeVarScope(localVars, "variables"),
1114
1118
  environment: makeVarScope(envVars, "environment"),
1115
1119
  collectionVariables: makeVarScope(collectionVars, "collectionVariables"),
1120
+ folder: makeVarScope(folderVars, "folder"),
1116
1121
  globals: makeVarScope(globals2, "globals"),
1117
1122
  // Convenience: get/set across all scopes (local wins)
1118
- variables_get: (key) => localVars[key] ?? envVars[key] ?? collectionVars[key] ?? globals2[key] ?? null,
1123
+ variables_get: (key) => localVars[key] ?? envVars[key] ?? folderVars[key] ?? collectionVars[key] ?? globals2[key] ?? null,
1119
1124
  variables_set: (key, value) => {
1120
1125
  localVars[key] = String(value);
1121
1126
  },
@@ -1174,6 +1179,14 @@ function buildAt(ctx, testResults, consoleOutput) {
1174
1179
  return String(binCode % 10 ** digits).padStart(digits, "0");
1175
1180
  }
1176
1181
  };
1182
+ const collected = ctx.messages ?? ctx.mqttMessages;
1183
+ if (collected) {
1184
+ sp.messages = collected.map((m) => ({
1185
+ ...m,
1186
+ json: () => JSON.parse(m.payload),
1187
+ text: () => m.payload
1188
+ }));
1189
+ }
1177
1190
  if (ctx.response) {
1178
1191
  const resp = ctx.response;
1179
1192
  let parsedJson = void 0;
@@ -1249,12 +1262,17 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1249
1262
  const collectionCopy = { ...ctx.collectionVars };
1250
1263
  const globalsCopy = { ...ctx.globals };
1251
1264
  const localVarsCopy = { ...ctx.localVars };
1265
+ const folderCopy = { ...ctx.folderVars ?? {} };
1252
1266
  const scriptCtx = {
1253
1267
  envVars: envVarsCopy,
1254
1268
  collectionVars: collectionCopy,
1255
1269
  globals: globalsCopy,
1256
1270
  localVars: localVarsCopy,
1271
+ folderVars: folderCopy,
1257
1272
  response: ctx.response,
1273
+ data: ctx.data,
1274
+ mqttMessages: ctx.mqttMessages,
1275
+ messages: ctx.messages,
1258
1276
  piiMaskPatterns: ctx.piiMaskPatterns
1259
1277
  };
1260
1278
  const sandbox = buildSandbox(scriptCtx, testResults, consoleOutput, faker);
@@ -1269,6 +1287,7 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1269
1287
  updatedCollectionVars: collectionCopy,
1270
1288
  updatedGlobals: globalsCopy,
1271
1289
  updatedLocalVars: localVarsCopy,
1290
+ updatedFolderVars: folderCopy,
1272
1291
  error: message
1273
1292
  };
1274
1293
  }
@@ -1278,7 +1297,8 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1278
1297
  updatedEnvVars: envVarsCopy,
1279
1298
  updatedCollectionVars: collectionCopy,
1280
1299
  updatedGlobals: globalsCopy,
1281
- updatedLocalVars: localVarsCopy
1300
+ updatedLocalVars: localVarsCopy,
1301
+ updatedFolderVars: folderCopy
1282
1302
  };
1283
1303
  }
1284
1304
  async function evaluateExpression(code, ctx, timeoutMs = 5e3) {
@@ -1357,6 +1377,7 @@ class StreamFramer {
1357
1377
  constructor(mode) {
1358
1378
  this.mode = mode;
1359
1379
  }
1380
+ mode;
1360
1381
  carry = "";
1361
1382
  /** Feed a decoded text chunk; returns the frames that completed. */
1362
1383
  push(text) {
@@ -1519,6 +1540,314 @@ async function readStream(body, kind, startMs, opts = {}) {
1519
1540
  }
1520
1541
  return { events, text, close, firstEventMs: Math.max(firstEventMs, 0) };
1521
1542
  }
1543
+ async function runMqttTest(cfg) {
1544
+ const messages = [];
1545
+ const collectMs = Math.max(0, Math.min(6e4, Math.floor(cfg.collectMs ?? 2e3)));
1546
+ const clientId = cfg.clientId?.trim() || `api-spector-test-${Date.now().toString(36)}-${Math.random().toString(16).slice(2, 10)}`;
1547
+ return new Promise((resolve2) => {
1548
+ let settled = false;
1549
+ let connected = false;
1550
+ let lastError = "";
1551
+ let client;
1552
+ let timer;
1553
+ const runAssertions = async (connectError) => {
1554
+ if (settled) return;
1555
+ settled = true;
1556
+ if (timer) clearTimeout(timer);
1557
+ try {
1558
+ client?.end(true);
1559
+ } catch {
1560
+ }
1561
+ if (connectError && messages.length === 0) {
1562
+ resolve2({ testResults: [], consoleOutput: [], error: connectError, messages, clientId });
1563
+ return;
1564
+ }
1565
+ const out = await runScript(cfg.script ?? "", {
1566
+ envVars: cfg.envVars ?? {},
1567
+ collectionVars: cfg.collectionVars ?? {},
1568
+ globals: cfg.globals ?? {},
1569
+ localVars: cfg.localVars ?? {},
1570
+ mqttMessages: messages
1571
+ });
1572
+ resolve2({ testResults: out.testResults, consoleOutput: out.consoleOutput, error: out.error, messages, clientId });
1573
+ };
1574
+ try {
1575
+ client = mqtt.connect(cfg.url, {
1576
+ clientId,
1577
+ username: cfg.username?.trim() || void 0,
1578
+ password: cfg.password ? cfg.password : void 0,
1579
+ clean: cfg.cleanSession !== false,
1580
+ reconnectPeriod: 0,
1581
+ connectTimeout: 15e3
1582
+ });
1583
+ } catch (err) {
1584
+ resolve2({ testResults: [], consoleOutput: [], error: err instanceof Error ? err.message : String(err), messages, clientId });
1585
+ return;
1586
+ }
1587
+ client.on("connect", () => {
1588
+ connected = true;
1589
+ const publish = () => {
1590
+ const topic = cfg.publishTopic?.trim();
1591
+ if (!topic) return;
1592
+ if (/[+#]/.test(topic)) return;
1593
+ client.publish(topic, cfg.publishPayload ?? "", { qos: cfg.qos ?? 0, retain: Boolean(cfg.retain) });
1594
+ };
1595
+ const sub = cfg.subscribeTopic?.trim();
1596
+ if (sub) {
1597
+ client.subscribe(sub, { qos: cfg.qos ?? 0 }, () => setTimeout(publish, 100));
1598
+ } else {
1599
+ publish();
1600
+ }
1601
+ timer = setTimeout(() => void runAssertions(), collectMs);
1602
+ });
1603
+ client.on("message", (topic, payload, packet) => {
1604
+ messages.push({ topic, payload: payload.toString("utf8"), qos: packet?.qos, retain: Boolean(packet?.retain), timestamp: Date.now() });
1605
+ });
1606
+ client.on("error", (err) => {
1607
+ const code = err?.code;
1608
+ lastError = [err?.message, code].filter(Boolean).join(" ");
1609
+ void runAssertions(err?.message || "Could not connect to the broker");
1610
+ });
1611
+ client.on("close", () => {
1612
+ if (settled) return;
1613
+ void runAssertions(connected ? `The test connection was dropped by the broker before the window finished${lastError ? ` [${lastError}]` : ""}. Common causes: publishing to a topic that contains a wildcard (+ or #), or another connection using the same client id. Check the broker's log.` : `Could not connect to the broker${lastError ? ` [${lastError}]` : ""}`);
1614
+ });
1615
+ });
1616
+ }
1617
+ function clampWindow(ms) {
1618
+ return Math.max(0, Math.min(6e4, Math.floor(ms ?? 3e3)));
1619
+ }
1620
+ async function assertOver(cfg, messages) {
1621
+ const out = await runScript(cfg.script ?? "", {
1622
+ envVars: cfg.envVars ?? {},
1623
+ collectionVars: cfg.collectionVars ?? {},
1624
+ globals: cfg.globals ?? {},
1625
+ localVars: cfg.localVars ?? {},
1626
+ messages
1627
+ });
1628
+ return { testResults: out.testResults, consoleOutput: out.consoleOutput, error: out.error, messages };
1629
+ }
1630
+ function errorResult(error, messages) {
1631
+ return { testResults: [], consoleOutput: [], error, messages };
1632
+ }
1633
+ function parseJsonObject(text, label) {
1634
+ if (!text || !text.trim()) return void 0;
1635
+ let parsed;
1636
+ try {
1637
+ parsed = JSON.parse(text);
1638
+ } catch {
1639
+ throw new Error(`${label} is not valid JSON`);
1640
+ }
1641
+ return parsed && typeof parsed === "object" ? parsed : void 0;
1642
+ }
1643
+ async function runWsTest(cfg) {
1644
+ const messages = [];
1645
+ const collectMs = clampWindow(cfg.collectMs);
1646
+ return new Promise((resolve2) => {
1647
+ let settled = false;
1648
+ let connected = false;
1649
+ let lastError = "";
1650
+ let ws;
1651
+ let timer;
1652
+ const finish = async (connectError) => {
1653
+ if (settled) return;
1654
+ settled = true;
1655
+ if (timer) clearTimeout(timer);
1656
+ try {
1657
+ ws?.close();
1658
+ } catch {
1659
+ }
1660
+ if (connectError && messages.length === 0) {
1661
+ resolve2(errorResult(connectError, messages));
1662
+ return;
1663
+ }
1664
+ resolve2(await assertOver(cfg, messages));
1665
+ };
1666
+ try {
1667
+ ws = new WebSocket(cfg.url, { headers: cfg.headers });
1668
+ } catch (err) {
1669
+ resolve2(errorResult(err instanceof Error ? err.message : String(err), messages));
1670
+ return;
1671
+ }
1672
+ ws.on("open", () => {
1673
+ connected = true;
1674
+ if (cfg.sendMessage) {
1675
+ try {
1676
+ ws.send(cfg.sendMessage);
1677
+ } catch {
1678
+ }
1679
+ }
1680
+ timer = setTimeout(() => void finish(), collectMs);
1681
+ });
1682
+ ws.on("message", (data) => {
1683
+ const text = data.toString();
1684
+ messages.push({ payload: text, data: text, timestamp: Date.now() });
1685
+ });
1686
+ ws.on("error", (err) => {
1687
+ lastError = err.message;
1688
+ void finish(err.message || "Could not connect to the server");
1689
+ });
1690
+ ws.on("close", () => {
1691
+ if (settled) return;
1692
+ void finish(connected ? `The WebSocket was closed before the window finished${lastError ? ` [${lastError}]` : ""}.` : `Could not connect to the server${lastError ? ` [${lastError}]` : ""}`);
1693
+ });
1694
+ });
1695
+ }
1696
+ function targetUrl(url, namespace) {
1697
+ const ns = (namespace ?? "").trim();
1698
+ if (!ns || ns === "/") return url;
1699
+ return url.replace(/\/+$/, "") + (ns.startsWith("/") ? ns : `/${ns}`);
1700
+ }
1701
+ async function runSocketIoTest(cfg) {
1702
+ const messages = [];
1703
+ const collectMs = clampWindow(cfg.collectMs);
1704
+ let auth;
1705
+ try {
1706
+ auth = parseJsonObject(cfg.auth, "Auth");
1707
+ } catch (e) {
1708
+ return errorResult(e instanceof Error ? e.message : String(e), messages);
1709
+ }
1710
+ let emitArgs = [];
1711
+ if (cfg.emitArgs && cfg.emitArgs.trim()) {
1712
+ try {
1713
+ const parsed = JSON.parse(cfg.emitArgs);
1714
+ emitArgs = Array.isArray(parsed) ? parsed : [parsed];
1715
+ } catch {
1716
+ return errorResult("Emit arguments are not valid JSON", messages);
1717
+ }
1718
+ }
1719
+ return new Promise((resolve2) => {
1720
+ let settled = false;
1721
+ let socket;
1722
+ let timer;
1723
+ const finish = async (connectError) => {
1724
+ if (settled) return;
1725
+ settled = true;
1726
+ if (timer) clearTimeout(timer);
1727
+ try {
1728
+ socket?.disconnect();
1729
+ } catch {
1730
+ }
1731
+ if (connectError && messages.length === 0) {
1732
+ resolve2(errorResult(connectError, messages));
1733
+ return;
1734
+ }
1735
+ resolve2(await assertOver(cfg, messages));
1736
+ };
1737
+ try {
1738
+ socket = socket_ioClient.io(targetUrl(cfg.url, cfg.namespace), {
1739
+ path: cfg.path?.trim() || "/socket.io",
1740
+ transports: ["websocket", "polling"],
1741
+ extraHeaders: cfg.headers,
1742
+ auth,
1743
+ forceNew: true,
1744
+ reconnection: false
1745
+ });
1746
+ } catch (err) {
1747
+ resolve2(errorResult(err instanceof Error ? err.message : String(err), messages));
1748
+ return;
1749
+ }
1750
+ socket.on("connect", () => {
1751
+ const ev = cfg.emitEvent?.trim();
1752
+ if (ev) setTimeout(() => {
1753
+ try {
1754
+ socket.emit(ev, ...emitArgs);
1755
+ } catch {
1756
+ }
1757
+ }, 100);
1758
+ timer = setTimeout(() => void finish(), collectMs);
1759
+ });
1760
+ socket.on("connect_error", (err) => {
1761
+ void finish(`Could not connect to the server${err.message ? ` [${err.message}]` : ""}`);
1762
+ });
1763
+ socket.onAny((event, ...args) => {
1764
+ const payload = JSON.stringify(args.length <= 1 ? args[0] ?? null : args);
1765
+ messages.push({ payload, event, args, timestamp: Date.now() });
1766
+ });
1767
+ });
1768
+ }
1769
+ const GQL_SUB_ID = "1";
1770
+ async function runGraphqlWsTest(cfg) {
1771
+ const messages = [];
1772
+ const collectMs = clampWindow(cfg.collectMs);
1773
+ let variables;
1774
+ let connectionParams;
1775
+ try {
1776
+ variables = parseJsonObject(cfg.variables, "Variables");
1777
+ connectionParams = parseJsonObject(cfg.connectionParams, "Connection params");
1778
+ } catch (e) {
1779
+ return errorResult(e instanceof Error ? e.message : String(e), messages);
1780
+ }
1781
+ return new Promise((resolve2) => {
1782
+ let settled = false;
1783
+ let connected = false;
1784
+ let lastError = "";
1785
+ let ws;
1786
+ let timer;
1787
+ const finish = async (connectError) => {
1788
+ if (settled) return;
1789
+ settled = true;
1790
+ if (timer) clearTimeout(timer);
1791
+ try {
1792
+ ws?.close();
1793
+ } catch {
1794
+ }
1795
+ if (connectError && messages.length === 0) {
1796
+ resolve2(errorResult(connectError, messages));
1797
+ return;
1798
+ }
1799
+ resolve2(await assertOver(cfg, messages));
1800
+ };
1801
+ try {
1802
+ ws = new WebSocket(cfg.url, "graphql-transport-ws", { headers: cfg.headers });
1803
+ } catch (err) {
1804
+ resolve2(errorResult(err instanceof Error ? err.message : String(err), messages));
1805
+ return;
1806
+ }
1807
+ ws.on("open", () => {
1808
+ connected = true;
1809
+ ws.send(JSON.stringify({ type: "connection_init", payload: connectionParams }));
1810
+ timer = setTimeout(() => void finish(), collectMs);
1811
+ });
1812
+ ws.on("message", (raw) => {
1813
+ let msg;
1814
+ try {
1815
+ msg = JSON.parse(raw.toString());
1816
+ } catch {
1817
+ return;
1818
+ }
1819
+ switch (msg.type) {
1820
+ case "connection_ack":
1821
+ ws.send(JSON.stringify({ id: GQL_SUB_ID, type: "subscribe", payload: { query: cfg.query, variables, operationName: cfg.operationName } }));
1822
+ break;
1823
+ case "next": {
1824
+ const payload = msg.payload;
1825
+ const data = payload?.data;
1826
+ messages.push({ payload: JSON.stringify(data ?? payload ?? null), data, errors: payload?.errors, timestamp: Date.now() });
1827
+ break;
1828
+ }
1829
+ case "error":
1830
+ lastError = JSON.stringify(msg.payload);
1831
+ void finish(`The subscription returned an error${lastError ? ` [${lastError}]` : ""}`);
1832
+ break;
1833
+ case "complete":
1834
+ void finish();
1835
+ break;
1836
+ case "ping":
1837
+ ws.send(JSON.stringify({ type: "pong" }));
1838
+ break;
1839
+ }
1840
+ });
1841
+ ws.on("error", (err) => {
1842
+ lastError = err.message;
1843
+ void finish(err.message || "Could not connect to the server");
1844
+ });
1845
+ ws.on("close", () => {
1846
+ if (settled) return;
1847
+ void finish(connected ? `The subscription connection was closed before the window finished${lastError ? ` [${lastError}]` : ""}.` : `Could not connect to the server${lastError ? ` [${lastError}]` : ""}`);
1848
+ });
1849
+ });
1850
+ }
1522
1851
  const SIGNATURE = Buffer.from("NTLMSSP\0", "latin1");
1523
1852
  const F_UNICODE = 1;
1524
1853
  const F_OEM = 2;
@@ -1695,7 +2024,7 @@ async function buildAuthHeaders(auth, vars) {
1695
2024
  const username = interpolate(auth.username ?? "", vars);
1696
2025
  headers["Authorization"] = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
1697
2026
  }
1698
- if (auth.type === "apikey" && auth.apiKeyIn === "header") {
2027
+ if (auth.type === "apikey" && (auth.apiKeyIn ?? "header") === "header") {
1699
2028
  let value = auth.apiKeyValue ?? "";
1700
2029
  if (!value && auth.apiKeySecretRef) value = await getSecret(auth.apiKeySecretRef) ?? "";
1701
2030
  value = interpolate(value, vars);
@@ -2286,6 +2615,7 @@ async function resolveInlineSecrets(req) {
2286
2615
  async function executeRunnerRequest(opts) {
2287
2616
  const { req, collectionVars, envVars, globals: globals2, dispatcher, piiMaskPatterns, proxy, tls, onScriptOutput } = opts;
2288
2617
  let { localVars } = opts;
2618
+ const folderVars = opts.folderVars ?? {};
2289
2619
  applyRequestDefaults(req);
2290
2620
  const base = {
2291
2621
  requestId: req.id,
@@ -2296,13 +2626,99 @@ async function executeRunnerRequest(opts) {
2296
2626
  };
2297
2627
  const dynamicVars = await buildDynamicVars();
2298
2628
  if (localVars && Object.keys(localVars).length > 0) {
2299
- localVars = resolveDataRow(localVars, mergeVars(envVars, collectionVars, globals2, {}, dynamicVars));
2629
+ localVars = resolveDataRow(localVars, mergeVars(envVars, collectionVars, globals2, {}, dynamicVars, folderVars));
2300
2630
  }
2301
- let vars = mergeVars(envVars, collectionVars, globals2, localVars, dynamicVars);
2631
+ let vars = mergeVars(envVars, collectionVars, globals2, localVars, dynamicVars, folderVars);
2302
2632
  let updatedEnvVars = { ...envVars };
2303
2633
  let updatedCollectionVars = { ...collectionVars };
2304
2634
  let updatedGlobals = { ...globals2 };
2635
+ let updatedFolderVars = { ...folderVars };
2305
2636
  let preScriptError;
2637
+ if (req.protocol === "mqtt") {
2638
+ const m = req.mqtt ?? {};
2639
+ const istr = (s) => s ? interpolate(s, vars) : void 0;
2640
+ const mqttStart = Date.now();
2641
+ const testRes = await runMqttTest({
2642
+ url: interpolate(req.url, vars),
2643
+ clientId: istr(m.clientId),
2644
+ username: istr(m.username),
2645
+ password: m.password ? interpolate(m.password, vars) : void 0,
2646
+ cleanSession: m.cleanSession !== false,
2647
+ subscribeTopic: istr(m.subscribeTopic),
2648
+ qos: m.qos,
2649
+ publishTopic: istr(m.publishTopic),
2650
+ publishPayload: istr(m.publishPayload),
2651
+ retain: m.retain,
2652
+ collectMs: m.collectMs ?? 2e3,
2653
+ script: m.testScript ?? "",
2654
+ envVars,
2655
+ collectionVars,
2656
+ globals: globals2,
2657
+ localVars
2658
+ });
2659
+ const status = testRes.error ? "error" : testRes.testResults.length === 0 ? "skipped" : testRes.testResults.every((t) => t.passed) ? "passed" : "failed";
2660
+ return {
2661
+ result: {
2662
+ ...base,
2663
+ status,
2664
+ durationMs: Date.now() - mqttStart,
2665
+ testResults: testRes.testResults,
2666
+ consoleOutput: testRes.consoleOutput,
2667
+ error: testRes.error
2668
+ },
2669
+ updatedEnvVars,
2670
+ updatedCollectionVars,
2671
+ updatedGlobals,
2672
+ updatedLocalVars: localVars,
2673
+ updatedFolderVars
2674
+ };
2675
+ }
2676
+ if (req.protocol === "websocket" || req.protocol === "socketio") {
2677
+ const rtHeaders = {};
2678
+ for (const h of req.headers ?? []) if (h.enabled && h.key) rtHeaders[interpolate(h.key, vars)] = interpolate(h.value, vars);
2679
+ const istr = (s) => s ? interpolate(s, vars) : void 0;
2680
+ const rtStart = Date.now();
2681
+ const testRes = req.protocol === "websocket" ? await runWsTest({
2682
+ url: interpolate(req.url, vars),
2683
+ headers: rtHeaders,
2684
+ sendMessage: istr(req.websocket?.sendMessage),
2685
+ collectMs: req.websocket?.collectMs ?? 3e3,
2686
+ script: req.websocket?.testScript ?? "",
2687
+ envVars,
2688
+ collectionVars,
2689
+ globals: globals2,
2690
+ localVars
2691
+ }) : await runSocketIoTest({
2692
+ url: interpolate(req.url, vars),
2693
+ namespace: req.socketio?.namespace,
2694
+ auth: istr(req.socketio?.auth),
2695
+ headers: rtHeaders,
2696
+ emitEvent: istr(req.socketio?.emitEvent),
2697
+ emitArgs: istr(req.socketio?.emitArgs),
2698
+ collectMs: req.socketio?.collectMs ?? 3e3,
2699
+ script: req.socketio?.testScript ?? "",
2700
+ envVars,
2701
+ collectionVars,
2702
+ globals: globals2,
2703
+ localVars
2704
+ });
2705
+ const status = testRes.error ? "error" : testRes.testResults.length === 0 ? "skipped" : testRes.testResults.every((t) => t.passed) ? "passed" : "failed";
2706
+ return {
2707
+ result: {
2708
+ ...base,
2709
+ status,
2710
+ durationMs: Date.now() - rtStart,
2711
+ testResults: testRes.testResults,
2712
+ consoleOutput: testRes.consoleOutput,
2713
+ error: testRes.error
2714
+ },
2715
+ updatedEnvVars,
2716
+ updatedCollectionVars,
2717
+ updatedGlobals,
2718
+ updatedLocalVars: localVars,
2719
+ updatedFolderVars
2720
+ };
2721
+ }
2306
2722
  let inlineSecrets = {};
2307
2723
  try {
2308
2724
  inlineSecrets = await resolveInlineSecrets(req);
@@ -2317,7 +2733,8 @@ async function executeRunnerRequest(opts) {
2317
2733
  updatedEnvVars,
2318
2734
  updatedCollectionVars,
2319
2735
  updatedGlobals,
2320
- updatedLocalVars: localVars
2736
+ updatedLocalVars: localVars,
2737
+ updatedFolderVars
2321
2738
  };
2322
2739
  }
2323
2740
  if (Object.keys(inlineSecrets).length) vars = { ...vars, ...inlineSecrets };
@@ -2327,6 +2744,7 @@ async function executeRunnerRequest(opts) {
2327
2744
  collectionVars: { ...collectionVars },
2328
2745
  globals: { ...globals2 },
2329
2746
  localVars: { ...localVars },
2747
+ folderVars: { ...updatedFolderVars },
2330
2748
  piiMaskPatterns
2331
2749
  });
2332
2750
  preScriptError = r.error;
@@ -2334,10 +2752,11 @@ async function executeRunnerRequest(opts) {
2334
2752
  updatedEnvVars = r.updatedEnvVars;
2335
2753
  updatedCollectionVars = r.updatedCollectionVars;
2336
2754
  updatedGlobals = r.updatedGlobals;
2755
+ updatedFolderVars = r.updatedFolderVars;
2337
2756
  patchGlobals(r.updatedGlobals);
2338
2757
  await persistGlobals();
2339
2758
  onScriptOutput?.("pre", r.consoleOutput, r.error);
2340
- vars = mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars);
2759
+ vars = mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars, updatedFolderVars);
2341
2760
  if (Object.keys(inlineSecrets).length) vars = { ...vars, ...inlineSecrets };
2342
2761
  }
2343
2762
  const resolvedUrl = buildUrl(req.url, req.params, vars);
@@ -2366,6 +2785,7 @@ async function executeRunnerRequest(opts) {
2366
2785
  collectionVars: updatedCollectionVars,
2367
2786
  globals: updatedGlobals,
2368
2787
  localVars,
2788
+ folderVars: updatedFolderVars,
2369
2789
  response: scriptResponse,
2370
2790
  piiMaskPatterns
2371
2791
  });
@@ -2375,6 +2795,7 @@ async function executeRunnerRequest(opts) {
2375
2795
  updatedEnvVars = r.updatedEnvVars;
2376
2796
  updatedCollectionVars = r.updatedCollectionVars;
2377
2797
  updatedGlobals = r.updatedGlobals;
2798
+ updatedFolderVars = r.updatedFolderVars;
2378
2799
  localVars = r.updatedLocalVars;
2379
2800
  patchGlobals(r.updatedGlobals);
2380
2801
  await persistGlobals();
@@ -2414,7 +2835,8 @@ async function executeRunnerRequest(opts) {
2414
2835
  updatedEnvVars,
2415
2836
  updatedCollectionVars,
2416
2837
  updatedGlobals,
2417
- updatedLocalVars: localVars
2838
+ updatedLocalVars: localVars,
2839
+ updatedFolderVars
2418
2840
  };
2419
2841
  } catch (err) {
2420
2842
  return {
@@ -2428,7 +2850,8 @@ async function executeRunnerRequest(opts) {
2428
2850
  updatedEnvVars,
2429
2851
  updatedCollectionVars,
2430
2852
  updatedGlobals,
2431
- updatedLocalVars: localVars
2853
+ updatedLocalVars: localVars,
2854
+ updatedFolderVars
2432
2855
  };
2433
2856
  }
2434
2857
  }
@@ -2510,7 +2933,11 @@ exports.registerSecretProvider = registerSecretProvider;
2510
2933
  exports.registeredSchemes = registeredSchemes;
2511
2934
  exports.resolveDataRow = resolveDataRow;
2512
2935
  exports.resolveExternalSecret = resolveExternalSecret;
2936
+ exports.runGraphqlWsTest = runGraphqlWsTest;
2937
+ exports.runMqttTest = runMqttTest;
2513
2938
  exports.runScript = runScript;
2939
+ exports.runSocketIoTest = runSocketIoTest;
2940
+ exports.runWsTest = runWsTest;
2514
2941
  exports.setGlobals = setGlobals;
2515
2942
  exports.setSecretsConfig = setSecretsConfig;
2516
2943
  exports.syntheticHttpFailure = syntheticHttpFailure;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ async function runPlanConcurrent(concurrency, items, isBarrier, run) {
3
+ const n = Math.max(1, Math.floor(concurrency));
4
+ const pool = [];
5
+ const settleOne = async () => {
6
+ const done = await Promise.race(pool.map((x) => x.p));
7
+ const pi = pool.findIndex((x) => x.i === done);
8
+ if (pi >= 0) pool.splice(pi, 1);
9
+ };
10
+ const drain = async () => {
11
+ while (pool.length) await settleOne();
12
+ };
13
+ for (let i = 0; i < items.length; i++) {
14
+ const item = items[i];
15
+ if (isBarrier(item)) {
16
+ await drain();
17
+ await run(item, i);
18
+ } else {
19
+ const idx = i;
20
+ pool.push({ p: run(item, idx).then(() => idx), i: idx });
21
+ if (pool.length >= n) await settleOne();
22
+ }
23
+ }
24
+ await drain();
25
+ }
26
+ exports.runPlanConcurrent = runPlanConcurrent;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const handle = require("./handle-Bz0C56Eq.js");
2
+ const handle = require("./handle-Crv1i9hb.js");
3
3
  const https = require("node:https");
4
4
  const http = require("node:http");
5
5
  const xmldom = require("@xmldom/xmldom");
@@ -313,7 +313,7 @@ function registerSoapHandlers(ipc) {
313
313
  handle.handleIpc(ipc, handle.IPC.wsdl.import, async (_event, opts) => {
314
314
  const { validateWsdlImport } = await Promise.resolve().then(() => require("./ipc-validate-sqUFqRmE.js"));
315
315
  validateWsdlImport(opts);
316
- const { importWsdl } = await Promise.resolve().then(() => require("./import-BhGBiW7j.js"));
316
+ const { importWsdl } = await Promise.resolve().then(() => require("./import-DTcZMRNu.js"));
317
317
  const wsdlText = opts.xml ?? (opts.url ? await fetchUrl(opts.url) : "");
318
318
  if (!wsdlText) throw new Error("wsdl:import requires either `url` or `xml`");
319
319
  return importWsdl(wsdlText, { name: opts.name, existingMockPorts: opts.existingMockPorts });
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  const promises = require("node:fs/promises");
4
4
  const path = require("node:path");
5
- const brokerClient = require("./chunks/broker-client-Df4PpJqB.js");
5
+ const brokerClient = require("./chunks/broker-client-BYpWeOWT.js");
6
6
  const escape = require("./chunks/escape-DDVAlOvZ.js");
7
7
  const crypto = require("node:crypto");
8
8
  const undici = require("undici");
@@ -11,16 +11,19 @@ const cliCommon = require("./chunks/cli-common-GnihVSjU.js");
11
11
  const node_child_process = require("node:child_process");
12
12
  const jsYaml = require("js-yaml");
13
13
  const environments = require("./chunks/environments-iM3SUM-4.js");
14
- require("./chunks/request-exec-B-F0K-pN.js");
14
+ require("./chunks/request-exec-Cv2jkrO1.js");
15
15
  require("fs/promises");
16
16
  require("tls");
17
- require("./chunks/handle-Bz0C56Eq.js");
17
+ require("./chunks/handle-Crv1i9hb.js");
18
18
  require("node:fs");
19
19
  require("dayjs");
20
20
  require("node:vm");
21
21
  require("tv4");
22
22
  require("jsonpath-plus");
23
23
  require("@xmldom/xmldom");
24
+ require("mqtt");
25
+ require("ws");
26
+ require("socket.io-client");
24
27
  require("node:http");
25
28
  require("ajv");
26
29
  require("./chunks/data-files-BYqhsoPe.js");