@dev-blinq/cucumber_client 1.0.1346-dev → 1.0.1346-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.
Files changed (53) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +107 -107
  2. package/bin/assets/preload/css_gen.js +10 -10
  3. package/bin/assets/preload/recorderv3.js +3 -1
  4. package/bin/assets/preload/toolbar.js +27 -29
  5. package/bin/assets/preload/unique_locators.js +1 -1
  6. package/bin/assets/preload/yaml.js +288 -275
  7. package/bin/assets/scripts/aria_snapshot.js +223 -220
  8. package/bin/assets/scripts/dom_attr.js +329 -329
  9. package/bin/assets/scripts/dom_parent.js +169 -174
  10. package/bin/assets/scripts/event_utils.js +94 -94
  11. package/bin/assets/scripts/pw.js +2050 -1949
  12. package/bin/assets/scripts/recorder.js +12 -22
  13. package/bin/assets/scripts/snapshot_capturer.js +153 -146
  14. package/bin/assets/scripts/unique_locators.js +941 -815
  15. package/bin/assets/scripts/yaml.js +796 -783
  16. package/bin/assets/templates/_hooks_template.txt +41 -0
  17. package/bin/assets/templates/utils_template.txt +2 -45
  18. package/bin/client/apiTest/apiTest.js +6 -0
  19. package/bin/client/cli_helpers.js +11 -13
  20. package/bin/client/code_cleanup/utils.js +5 -1
  21. package/bin/client/code_gen/api_codegen.js +2 -2
  22. package/bin/client/code_gen/code_inversion.js +112 -4
  23. package/bin/client/code_gen/page_reflection.js +839 -906
  24. package/bin/client/code_gen/playwright_codeget.js +25 -11
  25. package/bin/client/cucumber/feature.js +89 -27
  26. package/bin/client/cucumber/feature_data.js +2 -2
  27. package/bin/client/cucumber/project_to_document.js +9 -3
  28. package/bin/client/cucumber/steps_definitions.js +6 -3
  29. package/bin/client/cucumber_selector.js +17 -1
  30. package/bin/client/local_agent.js +6 -5
  31. package/bin/client/parse_feature_file.js +23 -26
  32. package/bin/client/playground/projects/env.json +2 -2
  33. package/bin/client/project.js +186 -196
  34. package/bin/client/recorderv3/bvt_recorder.js +202 -89
  35. package/bin/client/recorderv3/implemented_steps.js +22 -12
  36. package/bin/client/recorderv3/index.js +59 -54
  37. package/bin/client/recorderv3/network.js +22 -5
  38. package/bin/client/recorderv3/scriptTest.js +1 -1
  39. package/bin/client/recorderv3/services.js +4 -16
  40. package/bin/client/recorderv3/step_runner.js +318 -209
  41. package/bin/client/recorderv3/step_utils.js +475 -16
  42. package/bin/client/recorderv3/update_feature.js +32 -30
  43. package/bin/client/recording.js +1 -0
  44. package/bin/client/run_cucumber.js +1 -1
  45. package/bin/client/scenario_report.js +0 -5
  46. package/bin/client/test_scenario.js +0 -1
  47. package/bin/client/upload-service.js +3 -2
  48. package/bin/client/utils/socket_logger.js +132 -0
  49. package/bin/index.js +2 -0
  50. package/bin/logger.js +3 -2
  51. package/bin/min/consoleApi.min.cjs +2 -3
  52. package/bin/min/injectedScript.min.cjs +16 -16
  53. package/package.json +21 -12
