@dev-blinq/cucumber_client 1.0.1437-stage → 1.0.1438-stage

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.
@@ -1,7 +1,6 @@
1
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
2
- import path from "path";
3
- import url from "url";
4
- import logger from "../../logger.js";
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import url from "node:url";
5
4
  import { CodePage, getAiConfig } from "../code_gen/page_reflection.js";
6
5
  import { generateCode, generatePageName } from "../code_gen/playwright_codeget.js";
7
6
  import { invertCodeToCommand } from "../code_gen/code_inversion.js";
@@ -9,8 +8,9 @@ import { Step } from "../cucumber/feature.js";
9
8
  import { locateDefinitionPath, StepsDefinitions } from "../cucumber/steps_definitions.js";
10
9
  import { Recording } from "../recording.js";
11
10
  import { generateApiCode } from "../code_gen/api_codegen.js";
12
- import { tmpdir } from "os";
13
- import { createHash } from "crypto";
11
+ import { tmpdir } from "node:os";
12
+ import { createHash } from "node:crypto";
13
+ import { getErrorMessage } from "../utils/socket_logger.js";
14
14
 
15
15
  const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
16
16
 
@@ -495,7 +495,15 @@ function makeStepTextUnique(step, stepsDefinitions) {
495
495
  step.text = stepText;
496
496
  }
497
497
 
498
- export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap }) {
498
+ export async function saveRecording({
499
+ step,
500
+ cucumberStep,
501
+ codePage,
502
+ projectDir,
503
+ stepsDefinitions,
504
+ parametersMap,
505
+ logger,
506
+ }) {
499
507
  if (step.commands && Array.isArray(step.commands)) {
500
508
  step.commands = step.commands.map((cmd) => toRecordingStep(cmd, parametersMap, step.text));
501
509
  }
@@ -506,21 +514,19 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
506
514
  rmSync(routesPath, { recursive: true });
507
515
  }
508
516
  mkdirSync(routesPath, { recursive: true });
509
- saveRoutes({ step, folderPath: routesPath });
517
+ saveRoutes({ step, folderPath: routesPath }, logger);
510
518
  } else {
511
519
  if (existsSync(routesPath)) {
512
- // remove the folder
513
520
  try {
514
521
  rmSync(routesPath, { recursive: true });
515
- //
516
522
  } catch (error) {
517
- //
523
+ logger.error(`Error removing temp routes folder: ${getErrorMessage(error)}`);
518
524
  }
519
525
  routesPath = path.join(projectDir, "data", "routes");
520
526
  if (!existsSync(routesPath)) {
521
527
  mkdirSync(routesPath, { recursive: true });
522
528
  }
523
- saveRoutes({ step, folderPath: routesPath });
529
+ saveRoutes({ step, folderPath: routesPath }, logger);
524
530
  }
525
531
  }
526
532
 
@@ -529,7 +535,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
529
535
  }
530
536
 
531
537
  if (step.isImplemented && step.shouldOverride) {
532
- let stepDef = stepsDefinitions.findMatchingStep(step.text);
538
+ const stepDef = stepsDefinitions.findMatchingStep(step.text);
533
539
  codePage = getCodePage(stepDef.file);
534
540
  } else {
535
541
  const isUtilStep = makeStepTextUnique(step, stepsDefinitions);
@@ -555,21 +561,20 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
555
561
  rmSync(routesPath, { recursive: true });
556
562
  }
557
563
  mkdirSync(routesPath, { recursive: true });
558
- saveRoutes({ step, folderPath: routesPath });
564
+ saveRoutes({ step, folderPath: routesPath }, logger);
559
565
  } else {
560
566
  if (existsSync(routesPath)) {
561
- // remove the folder
562
567
  try {
563
568
  rmSync(routesPath, { recursive: true });
564
569
  } catch (error) {
565
- //
570
+ logger.error(`Error removing temp routes folder: ${getErrorMessage(error)}`);
566
571
  }
567
572
  }
568
573
  routesPath = path.join(projectDir, "data", "routes");
569
574
  if (!existsSync(routesPath)) {
570
575
  mkdirSync(routesPath, { recursive: true });
571
576
  }
572
- saveRoutes({ step, folderPath: routesPath });
577
+ saveRoutes({ step, folderPath: routesPath }, logger);
573
578
  }
