@testsmith/api-spector 0.2.1 → 0.2.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.
@@ -56237,7 +56237,6 @@ const SNIPPET_GROUPS = [
56237
56237
  {
56238
56238
  label: "Check JSON value",
56239
56239
  code: `sp.test("JSON field equals value", function() {
56240
- const json = sp.response.json();
56241
56240
  sp.expect(json.field).to.equal("expected_value");
56242
56241
  });`
56243
56242
  },
@@ -56252,7 +56251,7 @@ const SNIPPET_GROUPS = [
56252
56251
  },
56253
56252
  required: ["id", "name"]
56254
56253
  };
56255
- sp.expect(tv4.validate(sp.response.json(), schema)).to.be.true;
56254
+ sp.expect(tv4.validate(json, schema)).to.be.true;
56256
56255
  });`
56257
56256
  }
56258
56257
  ]
@@ -56284,7 +56283,6 @@ const SNIPPET_GROUPS = [
56284
56283
  {
56285
56284
  label: "Save token from response (use in next requests)",
56286
56285
  code: `// Use collectionVariables so the value persists across requests
56287
- const json = sp.response.json();
56288
56286
  sp.collectionVariables.set("token", json.access_token);`
56289
56287
  },
56290
56288
  {
@@ -56369,22 +56367,20 @@ sp.collectionVariables.set("token", json.access_token);`
56369
56367
  items: [
56370
56368
  {
56371
56369
  label: "Save JSON field to variable",
56372
- code: `const json = sp.response.json();
56373
- sp.variables.set("field_value", json.field);`
56370
+ code: `sp.variables.set("field_value", json.field);`
56374
56371
  },
56375
56372
  {
56376
56373
  label: "Save JSON field to environment",
56377
- code: `const json = sp.response.json();
56378
- sp.environment.set("token", json.token);`
56374
+ code: `sp.environment.set("token", json.token);`
56379
56375
  },
56380
56376
  {
56381
56377
  label: "Extract via JSONPath to variable",
56382
- code: `const matches = sp.jsonPath(sp.response.json(), '$.data[0].id');
56378
+ code: `const matches = sp.jsonPath(json, '$.data[0].id');
56383
56379
  sp.variables.set("extracted_value", String(matches[0] ?? ''));`
56384
56380
  },
56385
56381
  {
56386
56382
  label: "Extract via JSONPath to environment",
56387
- code: `const matches = sp.jsonPath(sp.response.json(), '$.data[0].id');
56383
+ code: `const matches = sp.jsonPath(json, '$.data[0].id');
56388
56384
  sp.environment.set("extracted_value", String(matches[0] ?? ''));`
56389
56385
  },
56390
56386
  {
@@ -56398,6 +56394,26 @@ sp.environment.set("extracted_value", String(matches[0] ?? ''));`
56398
56394
  ]
56399
56395
  }
56400
56396
  ];
56397
+ const JSON_DECL = "const json = sp.response.json();";
56398
+ const JSON_DECL_RX_G = /[ \t]*const\s+json\s*=\s*sp\.response\.json\(\)\s*;?\s*\n?/g;
56399
+ function snippetUsesJson(snippet2) {
56400
+ const withoutDecl = snippet2.replace(JSON_DECL_RX_G, "");
56401
+ return /\bjson\b/.test(withoutDecl);
56402
+ }
56403
+ function appendSnippetToScript(existing, snippet2) {
56404
+ const cleanedSnippet = snippet2.replace(JSON_DECL_RX_G, "").replace(/^\n+/, "");
56405
+ const sep = existing.trim() ? "\n\n" : "";
56406
+ let combined = existing + sep + cleanedSnippet;
56407
+ const needsJson = snippetUsesJson(existing) || snippetUsesJson(cleanedSnippet);
56408
+ const hasTopDecl = /^\s*const\s+json\s*=\s*sp\.response\.json\(\)/m.test(combined);
56409
+ if (needsJson && !hasTopDecl) {
56410
+ combined = combined.replace(JSON_DECL_RX_G, "");
56411
+ combined = `${JSON_DECL}
56412
+
56413
+ ${combined.replace(/^\n+/, "")}`;
56414
+ }
56415
+ return combined;
56416
+ }
56401
56417
  function ScriptsTab({ request, onChange }) {
56402
56418
  const activeTabId = useStore((s) => s.activeTabId);
56403
56419
  const activeAppTab = useStore((s) => s.tabs.find((t2) => t2.id === s.activeTabId));
@@ -56422,9 +56438,12 @@ function ScriptsTab({ request, onChange }) {
56422
56438
  else onChange({ graphqlIntrospectionScript: code2 });
56423
56439
  }
56424
56440
  function insertSnippet2(code2) {
56425
- const current2 = value;
56426
- const separator = current2.trim() ? "\n\n" : "";
56427
- handleChange(current2 + separator + code2);
56441
+ if (scriptType === "post") {
56442
+ handleChange(appendSnippetToScript(value, code2));
56443
+ } else {
56444
+ const separator = value.trim() ? "\n\n" : "";
56445
+ handleChange(value + separator + code2);
56446
+ }
56428
56447
  }
56429
56448
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 h-full min-h-0", children: [
56430
56449
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-w-0 gap-2", children: [
@@ -63544,28 +63563,23 @@ function makeJsonSnippet(path, value, mode) {
63544
63563
  const acc = jsonAccessor(path);
63545
63564
  const label = jsonPathLabel(path);
63546
63565
  const lit = toLit(value);
63547
- const decl = "const json = sp.response.json();";
63548
63566
  switch (mode) {
63549
63567
  case "equals":
63550
63568
  return `sp.test('${label} equals ${lit}', function() {
63551
- ${decl}
63552
63569
  sp.expect(${acc}).to.equal(${lit});
63553
63570
  });`;
63554
63571
  case "exists":
63555
63572
  return `sp.test('${label} exists', function() {
63556
- ${decl}
63557
63573
  sp.expect(${acc}).to.not.be.oneOf([null, undefined]);
63558
63574
  });`;
63559
63575
  case "type": {
63560
63576
  const t2 = value === null ? "null" : typeof value;
63561
63577
  return `sp.test('${label} is ${t2}', function() {
63562
- ${decl}
63563
63578
  sp.expect(${acc}).to.be.a("${t2}");
63564
63579
  });`;
63565
63580
  }
63566
63581
  case "contains":
63567
63582
  return `sp.test('${label} contains ${lit}', function() {
63568
- ${decl}
63569
63583
  sp.expect(${acc}).to.include(${lit});
63570
63584
  });`;
63571
63585
  }
@@ -63574,7 +63588,7 @@ function makeJsonPathSnippet(path, value, filterKey, filterValue) {
63574
63588
  const expr = toJsonPathExpr(path, filterKey, filterValue);
63575
63589
  const lit = toLit(value);
63576
63590
  return `sp.test('${expr} equals ${lit}', function() {
63577
- const matches = sp.jsonPath(sp.response.json(), '${expr}');
63591
+ const matches = sp.jsonPath(json, '${expr}');
63578
63592
  sp.expect(matches.length).to.be.above(0);
63579
63593
  sp.expect(matches[0]).to.equal(${lit});
63580
63594
  });`;
@@ -63599,13 +63613,12 @@ function makeXmlSnippet(selector, value, mode) {
63599
63613
  function makeJsonExtractSnippet(path, target) {
63600
63614
  const acc = jsonAccessor(path);
63601
63615
  const varName = varNameFromPath(path);
63602
- return `const json = sp.response.json();
63603
- sp.${target}.set("${varName}", String(${acc}));`;
63616
+ return `sp.${target}.set("${varName}", String(${acc}));`;
63604
63617
  }
63605
63618
  function makeJsonPathExtractSnippet(path, filterKey, filterValue, target) {
63606
63619
  const expr = toJsonPathExpr(path, filterKey, filterValue);
63607
63620
  const varName = varNameFromPath(path);
63608
- return `const matches = sp.jsonPath(sp.response.json(), '${expr}');
63621
+ return `const matches = sp.jsonPath(json, '${expr}');
63609
63622
  sp.${target}.set("${varName}", String(matches[0] ?? ''));`;
63610
63623
  }
63611
63624
  function makeXmlExtractSnippet(selector, target) {
@@ -64402,12 +64415,7 @@ function ResponseViewer() {
64402
64415
  const req = Object.values(state.collections).find((c) => c.data.requests[requestId])?.data.requests[requestId];
64403
64416
  if (!req) return;
64404
64417
  const existing = req.postRequestScript ?? "";
64405
- let cleaned = snippet2;
64406
- if (existing.includes("const json = sp.response.json()")) {
64407
- cleaned = cleaned.replace(/^\s*const json = sp\.response\.json\(\);?\s*\n?/m, "").replace(/\n\s*const json = sp\.response\.json\(\);?\s*\n/g, "\n");
64408
- }
64409
- const sep = existing.trim() ? "\n\n" : "";
64410
- updateRequest(requestId, { postRequestScript: existing + sep + cleaned });
64418
+ updateRequest(requestId, { postRequestScript: appendSnippetToScript(existing, snippet2) });
64411
64419
  if (activeTabId) {
64412
64420
  setTabRequestTab(activeTabId, "scripts");
64413
64421
  setTabScriptTab(activeTabId, "post");
@@ -70233,7 +70241,7 @@ function App() {
70233
70241
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
70234
70242
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
70235
70243
  "v",
70236
- "0.2.1"
70244
+ "0.2.2"
70237
70245
  ] }),
70238
70246
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", children: "·" }),
70239
70247
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -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-DPHZdvL5.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-C_vjoxxA.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="./assets/index-DVaubmCJ.css">
10
10
  </head>
11
11
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@testsmith/api-spector",
3
3
  "productName": "API Spector",
4
- "version": "0.2.1",
4
+ "version": "0.2.2",
5
5
  "description": "Local-first API testing tool to inspect, test and mock APIs",
6
6
  "repository": {
7
7
  "type": "git",