systemview 1.18.1 → 1.20.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/api/Connections.js +5 -0
- package/api/connections.json +1 -1
- package/api/index.js +16 -0
- package/build/asset-manifest.json +6 -8
- package/build/index.html +1 -1
- package/build/static/css/{main.2c749bba.css → main.3396e24d.css} +3 -3
- package/build/static/css/main.3396e24d.css.map +1 -0
- package/build/static/js/main.c3485d98.js +3 -0
- package/build/static/js/{main.e94b392a.js.LICENSE.txt → main.c3485d98.js.LICENSE.txt} +48 -26
- package/build/static/js/main.c3485d98.js.map +1 -0
- package/cli/cookieClient.js +5 -3
- package/cli/index.js +52 -3
- package/cli/listTests.js +162 -0
- package/cli/openBrowser.js +22 -8
- package/cli/probe.js +3 -2
- package/cli/runTests.js +199 -43
- package/cli/utils/cli.js +52 -2
- package/cli/utils/resolveNamespace.js +16 -0
- package/cli/utils/truncate.js +31 -0
- package/package.json +1 -1
- package/build/static/css/main.2c749bba.css.map +0 -1
- package/build/static/js/422.3649b867.chunk.js +0 -2
- package/build/static/js/422.3649b867.chunk.js.map +0 -1
- package/build/static/js/main.e94b392a.js +0 -3
- package/build/static/js/main.e94b392a.js.map +0 -1
package/cli/runTests.js
CHANGED
|
@@ -1,17 +1,59 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { createCookieClient } = require("./cookieClient");
|
|
4
|
-
const Client = createCookieClient();
|
|
5
4
|
const { initializeSavedTests } = require("../testing-utilities/transformTests");
|
|
6
5
|
const FullTestController = require("../testing-utilities/FullTestController");
|
|
7
6
|
const log = require("./logger");
|
|
8
7
|
const validationMessages = require("../testing-utilities/validtionMessages");
|
|
8
|
+
const { truncate, TruncationMarker } = require("./utils/truncate");
|
|
9
|
+
|
|
10
|
+
function formatTruncated(value, indent = 0) {
|
|
11
|
+
const pad = " ".repeat(indent);
|
|
12
|
+
const inner = " ".repeat(indent + 1);
|
|
13
|
+
if (value instanceof TruncationMarker) return chalk.dim(value.message);
|
|
14
|
+
if (value === null) return "null";
|
|
15
|
+
if (typeof value !== "object") return JSON.stringify(value);
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
if (!value.length) return "[]";
|
|
18
|
+
const items = value.map((v) =>
|
|
19
|
+
v instanceof TruncationMarker
|
|
20
|
+
? inner + chalk.dim(v.message)
|
|
21
|
+
: inner + formatTruncated(v, indent + 1)
|
|
22
|
+
);
|
|
23
|
+
return "[\n" + items.join(",\n") + "\n" + pad + "]";
|
|
24
|
+
}
|
|
25
|
+
const keys = Object.keys(value);
|
|
26
|
+
if (!keys.length) return "{}";
|
|
27
|
+
const entries = keys.map((k) => {
|
|
28
|
+
const v = value[k];
|
|
29
|
+
if (k === "__more__" && v instanceof TruncationMarker)
|
|
30
|
+
return inner + chalk.dim(v.message);
|
|
31
|
+
return inner + JSON.stringify(k) + ": " + formatTruncated(v, indent + 1);
|
|
32
|
+
});
|
|
33
|
+
return "{\n" + entries.join(",\n") + "\n" + pad + "}";
|
|
34
|
+
}
|
|
9
35
|
const { runFullTest } = new FullTestController();
|
|
10
36
|
|
|
11
37
|
const chalk = require("chalk");
|
|
12
38
|
const DIVIDER = chalk.dim(" " + "─".repeat(60));
|
|
39
|
+
const SUITE_DIVIDER = chalk.cyan(" " + "─".repeat(60));
|
|
13
40
|
|
|
14
|
-
module.exports = async function runTests(
|
|
41
|
+
module.exports = async function runTests(
|
|
42
|
+
url,
|
|
43
|
+
project_code,
|
|
44
|
+
namespace,
|
|
45
|
+
{
|
|
46
|
+
json = false,
|
|
47
|
+
verbose = false,
|
|
48
|
+
manifest: manifestPath,
|
|
49
|
+
headers: cliHeaders = {},
|
|
50
|
+
bail = false,
|
|
51
|
+
dryRun = false,
|
|
52
|
+
phase: phaseFilter = null,
|
|
53
|
+
index: indexFilter = undefined,
|
|
54
|
+
skip: skipPatterns = [],
|
|
55
|
+
} = {}
|
|
56
|
+
) {
|
|
15
57
|
const api = `${url}/systemview/api`;
|
|
16
58
|
|
|
17
59
|
if (!project_code) {
|
|
@@ -19,26 +61,34 @@ module.exports = async function runTests(url, project_code, namespace, { json =
|
|
|
19
61
|
return 1;
|
|
20
62
|
}
|
|
21
63
|
|
|
22
|
-
const connectedServices = await resolveServices(
|
|
64
|
+
const { services: connectedServices, probeHeaders: manifestHeaders } = await resolveServices(
|
|
65
|
+
api,
|
|
66
|
+
project_code,
|
|
67
|
+
manifestPath
|
|
68
|
+
);
|
|
23
69
|
if (!connectedServices || !connectedServices.length) {
|
|
24
70
|
log.warn("No connected services found for project: " + project_code);
|
|
25
71
|
return 1;
|
|
26
72
|
}
|
|
27
73
|
|
|
74
|
+
const extraHeaders = { ...manifestHeaders, ...cliHeaders };
|
|
75
|
+
const Client = createCookieClient(extraHeaders);
|
|
76
|
+
|
|
28
77
|
if (!json) {
|
|
29
78
|
connectedServices.forEach(({ serviceId, system }) => {
|
|
30
79
|
log.success(`connected: ${serviceId} @ ${system.connectionData.serviceUrl}`);
|
|
31
80
|
});
|
|
32
81
|
}
|
|
33
82
|
|
|
34
|
-
const allTestLists = await getTests(connectedServices);
|
|
83
|
+
const allTestLists = await getTests(connectedServices, Client);
|
|
35
84
|
const testToRun = allTestLists
|
|
36
85
|
.map((list) =>
|
|
37
|
-
namespace
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
86
|
+
list.filter(({ namespace: n }) => {
|
|
87
|
+
const full = `${n.serviceId}.${n.moduleName}.${n.methodName}`;
|
|
88
|
+
const matchesInclude = !namespace || full.includes(namespace);
|
|
89
|
+
const matchesSkip = skipPatterns.length && skipPatterns.some((p) => full.includes(p));
|
|
90
|
+
return matchesInclude && !matchesSkip;
|
|
91
|
+
})
|
|
42
92
|
)
|
|
43
93
|
.filter((list) => list.length);
|
|
44
94
|
|
|
@@ -47,8 +97,24 @@ module.exports = async function runTests(url, project_code, namespace, { json =
|
|
|
47
97
|
return 0;
|
|
48
98
|
}
|
|
49
99
|
|
|
100
|
+
if (dryRun) {
|
|
101
|
+
const total = testToRun.reduce((n, list) => n + list.length, 0);
|
|
102
|
+
console.log("");
|
|
103
|
+
console.log(` Would run ${total} ${total === 1 ? "test" : "tests"}:`);
|
|
104
|
+
console.log("");
|
|
105
|
+
testToRun.forEach((list) => {
|
|
106
|
+
list.forEach(({ namespace: n, title }) => {
|
|
107
|
+
console.log(` ${chalk.cyan(`${n.serviceId}.${n.moduleName}.${n.methodName}`)} — "${title}"`);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
console.log("");
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
50
114
|
const jsonOutput = json ? { projectCode: project_code, passed: 0, failed: 0, tests: [] } : null;
|
|
51
115
|
let totalFailed = 0;
|
|
116
|
+
const serviceSummaries = [];
|
|
117
|
+
const allFailures = [];
|
|
52
118
|
|
|
53
119
|
for (const testList of testToRun) {
|
|
54
120
|
const { serviceId } = testList[0].namespace;
|
|
@@ -56,7 +122,14 @@ module.exports = async function runTests(url, project_code, namespace, { json =
|
|
|
56
122
|
|
|
57
123
|
try {
|
|
58
124
|
const initialized = initializeSavedTests(testList, connectedServices, Client);
|
|
59
|
-
const { passed, failed, jsonTests } = await runAllTests(
|
|
125
|
+
const { passed, failed, jsonTests, failures } = await runAllTests(
|
|
126
|
+
initialized,
|
|
127
|
+
url,
|
|
128
|
+
project_code,
|
|
129
|
+
json,
|
|
130
|
+
verbose,
|
|
131
|
+
{ bail, phaseFilter, indexFilter }
|
|
132
|
+
);
|
|
60
133
|
totalFailed += failed;
|
|
61
134
|
|
|
62
135
|
if (json) {
|
|
@@ -64,10 +137,11 @@ module.exports = async function runTests(url, project_code, namespace, { json =
|
|
|
64
137
|
jsonOutput.failed += failed;
|
|
65
138
|
jsonOutput.tests.push(...jsonTests);
|
|
66
139
|
} else {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
);
|
|
140
|
+
serviceSummaries.push({ serviceId, passed, failed });
|
|
141
|
+
allFailures.push(...failures);
|
|
70
142
|
}
|
|
143
|
+
|
|
144
|
+
if (bail && failed > 0) break;
|
|
71
145
|
} catch (error) {
|
|
72
146
|
log.error(`Unexpected error for ${serviceId}: ${error.message}`);
|
|
73
147
|
}
|
|
@@ -79,22 +153,67 @@ module.exports = async function runTests(url, project_code, namespace, { json =
|
|
|
79
153
|
console.log("");
|
|
80
154
|
log.info("TEST COMPLETE");
|
|
81
155
|
console.log("");
|
|
156
|
+
|
|
157
|
+
serviceSummaries.forEach(({ serviceId, passed, failed }) => {
|
|
158
|
+
const total = passed + failed;
|
|
159
|
+
log[failed ? "error" : "success"](
|
|
160
|
+
`${serviceId}: ${total} tests, ${passed} passed, ${failed} failed`
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (allFailures.length) {
|
|
165
|
+
console.log("");
|
|
166
|
+
log.warn("FAILED:");
|
|
167
|
+
allFailures.forEach(({ serviceId, moduleName, methodName, title, failedPhases }) => {
|
|
168
|
+
console.log("");
|
|
169
|
+
log.error(` ${serviceId}.${moduleName}.${methodName} — "${title}"`);
|
|
170
|
+
failedPhases.forEach(({ phase, actions }) => {
|
|
171
|
+
actions.forEach(({ actionTitle, errors }) => {
|
|
172
|
+
console.log(` ${phase}: "${actionTitle}"`);
|
|
173
|
+
errors.forEach((err) => console.log(` → ${validationMessages(err)}`));
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
console.log("");
|
|
178
|
+
}
|
|
82
179
|
}
|
|
83
180
|
|
|
84
181
|
return totalFailed > 0 ? 1 : 0;
|
|
85
182
|
};
|
|
86
183
|
|
|
87
|
-
const runAllTests = async (savedTests, url, project_code, json, verbose) => {
|
|
88
|
-
const
|
|
184
|
+
const runAllTests = async (savedTests, url, project_code, json, verbose, opts = {}) => {
|
|
185
|
+
const { bail = false, phaseFilter = null, indexFilter = undefined } = opts;
|
|
186
|
+
const sum = { passed: 0, failed: 0, jsonTests: [], failures: [] };
|
|
187
|
+
|
|
188
|
+
for (const { Before: B, Main: M, Events: E, After: A, title, namespace } of savedTests) {
|
|
189
|
+
let Before = [...B];
|
|
190
|
+
let Main = [...M];
|
|
191
|
+
let Events = [...E];
|
|
192
|
+
let After = [...A];
|
|
193
|
+
|
|
194
|
+
if (phaseFilter) {
|
|
195
|
+
const allowed = phaseFilter.split(",").map((p) => p.trim().toLowerCase());
|
|
196
|
+
if (!allowed.includes("before")) Before = [];
|
|
197
|
+
if (!allowed.includes("main")) Main = [];
|
|
198
|
+
if (!allowed.includes("events")) Events = [];
|
|
199
|
+
if (!allowed.includes("after")) After = [];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (indexFilter !== undefined) {
|
|
203
|
+
Before = Before.slice(indexFilter, indexFilter + 1);
|
|
204
|
+
Main = Main.slice(indexFilter, indexFilter + 1);
|
|
205
|
+
Events = Events.slice(indexFilter, indexFilter + 1);
|
|
206
|
+
After = After.slice(indexFilter, indexFilter + 1);
|
|
207
|
+
}
|
|
89
208
|
|
|
90
|
-
for (const { Before, Main, Events, After, title, namespace } of savedTests) {
|
|
91
|
-
const { moduleName, methodName, serviceId } = namespace;
|
|
92
209
|
const fullTest = [Before, Main, Events, After];
|
|
210
|
+
const { moduleName, methodName, serviceId } = namespace;
|
|
93
211
|
|
|
94
212
|
if (!json) {
|
|
95
|
-
console.log(
|
|
96
|
-
console.log(" " + chalk.bold.cyan(
|
|
97
|
-
console.log(
|
|
213
|
+
console.log(SUITE_DIVIDER);
|
|
214
|
+
console.log(" " + chalk.bold("Test: ") + chalk.bold.cyan(title));
|
|
215
|
+
console.log(SUITE_DIVIDER);
|
|
216
|
+
console.log(chalk.dim(` ${serviceId}.${moduleName}.${methodName} → ${url}/${project_code}/${serviceId}/${moduleName}/${methodName}`));
|
|
98
217
|
console.log("");
|
|
99
218
|
}
|
|
100
219
|
|
|
@@ -103,8 +222,24 @@ const runAllTests = async (savedTests, url, project_code, json, verbose) => {
|
|
|
103
222
|
const hasFailed =
|
|
104
223
|
countErrors(Before) + countErrors(Main) + countErrors(Events) + countErrors(After) > 0;
|
|
105
224
|
|
|
106
|
-
if (hasFailed)
|
|
107
|
-
|
|
225
|
+
if (hasFailed) {
|
|
226
|
+
sum.failed++;
|
|
227
|
+
const failedPhases = [];
|
|
228
|
+
[
|
|
229
|
+
{ phase: "Before", tests: Before },
|
|
230
|
+
{ phase: "Main", tests: Main },
|
|
231
|
+
{ phase: "Events", tests: Events },
|
|
232
|
+
{ phase: "After", tests: After },
|
|
233
|
+
].forEach(({ phase, tests }) => {
|
|
234
|
+
const actions = tests
|
|
235
|
+
.filter((t) => t.errors && t.errors.length)
|
|
236
|
+
.map((t) => ({ actionTitle: t.title, errors: t.errors }));
|
|
237
|
+
if (actions.length) failedPhases.push({ phase, actions });
|
|
238
|
+
});
|
|
239
|
+
sum.failures.push({ serviceId, moduleName, methodName, title, failedPhases });
|
|
240
|
+
} else {
|
|
241
|
+
sum.passed++;
|
|
242
|
+
}
|
|
108
243
|
|
|
109
244
|
if (json) {
|
|
110
245
|
sum.jsonTests.push({
|
|
@@ -119,47 +254,65 @@ const runAllTests = async (savedTests, url, project_code, json, verbose) => {
|
|
|
119
254
|
After: serializePhase(After),
|
|
120
255
|
});
|
|
121
256
|
} else {
|
|
122
|
-
|
|
123
|
-
logPhase(
|
|
124
|
-
logPhase(
|
|
125
|
-
logPhase(
|
|
257
|
+
const compact = !verbose;
|
|
258
|
+
logPhase(Before, "Before", verbose, compact, false);
|
|
259
|
+
logPhase(Main, "Main", verbose, false, true);
|
|
260
|
+
logPhase(Events, "Events", verbose, compact, false);
|
|
261
|
+
logPhase(After, "After", verbose, compact, false);
|
|
126
262
|
}
|
|
263
|
+
|
|
264
|
+
if (bail && hasFailed) break;
|
|
127
265
|
}
|
|
128
266
|
|
|
129
267
|
return sum;
|
|
130
268
|
};
|
|
131
269
|
|
|
132
|
-
function
|
|
133
|
-
return tests.reduce((n, t) => n + (t.errors ? t.errors.length : 0), 0);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function logPhase(tests, section, logSuccess = false, verbose = false) {
|
|
270
|
+
function logPhase(tests, section, verbose = false, compact = false, isMain = false) {
|
|
137
271
|
tests.forEach(({ errors, results, namespace, title, args }) => {
|
|
138
272
|
const { serviceId, moduleName, methodName } = namespace;
|
|
139
273
|
const failed = errors && errors.length;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
274
|
+
|
|
275
|
+
const label = isMain ? chalk.bold.green(section) : chalk.blue(section);
|
|
276
|
+
console.log(` ${label}: ${chalk.dim(title)}`);
|
|
277
|
+
if (failed) {
|
|
278
|
+
console.log(" " + chalk.bold.red(`${serviceId}.${moduleName}.${methodName}(...)`));
|
|
279
|
+
} else if (isMain) {
|
|
280
|
+
console.log(" " + chalk.bold.green(`${serviceId}.${moduleName}.${methodName}(...)`));
|
|
281
|
+
} else {
|
|
282
|
+
log.success(` ${serviceId}.${moduleName}.${methodName}(...)`);
|
|
283
|
+
}
|
|
284
|
+
|
|
145
285
|
if (verbose && args && args.length) {
|
|
146
286
|
console.log("");
|
|
147
287
|
args.forEach(({ name, input }) => {
|
|
148
288
|
console.log(` ${chalk.dim(name)}`, JSON.stringify(input));
|
|
149
289
|
});
|
|
150
290
|
}
|
|
291
|
+
|
|
151
292
|
console.log("");
|
|
152
|
-
|
|
293
|
+
if (compact) {
|
|
294
|
+
console.log(" results:", JSON.stringify(truncate(results)));
|
|
295
|
+
} else if (verbose) {
|
|
296
|
+
console.log(" results:", JSON.stringify(results, null, 2).replace(/\n/g, "\n "));
|
|
297
|
+
} else {
|
|
298
|
+
console.log(" results:", formatTruncated(truncate(results)).replace(/\n/g, "\n "));
|
|
299
|
+
}
|
|
153
300
|
console.log("");
|
|
301
|
+
|
|
154
302
|
if (failed) {
|
|
155
303
|
log.warn(` ${errors.length} validation error(s)`);
|
|
156
304
|
errors.forEach((err) => console.log(` → ${validationMessages(err)}`));
|
|
157
305
|
console.log("");
|
|
158
306
|
}
|
|
307
|
+
|
|
159
308
|
console.log(DIVIDER);
|
|
160
309
|
});
|
|
161
310
|
}
|
|
162
311
|
|
|
312
|
+
function countErrors(tests) {
|
|
313
|
+
return tests.reduce((n, t) => n + (t.errors ? t.errors.length : 0), 0);
|
|
314
|
+
}
|
|
315
|
+
|
|
163
316
|
function serializePhase(tests) {
|
|
164
317
|
return tests.map((test) => {
|
|
165
318
|
const { title, namespace, args, results, errors, evaluations } = test;
|
|
@@ -188,7 +341,7 @@ function serializePhase(tests) {
|
|
|
188
341
|
});
|
|
189
342
|
}
|
|
190
343
|
|
|
191
|
-
async function getTests(connectedServices) {
|
|
344
|
+
async function getTests(connectedServices, Client) {
|
|
192
345
|
const results = [];
|
|
193
346
|
for (const { system } of connectedServices) {
|
|
194
347
|
const { connectionData } = system;
|
|
@@ -207,25 +360,28 @@ async function resolveServices(api, project_code, manifestPath) {
|
|
|
207
360
|
if (fs.existsSync(manifestFile)) {
|
|
208
361
|
try {
|
|
209
362
|
const raw = JSON.parse(fs.readFileSync(manifestFile, "utf8"));
|
|
210
|
-
// Support both { projectCode, services: [] } and single-service { projectCode, serviceId, system, specList }
|
|
211
363
|
const services = raw.services
|
|
212
364
|
? raw.services
|
|
213
365
|
: [{ serviceId: raw.serviceId, system: raw.system, specList: raw.specList }];
|
|
214
366
|
|
|
215
367
|
if (project_code && raw.projectCode && raw.projectCode !== project_code) {
|
|
216
|
-
log.warn(
|
|
368
|
+
log.warn(
|
|
369
|
+
`Manifest projectCode "${raw.projectCode}" doesn't match "${project_code}", falling back to API`
|
|
370
|
+
);
|
|
217
371
|
} else {
|
|
218
|
-
return services;
|
|
372
|
+
return { services, probeHeaders: raw.probeHeaders || {} };
|
|
219
373
|
}
|
|
220
374
|
} catch (err) {
|
|
221
375
|
log.warn(`Failed to read manifest: ${err.message}`);
|
|
222
376
|
}
|
|
223
377
|
}
|
|
224
378
|
|
|
225
|
-
|
|
379
|
+
const BaseClient = createCookieClient();
|
|
380
|
+
const services = await getConnectedServices(api, project_code, BaseClient);
|
|
381
|
+
return { services, probeHeaders: {} };
|
|
226
382
|
}
|
|
227
383
|
|
|
228
|
-
async function getConnectedServices(api, project_code) {
|
|
384
|
+
async function getConnectedServices(api, project_code, Client) {
|
|
229
385
|
try {
|
|
230
386
|
const { SystemView } = await Client.loadService(api);
|
|
231
387
|
return await SystemView.getServices(project_code);
|
package/cli/utils/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ const HELP_TEXT = `
|
|
|
7
7
|
Commands:
|
|
8
8
|
start [port] Launch SystemView UI (default port 3000)
|
|
9
9
|
test <projectCode> [namespace] Run saved tests for a project
|
|
10
|
+
list [projectCode] [namespace] List projects, services, or tests
|
|
10
11
|
connect <serviceId> <url> Register a service and write manifest
|
|
11
12
|
connect Re-probe all services in existing manifest
|
|
12
13
|
probe <ServiceId.Module.method> [args] Call a method ad-hoc
|
|
@@ -14,33 +15,82 @@ const HELP_TEXT = `
|
|
|
14
15
|
shutdown [port] Stop a running SystemView instance
|
|
15
16
|
|
|
16
17
|
Flags:
|
|
18
|
+
--version Print version and exit
|
|
17
19
|
--json Output results as JSON (for agents/CI)
|
|
18
|
-
--verbose
|
|
20
|
+
--verbose test: full results and args for all phases; list: expand to show methods and test titles
|
|
19
21
|
--manifest <path> Path to manifest file (default: ./systemview.manifest.json)
|
|
22
|
+
--header "Name: Value" Extra request header (repeatable; overrides manifest.probeHeaders)
|
|
23
|
+
--skip <pattern> Exclude tests matching pattern (repeatable)
|
|
24
|
+
--bail Stop after first failure
|
|
25
|
+
--dry-run Print which tests would run without executing
|
|
26
|
+
--phase <before|main|events|after> Run only specified phase(s), comma-separated
|
|
27
|
+
--index <n> Run only action at index n within each phase (0-based)
|
|
20
28
|
|
|
21
29
|
Examples:
|
|
22
30
|
systemview start
|
|
23
31
|
systemview test buAPI
|
|
24
32
|
systemview test buAPI Users.signUp --json
|
|
33
|
+
systemview test buAPI --skip deleteUser --bail
|
|
34
|
+
systemview test buAPI Users.signIn --phase main --index 0
|
|
35
|
+
systemview list
|
|
36
|
+
systemview list buAPI
|
|
37
|
+
systemview list buAPI --verbose
|
|
38
|
+
systemview list buAPI signUp
|
|
25
39
|
systemview connect ProfilesService http://localhost:4100/bu/api/profiles
|
|
26
40
|
systemview probe ProfilesService.Users.getUser '{"userId":"123"}'
|
|
41
|
+
systemview open buAPI signUp
|
|
42
|
+
systemview test buAPI --header "X-Api-Key: secret"
|
|
27
43
|
`;
|
|
28
44
|
|
|
29
45
|
const rawArgs = process.argv.slice(2);
|
|
30
46
|
|
|
47
|
+
const flagValueArgs = ["--manifest", "--header", "--skip", "--phase", "--index"];
|
|
48
|
+
|
|
31
49
|
const flags = {
|
|
32
50
|
json: rawArgs.includes("--json"),
|
|
33
51
|
verbose: rawArgs.includes("--verbose") || rawArgs.includes("-v"),
|
|
34
52
|
debug: rawArgs.includes("--debug") || rawArgs.includes("-d"),
|
|
53
|
+
bail: rawArgs.includes("--bail"),
|
|
54
|
+
dryRun: rawArgs.includes("--dry-run"),
|
|
35
55
|
manifest: (() => {
|
|
36
56
|
const i = rawArgs.indexOf("--manifest");
|
|
37
57
|
return i !== -1 ? rawArgs[i + 1] : null;
|
|
38
58
|
})(),
|
|
59
|
+
phase: (() => {
|
|
60
|
+
const i = rawArgs.indexOf("--phase");
|
|
61
|
+
return i !== -1 ? rawArgs[i + 1] : null;
|
|
62
|
+
})(),
|
|
63
|
+
index: (() => {
|
|
64
|
+
const i = rawArgs.indexOf("--index");
|
|
65
|
+
if (i === -1) return undefined;
|
|
66
|
+
const val = parseInt(rawArgs[i + 1], 10);
|
|
67
|
+
return isNaN(val) ? 0 : val;
|
|
68
|
+
})(),
|
|
69
|
+
skip: (() => {
|
|
70
|
+
const result = [];
|
|
71
|
+
rawArgs.forEach((a, i) => {
|
|
72
|
+
if (a === "--skip" && rawArgs[i + 1]) result.push(rawArgs[i + 1]);
|
|
73
|
+
});
|
|
74
|
+
return result;
|
|
75
|
+
})(),
|
|
76
|
+
headers: (() => {
|
|
77
|
+
const result = {};
|
|
78
|
+
rawArgs.forEach((a, i) => {
|
|
79
|
+
if (a === "--header" && rawArgs[i + 1]) {
|
|
80
|
+
const val = rawArgs[i + 1];
|
|
81
|
+
const colonIdx = val.indexOf(":");
|
|
82
|
+
if (colonIdx !== -1) {
|
|
83
|
+
result[val.slice(0, colonIdx).trim()] = val.slice(colonIdx + 1).trim();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
return result;
|
|
88
|
+
})(),
|
|
39
89
|
};
|
|
40
90
|
|
|
41
91
|
const input = rawArgs.filter((a, i) => {
|
|
42
92
|
if (a.startsWith("-")) return false;
|
|
43
|
-
if (i > 0 && rawArgs[i - 1]
|
|
93
|
+
if (i > 0 && flagValueArgs.includes(rawArgs[i - 1])) return false;
|
|
44
94
|
return true;
|
|
45
95
|
});
|
|
46
96
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports = function resolveNamespace(partial, connectedServices) {
|
|
2
|
+
if (!partial || !connectedServices || !connectedServices.length) return [];
|
|
3
|
+
const matches = [];
|
|
4
|
+
for (const { serviceId, system } of connectedServices) {
|
|
5
|
+
const modules = (system && system.connectionData && system.connectionData.modules) || [];
|
|
6
|
+
for (const { name: moduleName, methods = [] } of modules) {
|
|
7
|
+
for (const { fn: methodName } of methods) {
|
|
8
|
+
const full = `${serviceId}.${moduleName}.${methodName}`;
|
|
9
|
+
if (full.includes(partial)) {
|
|
10
|
+
matches.push({ serviceId, moduleName, methodName });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return matches;
|
|
16
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class TruncationMarker {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
this.message = message;
|
|
4
|
+
}
|
|
5
|
+
toJSON() {
|
|
6
|
+
return this.message;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function truncate(value, maxItems = 3, maxStrLen = 100) {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
const slice = value.slice(0, maxItems).map((item) => truncate(item, maxItems, maxStrLen));
|
|
13
|
+
if (value.length > maxItems) slice.push(new TruncationMarker(`...${value.length - maxItems} more`));
|
|
14
|
+
return slice;
|
|
15
|
+
}
|
|
16
|
+
if (value !== null && typeof value === "object") {
|
|
17
|
+
const keys = Object.keys(value);
|
|
18
|
+
const result = {};
|
|
19
|
+
keys.slice(0, maxItems).forEach((k) => {
|
|
20
|
+
result[k] = truncate(value[k], maxItems, maxStrLen);
|
|
21
|
+
});
|
|
22
|
+
if (keys.length > maxItems) result.__more__ = new TruncationMarker(`...${keys.length - maxItems} more`);
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === "string" && value.length > maxStrLen) {
|
|
26
|
+
return value.slice(0, maxStrLen) + `...[${value.length - maxStrLen} more chars]`;
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = { truncate, TruncationMarker };
|