@dev-blinq/cucumber_client 1.0.1417-dev → 1.0.1419-dev
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/bin/client/code_cleanup/utils.js +5 -1
- package/bin/client/code_gen/playwright_codeget.js +2 -0
- package/bin/client/cucumber/feature.js +4 -0
- package/bin/client/recorderv3/bvt_recorder.js +49 -46
- package/bin/client/recorderv3/index.js +26 -54
- package/bin/client/recorderv3/services.js +3 -15
- package/bin/client/utils/socket_logger.js +132 -0
- package/package.json +2 -2
|
@@ -7,10 +7,11 @@ const { default: traverse } = pkg;
|
|
|
7
7
|
import pkg1 from "@babel/generator";
|
|
8
8
|
const { default: generate } = pkg1;
|
|
9
9
|
import * as t from "@babel/types";
|
|
10
|
-
|
|
11
10
|
import { CucumberExpression, ParameterTypeRegistry } from "@cucumber/cucumber-expressions";
|
|
12
11
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
13
12
|
import { getAiConfig } from "../code_gen/page_reflection.js";
|
|
13
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
14
|
+
|
|
14
15
|
const STEP_KEYWORDS = new Set(["Given", "When", "Then"]);
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -307,14 +308,17 @@ export function getDefaultPrettierConfig() {
|
|
|
307
308
|
const configContent = readFileSync(prettierConfigPath, "utf-8");
|
|
308
309
|
prettierConfig = JSON.parse(configContent);
|
|
309
310
|
} catch (error) {
|
|
311
|
+
socketLogger.error("Error parsing Prettier config file", error);
|
|
310
312
|
console.error(`Error parsing Prettier config file: ${error}`);
|
|
311
313
|
}
|
|
312
314
|
} else {
|
|
313
315
|
// save the default config to .prettierrc
|
|
314
316
|
try {
|
|
315
317
|
writeFileSync(prettierConfigPath, JSON.stringify(prettierConfig, null, 2), "utf-8");
|
|
318
|
+
socketLogger.info(`Created default Prettier config at ${prettierConfigPath}`);
|
|
316
319
|
console.log(`Created default Prettier config at ${prettierConfigPath}`);
|
|
317
320
|
} catch (error) {
|
|
321
|
+
socketLogger.error(`Error writing Prettier config file: ${error}`);
|
|
318
322
|
console.error(`Error writing Prettier config file: ${error}`);
|
|
319
323
|
}
|
|
320
324
|
}
|
|
@@ -4,6 +4,7 @@ import { StepsDefinitions } from "../cucumber/steps_definitions.js";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { CodePage } from "./page_reflection.js";
|
|
6
6
|
import { convertToIdentifier, escapeNonPrintables } from "./utils.js";
|
|
7
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
7
8
|
const findElementIdentifier = (node, step, userData, elements) => {
|
|
8
9
|
if (node.key) {
|
|
9
10
|
// incase of rerunning implemented steps
|
|
@@ -725,6 +726,7 @@ const generateCode = (recording, codePage, userData, projectDir, methodName) =>
|
|
|
725
726
|
}
|
|
726
727
|
let elements = {};
|
|
727
728
|
if (!codePage) {
|
|
729
|
+
socketLogger.info("CodePage is null");
|
|
728
730
|
console.log("codePage is null");
|
|
729
731
|
} else {
|
|
730
732
|
elements = codePage.getVariableDeclarationAsObject("elements");
|
|
@@ -8,6 +8,7 @@ import { parseStepTextParameters, toCucumberExpression, unEscapeNonPrintables }
|
|
|
8
8
|
import stream from "stream";
|
|
9
9
|
import { testStringForRegex } from "../recorderv3/update_feature.js";
|
|
10
10
|
import { generateTestData } from "./feature_data.js";
|
|
11
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
11
12
|
class DataTable {
|
|
12
13
|
constructor(dataTableDocument) {
|
|
13
14
|
if (!dataTableDocument) {
|
|
@@ -544,6 +545,9 @@ const scenarioResolution = async (featureFilePath) => {
|
|
|
544
545
|
fs.rmSync(tmpDir, { recursive: true });
|
|
545
546
|
}
|
|
546
547
|
} catch (e) {
|
|
548
|
+
socketLogger.error(
|
|
549
|
+
`An error has occurred while removing the temp folder at ${tmpDir}. Please remove it manually. Error: ${e}`
|
|
550
|
+
);
|
|
547
551
|
console.error(
|
|
548
552
|
`An error has occurred while removing the temp folder at ${tmpDir}. Please remove it manually. Error: ${e}`
|
|
549
553
|
);
|
|
@@ -12,11 +12,9 @@ import { updateFeatureFile } from "./update_feature.js";
|
|
|
12
12
|
import { parseStepTextParameters } from "../cucumber/utils.js";
|
|
13
13
|
import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherkin";
|
|
14
14
|
import chokidar from "chokidar";
|
|
15
|
-
import logger from "../../logger.js";
|
|
16
15
|
import { unEscapeNonPrintables } from "../cucumber/utils.js";
|
|
17
16
|
import { findAvailablePort } from "../utils/index.js";
|
|
18
|
-
import
|
|
19
|
-
|
|
17
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
20
18
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
21
19
|
|
|
22
20
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -45,7 +43,6 @@ async function evaluate(frame, script) {
|
|
|
45
43
|
async function findNestedFrameSelector(frame, obj) {
|
|
46
44
|
try {
|
|
47
45
|
const parent = frame.parentFrame();
|
|
48
|
-
if (parent) console.log(`Parent frame: ${JSON.stringify(parent)}`);
|
|
49
46
|
if (!parent) return { children: obj };
|
|
50
47
|
const frameElement = await frame.frameElement();
|
|
51
48
|
if (!frameElement) return;
|
|
@@ -54,6 +51,7 @@ async function findNestedFrameSelector(frame, obj) {
|
|
|
54
51
|
}, frameElement);
|
|
55
52
|
return findNestedFrameSelector(parent, { children: obj, selectors });
|
|
56
53
|
} catch (e) {
|
|
54
|
+
socketLogger.error(`Error in findNestedFrameSelector: ${e}`);
|
|
57
55
|
console.error(e);
|
|
58
56
|
}
|
|
59
57
|
}
|
|
@@ -150,6 +148,7 @@ const transformAction = (action, el, isVerify, isPopupCloseClick, isInHoverMode,
|
|
|
150
148
|
};
|
|
151
149
|
}
|
|
152
150
|
default: {
|
|
151
|
+
socketLogger.error(`Action not supported: ${action.name}`);
|
|
153
152
|
console.log("action not supported", action);
|
|
154
153
|
throw new Error("action not supported");
|
|
155
154
|
}
|
|
@@ -161,6 +160,7 @@ const transformAction = (action, el, isVerify, isPopupCloseClick, isInHoverMode,
|
|
|
161
160
|
* @property {string} projectDir
|
|
162
161
|
* @property {string} TOKEN
|
|
163
162
|
* @property {(name:string, data:any)=> void} sendEvent
|
|
163
|
+
* @property {Object} logger
|
|
164
164
|
*/
|
|
165
165
|
export class BVTRecorder {
|
|
166
166
|
#currentURL = "";
|
|
@@ -174,7 +174,6 @@ export class BVTRecorder {
|
|
|
174
174
|
*/
|
|
175
175
|
constructor(initialState) {
|
|
176
176
|
Object.assign(this, initialState);
|
|
177
|
-
this.logger = logger;
|
|
178
177
|
this.screenshotMap = new Map();
|
|
179
178
|
this.snapshotMap = new Map();
|
|
180
179
|
this.scenariosStepsMap = new Map();
|
|
@@ -186,7 +185,6 @@ export class BVTRecorder {
|
|
|
186
185
|
});
|
|
187
186
|
this.pageSet = new Set();
|
|
188
187
|
this.lastKnownUrlPath = "";
|
|
189
|
-
// TODO: what is world?
|
|
190
188
|
this.world = { attach: () => {} };
|
|
191
189
|
this.shouldTakeScreenshot = true;
|
|
192
190
|
this.watcher = null;
|
|
@@ -209,7 +207,7 @@ export class BVTRecorder {
|
|
|
209
207
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
210
208
|
this.#activeFrame = frame;
|
|
211
209
|
const nestFrmLoc = await findNestedFrameSelector(frame);
|
|
212
|
-
|
|
210
|
+
this.logger.info(`Time taken for action: ${event.statistics.time}`);
|
|
213
211
|
await this.onAction({ ...event, nestFrmLoc });
|
|
214
212
|
},
|
|
215
213
|
__bvt_getMode: async () => {
|
|
@@ -228,8 +226,7 @@ export class BVTRecorder {
|
|
|
228
226
|
await this.onClosePopup();
|
|
229
227
|
},
|
|
230
228
|
__bvt_log: async (src, message) => {
|
|
231
|
-
|
|
232
|
-
console.log(`Inside Browser: ${message}`);
|
|
229
|
+
this.logger.info(`Inside Browser: ${message}`);
|
|
233
230
|
},
|
|
234
231
|
__bvt_getObject: (_src, obj) => {
|
|
235
232
|
this.processObject(obj);
|
|
@@ -303,7 +300,7 @@ export class BVTRecorder {
|
|
|
303
300
|
try {
|
|
304
301
|
ai_config = JSON.parse(readFileSync(ai_config_file, "utf8"));
|
|
305
302
|
} catch (error) {
|
|
306
|
-
|
|
303
|
+
this.logger.error("Error reading ai_config.json", error);
|
|
307
304
|
}
|
|
308
305
|
}
|
|
309
306
|
this.config = ai_config;
|
|
@@ -315,10 +312,7 @@ export class BVTRecorder {
|
|
|
315
312
|
],
|
|
316
313
|
};
|
|
317
314
|
|
|
318
|
-
let startTime = Date.now();
|
|
319
315
|
const bvtContext = await initContext(url, false, false, this.world, 450, initScripts, this.envName);
|
|
320
|
-
let stopTime = Date.now();
|
|
321
|
-
this.logger.info(`Browser launched in ${(stopTime - startTime) / 1000} s`);
|
|
322
316
|
this.bvtContext = bvtContext;
|
|
323
317
|
this.stepRunner = new BVTStepRunner({
|
|
324
318
|
projectDir: this.projectDir,
|
|
@@ -326,23 +320,18 @@ export class BVTRecorder {
|
|
|
326
320
|
if (data && data.type) {
|
|
327
321
|
switch (data.type) {
|
|
328
322
|
case "cmdExecutionStart":
|
|
329
|
-
console.log("Sending cmdExecutionStart event for cmdId:", data);
|
|
330
323
|
this.sendEvent(this.events.cmdExecutionStart, data);
|
|
331
324
|
break;
|
|
332
325
|
case "cmdExecutionSuccess":
|
|
333
|
-
console.log("Sending cmdExecutionSuccess event for cmdId:", data);
|
|
334
326
|
this.sendEvent(this.events.cmdExecutionSuccess, data);
|
|
335
327
|
break;
|
|
336
328
|
case "cmdExecutionError":
|
|
337
|
-
console.log("Sending cmdExecutionError event for cmdId:", data);
|
|
338
329
|
this.sendEvent(this.events.cmdExecutionError, data);
|
|
339
330
|
break;
|
|
340
331
|
case "interceptResults":
|
|
341
|
-
console.log("Sending interceptResults event");
|
|
342
332
|
this.sendEvent(this.events.interceptResults, data);
|
|
343
333
|
break;
|
|
344
334
|
default:
|
|
345
|
-
console.warn("Unknown command execution status type:", data.type);
|
|
346
335
|
break;
|
|
347
336
|
}
|
|
348
337
|
}
|
|
@@ -381,13 +370,15 @@ export class BVTRecorder {
|
|
|
381
370
|
}
|
|
382
371
|
return;
|
|
383
372
|
} catch (error) {
|
|
384
|
-
console.error("Error evaluting in context:", error);
|
|
373
|
+
// console.error("Error evaluting in context:", error);
|
|
374
|
+
this.logger.error("Error evaluating in context:", error);
|
|
385
375
|
}
|
|
386
376
|
}
|
|
387
377
|
}
|
|
388
378
|
|
|
389
379
|
getMode() {
|
|
390
|
-
console.log("getMode", this.#mode);
|
|
380
|
+
// console.log("getMode", this.#mode);
|
|
381
|
+
this.logger.info("Current mode:", this.#mode);
|
|
391
382
|
return this.#mode;
|
|
392
383
|
}
|
|
393
384
|
|
|
@@ -429,6 +420,8 @@ export class BVTRecorder {
|
|
|
429
420
|
this.sendEvent(this.events.onBrowserClose);
|
|
430
421
|
}
|
|
431
422
|
} catch (error) {
|
|
423
|
+
this.logger.error("Error in page close event");
|
|
424
|
+
this.logger.error(error);
|
|
432
425
|
console.error("Error in page close event");
|
|
433
426
|
console.error(error);
|
|
434
427
|
}
|
|
@@ -439,8 +432,10 @@ export class BVTRecorder {
|
|
|
439
432
|
if (frame !== page.mainFrame()) return;
|
|
440
433
|
this.handlePageTransition();
|
|
441
434
|
} catch (error) {
|
|
435
|
+
this.logger.error("Error in handlePageTransition event");
|
|
436
|
+
this.logger.error(error);
|
|
442
437
|
console.error("Error in handlePageTransition event");
|
|
443
|
-
|
|
438
|
+
console.error(error);
|
|
444
439
|
}
|
|
445
440
|
try {
|
|
446
441
|
if (frame !== this.#activeFrame) return;
|
|
@@ -459,6 +454,8 @@ export class BVTRecorder {
|
|
|
459
454
|
// await this._setRecordingMode(frame);
|
|
460
455
|
// await this._initPage(page);
|
|
461
456
|
} catch (error) {
|
|
457
|
+
this.logger.error("Error in frame navigate event");
|
|
458
|
+
this.logger.error(error);
|
|
462
459
|
console.error("Error in frame navigate event");
|
|
463
460
|
// console.error(error);
|
|
464
461
|
}
|
|
@@ -541,13 +538,9 @@ export class BVTRecorder {
|
|
|
541
538
|
|
|
542
539
|
try {
|
|
543
540
|
const result = await client.send("Page.getNavigationHistory");
|
|
544
|
-
// console.log("Navigation History:", result);
|
|
545
541
|
const entries = result.entries;
|
|
546
542
|
const currentIndex = result.currentIndex;
|
|
547
543
|
|
|
548
|
-
// ignore if currentIndex is not the last entry
|
|
549
|
-
// if (currentIndex !== entries.length - 1) return;
|
|
550
|
-
|
|
551
544
|
const currentEntry = entries[currentIndex];
|
|
552
545
|
const transitionInfo = this.analyzeTransitionType(entries, currentIndex, currentEntry);
|
|
553
546
|
this.previousIndex = currentIndex;
|
|
@@ -560,6 +553,8 @@ export class BVTRecorder {
|
|
|
560
553
|
navigationAction: transitionInfo.action,
|
|
561
554
|
};
|
|
562
555
|
} catch (error) {
|
|
556
|
+
this.logger.error("Error in getCurrentTransition event");
|
|
557
|
+
this.logger.error(error);
|
|
563
558
|
console.error("Error in getTransistionType event", error);
|
|
564
559
|
} finally {
|
|
565
560
|
await client.detach();
|
|
@@ -628,6 +623,8 @@ export class BVTRecorder {
|
|
|
628
623
|
// add listener for frame navigation on new tab
|
|
629
624
|
this._addFrameNavigateListener(page);
|
|
630
625
|
} catch (error) {
|
|
626
|
+
this.logger.error("Error in page event");
|
|
627
|
+
this.logger.error(error);
|
|
631
628
|
console.error("Error in page event");
|
|
632
629
|
console.error(error);
|
|
633
630
|
}
|
|
@@ -669,6 +666,7 @@ export class BVTRecorder {
|
|
|
669
666
|
const { data } = await client.send("Page.captureScreenshot", { format: "png" });
|
|
670
667
|
return data;
|
|
671
668
|
} catch (error) {
|
|
669
|
+
this.logger.error("Error in taking browser screenshot");
|
|
672
670
|
console.error("Error in taking browser screenshot", error);
|
|
673
671
|
} finally {
|
|
674
672
|
await client.detach();
|
|
@@ -838,6 +836,7 @@ export class BVTRecorder {
|
|
|
838
836
|
BLINQ_ENV: this.envName,
|
|
839
837
|
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
840
838
|
CURRENT_STEP_ID: step.id,
|
|
839
|
+
DEBUG: "blinq:route",
|
|
841
840
|
};
|
|
842
841
|
|
|
843
842
|
this.bvtContext.navigate = true;
|
|
@@ -966,10 +965,11 @@ export class BVTRecorder {
|
|
|
966
965
|
if (existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
967
966
|
try {
|
|
968
967
|
const testData = JSON.parse(readFileSync(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
|
|
969
|
-
this.logger.info("Test data", testData);
|
|
968
|
+
// this.logger.info("Test data", testData);
|
|
970
969
|
this.sendEvent(this.events.getTestData, testData);
|
|
971
970
|
} catch (e) {
|
|
972
|
-
this.logger.error("Error reading test data file", e);
|
|
971
|
+
// this.logger.error("Error reading test data file", e);
|
|
972
|
+
console.log("Error reading test data file", e);
|
|
973
973
|
}
|
|
974
974
|
}
|
|
975
975
|
|
|
@@ -978,10 +978,12 @@ export class BVTRecorder {
|
|
|
978
978
|
this.watcher.on("all", async (event, path) => {
|
|
979
979
|
try {
|
|
980
980
|
const testData = JSON.parse(await readFile(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
|
|
981
|
-
this.logger.info("Test data", testData);
|
|
981
|
+
// this.logger.info("Test data", testData);
|
|
982
|
+
console.log("Test data changed", testData);
|
|
982
983
|
this.sendEvent(this.events.getTestData, testData);
|
|
983
984
|
} catch (e) {
|
|
984
|
-
this.logger.error("Error reading test data file", e);
|
|
985
|
+
// this.logger.error("Error reading test data file", e);
|
|
986
|
+
console.log("Error reading test data file", e);
|
|
985
987
|
}
|
|
986
988
|
});
|
|
987
989
|
}
|
|
@@ -1014,7 +1016,7 @@ export class BVTRecorder {
|
|
|
1014
1016
|
.filter((file) => file.endsWith(".feature"))
|
|
1015
1017
|
.map((file) => path.join(this.projectDir, "features", file));
|
|
1016
1018
|
try {
|
|
1017
|
-
const parsedFiles = featureFiles.map((file) => parseFeatureFile(file));
|
|
1019
|
+
const parsedFiles = featureFiles.map((file) => this.parseFeatureFile(file));
|
|
1018
1020
|
const output = {};
|
|
1019
1021
|
parsedFiles.forEach((file) => {
|
|
1020
1022
|
if (!file.feature) return;
|
|
@@ -1042,7 +1044,7 @@ export class BVTRecorder {
|
|
|
1042
1044
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
1043
1045
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
1044
1046
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
1045
|
-
const gherkinDoc = parseFeatureFile(featureFilePath);
|
|
1047
|
+
const gherkinDoc = this.parseFeatureFile(featureFilePath);
|
|
1046
1048
|
const scenario = gherkinDoc.feature.children.find((child) => child.scenario.name === scenarioName)?.scenario;
|
|
1047
1049
|
|
|
1048
1050
|
const steps = [];
|
|
@@ -1201,20 +1203,21 @@ export class BVTRecorder {
|
|
|
1201
1203
|
await this.cleanupExecution({ tags });
|
|
1202
1204
|
await this.initExecution({ tags });
|
|
1203
1205
|
}
|
|
1204
|
-
}
|
|
1205
1206
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1207
|
+
parseFeatureFile(featureFilePath) {
|
|
1208
|
+
try {
|
|
1209
|
+
let id = 0;
|
|
1210
|
+
const uuidFn = () => (++id).toString(16);
|
|
1211
|
+
const builder = new AstBuilder(uuidFn);
|
|
1212
|
+
const matcher = new GherkinClassicTokenMatcher();
|
|
1213
|
+
const parser = new Parser(builder, matcher);
|
|
1214
|
+
const source = readFileSync(featureFilePath, "utf8");
|
|
1215
|
+
const gherkinDocument = parser.parse(source);
|
|
1216
|
+
return gherkinDocument;
|
|
1217
|
+
} catch (e) {
|
|
1218
|
+
this.logger.error(`Error parsing feature file: ${featureFilePath}`);
|
|
1219
|
+
console.log(e);
|
|
1220
|
+
}
|
|
1221
|
+
return {};
|
|
1218
1222
|
}
|
|
1219
|
-
|
|
1220
|
-
};
|
|
1223
|
+
}
|
|
@@ -4,6 +4,7 @@ import { BVTRecorder } from "./bvt_recorder.js";
|
|
|
4
4
|
import { compareWithScenario } from "../code_gen/duplication_analysis.js";
|
|
5
5
|
import { getAppDataDir } from "./app_dir.js";
|
|
6
6
|
import { readdir } from "fs/promises";
|
|
7
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
7
8
|
|
|
8
9
|
let port = process.env.EDITOR_PORT || 3003;
|
|
9
10
|
const WS_URL = "http://localhost:" + port;
|
|
@@ -16,7 +17,9 @@ class PromisifiedSocketServer {
|
|
|
16
17
|
init() {
|
|
17
18
|
this.socket.on("request", async (data) => {
|
|
18
19
|
const { event, input, id, roomId, socketId } = data;
|
|
19
|
-
|
|
20
|
+
if (event !== "recorderWindow.getCurrentChromiumPath") {
|
|
21
|
+
socketLogger.info("Received request", { event, input, id, roomId, socketId });
|
|
22
|
+
}
|
|
20
23
|
try {
|
|
21
24
|
const handler = this.routes[event];
|
|
22
25
|
if (!handler) {
|
|
@@ -24,17 +27,12 @@ class PromisifiedSocketServer {
|
|
|
24
27
|
return;
|
|
25
28
|
}
|
|
26
29
|
const response = await handler(input);
|
|
27
|
-
|
|
30
|
+
if (event !== "recorderWindow.getCurrentChromiumPath") {
|
|
31
|
+
socketLogger.info(`Sending response`, { event, id, value: response, roomId, socketId });
|
|
32
|
+
}
|
|
28
33
|
this.socket.emit("response", { id, value: response, roomId, socketId });
|
|
29
34
|
} catch (error) {
|
|
30
|
-
|
|
31
|
-
console.error("response", { id, error, roomId, socketId });
|
|
32
|
-
// console.error({
|
|
33
|
-
// message: error?.message,
|
|
34
|
-
// code: error?.code,
|
|
35
|
-
// info: error?.info,
|
|
36
|
-
// stack: error?.stack,
|
|
37
|
-
// })
|
|
35
|
+
socketLogger.error("Error handling request", { event, input, id, roomId, socketId, error });
|
|
38
36
|
this.socket.emit("response", {
|
|
39
37
|
id,
|
|
40
38
|
error: {
|
|
@@ -51,45 +49,17 @@ class PromisifiedSocketServer {
|
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
function memorySizeOf(obj) {
|
|
55
|
-
var bytes = 0;
|
|
56
|
-
|
|
57
|
-
function sizeOf(obj) {
|
|
58
|
-
if (obj !== null && obj !== undefined) {
|
|
59
|
-
switch (typeof obj) {
|
|
60
|
-
case "number":
|
|
61
|
-
bytes += 8;
|
|
62
|
-
break;
|
|
63
|
-
case "string":
|
|
64
|
-
bytes += obj.length * 2;
|
|
65
|
-
break;
|
|
66
|
-
case "boolean":
|
|
67
|
-
bytes += 4;
|
|
68
|
-
break;
|
|
69
|
-
case "object":
|
|
70
|
-
var objClass = Object.prototype.toString.call(obj).slice(8, -1);
|
|
71
|
-
if (objClass === "Object" || objClass === "Array") {
|
|
72
|
-
for (var key in obj) {
|
|
73
|
-
if (!obj.hasOwnProperty(key)) continue;
|
|
74
|
-
sizeOf(obj[key]);
|
|
75
|
-
}
|
|
76
|
-
} else bytes += obj.toString().length * 2;
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return bytes;
|
|
81
|
-
}
|
|
82
|
-
return sizeOf(obj);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
52
|
const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
86
|
-
console.log("
|
|
53
|
+
console.log("Connecting to " + WS_URL);
|
|
87
54
|
const socket = io(WS_URL);
|
|
55
|
+
socketLogger.init(socket, { context: "BVTRecorder", eventName: "BVTRecorder.log" });
|
|
88
56
|
socket.on("connect", () => {
|
|
89
|
-
|
|
57
|
+
socketLogger.info("Connected to BVTRecorder server");
|
|
58
|
+
console.log("Connected to BVTRecorder server");
|
|
90
59
|
});
|
|
91
60
|
socket.on("disconnect", () => {
|
|
92
|
-
|
|
61
|
+
socketLogger.info("Disconnected from server");
|
|
62
|
+
console.log("Disconnected from server");
|
|
93
63
|
});
|
|
94
64
|
socket.emit("joinRoom", { id: roomId, window: "cucumber_client/bvt_recorder" });
|
|
95
65
|
const recorder = new BVTRecorder({
|
|
@@ -97,20 +67,19 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
97
67
|
projectDir,
|
|
98
68
|
TOKEN,
|
|
99
69
|
sendEvent: (event, data) => {
|
|
100
|
-
|
|
101
|
-
console.log("----", event, data, "roomId", roomId);
|
|
70
|
+
socketLogger.info("Sending event", { event, data, roomId });
|
|
102
71
|
socket.emit(event, data, roomId);
|
|
103
|
-
console.log("Successfully sent event", event, "to room", roomId);
|
|
104
72
|
},
|
|
73
|
+
logger: socketLogger,
|
|
105
74
|
});
|
|
106
75
|
recorder
|
|
107
76
|
.openBrowser()
|
|
108
77
|
.then(() => {
|
|
109
|
-
|
|
78
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
110
79
|
socket.emit("BVTRecorder.browserOpened", null, roomId);
|
|
111
80
|
})
|
|
112
81
|
.catch((e) => {
|
|
113
|
-
|
|
82
|
+
socketLogger.error("BVTRecorder.browserLaunchFailed", e);
|
|
114
83
|
socket.emit("BVTRecorder.browserLaunchFailed", e, roomId);
|
|
115
84
|
});
|
|
116
85
|
const timeOutForFunction = async (promise, timeout = 5000) => {
|
|
@@ -121,6 +90,7 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
121
90
|
return res;
|
|
122
91
|
} catch (error) {
|
|
123
92
|
console.error(error);
|
|
93
|
+
socketLogger.error(error);
|
|
124
94
|
throw error;
|
|
125
95
|
}
|
|
126
96
|
};
|
|
@@ -130,10 +100,13 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
130
100
|
return recorder
|
|
131
101
|
.openBrowser(input)
|
|
132
102
|
.then(() => {
|
|
103
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
104
|
+
console.info("BVTRecorder.browserOpened");
|
|
133
105
|
socket.emit("BVTRecorder.browserOpened", { roomId, window: "cucumber_client/bvt_recorder" });
|
|
134
106
|
})
|
|
135
107
|
.catch((e) => {
|
|
136
|
-
|
|
108
|
+
socketLogger.error("Error opening browser", e);
|
|
109
|
+
console.error("BVTRecorder.browserLaunchFailed", e);
|
|
137
110
|
socket.emit("BVTRecorder.browserLaunchFailed", { roomId, window: "cucumber_client/bvt_recorder" });
|
|
138
111
|
});
|
|
139
112
|
},
|
|
@@ -144,10 +117,12 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
144
117
|
return recorder
|
|
145
118
|
.reOpenBrowser(input)
|
|
146
119
|
.then(() => {
|
|
147
|
-
|
|
120
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
121
|
+
console.log("BVTRecorder.browserOpened");
|
|
148
122
|
socket.emit("BVTRecorder.browserOpened", null, roomId);
|
|
149
123
|
})
|
|
150
124
|
.catch((e) => {
|
|
125
|
+
socketLogger.info("BVTRecorder.browserLaunchFailed");
|
|
151
126
|
console.error("BVTRecorder.browserLaunchFailed", e);
|
|
152
127
|
socket.emit("BVTRecorder.browserLaunchFailed", null, roomId);
|
|
153
128
|
});
|
|
@@ -247,9 +222,7 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
247
222
|
"recorderWindow.getSnapshotFiles": async (input) => {
|
|
248
223
|
const snapshotFolder = recorder.getSnapshotFolder();
|
|
249
224
|
if (snapshotFolder) {
|
|
250
|
-
// Get the list of filenames in the snapshot folder
|
|
251
225
|
const files = await readdir(snapshotFolder);
|
|
252
|
-
// Filter the files to only include .png files
|
|
253
226
|
const ymlFiles = files.filter((file) => file.endsWith(".yml") || file.endsWith(".yaml"));
|
|
254
227
|
return { folder: snapshotFolder, files: ymlFiles };
|
|
255
228
|
} else return { folder: null, files: [] };
|
|
@@ -318,7 +291,6 @@ try {
|
|
|
318
291
|
showUsage(error, usage);
|
|
319
292
|
}
|
|
320
293
|
try {
|
|
321
|
-
// console.log({ envName, projectDir, featureName, scenarioName, stepIndex, roomId })
|
|
322
294
|
init({
|
|
323
295
|
envName,
|
|
324
296
|
projectDir,
|
|
@@ -15,20 +15,7 @@ export class NamesService {
|
|
|
15
15
|
if (!screenshot && commands.length > 1) {
|
|
16
16
|
screenshot = this.screenshotMap.get(commands[commands.length - 2].inputID);
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
"data: " +
|
|
20
|
-
JSON.stringify(
|
|
21
|
-
{
|
|
22
|
-
commands,
|
|
23
|
-
stepsNames,
|
|
24
|
-
parameters,
|
|
25
|
-
map,
|
|
26
|
-
},
|
|
27
|
-
null,
|
|
28
|
-
2
|
|
29
|
-
)
|
|
30
|
-
);
|
|
31
|
-
// get screenshot for the last command
|
|
18
|
+
|
|
32
19
|
const url = `${getRunsServiceBaseURL()}/generate-step-information/generate`;
|
|
33
20
|
const TIMEOUT = 120; // 2 minutes
|
|
34
21
|
const { data } = await axiosClient({
|
|
@@ -65,6 +52,7 @@ export class NamesService {
|
|
|
65
52
|
}
|
|
66
53
|
} catch (error) {
|
|
67
54
|
if (i === TIMEOUT - 1) {
|
|
55
|
+
this.logger.error("Timeout while generating step details: ", error);
|
|
68
56
|
console.error("Timeout while generating step details: ", error);
|
|
69
57
|
}
|
|
70
58
|
}
|
|
@@ -96,7 +84,6 @@ export class NamesService {
|
|
|
96
84
|
scenario: scenarioAsText,
|
|
97
85
|
};
|
|
98
86
|
|
|
99
|
-
this.logger.info("data: " + JSON.stringify(genObject, null, 2));
|
|
100
87
|
// get screenshot for the last command
|
|
101
88
|
const url = `${getRunsServiceBaseURL()}/generate-step-information/generate_scenario_feature`;
|
|
102
89
|
const TIMEOUT = 120; // 2 minutes
|
|
@@ -140,6 +127,7 @@ export class NamesService {
|
|
|
140
127
|
if (result.status !== 200) {
|
|
141
128
|
return { success: false, message: "Error while generating step details" };
|
|
142
129
|
}
|
|
130
|
+
|
|
143
131
|
return result.data;
|
|
144
132
|
}
|
|
145
133
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} SocketLoggerEventPayload
|
|
3
|
+
* @property {string} level Log level (e.g. "info", "warn", "error", "debug")
|
|
4
|
+
* @property {string} context Log context/subsystem (e.g. "BVTRecorder")
|
|
5
|
+
* @property {*} data The log message payload (string, object, etc)
|
|
6
|
+
* @property {string} timestamp ISO string when the log was emitted
|
|
7
|
+
* @property {number} dataSize Size of data in bytes (-1 if unknown)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} SocketLoggerInitOptions
|
|
12
|
+
* @property {string=} context Default context for all logs (optional)
|
|
13
|
+
* @property {string=} eventName Default event name (default: "recorder.log")
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* SocketLogger - Singleton for structured socket-based logging.
|
|
18
|
+
*
|
|
19
|
+
* @namespace SocketLogger
|
|
20
|
+
* @property {function(import('socket.io-client').Socket|import('socket.io').Socket, SocketLoggerInitOptions=):void} init
|
|
21
|
+
* @property {function(string, (string|*), Object=, string=, string=):void} log
|
|
22
|
+
* @property {function((string|*), Object=):void} info
|
|
23
|
+
* @property {function((string|*), Object=):void} warn
|
|
24
|
+
* @property {function((string|*), Object=):void} debug
|
|
25
|
+
* @property {function((string|*), Object=):void} error
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* import logger from "./socket_logger.js";
|
|
29
|
+
* logger.init(socket, { context: "BVTRecorder" });
|
|
30
|
+
* logger.info("Step started", { step: 2 });
|
|
31
|
+
* logger.error("Failed!", { error: "bad stuff" });
|
|
32
|
+
*/
|
|
33
|
+
const SocketLogger = (function () {
|
|
34
|
+
/** @type {import('socket.io-client').Socket|import('socket.io').Socket|null} */
|
|
35
|
+
let socket = null;
|
|
36
|
+
/** @type {string} */
|
|
37
|
+
let defaultContext = "";
|
|
38
|
+
/** @type {string} */
|
|
39
|
+
let defaultEventName = "recorder.log";
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Initialize the logger (call once).
|
|
43
|
+
* @param {import('socket.io-client').Socket|import('socket.io').Socket} sock
|
|
44
|
+
* @param {SocketLoggerInitOptions=} opts
|
|
45
|
+
*/
|
|
46
|
+
function init(sock, opts) {
|
|
47
|
+
socket = sock;
|
|
48
|
+
defaultContext = (opts && opts.context) || "";
|
|
49
|
+
defaultEventName = (opts && opts.eventName) || "recorder.log";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Low-level log method (most users use info/warn/debug/error).
|
|
54
|
+
* @param {string} level Log level ("info", "warn", "debug", "error")
|
|
55
|
+
* @param {string|*} message The log message or object
|
|
56
|
+
* @param {Object=} extra Extra fields (will be merged into log payload)
|
|
57
|
+
* @param {string=} eventName Override event name for this log (default: "recorder.log")
|
|
58
|
+
* @param {string=} context Override log context for this log (default: set in init)
|
|
59
|
+
*/
|
|
60
|
+
function log(level, message, extra, eventName, context) {
|
|
61
|
+
if (!socket || typeof socket.emit !== "function") return;
|
|
62
|
+
/** @type {*} */
|
|
63
|
+
var data = typeof message === "object" ? message : { message: message };
|
|
64
|
+
/** @type {number} */
|
|
65
|
+
var dataSize = 0;
|
|
66
|
+
try {
|
|
67
|
+
dataSize = Buffer.byteLength(JSON.stringify(data || ""), "utf8");
|
|
68
|
+
} catch (e) {
|
|
69
|
+
dataSize = -1;
|
|
70
|
+
}
|
|
71
|
+
/** @type {SocketLoggerEventPayload} */
|
|
72
|
+
var eventPayload = Object.assign(
|
|
73
|
+
{
|
|
74
|
+
level: level,
|
|
75
|
+
context: context || defaultContext,
|
|
76
|
+
data: data,
|
|
77
|
+
timestamp: new Date().toISOString(),
|
|
78
|
+
dataSize: dataSize,
|
|
79
|
+
},
|
|
80
|
+
extra || {}
|
|
81
|
+
);
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
try {
|
|
84
|
+
if (socket) {
|
|
85
|
+
socket.emit(eventName || defaultEventName, eventPayload);
|
|
86
|
+
}
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error("Socket logging error:", e);
|
|
89
|
+
console.log("Socket event payload:", eventPayload);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Write an info-level log event.
|
|
95
|
+
* @param {string|*} msg The message or object
|
|
96
|
+
* @param {Object=} ext Any extra fields/metadata
|
|
97
|
+
*/
|
|
98
|
+
function info(msg, ext) {
|
|
99
|
+
log("info", msg, ext);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Write a warn-level log event.
|
|
104
|
+
* @param {string|*} msg The message or object
|
|
105
|
+
* @param {Object=} ext Any extra fields/metadata
|
|
106
|
+
*/
|
|
107
|
+
function warn(msg, ext) {
|
|
108
|
+
log("warn", msg, ext);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Write a debug-level log event.
|
|
113
|
+
* @param {string|*} msg The message or object
|
|
114
|
+
* @param {Object=} ext Any extra fields/metadata
|
|
115
|
+
*/
|
|
116
|
+
function debug(msg, ext) {
|
|
117
|
+
log("debug", msg, ext);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Write an error-level log event.
|
|
122
|
+
* @param {string|*} msg The message or object
|
|
123
|
+
* @param {Object=} ext Any extra fields/metadata
|
|
124
|
+
*/
|
|
125
|
+
function error(msg, ext) {
|
|
126
|
+
log("error", msg, ext);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return { init, log, info, warn, debug, error };
|
|
130
|
+
})();
|
|
131
|
+
|
|
132
|
+
export default SocketLogger;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev-blinq/cucumber_client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1419-dev",
|
|
4
4
|
"description": " ",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"types": "bin/index.d.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@cucumber/tag-expressions": "^6.1.1",
|
|
35
35
|
"@dev-blinq/cucumber-js": "1.0.184-dev",
|
|
36
36
|
"@faker-js/faker": "^8.1.0",
|
|
37
|
-
"automation_model": "1.0.
|
|
37
|
+
"automation_model": "1.0.825-dev",
|
|
38
38
|
"axios": "^1.7.4",
|
|
39
39
|
"chokidar": "^3.6.0",
|
|
40
40
|
"create-require": "^1.1.1",
|