574
579
 
575
580
  cucumberStep.text = step.text;
@@ -638,7 +643,6 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
638
643
  } else {
639
644
  const generateCodeResult = generateCode(recording, codePage, userData, projectDir, methodName);
640
645
  if (generateCodeResult.noCode === true) {
641
- logger.log("No code generated for step: " + step.text);
642
646
  return generateCodeResult.page;
643
647
  }
644
648
  codePage = generateCodeResult.page;
@@ -747,7 +751,7 @@ export const getCommandsForImplementedStep = (stepName, stepsDefinitions, stepPa
747
751
  const file = step?.file;
748
752
  const locatorsJson = getLocatorsJson(file);
749
753
  if (!step) {
750
- throw new Error("Step definition not found" + stepName);
754
+ throw new Error(`Step definition not found: ${stepName}`);
751
755
  }
752
756
  isImplemented = true;
753
757
  const { codeCommands, codePage, elements, parametersNames, error } =
@@ -831,7 +835,7 @@ export async function executeStep({ stepsDefinitions, cucumberStep, context, cod
831
835
  }
832
836
  }
833
837
 
834
- export async function updateStepDefinitions({ scenario, featureName, projectDir }) {
838
+ export async function updateStepDefinitions({ scenario, featureName, projectDir, logger }) {
835
839
  // set the candidate step definition file name
836
840
  // set the utils file path
837
841
  const utilsFilePath = path.join(projectDir, "features", "step_definitions", "utils.mjs");
@@ -865,32 +869,25 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
865
869
  if ((step.isImplemented && !step.shouldOverride) || step.commands.length === 0) {
866
870
  let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
867
871
  if (process.env.TEMP_RUN === "true") {
868
- console.log("Save routes in temp folder for running:", routesPath);
869
872
  if (existsSync(routesPath)) {
870
- console.log("Removing existing temp_routes_folder:", routesPath);
871
873
  routesPath = path.join(tmpdir(), `blinq_temp_routes`);
872
874
  rmSync(routesPath, { recursive: true });
873
875
  }
874
876
  mkdirSync(routesPath, { recursive: true });
875
- console.log("Created temp_routes_folder:", routesPath);
876
- saveRoutes({ step, folderPath: routesPath });
877
+ saveRoutes({ step, folderPath: routesPath }, logger);
877
878
  } else {
878
- console.log("Saving routes in project directory:", projectDir);
879
879
  if (existsSync(routesPath)) {
880
- // remove the folder
881
880
  try {
882
881
  rmSync(routesPath, { recursive: true });
883
- console.log("Removed temp_routes_folder:", routesPath);
884
882
  } catch (error) {
885
- console.error("Error removing temp_routes folder", error);
883
+ logger.error(`Error removing temp routes folder: ${getErrorMessage(error)}`);
886
884
  }
887
885
  }
888
886
  routesPath = path.join(projectDir, "data", "routes");
889
- console.log("Saving routes to:", routesPath);
890
887
  if (!existsSync(routesPath)) {
891
888
  mkdirSync(routesPath, { recursive: true });
892
889
  }
893
- saveRoutes({ step, folderPath: routesPath });
890
+ saveRoutes({ step, folderPath: routesPath }, logger);
894
891
  }
895
892
  if (step.commands && Array.isArray(step.commands)) {
896
893
  step.commands = step.commands.map((cmd) => toRecordingStep(cmd, scenario.parametersMap));
@@ -900,7 +897,6 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
900
897
  const cucumberStep = getCucumberStep({ step });
901
898
  const pageName = generatePageName(step.startFrame?.url ?? "default");
902
899
  const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
903
- // path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
904
900
  let codePage = getCodePage(stepDefsFilePath);
905
901
  codePage = await saveRecording({
906
902
  step,
@@ -921,7 +917,7 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
921
917
  writeFileSync(utilsFilePath, utilsContent, "utf8");
922
918
  }
923
919
 
924
- export function saveRoutes({ step, folderPath }) {
920
+ export function saveRoutes({ step, folderPath }, logger) {
925
921
  const routeItems = step.routeItems;
926
922
  if (!routeItems || routeItems.length === 0) {
927
923
  return;
@@ -944,21 +940,18 @@ export function saveRoutes({ step, folderPath }) {
944
940
  };
945
941
  });
946
942
 
947
- const routesFilePath = path.join(folderPath, stepNameHash + ".json");
948
- console.log("Routes file path:", routesFilePath);
943
+ const routesFilePath = path.join(folderPath, `${stepNameHash}.json`);
949
944
  const routesData = {
950
945
  template,
951
946
  routes: routeItemsWithFilters,
952
947
  };
953
- console.log("Routes data to save:", routesData);
954
948
 
955
949
  if (!existsSync(folderPath)) {
956
950
  mkdirSync(folderPath, { recursive: true });
957
951
  }
958
952
  try {
959
953
  writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), "utf8");
960
- console.log("Saved routes to", routesFilePath);
961
954
  } catch (error) {
962
- console.error("Failed to save routes to", routesFilePath, "Error:", error);
955
+ logger.error(`Error saving routes to ${routesFilePath}: ${getErrorMessage(error)}`);
963
956
  }
964
957
  }
@@ -1,8 +1,9 @@
1
- import { existsSync, readFileSync, writeFileSync } from "fs";
2
- import path from "path";
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
3
  import { getDefaultPrettierConfig } from "../code_cleanup/utils.js";
4
4
  import prettier from "prettier";
5
- export function containsScenario({ featureFileContent, scenarioName }) {
5
+
6
+ function containsScenario({ featureFileContent, scenarioName }) {
6
7
  const lines = featureFileContent.split("\n");
7
8
  for (const line of lines) {
8
9
  const trimmedLine = line.trim();
@@ -14,7 +15,7 @@ export function containsScenario({ featureFileContent, scenarioName }) {
14
15
  }
15
16
  }
16
17
 
17
- export function testStringForRegex(text) {
18
+ function testStringForRegex(text) {
18
19
  const regexEndPattern = /\/([gimuy]*)$/;
19
20
  if (text.startsWith("/")) {
20
21
  const match = regexEndPattern.test(text);
@@ -31,7 +32,7 @@ export function testStringForRegex(text) {
31
32
  return false;
32
33
  }
33
34
 
34
- const escapeNonPrintables = (text) => {
35
+ function escapeNonPrintables(text) {
35
36
  const t = text.replace(/\n/g, "\\n").replace(/\t/g, "\\t"); // .replace(/\|/g, "\\|");
36
37
  let result = "";
37
38
  // replace \ with \\ and | with \|
@@ -60,8 +61,9 @@ const escapeNonPrintables = (text) => {
60
61
  }
61
62
  }
62
63
  return result;
63
- };
64
- export function getCommandContent(command) {
64
+ }
65
+
66
+ function getCommandContent(command) {
65
67
  switch (command.type) {
66
68
  case "click_element": {
67
69
  return `${command.count === 2 ? "Double click" : "Click"} on ${escapeNonPrintables(command.element.name)}`;
@@ -108,15 +110,15 @@ export function getCommandContent(command) {
108
110
  }
109
111
  }
110
112
 
111
- export function getExamplesContent(parametersMap, datasets) {
113
+ function getExamplesContent(parametersMap, datasets) {
112
114
  if (datasets && datasets.length > 0) {
113
- let result = ''
115
+ let result = "";
114
116
  const keys = Object.keys(parametersMap);
115
117
  result += "\t\tExamples:\n";
116
118
 
117
119
  result += `\t\t| ${keys.join(" | ")} |\n`;
118
120
  for (const dataset of datasets) {
119
- result += `\t\t| ${dataset.data.map(d => escapeNonPrintables(d.value)).join(" | ")} |\n`;
121
+ result += `\t\t| ${dataset.data.map((d) => escapeNonPrintables(d.value)).join(" | ")} |\n`;
120
122
  }
121
123
  return result;
122
124
  }
@@ -155,19 +157,19 @@ function getTagsContent(scenario, featureFileObject) {
155
157
  return tagsContent;
156
158
  }
157
159
 
158
- export function getScenarioContent({ scenario }, featureFileObject) {
160
+ function getScenarioContent({ scenario }, featureFileObject) {
159
161
  const prametersMap = scenario.parametersMap ?? {};
160
162
  const isParmatersMapEmpty = Object.keys(prametersMap).length === 0;
161
163
  let scenarioContent = isParmatersMapEmpty ? `Scenario: ${scenario.name}\n` : `Scenario Outline: ${scenario.name}\n`;
162
164
 
163
- let tagsContent = getTagsContent(scenario, featureFileObject);
165
+ const tagsContent = getTagsContent(scenario, featureFileObject);
164
166
 
165
- scenarioContent = "\t" + tagsContent + "\n" + scenarioContent;
167
+ scenarioContent = `\t${tagsContent}\n${scenarioContent}`;
166
168
 
167
169
  for (const step of scenario.steps) {
168
170
  const commands = step.commands ?? [];
169
- let commentContents = commands.map(getCommandContent).map(escapeNonPrintables);
170
- let commentContent = commentContents.filter((content) => content.length > 0).join(", ");
171
+ const commentContents = commands.map(getCommandContent).map(escapeNonPrintables);
172
+ const commentContent = commentContents.filter((content) => content.length > 0).join(", ");
171
173
 
172
174
  if (commentContent) {
173
175
  scenarioContent += `\t# ${commentContent}\n`;
@@ -179,14 +181,15 @@ export function getScenarioContent({ scenario }, featureFileObject) {
179
181
  }
180
182
  return scenarioContent;
181
183
  }
182
- export const escapeString = (str) => {
184
+
185
+ function escapeString(str) {
183
186
  // Step 1: Replace all literal newline characters with a temporary placeholder
184
187
  const placeholder = "\\n";
185
188
  str = str.replace(/\n/g, placeholder);
186
189
  return str;
187
- };
190
+ }
188
191
 
189
- const GherkinToObject = (gherkin) => {
192
+ function GherkinToObject(gherkin) {
190
193
  const obj = {
191
194
  featureName: "",
192
195
  scenarios: [],
@@ -222,7 +225,7 @@ const GherkinToObject = (gherkin) => {
222
225
  }
223
226
 
224
227
  const getScenario = () => {
225
- let scenario = {
228
+ const scenario = {
226
229
  name: "",
227
230
  tags: [],
228
231
  steps: [],
@@ -299,7 +302,7 @@ const GherkinToObject = (gherkin) => {
299
302
  skipEmptyLines();
300
303
  }
301
304
  return obj;
302
- };
305
+ }
303
306
 
304
307
  // remove lines starting with "Scenario:" or "Scenario Outline:" that contain the scenario name until the next scenario and then append the new scenario content
305
308
  // assumes that there are no multiple scenarios with the same name and having comments and tags in each scenario
@@ -333,14 +336,14 @@ function updateExistingScenario({
333
336
  continue;
334
337
  }
335
338
 
336
- let scenarioHeader = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
339
+ const scenarioHeader = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
337
340
  let tagsLine;
338
341
 
339
342
  if (scenario.tags?.length > 0) {
340
343
  tagsLine = scenario.tags.map((t) => `@${t}`).join(" ");
341
344
  }
342
345
 
343
- if (tagsLine) results.push("\t" + tagsLine);
346
+ if (tagsLine) results.push(`\t${tagsLine}`);
344
347
  results.push(`\t${scenarioHeader}`);
345
348
 
346
349
  for (const step of scenario.steps) {
@@ -359,8 +362,8 @@ function updateExistingScenario({
359
362
  return results.join("\n");
360
363
  }
361
364
 
362
- export async function updateFeatureFile({ featureName, scenario, override, projectDir }) {
363
- const featureFilePath = path.join(projectDir, "features", featureName + ".feature");
365
+ async function updateFeatureFile({ featureName, scenario, override, projectDir, logger }) {
366
+ const featureFilePath = path.join(projectDir, "features", `${featureName}.feature`);
364
367
  const isFeatureFileExists = existsSync(featureFilePath);
365
368
  const scenarioContent = getScenarioContent(
366
369
  { scenario },
@@ -391,13 +394,13 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
391
394
  plugins: ["prettier-plugin-gherkin"],
392
395
  });
393
396
  } catch (error) {
394
- console.error("Error formatting feature file content with Prettier:", error);
397
+ logger.error("Error formatting feature file content with Prettier:", error);
395
398
  }
396
399
  writeFileSync(featureFilePath, updatedFeatureFileContent);
397
400
  return;
398
401
  }
399
402
  }
400
- let updatedFeatureFileContent = featureFileContent + "\n" + scenarioContent;
403
+ let updatedFeatureFileContent = `${featureFileContent}\n${scenarioContent}`;
401
404
  try {
402
405
  updatedFeatureFileContent = await prettier.format(updatedFeatureFileContent, {
403
406
  ...prettierConfig,
@@ -405,7 +408,7 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
405
408
  plugins: ["prettier-plugin-gherkin"],
406
409
  });
407
410
  } catch (error) {
408
- console.error("Error formatting feature file content with Prettier:", error);
411
+ logger.error("Error formatting feature file content with Prettier:", error);
409
412
  }
410
413
  writeFileSync(featureFilePath, updatedFeatureFileContent);
411
414
  } else {
@@ -417,8 +420,22 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
417
420
  plugins: ["prettier-plugin-gherkin"],
418
421
  });
419
422
  } catch (error) {
420
- console.error("Error formatting feature file content with Prettier:", error);
423
+ logger.error("Error formatting feature file content with Prettier:", error);
421
424
  }
422
425
  writeFileSync(featureFilePath, featureFileContent);
423
426
  }
424
427
  }
428
+
429
+ export {
430
+ containsScenario,
431
+ testStringForRegex,
432
+ escapeNonPrintables,
433
+ getCommandContent,
434
+ getExamplesContent,
435
+ getTagsContent,
436
+ getScenarioContent,
437
+ escapeString,
438
+ GherkinToObject,
439
+ updateExistingScenario,
440
+ updateFeatureFile,
441
+ };
@@ -0,0 +1,21 @@
1
+ import path from "node:path";
2
+ import os from "node:os";
3
+ function getAppDataDir(project_id) {
4
+ if (process.env.BLINQ_APPDATA_DIR) {
5
+ return path.join(process.env.BLINQ_APPDATA_DIR, "blinq.io", project_id);
6
+ }
7
+ let appDataDir;
8
+ switch (process.platform) {
9
+ case "win32":
10
+ appDataDir = path.join(process.env.APPDATA, "blinq.io", project_id);
11
+ break;
12
+ case "darwin":
13
+ appDataDir = path.join(os.homedir(), "Library", "Application Support", "blinq.io", project_id);
14
+ break;
15
+ default:
16
+ appDataDir = path.join(os.homedir(), ".config", "blinq.io", project_id);
17
+ break;
18
+ }
19
+ return appDataDir;
20
+ }
21
+ export { getAppDataDir };
@@ -1,132 +1,94 @@
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
-
1
+ function getErrorMessage(err) {
2
+ if (typeof err === "string") {
3
+ return err;
4
+ }
5
+ else if (err instanceof Error) {
6
+ return err.message;
7
+ }
8
+ else {
9
+ try {
10
+ return JSON.stringify(err);
11
+ }
12
+ catch {
13
+ return String(err);
14
+ }
15
+ }
16
+ }
16
17
  /**
17
18
  * SocketLogger - Singleton for structured socket-based logging.
18
19
  *
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
20
  * @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" });
21
+ * import SocketLogger from "./socket_logger";
22
+ * SocketLogger.getInstance().init(socket, { context: "BVTRecorder" });
23
+ * SocketLogger.getInstance().info("Step started", { step: 2 });
24
+ * SocketLogger.getInstance().error("Failed!", { error: "bad stuff" });
32
25
  */
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;
26
+ export class SocketLogger {
27
+ static instance;
28
+ socket = null;
29
+ defaultContext = "BVTRecorder";
30
+ defaultEventName = "BVTRecorder.log";
31
+ constructor() { }
32
+ static getInstance() {
33
+ if (!SocketLogger.instance) {
34
+ SocketLogger.instance = new SocketLogger();
35
+ }
36
+ return SocketLogger.instance;
37
+ }
38
+ init(sock, opts) {
39
+ this.socket = sock;
40
+ this.defaultContext = opts?.context || "";
41
+ this.defaultEventName = opts?.eventName || "recorder.log";
42
+ }
43
+ log(level, message, extra, context) {
44
+ if (!this.socket || typeof this.socket.emit !== "function")
45
+ return;
46
+ const data = typeof message === "object" ? message : { message };
47
+ let dataSize = 0;
48
+ try {
49
+ dataSize = Buffer.byteLength(JSON.stringify(data || ""), "utf8");
50
+ }
51
+ catch {
52
+ dataSize = -1;
53
+ }
54
+ const eventPayload = {
55
+ level,
56
+ context: context || this.defaultContext,
57
+ data: JSON.stringify({
58
+ ...data,
59
+ errorMessage: level === "error" && data ? getErrorMessage(data) : undefined,
60
+ }),
61
+ timestamp: new Date().toISOString(),
62
+ dataSize,
63
+ ...extra,
64
+ };
65
+ try {
66
+ if (this.socket) {
67
+ this.socket.emit(this.defaultEventName, eventPayload);
68
+ }
69
+ console.log(`${context ?? this.defaultContext} [${level.toUpperCase()}]:`, {
70
+ ...data,
71
+ ...extra,
72
+ });
73
+ }
74
+ catch (e) {
75
+ console.error("Socket logging error:", e);
76
+ console.log("Socket event payload:", eventPayload);
77
+ }
78
+ }
79
+ info(msg, ext, ctx) {
80
+ this.log("info", msg, ext, ctx);
81
+ }
82
+ warn(msg, ext, ctx) {
83
+ this.log("warn", msg, ext, ctx);
84
+ }
85
+ debug(msg, ext, ctx) {
86
+ this.log("debug", msg, ext, ctx);
70
87
  }
71
- /** @type {SocketLoggerEventPayload} */
72
- var eventPayload = Object.assign(
73
- {
74
- level: level,
75
- context: context || defaultContext,
76
- data: JSON.stringify(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);
88
+ error(msg, ext, ctx) {
89
+ this.log("error", msg, ext, ctx);
90
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;
91
+ }
92
+ const socketLoggerInstance = SocketLogger.getInstance();
93
+ export default socketLoggerInstance;
94
+ export { getErrorMessage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-blinq/cucumber_client",
3
- "version": "1.0.1437-stage",
3
+ "version": "1.0.1438-stage",
4
4
  "description": " ",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -14,6 +14,8 @@
14
14
  "tests_prod": "rm -rf results.json && cross-env NODE_ENV_BLINQ=prod TOKEN=xxx npx mocha --parallel --jobs=10 ./tests",
15
15
  "tests": "node ./multi_test_runner.js",
16
16
  "lint": "eslint ./src/**/*.js",
17
+ "test:unit": "vitest run",
18
+ "test:unit:watch": "vitest watch",
17
19
  "clean_old": "rimraf -g build1 && rimraf -g types1",
18
20
  "clean": "rimraf -g build && rimraf -g types",
19
21
  "build_old": "npm run clean_old && npm run pack_old",
@@ -77,6 +79,8 @@
77
79
  "readline-sync": "^1.4.10",
78
80
  "ts-node": "^10.9.2",
79
81
  "tsup": "^8.5.0",
80
- "typescript": "^5.9.2"
82
+ "typescript": "^5.9.2",
83
+ "vite-tsconfig-paths": "^6.0.4",
84
+ "vitest": "^2.1.4"
81
85
  }
82
86
  }