neuron-inspector 0.5.6 → 0.6.0
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/dist/collections/__tests__/assertions.test.d.ts +1 -0
- package/dist/collections/__tests__/assertions.test.js +203 -0
- package/dist/collections/__tests__/assertions.test.js.map +1 -0
- package/dist/collections/__tests__/dynamic-vars.test.d.ts +1 -0
- package/dist/collections/__tests__/dynamic-vars.test.js +169 -0
- package/dist/collections/__tests__/dynamic-vars.test.js.map +1 -0
- package/dist/collections/__tests__/execution.test.d.ts +1 -0
- package/dist/collections/__tests__/execution.test.js +271 -0
- package/dist/collections/__tests__/execution.test.js.map +1 -0
- package/dist/collections/__tests__/integration.test.d.ts +1 -0
- package/dist/collections/__tests__/integration.test.js +478 -0
- package/dist/collections/__tests__/integration.test.js.map +1 -0
- package/dist/collections/__tests__/resolver.test.d.ts +1 -0
- package/dist/collections/__tests__/resolver.test.js +282 -0
- package/dist/collections/__tests__/resolver.test.js.map +1 -0
- package/dist/collections/__tests__/scenario.test.d.ts +1 -0
- package/dist/collections/__tests__/scenario.test.js +367 -0
- package/dist/collections/__tests__/scenario.test.js.map +1 -0
- package/dist/collections/__tests__/scripts.test.d.ts +1 -0
- package/dist/collections/__tests__/scripts.test.js +245 -0
- package/dist/collections/__tests__/scripts.test.js.map +1 -0
- package/dist/collections/__tests__/store.test.d.ts +1 -0
- package/dist/collections/__tests__/store.test.js +313 -0
- package/dist/collections/__tests__/store.test.js.map +1 -0
- package/dist/collections/assertions.d.ts +16 -0
- package/dist/collections/assertions.js +107 -0
- package/dist/collections/assertions.js.map +1 -0
- package/dist/collections/dynamic-vars.d.ts +75 -0
- package/dist/collections/dynamic-vars.js +187 -0
- package/dist/collections/dynamic-vars.js.map +1 -0
- package/dist/collections/executor.d.ts +94 -0
- package/dist/collections/executor.js +251 -0
- package/dist/collections/executor.js.map +1 -0
- package/dist/collections/http.d.ts +4 -0
- package/dist/collections/http.js +84 -0
- package/dist/collections/http.js.map +1 -0
- package/dist/collections/index.d.ts +12 -0
- package/dist/collections/index.js +27 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/postman.d.ts +10 -0
- package/dist/collections/postman.js +288 -0
- package/dist/collections/postman.js.map +1 -0
- package/dist/collections/resolver.d.ts +74 -0
- package/dist/collections/resolver.js +253 -0
- package/dist/collections/resolver.js.map +1 -0
- package/dist/collections/scripts.d.ts +9 -0
- package/dist/collections/scripts.js +55 -0
- package/dist/collections/scripts.js.map +1 -0
- package/dist/collections/store.d.ts +40 -0
- package/dist/collections/store.js +356 -0
- package/dist/collections/store.js.map +1 -0
- package/dist/collections/tools.d.ts +8 -0
- package/dist/collections/tools.js +838 -0
- package/dist/collections/tools.js.map +1 -0
- package/dist/collections/types.d.ts +177 -0
- package/dist/collections/types.js +3 -0
- package/dist/collections/types.js.map +1 -0
- package/dist/server.js +3 -0
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { resolveTemplate, resolveDeep, findUnresolved, checkUnresolved, buildDefaultPipeline, buildResolvedRequest, ProcessEnvResolver, EnvironmentResolver, CollectionDefaultsResolver, FolderResolver, RequestResolver, ExtractedResolver, ScriptVarResolver, } from "../resolver.js";
|
|
3
|
+
// ── resolveTemplate ─────────────────────────────────────────────
|
|
4
|
+
describe("resolveTemplate", () => {
|
|
5
|
+
const simpleStep = {
|
|
6
|
+
name: "test",
|
|
7
|
+
resolve: (key) => (key === "name" ? "Rasheed" : key === "city" ? "Lagos" : undefined),
|
|
8
|
+
};
|
|
9
|
+
it("replaces known variables", () => {
|
|
10
|
+
expect(resolveTemplate("Hello {{name}} from {{city}}", [simpleStep], {})).toBe("Hello Rasheed from Lagos");
|
|
11
|
+
});
|
|
12
|
+
it("leaves unknown variables unresolved", () => {
|
|
13
|
+
expect(resolveTemplate("Hello {{unknown}}", [simpleStep], {})).toBe("Hello {{unknown}}");
|
|
14
|
+
});
|
|
15
|
+
it("trims whitespace in variable names", () => {
|
|
16
|
+
expect(resolveTemplate("{{ name }}", [simpleStep], {})).toBe("Rasheed");
|
|
17
|
+
});
|
|
18
|
+
it("handles no variables", () => {
|
|
19
|
+
expect(resolveTemplate("plain text", [simpleStep], {})).toBe("plain text");
|
|
20
|
+
});
|
|
21
|
+
it("handles multiple occurrences of the same variable", () => {
|
|
22
|
+
expect(resolveTemplate("{{name}} and {{name}}", [simpleStep], {})).toBe("Rasheed and Rasheed");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
// ── resolveDeep ─────────────────────────────────────────────────
|
|
26
|
+
describe("resolveDeep", () => {
|
|
27
|
+
const step = {
|
|
28
|
+
name: "test",
|
|
29
|
+
resolve: (key) => (key === "token" ? "abc123" : undefined),
|
|
30
|
+
};
|
|
31
|
+
it("resolves strings in nested objects", () => {
|
|
32
|
+
const result = resolveDeep({ headers: { auth: "Bearer {{token}}" }, nested: { deep: "{{token}}" } }, [step], {});
|
|
33
|
+
expect(result).toEqual({
|
|
34
|
+
headers: { auth: "Bearer abc123" },
|
|
35
|
+
nested: { deep: "abc123" },
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
it("resolves strings in arrays", () => {
|
|
39
|
+
const result = resolveDeep(["{{token}}", "literal"], [step], {});
|
|
40
|
+
expect(result).toEqual(["abc123", "literal"]);
|
|
41
|
+
});
|
|
42
|
+
it("passes through numbers and booleans", () => {
|
|
43
|
+
const result = resolveDeep({ count: 5, flag: true }, [step], {});
|
|
44
|
+
expect(result).toEqual({ count: 5, flag: true });
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
// ── findUnresolved & checkUnresolved ────────────────────────────
|
|
48
|
+
describe("findUnresolved", () => {
|
|
49
|
+
it("finds unresolved variables", () => {
|
|
50
|
+
expect(findUnresolved("{{a}} and {{b}}")).toEqual(["a", "b"]);
|
|
51
|
+
});
|
|
52
|
+
it("returns empty for fully resolved text", () => {
|
|
53
|
+
expect(findUnresolved("no variables here")).toEqual([]);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe("checkUnresolved", () => {
|
|
57
|
+
it("scans url, headers, and body", () => {
|
|
58
|
+
const result = checkUnresolved({
|
|
59
|
+
url: "https://api.example.com/{{version}}/bots",
|
|
60
|
+
headers: { Authorization: "Bearer {{token}}" },
|
|
61
|
+
body: '{"name": "{{bot_name}}"}',
|
|
62
|
+
});
|
|
63
|
+
expect(result).toContain("version");
|
|
64
|
+
expect(result).toContain("token");
|
|
65
|
+
expect(result).toContain("bot_name");
|
|
66
|
+
});
|
|
67
|
+
it("returns empty when everything is resolved", () => {
|
|
68
|
+
const result = checkUnresolved({
|
|
69
|
+
url: "https://api.example.com/v1/bots",
|
|
70
|
+
headers: { Authorization: "Bearer abc" },
|
|
71
|
+
});
|
|
72
|
+
expect(result).toEqual([]);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
// ── Individual resolver steps ───────────────────────────────────
|
|
76
|
+
describe("ProcessEnvResolver", () => {
|
|
77
|
+
it("resolves from process.env", () => {
|
|
78
|
+
process.env.TEST_RESOLVER_VAR = "hello";
|
|
79
|
+
const resolver = new ProcessEnvResolver();
|
|
80
|
+
expect(resolver.resolve("TEST_RESOLVER_VAR", {})).toBe("hello");
|
|
81
|
+
delete process.env.TEST_RESOLVER_VAR;
|
|
82
|
+
});
|
|
83
|
+
it("returns undefined for missing vars", () => {
|
|
84
|
+
const resolver = new ProcessEnvResolver();
|
|
85
|
+
expect(resolver.resolve("NONEXISTENT_VAR_12345", {})).toBeUndefined();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe("EnvironmentResolver", () => {
|
|
89
|
+
it("resolves from environment variables", () => {
|
|
90
|
+
const resolver = new EnvironmentResolver();
|
|
91
|
+
const ctx = {
|
|
92
|
+
environment: { base_url: "https://api.example.com", variables: { token: "env-token" } },
|
|
93
|
+
};
|
|
94
|
+
expect(resolver.resolve("token", ctx)).toBe("env-token");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe("CollectionDefaultsResolver", () => {
|
|
98
|
+
it("resolves from collection defaults", () => {
|
|
99
|
+
const resolver = new CollectionDefaultsResolver();
|
|
100
|
+
const ctx = {
|
|
101
|
+
collection: { name: "Test", defaults: { variables: { api_version: "v2" } } },
|
|
102
|
+
};
|
|
103
|
+
expect(resolver.resolve("api_version", ctx)).toBe("v2");
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("FolderResolver", () => {
|
|
107
|
+
it("resolves from folder variables", () => {
|
|
108
|
+
const resolver = new FolderResolver();
|
|
109
|
+
const ctx = {
|
|
110
|
+
folder: { endpoints: [], variables: { folder_var: "yes" } },
|
|
111
|
+
};
|
|
112
|
+
expect(resolver.resolve("folder_var", ctx)).toBe("yes");
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe("RequestResolver", () => {
|
|
116
|
+
it("resolves from endpoint variables", () => {
|
|
117
|
+
const resolver = new RequestResolver();
|
|
118
|
+
const ctx = {
|
|
119
|
+
endpoint: { name: "Test", method: "GET", path: "/", variables: { req_var: "req" } },
|
|
120
|
+
};
|
|
121
|
+
expect(resolver.resolve("req_var", ctx)).toBe("req");
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe("ExtractedResolver", () => {
|
|
125
|
+
it("resolves from extracted variables", () => {
|
|
126
|
+
const resolver = new ExtractedResolver();
|
|
127
|
+
const ctx = { extracted: { bot_id: "uuid-123" } };
|
|
128
|
+
expect(resolver.resolve("bot_id", ctx)).toBe("uuid-123");
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe("ScriptVarResolver", () => {
|
|
132
|
+
it("resolves from script-set variables", () => {
|
|
133
|
+
const resolver = new ScriptVarResolver();
|
|
134
|
+
const ctx = { scriptVars: { computed: "value" } };
|
|
135
|
+
expect(resolver.resolve("computed", ctx)).toBe("value");
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
// ── Pipeline precedence ─────────────────────────────────────────
|
|
139
|
+
describe("resolver pipeline precedence", () => {
|
|
140
|
+
it("later steps override earlier steps", () => {
|
|
141
|
+
const steps = [
|
|
142
|
+
{ name: "low", resolve: (k) => (k === "x" ? "low" : undefined) },
|
|
143
|
+
{ name: "high", resolve: (k) => (k === "x" ? "high" : undefined) },
|
|
144
|
+
];
|
|
145
|
+
// Pipeline is checked in order, first match wins
|
|
146
|
+
// So "low" wins because it's checked first
|
|
147
|
+
expect(resolveTemplate("{{x}}", steps, {})).toBe("low");
|
|
148
|
+
});
|
|
149
|
+
it("falls through to next step when current returns undefined", () => {
|
|
150
|
+
const steps = [
|
|
151
|
+
{ name: "specific", resolve: (k) => (k === "a" ? "from-specific" : undefined) },
|
|
152
|
+
{ name: "fallback", resolve: (k) => (k === "b" ? "from-fallback" : undefined) },
|
|
153
|
+
];
|
|
154
|
+
expect(resolveTemplate("{{a}} {{b}}", steps, {})).toBe("from-specific from-fallback");
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
// ── buildResolvedRequest ────────────────────────────────────────
|
|
158
|
+
describe("buildResolvedRequest", () => {
|
|
159
|
+
const collection = {
|
|
160
|
+
name: "Test API",
|
|
161
|
+
defaults: {
|
|
162
|
+
headers: { "Content-Type": "application/json" },
|
|
163
|
+
timeout_ms: 15000,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
const environment = {
|
|
167
|
+
base_url: "https://api.example.com/v1",
|
|
168
|
+
variables: { auth_token: "env-token-123" },
|
|
169
|
+
headers: { "X-Env": "staging" },
|
|
170
|
+
};
|
|
171
|
+
const folder = {
|
|
172
|
+
endpoints: [],
|
|
173
|
+
headers: { "X-Folder": "bots" },
|
|
174
|
+
};
|
|
175
|
+
it("merges headers from all levels", () => {
|
|
176
|
+
const endpoint = {
|
|
177
|
+
name: "List",
|
|
178
|
+
method: "GET",
|
|
179
|
+
path: "/bots",
|
|
180
|
+
headers: { "X-Custom": "yes" },
|
|
181
|
+
};
|
|
182
|
+
const pipeline = buildDefaultPipeline();
|
|
183
|
+
const req = buildResolvedRequest({ collection, environment, folder, endpoint, pipeline });
|
|
184
|
+
expect(req.headers["Content-Type"]).toBe("application/json");
|
|
185
|
+
expect(req.headers["X-Env"]).toBe("staging");
|
|
186
|
+
expect(req.headers["X-Folder"]).toBe("bots");
|
|
187
|
+
expect(req.headers["X-Custom"]).toBe("yes");
|
|
188
|
+
});
|
|
189
|
+
it("builds URL from base_url + path", () => {
|
|
190
|
+
const endpoint = { name: "List", method: "GET", path: "/bots" };
|
|
191
|
+
const pipeline = buildDefaultPipeline();
|
|
192
|
+
const req = buildResolvedRequest({ collection, environment, folder, endpoint, pipeline });
|
|
193
|
+
expect(req.url).toBe("https://api.example.com/v1/bots");
|
|
194
|
+
});
|
|
195
|
+
it("resolves variables in path", () => {
|
|
196
|
+
const endpoint = {
|
|
197
|
+
name: "Get",
|
|
198
|
+
method: "GET",
|
|
199
|
+
path: "/bots/{{bot_id}}",
|
|
200
|
+
};
|
|
201
|
+
const pipeline = buildDefaultPipeline();
|
|
202
|
+
const req = buildResolvedRequest({
|
|
203
|
+
collection,
|
|
204
|
+
environment,
|
|
205
|
+
folder,
|
|
206
|
+
endpoint,
|
|
207
|
+
pipeline,
|
|
208
|
+
extracted: { bot_id: "uuid-456" },
|
|
209
|
+
});
|
|
210
|
+
expect(req.url).toBe("https://api.example.com/v1/bots/uuid-456");
|
|
211
|
+
});
|
|
212
|
+
it("resolves variables in body", () => {
|
|
213
|
+
const endpoint = {
|
|
214
|
+
name: "Create",
|
|
215
|
+
method: "POST",
|
|
216
|
+
path: "/bots",
|
|
217
|
+
body: { name: "Bot", token: "{{auth_token}}" },
|
|
218
|
+
};
|
|
219
|
+
const pipeline = buildDefaultPipeline();
|
|
220
|
+
const req = buildResolvedRequest({ collection, environment, folder, endpoint, pipeline });
|
|
221
|
+
const body = JSON.parse(req.body);
|
|
222
|
+
expect(body.token).toBe("env-token-123");
|
|
223
|
+
});
|
|
224
|
+
it("uses endpoint timeout > environment timeout > collection timeout", () => {
|
|
225
|
+
const endpoint = { name: "Fast", method: "GET", path: "/fast", timeout_ms: 5000 };
|
|
226
|
+
const pipeline = buildDefaultPipeline();
|
|
227
|
+
const req = buildResolvedRequest({ collection, environment, folder, endpoint, pipeline });
|
|
228
|
+
expect(req.timeout_ms).toBe(5000);
|
|
229
|
+
});
|
|
230
|
+
it("falls back to collection default timeout", () => {
|
|
231
|
+
const endpoint = { name: "Default", method: "GET", path: "/default" };
|
|
232
|
+
const pipeline = buildDefaultPipeline();
|
|
233
|
+
const req = buildResolvedRequest({ collection, environment, folder, endpoint, pipeline });
|
|
234
|
+
expect(req.timeout_ms).toBe(15000);
|
|
235
|
+
});
|
|
236
|
+
it("injects bearer auth header", () => {
|
|
237
|
+
const collWithAuth = {
|
|
238
|
+
name: "Auth API",
|
|
239
|
+
defaults: { auth: { type: "bearer", token: "{{auth_token}}" } },
|
|
240
|
+
};
|
|
241
|
+
const endpoint = { name: "Protected", method: "GET", path: "/me" };
|
|
242
|
+
const pipeline = buildDefaultPipeline();
|
|
243
|
+
const req = buildResolvedRequest({
|
|
244
|
+
collection: collWithAuth,
|
|
245
|
+
environment,
|
|
246
|
+
folder,
|
|
247
|
+
endpoint,
|
|
248
|
+
pipeline,
|
|
249
|
+
});
|
|
250
|
+
expect(req.headers["Authorization"]).toBe("Bearer env-token-123");
|
|
251
|
+
});
|
|
252
|
+
it("injects basic auth header", () => {
|
|
253
|
+
const collWithAuth = {
|
|
254
|
+
name: "Basic API",
|
|
255
|
+
defaults: { auth: { type: "basic", username: "user", password: "pass" } },
|
|
256
|
+
};
|
|
257
|
+
const endpoint = { name: "Protected", method: "GET", path: "/me" };
|
|
258
|
+
const pipeline = buildDefaultPipeline();
|
|
259
|
+
const req = buildResolvedRequest({
|
|
260
|
+
collection: collWithAuth,
|
|
261
|
+
environment,
|
|
262
|
+
folder,
|
|
263
|
+
endpoint,
|
|
264
|
+
pipeline,
|
|
265
|
+
});
|
|
266
|
+
expect(req.headers["Authorization"]).toBe(`Basic ${Buffer.from("user:pass").toString("base64")}`);
|
|
267
|
+
});
|
|
268
|
+
it("serializes non-string body as JSON", () => {
|
|
269
|
+
const endpoint = {
|
|
270
|
+
name: "Create",
|
|
271
|
+
method: "POST",
|
|
272
|
+
path: "/bots",
|
|
273
|
+
body: { name: "Bot", count: 5 },
|
|
274
|
+
};
|
|
275
|
+
const pipeline = buildDefaultPipeline();
|
|
276
|
+
const req = buildResolvedRequest({ collection, environment, folder, endpoint, pipeline });
|
|
277
|
+
const parsed = JSON.parse(req.body);
|
|
278
|
+
expect(parsed.name).toBe("Bot");
|
|
279
|
+
expect(parsed.count).toBe(5);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
//# sourceMappingURL=resolver.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.test.js","sourceRoot":"","sources":["../../../src/collections/__tests__/resolver.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { YamlCollectionStore } from "../store.js";
|
|
6
|
+
import { OperatorRegistry } from "../assertions.js";
|
|
7
|
+
import { buildCollectionHandler } from "../tools.js";
|
|
8
|
+
import { buildDefaultPipeline } from "../resolver.js";
|
|
9
|
+
// ── Mock HTTP executor with route-based responses ───────────────
|
|
10
|
+
class RoutedMockHttp {
|
|
11
|
+
calls = [];
|
|
12
|
+
routes = {};
|
|
13
|
+
defaultResponse = {
|
|
14
|
+
status: 200,
|
|
15
|
+
statusText: "OK",
|
|
16
|
+
headers: { "content-type": "application/json" },
|
|
17
|
+
body: "{}",
|
|
18
|
+
timing: { total_ms: 30, ttfb_ms: 10 },
|
|
19
|
+
};
|
|
20
|
+
addRoute(method, pathSuffix, response) {
|
|
21
|
+
const key = `${method.toUpperCase()} ${pathSuffix}`;
|
|
22
|
+
this.routes[key] = { ...this.defaultResponse, ...response };
|
|
23
|
+
}
|
|
24
|
+
async execute(request) {
|
|
25
|
+
this.calls.push(request);
|
|
26
|
+
// Match by method + path suffix
|
|
27
|
+
for (const [pattern, response] of Object.entries(this.routes)) {
|
|
28
|
+
const [method, path] = pattern.split(" ", 2);
|
|
29
|
+
if (request.method === method && request.url.endsWith(path)) {
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return this.defaultResponse;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
let globalDir;
|
|
37
|
+
let projectDir;
|
|
38
|
+
let store;
|
|
39
|
+
let mockHttp;
|
|
40
|
+
let handler;
|
|
41
|
+
const testCollection = {
|
|
42
|
+
name: "Test API",
|
|
43
|
+
environments: {
|
|
44
|
+
test: {
|
|
45
|
+
base_url: "https://api.test.com/v1",
|
|
46
|
+
variables: { auth_token: "test-token" },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
active_environment: "test",
|
|
50
|
+
defaults: {
|
|
51
|
+
headers: { "Content-Type": "application/json" },
|
|
52
|
+
auth: { type: "bearer", token: "{{auth_token}}" },
|
|
53
|
+
},
|
|
54
|
+
folders: {
|
|
55
|
+
auth: {
|
|
56
|
+
endpoints: [
|
|
57
|
+
{
|
|
58
|
+
name: "Login",
|
|
59
|
+
method: "POST",
|
|
60
|
+
path: "/auth/login",
|
|
61
|
+
body: { email: "test@test.com", password: "pass" },
|
|
62
|
+
tests: [
|
|
63
|
+
{ check: "status", expect: 200 },
|
|
64
|
+
{ check: "body.token", op: "exists" },
|
|
65
|
+
],
|
|
66
|
+
extract: { auth_token: "body.token" },
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
bots: {
|
|
71
|
+
endpoints: [
|
|
72
|
+
{
|
|
73
|
+
name: "List Bots",
|
|
74
|
+
method: "GET",
|
|
75
|
+
path: "/bots",
|
|
76
|
+
tests: [
|
|
77
|
+
{ check: "status", expect: 200 },
|
|
78
|
+
{ check: "body", op: "isArray" },
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "Create Bot",
|
|
83
|
+
method: "POST",
|
|
84
|
+
path: "/bots",
|
|
85
|
+
body: { name: "Test Bot" },
|
|
86
|
+
tests: [
|
|
87
|
+
{ check: "status", expect: 201 },
|
|
88
|
+
{ check: "body.id", op: "exists" },
|
|
89
|
+
],
|
|
90
|
+
extract: { bot_id: "body.id" },
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "Get Bot",
|
|
94
|
+
method: "GET",
|
|
95
|
+
path: "/bots/{{bot_id}}",
|
|
96
|
+
tests: [
|
|
97
|
+
{ check: "status", expect: 200 },
|
|
98
|
+
{ check: "body.name", expect: "Test Bot" },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "Delete Bot",
|
|
103
|
+
method: "DELETE",
|
|
104
|
+
path: "/bots/{{bot_id}}",
|
|
105
|
+
tests: [{ check: "status", expect: 200 }],
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
scenarios: {
|
|
111
|
+
"bot-lifecycle": {
|
|
112
|
+
description: "Create, inspect, and clean up a bot",
|
|
113
|
+
steps: [
|
|
114
|
+
{ ref: "auth/Login" },
|
|
115
|
+
{ ref: "bots/Create Bot" },
|
|
116
|
+
{ ref: "bots/Get Bot" },
|
|
117
|
+
{ ref: "bots/Delete Bot" },
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
"auth-failure": {
|
|
121
|
+
description: "Verify 401 on expired token",
|
|
122
|
+
steps: [
|
|
123
|
+
{
|
|
124
|
+
ref: "bots/List Bots",
|
|
125
|
+
overrides: {
|
|
126
|
+
headers: { Authorization: "Bearer expired" },
|
|
127
|
+
tests: [{ check: "status", expect: 401 }],
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
"bad-ref": {
|
|
133
|
+
description: "Scenario with invalid ref",
|
|
134
|
+
steps: [{ ref: "nonexistent/Fake" }],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
beforeEach(async () => {
|
|
139
|
+
globalDir = await mkdtemp(join(tmpdir(), "neuron-scenario-global-"));
|
|
140
|
+
projectDir = await mkdtemp(join(tmpdir(), "neuron-scenario-project-"));
|
|
141
|
+
store = new YamlCollectionStore(globalDir, projectDir);
|
|
142
|
+
mockHttp = new RoutedMockHttp();
|
|
143
|
+
const pipeline = buildDefaultPipeline();
|
|
144
|
+
const evaluator = new OperatorRegistry();
|
|
145
|
+
handler = buildCollectionHandler(store, mockHttp, pipeline, evaluator);
|
|
146
|
+
// Set up routes
|
|
147
|
+
mockHttp.addRoute("POST", "/auth/login", {
|
|
148
|
+
status: 200,
|
|
149
|
+
body: JSON.stringify({ token: "fresh-token-abc" }),
|
|
150
|
+
});
|
|
151
|
+
mockHttp.addRoute("GET", "/bots", {
|
|
152
|
+
status: 200,
|
|
153
|
+
body: JSON.stringify([{ id: "bot-1" }, { id: "bot-2" }]),
|
|
154
|
+
});
|
|
155
|
+
mockHttp.addRoute("POST", "/bots", {
|
|
156
|
+
status: 201,
|
|
157
|
+
body: JSON.stringify({ id: "bot-new-123", name: "Test Bot" }),
|
|
158
|
+
});
|
|
159
|
+
mockHttp.addRoute("DELETE", "/bots/bot-new-123", {
|
|
160
|
+
status: 200,
|
|
161
|
+
body: JSON.stringify({ deleted: true }),
|
|
162
|
+
});
|
|
163
|
+
await store.save("api", testCollection);
|
|
164
|
+
});
|
|
165
|
+
afterEach(async () => {
|
|
166
|
+
await rm(globalDir, { recursive: true, force: true });
|
|
167
|
+
await rm(projectDir, { recursive: true, force: true });
|
|
168
|
+
});
|
|
169
|
+
// ── Single endpoint with assertions ─────────────────────────────
|
|
170
|
+
describe("neuron_api_run single endpoint with assertions", () => {
|
|
171
|
+
it("returns assertion results", async () => {
|
|
172
|
+
const result = (await handler("neuron_api_run", {
|
|
173
|
+
collection: "api",
|
|
174
|
+
folder: "bots",
|
|
175
|
+
method: "GET",
|
|
176
|
+
path: "/bots",
|
|
177
|
+
}));
|
|
178
|
+
expect(result.assertions).toHaveLength(2);
|
|
179
|
+
expect(result.assertions[0]).toEqual({
|
|
180
|
+
passed: true,
|
|
181
|
+
check: "status",
|
|
182
|
+
op: "equals",
|
|
183
|
+
expected: 200,
|
|
184
|
+
actual: 200,
|
|
185
|
+
});
|
|
186
|
+
expect(result.assertions[1].passed).toBe(true);
|
|
187
|
+
expect(result.assertions[1].op).toBe("isArray");
|
|
188
|
+
});
|
|
189
|
+
it("reports failed assertions", async () => {
|
|
190
|
+
// List Bots expects 200, but we override the route
|
|
191
|
+
mockHttp.addRoute("GET", "/bots", { status: 500, body: '{"error":"server error"}' });
|
|
192
|
+
const result = (await handler("neuron_api_run", {
|
|
193
|
+
collection: "api",
|
|
194
|
+
folder: "bots",
|
|
195
|
+
method: "GET",
|
|
196
|
+
path: "/bots",
|
|
197
|
+
}));
|
|
198
|
+
expect(result.assertions[0].passed).toBe(false);
|
|
199
|
+
expect(result.assertions[0].actual).toBe(500);
|
|
200
|
+
expect(result.assertions[0].expected).toBe(200);
|
|
201
|
+
});
|
|
202
|
+
it("extracts variables from response", async () => {
|
|
203
|
+
const result = (await handler("neuron_api_run", {
|
|
204
|
+
collection: "api",
|
|
205
|
+
folder: "bots",
|
|
206
|
+
method: "POST",
|
|
207
|
+
path: "/bots",
|
|
208
|
+
}));
|
|
209
|
+
expect(result.extracted).toEqual({ bot_id: "bot-new-123" });
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
// ── Folder execution ────────────────────────────────────────────
|
|
213
|
+
describe("neuron_api_run folder mode", () => {
|
|
214
|
+
it("runs all endpoints in a folder sequentially", async () => {
|
|
215
|
+
// Add a route for Get Bot that matches any bot ID
|
|
216
|
+
mockHttp.addRoute("GET", "/bots/bot-new-123", {
|
|
217
|
+
status: 200,
|
|
218
|
+
body: JSON.stringify({ id: "bot-new-123", name: "Test Bot" }),
|
|
219
|
+
});
|
|
220
|
+
const result = (await handler("neuron_api_run", {
|
|
221
|
+
collection: "api",
|
|
222
|
+
folder: "bots",
|
|
223
|
+
}));
|
|
224
|
+
expect(result.folder).toBe("bots");
|
|
225
|
+
expect(result.results).toHaveLength(4);
|
|
226
|
+
expect(result.results[0].endpoint.name).toBe("List Bots");
|
|
227
|
+
expect(result.results[1].endpoint.name).toBe("Create Bot");
|
|
228
|
+
expect(result.results[2].endpoint.name).toBe("Get Bot");
|
|
229
|
+
expect(result.results[3].endpoint.name).toBe("Delete Bot");
|
|
230
|
+
});
|
|
231
|
+
it("carries extracted variables between endpoints", async () => {
|
|
232
|
+
mockHttp.addRoute("GET", "/bots/bot-new-123", {
|
|
233
|
+
status: 200,
|
|
234
|
+
body: JSON.stringify({ id: "bot-new-123", name: "Test Bot" }),
|
|
235
|
+
});
|
|
236
|
+
const result = (await handler("neuron_api_run", {
|
|
237
|
+
collection: "api",
|
|
238
|
+
folder: "bots",
|
|
239
|
+
}));
|
|
240
|
+
// Create Bot extracts bot_id, Get Bot uses {{bot_id}} in path
|
|
241
|
+
// Check that the Get Bot request used the extracted ID
|
|
242
|
+
const getBotCall = mockHttp.calls.find((c) => c.method === "GET" && c.url.includes("/bots/bot-new-123"));
|
|
243
|
+
expect(getBotCall).toBeDefined();
|
|
244
|
+
});
|
|
245
|
+
it("continues on failure (does not halt)", async () => {
|
|
246
|
+
// Make List Bots fail
|
|
247
|
+
mockHttp.addRoute("GET", "/bots", { status: 500, body: '{"error":"fail"}' });
|
|
248
|
+
mockHttp.addRoute("GET", "/bots/bot-new-123", {
|
|
249
|
+
status: 200,
|
|
250
|
+
body: JSON.stringify({ id: "bot-new-123", name: "Test Bot" }),
|
|
251
|
+
});
|
|
252
|
+
const result = (await handler("neuron_api_run", {
|
|
253
|
+
collection: "api",
|
|
254
|
+
folder: "bots",
|
|
255
|
+
}));
|
|
256
|
+
// All 4 endpoints should still have been attempted
|
|
257
|
+
expect(result.results).toHaveLength(4);
|
|
258
|
+
expect(result.failed).toBeGreaterThan(0);
|
|
259
|
+
});
|
|
260
|
+
it("reports pass/fail/error counts", async () => {
|
|
261
|
+
mockHttp.addRoute("GET", "/bots/bot-new-123", {
|
|
262
|
+
status: 200,
|
|
263
|
+
body: JSON.stringify({ id: "bot-new-123", name: "Test Bot" }),
|
|
264
|
+
});
|
|
265
|
+
const result = (await handler("neuron_api_run", {
|
|
266
|
+
collection: "api",
|
|
267
|
+
folder: "bots",
|
|
268
|
+
}));
|
|
269
|
+
expect(typeof result.passed).toBe("number");
|
|
270
|
+
expect(typeof result.failed).toBe("number");
|
|
271
|
+
expect(typeof result.errors).toBe("number");
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
// ── Collection-wide execution ───────────────────────────────────
|
|
275
|
+
describe("neuron_api_run collection mode", () => {
|
|
276
|
+
it("runs all folders in the collection", async () => {
|
|
277
|
+
mockHttp.addRoute("GET", "/bots/bot-new-123", {
|
|
278
|
+
status: 200,
|
|
279
|
+
body: JSON.stringify({ id: "bot-new-123", name: "Test Bot" }),
|
|
280
|
+
});
|
|
281
|
+
const result = (await handler("neuron_api_run", {
|
|
282
|
+
collection: "api",
|
|
283
|
+
}));
|
|
284
|
+
expect(result.folders).toHaveLength(2);
|
|
285
|
+
expect(result.folders[0].folder).toBe("auth");
|
|
286
|
+
expect(result.folders[1].folder).toBe("bots");
|
|
287
|
+
expect(typeof result.total_passed).toBe("number");
|
|
288
|
+
expect(typeof result.total_failed).toBe("number");
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
// ── Scenario execution ──────────────────────────────────────────
|
|
292
|
+
describe("neuron_api_run_scenario", () => {
|
|
293
|
+
it("executes steps in order with variable chaining", async () => {
|
|
294
|
+
mockHttp.addRoute("GET", "/bots/bot-new-123", {
|
|
295
|
+
status: 200,
|
|
296
|
+
body: JSON.stringify({ id: "bot-new-123", name: "Test Bot" }),
|
|
297
|
+
});
|
|
298
|
+
const result = (await handler("neuron_api_run_scenario", {
|
|
299
|
+
collection: "api",
|
|
300
|
+
scenario: "bot-lifecycle",
|
|
301
|
+
}));
|
|
302
|
+
expect(result.passed).toBe(true);
|
|
303
|
+
expect(result.steps).toHaveLength(4);
|
|
304
|
+
expect(result.steps[0].ref).toBe("auth/Login");
|
|
305
|
+
expect(result.steps[1].ref).toBe("bots/Create Bot");
|
|
306
|
+
expect(result.steps[2].ref).toBe("bots/Get Bot");
|
|
307
|
+
expect(result.steps[3].ref).toBe("bots/Delete Bot");
|
|
308
|
+
// Verify variable chaining worked: Login extracted auth_token, Create extracted bot_id
|
|
309
|
+
expect(result.extracted.auth_token).toBe("fresh-token-abc");
|
|
310
|
+
expect(result.extracted.bot_id).toBe("bot-new-123");
|
|
311
|
+
});
|
|
312
|
+
it("halts on first failure", async () => {
|
|
313
|
+
// Make Create Bot return 500
|
|
314
|
+
mockHttp.addRoute("POST", "/bots", {
|
|
315
|
+
status: 500,
|
|
316
|
+
body: '{"error":"server error"}',
|
|
317
|
+
});
|
|
318
|
+
const result = (await handler("neuron_api_run_scenario", {
|
|
319
|
+
collection: "api",
|
|
320
|
+
scenario: "bot-lifecycle",
|
|
321
|
+
}));
|
|
322
|
+
expect(result.passed).toBe(false);
|
|
323
|
+
expect(result.halted_at).toBe(1); // Step 1 (Create Bot) failed
|
|
324
|
+
expect(result.steps).toHaveLength(2); // Only Login and Create Bot executed
|
|
325
|
+
expect(result.steps[1].assertions[0].passed).toBe(false);
|
|
326
|
+
});
|
|
327
|
+
it("applies step overrides", async () => {
|
|
328
|
+
mockHttp.addRoute("GET", "/bots", {
|
|
329
|
+
status: 401,
|
|
330
|
+
body: '{"error":"unauthorized"}',
|
|
331
|
+
});
|
|
332
|
+
const result = (await handler("neuron_api_run_scenario", {
|
|
333
|
+
collection: "api",
|
|
334
|
+
scenario: "auth-failure",
|
|
335
|
+
}));
|
|
336
|
+
expect(result.passed).toBe(true);
|
|
337
|
+
expect(result.steps[0].assertions[0].expected).toBe(401);
|
|
338
|
+
expect(result.steps[0].assertions[0].passed).toBe(true);
|
|
339
|
+
// Verify the override header was sent
|
|
340
|
+
const call = mockHttp.calls[0];
|
|
341
|
+
expect(call.headers["Authorization"]).toBe("Bearer expired");
|
|
342
|
+
});
|
|
343
|
+
it("returns error for invalid step ref", async () => {
|
|
344
|
+
const result = (await handler("neuron_api_run_scenario", {
|
|
345
|
+
collection: "api",
|
|
346
|
+
scenario: "bad-ref",
|
|
347
|
+
}));
|
|
348
|
+
expect(result.passed).toBe(false);
|
|
349
|
+
expect(result.halted_at).toBe(0);
|
|
350
|
+
expect(result.steps[0].error).toContain("Could not resolve");
|
|
351
|
+
});
|
|
352
|
+
it("returns error for missing scenario", async () => {
|
|
353
|
+
const result = (await handler("neuron_api_run_scenario", {
|
|
354
|
+
collection: "api",
|
|
355
|
+
scenario: "nonexistent",
|
|
356
|
+
}));
|
|
357
|
+
expect(result.error).toContain("not found");
|
|
358
|
+
});
|
|
359
|
+
it("returns error for missing collection", async () => {
|
|
360
|
+
const result = (await handler("neuron_api_run_scenario", {
|
|
361
|
+
collection: "nope",
|
|
362
|
+
scenario: "bot-lifecycle",
|
|
363
|
+
}));
|
|
364
|
+
expect(result.error).toContain("not found");
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
//# sourceMappingURL=scenario.test.js.map
|