@@ -64,7 +64,7 @@ const escapeNonPrintables = (text) => {
64
64
  export function getCommandContent(command) {
65
65
  switch (command.type) {
66
66
  case "click_element": {
67
- return `click on ${escapeNonPrintables(command.element.name)}`;
67
+ return `${command.count === 2 ? "Double click" : "Click"} on ${escapeNonPrintables(command.element.name)}`;
68
68
  }
69
69
  case "fill_element": {
70
70
  return `fill ${escapeNonPrintables(command.element.name)} with ${escapeNonPrintables(command.parameters[0])}${command.parameters[1] ? ` and press enter key` : ""}`;
@@ -82,7 +82,7 @@ export function getCommandContent(command) {
82
82
  return `verify the element ${escapeNonPrintables(command.element.name)} contains text ${escapeNonPrintables(command.parameters[0])}`;
83
83
  }
84
84
  case "context_click": {
85
- return `click on ${escapeNonPrintables(command.label)} in the context of ${escapeNonPrintables(command.value)}`;
85
+ return `${command.count === 2 ? "Double click" : "Click"} on ${escapeNonPrintables(command.label)} in the context of ${escapeNonPrintables(command.value)}`;
86
86
  }
87
87
  case "hover_element": {
88
88
  return `hover over ${escapeNonPrintables(command.element.name)}`;
@@ -99,6 +99,9 @@ export function getCommandContent(command) {
99
99
  case "verify_page_snapshot": {
100
100
  return `verify page snapshot stored in ${command.parameters[0]}`;
101
101
  }
102
+ case "parameterized_click": {
103
+ return `${command.count === 2 ? "Parameterized double click" : "Parameterized click"} on ${escapeNonPrintables(command.element.name)}`;
104
+ }
102
105
  default: {
103
106
  return "";
104
107
  }
@@ -126,10 +129,14 @@ export function getExamplesContent(parametersMap) {
126
129
  function getTagsContent(scenario, featureFileObject) {
127
130
  let oldTags = featureFileObject?.scenarios?.find((s) => s.name === scenario.name)?.tags ?? [];
128
131
  for (const tag of scenario.tags) {
129
- if (oldTags.includes(tag)) {
130
- oldTags = oldTags.filter((t) => t !== tag);
131
- } else {
132
- oldTags.push(tag);
132
+ if (tag === "global_test_data") {
133
+ if (!oldTags.includes("global_test_data")) {
134
+ oldTags.push("global_test_data");
135
+ }
136
+ }
137
+
138
+ if (tag === "remove_global_test_data") {
139
+ oldTags = oldTags.filter((t) => t !== "global_test_data");
133
140
  }
134
141
  }
135
142
 
@@ -210,14 +217,12 @@ const GherkinToObject = (gherkin) => {
210
217
  steps: [],
211
218
  };
212
219
  while (idx < lines.length && lines[idx].startsWith("@")) {
213
- skipEmptyLines();
214
220
  const tags = [...lines[idx].matchAll(/@([^@]+)/g)].map((match) => match[1].trim());
215
221
  scenario.tags.push(...(tags ?? []));
216
222
  idx++;
223
+ skipEmptyLines();
217
224
  }
218
225
 
219
- skipEmptyLines();
220
-
221
226
  if (idx < lines.length && (lines[idx].startsWith("Scenario:") || lines[idx].startsWith("Scenario Outline:"))) {
222
227
  scenario.name = lines[idx].substring(lines[idx].indexOf(":") + 1).trim();
223
228
  idx++;
@@ -240,32 +245,32 @@ const GherkinToObject = (gherkin) => {
240
245
  !lines[idx].startsWith("@")
241
246
  ) {
242
247
  const line = lines[idx++];
243
- if (line.startsWith("#")) {
244
- const comment = line;
245
- if (comment) {
246
- const command = {
247
- type: "comment",
248
- text: comment,
249
- };
250
- scenario.steps.push(command);
251
- }
252
- } else if (line.startsWith("Examples:")) {
253
- obj.hasParams = true;
254
- const command = {
248
+ let command;
249
+ if (line.startsWith("Examples:")) {
250
+ scenario.hasParams = true;
251
+ command = {
255
252
  type: "examples",
256
253
  lines: [],
257
254
  };
258
-
259
255
  while (idx < lines.length && lines[idx].startsWith("|")) {
260
256
  const line = lines[idx++];
261
257
  command.lines.push(line);
262
258
  }
263
259
  } else {
264
- scenario.steps.push({
265
- type: "step",
266
- text: line,
267
- });
260
+ if (line.startsWith("#")) {
261
+ command = {
262
+ type: "comment",
263
+ text: line,
264
+ };
265
+ } else {
266
+ command = {
267
+ type: "step",
268
+ text: line,
269
+ };
270
+ }
268
271
  }
272
+ scenario.steps.push(command);
273
+ skipEmptyLines();
269
274
  }
270
275
 
271
276
  return scenario;
@@ -274,7 +279,6 @@ const GherkinToObject = (gherkin) => {
274
279
  while (idx < lines.length) {
275
280
  const scenario = getScenario();
276
281
  if (scenario === -1) break;
277
-
278
282
  if (scenario.error) {
279
283
  return {
280
284
  error: scenario.error,
@@ -300,8 +304,7 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
300
304
  skipScenarioIndex = i;
301
305
  continue;
302
306
  }
303
- let scenarioContent = `${featureFileObject.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
304
-
307
+ let scenarioContent = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
305
308
  let tagsLine;
306
309
  if (scenario.tags?.length > 0) {
307
310
  tagsLine = `${scenario.tags.map((t) => `@${t}`).join(" ")}`;
@@ -324,7 +327,6 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
324
327
  if (skipScenarioIndex !== -1) {
325
328
  finalContent = results.join("\n") + "\n" + scenarioContent;
326
329
  }
327
-
328
330
  return finalContent;
329
331
  }
330
332
  export async function updateFeatureFile({ featureName, scenario, override, projectDir }) {
@@ -53,6 +53,7 @@ const Types = {
53
53
  SET_INPUT_FILES: "set_input_files",
54
54
  VERIFY_PAGE_SNAPSHOT: "verify_page_snapshot",
55
55
  CONDITIONAL_WAIT: "conditional_wait",
56
+ SLEEP: "sleep",
56
57
  };
57
58
  class Recording {
58
59
  steps = [];
@@ -359,7 +359,7 @@ const runCucumber = async (
359
359
  await aiAgent.createNewStepLocal(
360
360
  featureName,
361
361
  cucumberStep,
362
- feature,
362
+ feature.comments,
363
363
  userData,
364
364
  first,
365
365
  previousTasks,
@@ -33,17 +33,12 @@ const findNextIdInFolder = (folder) => {
33
33
  // get temp file path from --temp-file arg
34
34
  const getTempFilePath = () => {
35
35
  let tempFilePath = null;
36
-
37
36
  for (const arg of process.argv) {
38
37
  const [key, path] = arg.split("=");
39
38
  if (key === "--temp-file" && !!path) {
40
39
  tempFilePath = path;
41
40
  }
42
41
  }
43
-
44
- if (tempFilePath === null) {
45
- tempFilePath = process.env.TEMP_FILE_PATH;
46
- }
47
42
  return tempFilePath;
48
43
  };
49
44
 
@@ -267,7 +267,6 @@ try {
267
267
  }
268
268
  if (validatePath !== "null") {
269
269
  await prevrunResult.context.stable.verifyPagePath(validatePath);
270
-
271
270
  }
272
271
  //finalCompare = true;
273
272
  } catch (e) {
@@ -12,6 +12,7 @@ class ScenarioUploadService {
12
12
  this.runsApiBaseURL + "/scenarios/create",
13
13
  {
14
14
  name,
15
+ branch: process.env.GIT_BRANCH ? process.env.GIT_BRANCH : "main",
15
16
  },
16
17
  {
17
18
  headers: {
@@ -37,7 +38,7 @@ class ScenarioUploadService {
37
38
  },
38
39
  });
39
40
 
40
- if(response.status === 401) {
41
+ if (response.status === 401) {
41
42
  throw new Error("Your trial plan has ended. Cannot upload reports and perform retraining");
42
43
  }
43
44
 
@@ -63,7 +64,7 @@ class ScenarioUploadService {
63
64
  }
64
65
  );
65
66
 
66
- if(response.status === 403) {
67
+ if (response.status === 403) {
67
68
  throw new Error("Your trial plan has ended. Cannot upload reports and perform retraining");
68
69
  }
69
70
 
@@ -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/bin/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./client/code_gen/page_reflection.js";
2
+
2
3
  export * from "./client/code_gen/playwright_codeget.js";
3
4
  export * from "./client/cucumber/feature.js";
4
5
  export * from "./client/cucumber/project_to_document.js";
@@ -13,4 +14,5 @@ export * from "./client/cucumber/feature_data.js";
13
14
  export * from "./client/cucumber/steps_definitions.js";
14
15
  export * from "./client/profiler.js";
15
16
  export * from "./client/code_cleanup/utils.js";
17
+
16
18
  export * from "./client/code_cleanup/find_step_definition_references.js";
package/bin/logger.js CHANGED
@@ -17,8 +17,8 @@ function formatWithInspect(val) {
17
17
  let alignColorsAndTime = null;
18
18
  let fileRotateTransport = null;
19
19
  let errorFileRotateTransport = null;
20
- export let logger = null;
21
20
  function initLogger() {
21
+ let logger = null;
22
22
  try {
23
23
  alignColorsAndTime = format.combine(
24
24
  format.timestamp({
@@ -59,9 +59,10 @@ function initLogger() {
59
59
  console.log(error);
60
60
  logger = console;
61
61
  }
62
+ return logger;
62
63
  }
63
64
 
64
- initLogger();
65
+ export const logger = initLogger();
65
66
  const changeToTaskLogger = (logFile) => {
66
67
  logger.remove(fileRotateTransport);
67
68
  fileRotateTransport.filename = logFile;