Skip to content

Commit f32673d

Browse files
authored
Merge pull request #115 from FlowTestAI/cli-logs
fix: use nested flow and display proper logs in cli
2 parents 19b8444 + a8ac485 commit f32673d

4 files changed

Lines changed: 26 additions & 95 deletions

File tree

packages/flowtest-cli/bin/index.js

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,6 @@ const { Graph } = require('../graph/Graph');
99
const { cloneDeep } = require('lodash');
1010
const dotenv = require('dotenv');
1111

12-
const omelette = require('omelette');
13-
14-
// Initialize tab completion
15-
const completion = omelette('flow');
16-
17-
completion.on('complete', (fragment, data) => {
18-
if (data.line.endsWith('--file ') || data.line.endsWith('--env ')) {
19-
completion.reply([]);
20-
} else {
21-
// Dynamically list directories and files as suggestions
22-
const fs = require('fs');
23-
const path = require('path');
24-
25-
const lineParts = data.line.split(' ');
26-
const basePath = lineParts[lineParts.length - 1];
27-
28-
try {
29-
const items = fs.readdirSync(basePath, { withFileTypes: true });
30-
// console.log(`Base path: ${basePath}`);
31-
// console.log(`Items: ${JSON.stringify(items)}`);
32-
const results = items.map((item) => path.join(basePath, item.name) + (item.isDirectory() ? '/' : ''));
33-
completion.reply(results);
34-
} catch (error) {
35-
completion.reply([]);
36-
}
37-
}
38-
});
39-
40-
completion.init();
41-
42-
if (~process.argv.indexOf('--completion')) {
43-
completion.setupShellInitFile();
44-
console.log('Run `source ~/.bashrc` or restart your terminal to activate completion.');
45-
process.exit();
46-
}
47-
4812
const getEnvVariables = (pathname) => {
4913
const content = readFile(pathname);
5014
const buf = Buffer.from(content);
@@ -82,7 +46,13 @@ const argv = yargs(hideBin(process.argv))
8246
async (argv) => {
8347
console.log(`Reading file: ${argv.file}`);
8448
if (argv.file.toLowerCase().endsWith(`.flow`)) {
85-
const content = readFile(argv.file);
49+
let content = undefined;
50+
try {
51+
content = readFile(argv.file);
52+
} catch (error) {
53+
console.error(chalk.red(`${error}`));
54+
process.exit(1);
55+
}
8656
try {
8757
const flowData = serialize(JSON.parse(content));
8858
// output json output to a file
@@ -94,7 +64,6 @@ const argv = yargs(hideBin(process.argv))
9464
startTime,
9565
argv.timeout ? argv.timeout : 60000,
9666
argv.env ? getEnvVariables(argv.env) : {},
97-
[],
9867
);
9968
console.log(chalk.yellow('Running Graph \n'));
10069
if (flowData.nodes.find((n) => n.type === 'complexNode')) {
@@ -115,7 +84,7 @@ const argv = yargs(hideBin(process.argv))
11584
process.exit(1);
11685
//console.log(chalk.green(JSON.stringify(result)));
11786
} catch (error) {
118-
console.error(chalk.red(`Error running flow due to: ${error}`));
87+
console.error(chalk.red(`Internal error running flow`));
11988
process.exit(1);
12089
}
12190
} else {

packages/flowtest-cli/graph/Graph.js

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const { cloneDeep } = require('lodash');
44
const authNode = require('./compute/authnode');
5-
// const complexNode = require('./compute/complexnode');
65
const assertNode = require('./compute/assertnode');
76
const requestNode = require('./compute/requestNode');
87
const setVarNode = require('./compute/setvarnode');
@@ -12,27 +11,25 @@ const readFile = require('../../flowtest-electron/src/utils/filemanager/readfile
1211
const { serialize } = require('../../flowtest-electron/src/utils/flowparser/parser');
1312
const Node = require('./compute/node');
1413

15-
class complexNode extends Node {
16-
constructor(nodes, edges, startTime, timeout, initialEnvVars, initialLogs) {
17-
super('complexNode');
14+
class nestedFlowNode extends Node {
15+
constructor(nodes, edges, startTime, timeout, initialEnvVars) {
16+
super('flowNode');
1817
try {
19-
this.internalGraph = new Graph(nodes, edges, startTime, timeout, initialEnvVars, initialLogs);
18+
this.internalGraph = new Graph(nodes, edges, startTime, timeout, initialEnvVars);
2019
} catch (error) {
2120
console.log(error);
2221
}
2322
}
2423

2524
async evaluate() {
26-
//console.log('Evaluating a complex node (nested graph):');
2725
return this.internalGraph.run();
2826
}
2927
}
3028

3129
class Graph {
32-
constructor(nodes, edges, startTime, timeout, initialEnvVars, initialLogs) {
30+
constructor(nodes, edges, startTime, timeout, initialEnvVars) {
3331
this.nodes = nodes;
3432
this.edges = edges;
35-
this.logs = initialLogs;
3633
this.timeout = timeout;
3734
this.startTime = startTime;
3835
this.graphRunNodeOutput = {};
@@ -83,11 +80,7 @@ class Graph {
8380
const prevNodeOutputData = this.#computeDataFromPreviousNodes(node);
8481

8582
try {
86-
//console.debug('Executing node: ', node);
87-
8883
if (node.type === 'outputNode') {
89-
//this.logs.push(`Output: ${JSON.stringify(prevNodeOutputData)}`);
90-
//useCanvasStore.getState().setOutputNode(node.id, prevNodeOutputData);
9184
console.log('Output Node');
9285
console.log(chalk.green(` ✓ `) + chalk.dim(`${JSON.stringify(prevNodeOutputData)}`));
9386
result = {
@@ -105,15 +98,13 @@ class Graph {
10598
this.logs,
10699
);
107100
if (eNode.evaluate()) {
108-
//this.logs.push('Result: true');
109101
console.log(chalk.green(` ✓ `) + chalk.dim('True'));
110102
result = {
111103
status: 'Success',
112104
data: prevNodeOutputData,
113105
output: true,
114106
};
115107
} else {
116-
//this.logs.push('Result: false');
117108
console.log(chalk.red(` ✕ `) + chalk.dim('False'));
118109
result = {
119110
status: 'Success',
@@ -130,7 +121,6 @@ class Graph {
130121
};
131122
console.log('Delay Node: ' + chalk.green(`....waiting for: ${delay} ms`));
132123
await wait(delay);
133-
//this.logs.push(`Wait for: ${delay} ms`);
134124
result = {
135125
status: 'Success',
136126
};
@@ -147,7 +137,7 @@ class Graph {
147137

148138
if (node.type === 'requestNode') {
149139
console.log('Request Node');
150-
const rNode = new requestNode(node.data, prevNodeOutputData, this.envVariables, this.auth, this.logs);
140+
const rNode = new requestNode(node.data, prevNodeOutputData, this.envVariables, this.auth);
151141
result = await rNode.evaluate();
152142
// add post response variables if any
153143
if (result.postRespVars) {
@@ -158,18 +148,17 @@ class Graph {
158148
}
159149
}
160150

161-
if (node.type === 'complexNode') {
162-
console.log('Complex Node (Nested graph)');
151+
if (node.type === 'flowNode') {
152+
console.log('Flow Node (Nested graph)');
163153
const content = readFile(path.join(process.cwd(), node.data.relativePath));
164154
const flowData = serialize(JSON.parse(content));
165155
if (flowData) {
166-
const cNode = new complexNode(
156+
const cNode = new nestedFlowNode(
167157
cloneDeep(flowData.nodes),
168158
cloneDeep(flowData.edges),
169159
this.startTime,
170160
this.timeout,
171161
this.envVariables,
172-
this.logs,
173162
);
174163
result = await cNode.evaluate();
175164
this.envVariables = result.envVars;
@@ -185,8 +174,7 @@ class Graph {
185174
const sNode = new setVarNode(node.data, prevNodeOutputData, this.envVariables);
186175
const newVariable = sNode.evaluate();
187176
if (newVariable != undefined) {
188-
//this.logs.push(`Evaluate variable: ${JSON.stringify(newVariable)}`);
189-
console.log(chalk.green(` ✓ `) + chalk.dim(`Evaluate variable: ${JSON.stringify(newVariable)}`));
177+
console.log(chalk.green(` ✓ `) + chalk.dim(`Set variable: ${JSON.stringify(newVariable)}`));
190178
this.envVariables = {
191179
...this.envVariables,
192180
...newVariable,
@@ -198,18 +186,17 @@ class Graph {
198186
}
199187

200188
if (this.#checkTimeout()) {
201-
console.log(chalk.red(`Timeout of ${this.timeout} ms exceeded, stopping graph run`));
202189
throw `Timeout of ${this.timeout} ms exceeded, stopping graph run`;
203190
}
204191
} catch (err) {
205-
this.logs.push(`Flow failed at: ${JSON.stringify(node)} due to ${err}`);
192+
console.log(chalk.red(`Flow failed at: ${JSON.stringify(node.data)} due to ${err}`));
206193
return {
207194
status: 'Failed',
208195
};
209196
}
210197

211198
if (result === undefined) {
212-
this.logs.push(`Flow failed at: ${JSON.stringify(node)}`);
199+
console.log(chalk.red(`Flow failed due to failure to evaluate result at node: ${node.data}`));
213200
return {
214201
status: 'Failed',
215202
};
@@ -219,7 +206,7 @@ class Graph {
219206
if (connectingEdge != undefined) {
220207
const nextNode = this.nodes.find(
221208
(node) =>
222-
['requestNode', 'outputNode', 'assertNode', 'delayNode', 'authNode', 'complexNode', 'setVarNode'].includes(
209+
['requestNode', 'outputNode', 'assertNode', 'delayNode', 'authNode', 'flowNode', 'setVarNode'].includes(
223210
node.type,
224211
) && node.id === connectingEdge.target,
225212
);
@@ -232,25 +219,15 @@ class Graph {
232219
}
233220

234221
async run() {
235-
// reset every output node for a fresh run
236-
// this.nodes.forEach((node) => {
237-
// if (node.type === 'outputNode') {
238-
// useCanvasStore.getState().unSetOutputNode(node.id);
239-
// }
240-
// });
241222
this.graphRunNodeOutput = {};
242223

243-
//this.logs.push('Start Flowtest');
244224
console.log(chalk.green('Start Flowtest'));
245225
const startNode = this.nodes.find((node) => node.type === 'startNode');
246226
if (startNode == undefined) {
247-
//this.logs.push('No start node found');
248-
//this.logs.push('End Flowtest');
249227
console.log(chalk.red(`✕ `) + chalk.red('No start node found'));
250228
console.log(chalk.red('End Flowtest'));
251229
return {
252230
status: 'Success',
253-
logs: this.logs,
254231
envVars: this.envVariables,
255232
};
256233
}
@@ -265,18 +242,14 @@ class Graph {
265242
} else {
266243
console.log(chalk.green('End Flowtest'));
267244
}
268-
//this.logs.push('End Flowtest');
269245
return {
270246
status: result.status,
271-
logs: this.logs,
272247
envVars: this.envVariables,
273248
};
274249
} else {
275-
//this.logs.push('End Flowtest');
276250
console.log(chalk.green('End Flowtest'));
277251
return {
278252
status: 'Success',
279-
logs: this.logs,
280253
envVars: this.envVariables,
281254
};
282255
}

packages/flowtest-cli/graph/compute/requestnode.js

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,15 @@ const convertBase64ToBlob = async (base64) => {
1818
};
1919

2020
class requestNode extends Node {
21-
constructor(nodeData, prevNodeOutputData, envVariables, auth, logs) {
21+
constructor(nodeData, prevNodeOutputData, envVariables, auth) {
2222
super('requestNode');
2323
this.nodeData = nodeData;
2424
this.prevNodeOutputData = prevNodeOutputData;
2525
this.envVariables = envVariables;
2626
this.auth = auth;
27-
this.logs = logs;
2827
}
2928

3029
async evaluate() {
31-
//console.log('Evaluating request node');
3230
// step1 evaluate pre request variables of this node
3331
const evalVariables = computeNodeVariables(this.nodeData.preReqVars, this.prevNodeOutputData);
3432

@@ -43,37 +41,28 @@ class requestNode extends Node {
4341
// step 3
4442
const options = this.formulateRequest(finalUrl, variablesDict);
4543

46-
//console.debug('Avialable variables: ', variablesDict);
47-
//console.debug('Evaluated Url: ', finalUrl);
44+
console.log(chalk.green(` ✓ `) + chalk.dim(`type = ${this.nodeData.requestType.toUpperCase()}`));
4845
console.log(chalk.green(` ✓ `) + chalk.dim(`url = ${finalUrl}`));
4946

5047
const res = await this.runHttpRequest(options);
5148

5249
if (res.error) {
53-
//console.debug('Failure at node: ', node);
54-
//console.debug('Error encountered: ', JSON.stringify(res.error));
55-
//this.logs.push(`Request failed: ${JSON.stringify(res.error)}`);
5650
console.log(chalk.red(` ✕ `) + chalk.dim(`Request failed: ${JSON.stringify(res.error)}`));
5751
return {
5852
status: 'Failed',
59-
//node,
6053
};
6154
} else {
62-
//this.logs.push(`Request successful: ${JSON.stringify(res)}`);
63-
//console.debug('Response: ', JSON.stringify(res));
6455
console.log(chalk.green(` ✓ `) + chalk.dim(`Request successful: ${JSON.stringify(res)}`));
6556
if (this.nodeData.postRespVars) {
6657
const evalPostRespVars = computeNodeVariables(this.nodeData.postRespVars, res.data);
6758
return {
6859
status: 'Success',
69-
//node,
7060
data: res.data,
7161
postRespVars: evalPostRespVars,
7262
};
7363
}
7464
return {
7565
status: 'Success',
76-
//node,
7766
data: res.data,
7867
};
7968
}
@@ -115,7 +104,6 @@ class requestNode extends Node {
115104
options.auth.password = this.auth.password;
116105
}
117106

118-
this.logs.push(`${restMethod} ${finalUrl}`);
119107
return options;
120108
}
121109

@@ -140,6 +128,7 @@ class requestNode extends Node {
140128
status: result.status,
141129
statusText: result.statusText,
142130
data: result.data,
131+
headers: result.headers,
143132
};
144133
} catch (error) {
145134
if (error?.response) {
@@ -153,7 +142,7 @@ class requestNode extends Node {
153142
} else {
154143
return {
155144
error: {
156-
message: `An unknown error occurred while running the request : ${error}`,
145+
message: `An error occurred while running the request : ${error?.message}`,
157146
},
158147
};
159148
}

src/components/molecules/headers/TabPanelHeader.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const TabPanelHeader = () => {
5252

5353
if (type === 'assertNode') {
5454
const data = log.node.data;
55-
message = `Assert : ${data.var1} ${data.operator} ${data.var2} = ${data.result}`;
55+
message = `Assert : ${data.var1} of type ${typeof data.var1} ${data.operator} ${data.var2} of type ${typeof data.var2} = ${data.result}`;
5656
}
5757

5858
if (type === 'delayNode') {

0 commit comments

Comments
 (0)