@skyramp/testbot-core 0.13.0-v3.181 → 0.13.0-v3.183

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.
@@ -11,11 +11,17 @@
11
11
  * statusCode: 201, language: "python", framework: "pytest", outputDir: "tests/api", output: "test_products.py" });
12
12
  * // several requests: a trace built from the steps, then an integration test from it
13
13
  * const trace = await api.trace([
14
- * { method: "POST", path: "/api/v1/products", request: { name: "Lamp" }, status: 201, response: { id: 7, name: "Lamp" } },
14
+ * { method: "POST", path: "/api/v1/products", request: { name: "Lamp" }, unique: ["name"], status: 201, response: { id: 7, name: "Lamp" } },
15
15
  * { method: "GET", path: "/api/v1/products/{{1.id}}", status: 200, response: { id: 7, name: "Lamp" } },
16
16
  * ], { baseUrl: "http://localhost:8000", authHeader: "Authorization", authScheme: "Bearer" });
17
17
  * await api.generate({ kind: "integration", trace, language: "python", framework: "pytest", outputDir: "tests/api", output: "test_product_flow.py" });
18
18
  *
19
+ * A generated test's data is its own across runs. `unique` (a step's, or a contract test's) names the request-body
20
+ * fields the API keeps unique (a name, slug, SKU or email): the test sends a run-unique value for each, so a rerun or
21
+ * a parallel run does not collide (409) with what an earlier one left. An integration test deletes what it created
22
+ * when it ends, failed or not. A contract test of a create does too when given `cleanupPath`, the item route of what
23
+ * it creates ("/api/v1/products/{product_id}"), with the id in `responseData`.
24
+ *
19
25
  * `{{N.field}}` in a step's path, query or request is the value of `field` (dotted) in step N's response (1-based). The
20
26
  * trace then carries the real value, and the generator chains it: the test reads it from that step's response.
21
27
  * `schema` (a spec path or URL) may stand in for requestData/responseData in a contract or fuzz test.
@@ -80,6 +86,8 @@ function resolveRefs(value, responses) {
80
86
  }
81
87
 
82
88
  const asJson = (v) => (v === undefined ? undefined : typeof v === "string" ? v : JSON.stringify(v));
89
+ // The MCP's path and query params are "key=value,key2=value2"; an object ({ product_id: 1 }) is written that way.
90
+ const asParams = (v) => (v && typeof v === "object" ? Object.entries(v).map(([k, x]) => `${k}=${x}`).join(",") : String(v));
83
91
  const parsed = (v) => {
84
92
  if (typeof v !== "string") return v;
85
93
  try { return JSON.parse(v); } catch { return v; }
@@ -111,6 +119,7 @@ function traceEntries(steps, opts, toEntry) {
111
119
  queryParams: asJson(query),
112
120
  responseBody: asJson(s.response),
113
121
  statusCode: s.status === undefined ? undefined : Number(s.status),
122
+ ...(Array.isArray(s.unique) && s.unique.length ? { uniqueFields: s.unique.map(String) } : {}),
114
123
  authHeader: opts.authHeader,
115
124
  authScheme: opts.authScheme,
116
125
  });
@@ -210,8 +219,13 @@ async function generate(opts) {
210
219
  ...(opts.authHeader !== undefined ? { authHeader: opts.authHeader } : {}),
211
220
  ...(opts.authScheme !== undefined ? { authScheme: opts.authScheme } : {}),
212
221
  ...(opts.chainingKey ? { chainingKey: opts.chainingKey } : {}),
213
- ...(opts.pathParams ? { pathParams: opts.pathParams } : {}),
214
- ...(opts.queryParams ? { queryParams: opts.queryParams } : {}),
222
+ ...(opts.pathParams ? { pathParams: asParams(opts.pathParams) } : {}),
223
+ ...(opts.queryParams ? { queryParams: asParams(opts.queryParams) } : {}),
224
+ // The test's data stays its own: an integration test cleans up what it created; a contract test sends unique
225
+ // values for the fields it names and deletes its create through cleanupPath.
226
+ ...(opts.kind === "integration" ? { emitIntegrationTeardown: true } : {}),
227
+ ...(opts.kind === "contract" && Array.isArray(opts.unique) && opts.unique.length ? { uniqueFields: opts.unique.map(String) } : {}),
228
+ ...(opts.kind === "contract" && opts.cleanupPath ? { cleanupPath: String(opts.cleanupPath) } : {}),
215
229
  language: opts.language,
216
230
  ...(opts.framework ? { framework: opts.framework } : {}),
217
231
  outputDir,
package/dist/VERSION.json CHANGED
@@ -1 +1 @@
1
- {"version":"0.13.0-v3.181","commit":"301a6fa10fd353e0dd1a5c52f8f0d3bac25d952e"}
1
+ {"version":"0.13.0-v3.183","commit":"cb6e5e20b9bca9342b8c9cd4e5e4e54efb1a91c6"}