@dev-blinq/cucumber_client 1.0.1469-stage → 1.0.1470-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.
@@ -100,18 +100,10 @@ class StepsDefinitions {
100
100
  this.initPage(codePage, mjsFile);
101
101
  }
102
102
  let stepCount = Object.keys(this.steps).length;
103
- if (this.steps["Before"]) {
104
- stepCount--;
105
- }
106
- if (this.steps["After"]) {
107
- stepCount--;
108
- }
109
- if (this.steps["BeforeAll"]) {
110
- stepCount--;
111
- }
112
- if (this.steps["AfterAll"]) {
113
- stepCount--;
114
- }
103
+ if (this.steps["Before"]) stepCount--;
104
+ if (this.steps["After"]) stepCount--;
105
+ if (this.steps["BeforeAll"]) stepCount--;
106
+ if (this.steps["AfterAll"]) stepCount--;
115
107
  if (print) {
116
108
  logger.info("total steps definitions found", stepCount);
117
109
  }
@@ -0,0 +1,45 @@
1
+ export const FIXED_FOLDER_NAMES = {
2
+ STEP_DEFINITIONS: "step_definitions",
3
+ FEATURES: "features",
4
+ ASSETS: "assets",
5
+ TEMPLATES: "templates",
6
+ BLINQ_TEMP_ROUTES: "blinq_temp_routes",
7
+ DATA: "data",
8
+ ROUTES: "routes",
9
+ };
10
+
11
+ export const FIXED_FILE_NAMES = {
12
+ UTILS: "utils.mjs",
13
+ UTILS_TEMPLATE: "utils_template.txt",
14
+ HOOKS_TEMPLATE: "_hooks_template.txt",
15
+ HOOKS: "_hooks.mjs",
16
+ };
17
+
18
+ export const UTF8_ENCODING = "utf8";
19
+
20
+ export class UpdateStepDefinitionsError extends Error {
21
+ constructor({ type, message, statusCode = 500, meta } = {}) {
22
+ super(message);
23
+
24
+ this.name = "UpdateStepDefinitionsError";
25
+ this.type = type;
26
+ this.statusCode = statusCode;
27
+ this.meta = meta;
28
+
29
+ if (typeof Object.setPrototypeOf === "function") {
30
+ Object.setPrototypeOf(this, new.target.prototype);
31
+ }
32
+ }
33
+ }
34
+ export const SaveJobErrorType = {
35
+ VALIDATION_ERROR: "VALIDATION_ERROR",
36
+ STEP_ERROR: "STEP_ERROR",
37
+ GIT_ERROR: "GIT_ERROR",
38
+ UNKNOWN: "UNKNOWN",
39
+ INTERNAL_ERROR: "INTERNAL_ERROR",
40
+ STEP_DEFINITION_UPDATE_FAILED: "STEP_DEFINITION_UPDATE_FAILED",
41
+ FILE_SYSTEM_ERROR: "FILE_SYSTEM_ERROR",
42
+ STEP_DEFINITIONS_LOADING_FAILED: "STEP_DEFINITIONS_LOADING_FAILED",
43
+ STEP_COMMANDS_PROCESSING_FAILED: "STEP_COMMANDS_PROCESSING_FAILED",
44
+ STEP_INITIALIZATION_FAILED: "STEP_INITIALIZATION_FAILED",
45
+ };
@@ -147,7 +147,7 @@ export class NamesService {
147
147
  }
148
148
  return result.data;
149
149
  }
150
- async generateLocatorDescriptions({ locatorsObj }) {
150
+ async generateLocatorDescriptions({ locatorsObj, }) {
151
151
  const url = `${getRunsServiceBaseURL()}/locate/generate_locator_summaries`;
152
152
  const result = await axiosClient({
153
153
  url,
@@ -172,6 +172,7 @@ export class PublishService {
172
172
  constructor(TOKEN) {
173
173
  this.TOKEN = TOKEN;
174
174
  }
175
+ //! deprecated
175
176
  async saveScenario({ scenario, featureName, override, branch, isEditing, projectId, env, AICode }) {
176
177
  const runsURL = getRunsServiceBaseURL();
177
178
  const workspaceURL = runsURL.replace("/runs", "/workspace");
@@ -11,6 +11,14 @@ import { generateApiCode } from "../code_gen/api_codegen.js";
11
11
  import { tmpdir } from "node:os";
12
12
  import { createHash } from "node:crypto";
13
13
  import { getErrorMessage } from "../utils/socket_logger.js";
14
+ import {
15
+ FIXED_FILE_NAMES,
16
+ FIXED_FOLDER_NAMES,
17
+ SaveJobErrorType,
18
+ UpdateStepDefinitionsError,
19
+ UTF8_ENCODING,
20
+ } from "./constants.js";
21
+ import { handleFileInitOps, potentialErrorWrapper, processScenarioSteps, writeTemplateFiles } from "./utils.js";
14
22
 
15
23
  const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
16
24
 
@@ -454,7 +462,7 @@ export function getCodePage(stepDefsFilePath) {
454
462
  return codePage;
455
463
  }
456
464
  // const templateFile = path.join(__dirname, "../../assets", "templates", "page_template.txt");
457
- // const initialCode = readFileSync(templateFile, "utf8");
465
+ // const initialCode = readFileSync(templateFile, UTF8_ENCODING);
458
466
  const codePage = new CodePage();
459
467
  codePage.generateModel();
460
468
  return codePage;
@@ -508,6 +516,7 @@ export async function saveRecording({
508
516
  stepsDefinitions,
509
517
  parametersMap,
510
518
  logger,
519
+ bvtSnapshotsDir,
511
520
  }) {
512
521
  if (step.commands && Array.isArray(step.commands)) {
513
522
  step.commands = step.commands.map((cmd) => toRecordingStep(cmd, parametersMap, step.text));
@@ -761,7 +770,7 @@ const getLocatorsJson = (file) => {
761
770
  return {};
762
771
  }
763
772
  try {
764
- const locatorsJson = readFileSync(locatorsFilePath, "utf8");
773
+ const locatorsJson = readFileSync(locatorsFilePath, UTF8_ENCODING);
765
774
  return JSON.parse(locatorsJson);
766
775
  } catch (error) {
767
776
  console.error(error);
@@ -863,7 +872,7 @@ export async function executeStep({ stepsDefinitions, cucumberStep, context, cod
863
872
  }
864
873
  }
865
874
 
866
- export async function updateStepDefinitions({ scenario, featureName, projectDir, logger }) {
875
+ export async function updateStepDefinitionsOld({ scenario, featureName, projectDir, logger }) {
867
876
  // set the candidate step definition file name
868
877
  // set the utils file path
869
878
  const utilsFilePath = path.join(projectDir, "features", "step_definitions", "utils.mjs");
@@ -945,6 +954,130 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir,
945
954
  writeFileSync(utilsFilePath, utilsContent, "utf8");
946
955
  }
947
956
 
957
+ export async function updateStepDefinitions({ scenario, featureName, projectDir, logger, bvtSnapshotsDir }) {
958
+ try {
959
+ const { featureFolder, utilsFilePath, utilsContent } = handleFileInitOps(projectDir);
960
+ const steps = scenario.steps;
961
+
962
+ const stepsDefinitions = new StepsDefinitions(projectDir);
963
+ await potentialErrorWrapper(
964
+ () => stepsDefinitions.load(false),
965
+ "Failed to load step definitions",
966
+ SaveJobErrorType.STEP_DEFINITIONS_LOADING_FAILED,
967
+ logger
968
+ );
969
+
970
+ for (let index = 0; index < steps.length; index++) {
971
+ const step = steps[index];
972
+ try {
973
+ if (step.internalImplementedStepId) {
974
+ const si = steps.findIndex((s) => s.id === step.internalImplementedStepId);
975
+ if (si !== -1) {
976
+ step.isImplementedWhileRecording = true;
977
+ }
978
+ }
979
+
980
+ const processed = await potentialErrorWrapper(
981
+ () => {
982
+ if (!step.isUtilStep && ((step.isImplemented && !step.shouldOverride) || step.commands.length === 0)) {
983
+ let routesPath = path.join(tmpdir(), FIXED_FOLDER_NAMES.BLINQ_TEMP_ROUTES);
984
+ if (process.env.TEMP_RUN === "true") {
985
+ if (existsSync(routesPath)) rmSync(routesPath, { recursive: true });
986
+ mkdirSync(routesPath, { recursive: true });
987
+ saveRoutes({ step, folderPath: routesPath }, logger);
988
+ } else {
989
+ if (existsSync(routesPath)) {
990
+ try {
991
+ rmSync(routesPath, { recursive: true });
992
+ } catch (error) {
993
+ logger.error(`❌ Error removing temp routes folder: ${getErrorMessage(error)}`);
994
+ }
995
+ }
996
+ routesPath = path.join(projectDir, FIXED_FOLDER_NAMES.DATA, FIXED_FOLDER_NAMES.ROUTES);
997
+ if (!existsSync(routesPath)) mkdirSync(routesPath, { recursive: true });
998
+ saveRoutes({ step, folderPath: routesPath }, logger);
999
+ }
1000
+
1001
+ if (step.commands && Array.isArray(step.commands)) {
1002
+ step.commands = step.commands.map((cmd) => toRecordingStep(cmd, scenario.parametersMap));
1003
+ }
1004
+
1005
+ return true;
1006
+ } else {
1007
+ return false;
1008
+ }
1009
+ },
1010
+ "Failed to process step commands and routes",
1011
+ SaveJobErrorType.STEP_COMMANDS_PROCESSING_FAILED,
1012
+ logger
1013
+ );
1014
+ if (processed) continue;
1015
+
1016
+ const { cucumberStep, stepDefsFilePath } = await potentialErrorWrapper(
1017
+ () => {
1018
+ const cucumberStep = getCucumberStep({ step });
1019
+ const pageName = generatePageName(step.startFrame?.url ?? "default", step.isUtilStep);
1020
+ const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
1021
+ return { cucumberStep, stepDefsFilePath };
1022
+ },
1023
+ "Failed to initialize cucumber step and locate definition path",
1024
+ SaveJobErrorType.STEP_INITIALIZATION_FAILED,
1025
+ logger
1026
+ );
1027
+
1028
+ const codePage = await potentialErrorWrapper(
1029
+ async () => {
1030
+ let codePage = getCodePage(stepDefsFilePath);
1031
+ codePage = await saveRecording({
1032
+ step,
1033
+ cucumberStep,
1034
+ codePage,
1035
+ projectDir,
1036
+ stepsDefinitions,
1037
+ parametersMap: scenario.parametersMap,
1038
+ bvtSnapshotsDir,
1039
+ });
1040
+ return codePage;
1041
+ },
1042
+ "Failed to generate and save step definition",
1043
+ SaveJobErrorType.STEP_DEFINITION_UPDATE_FAILED,
1044
+ logger
1045
+ );
1046
+
1047
+ if (!codePage) continue;
1048
+
1049
+ const res = await codePage.save();
1050
+ if (!res) {
1051
+ throw new UpdateStepDefinitionsError({
1052
+ type: SaveJobErrorType.STEP_DEFINITION_UPDATE_FAILED,
1053
+ message: `Failed to save step definition for "${cucumberStep.text}" in "${codePage.sourceFileName}"`,
1054
+ });
1055
+ }
1056
+ } catch (error) {
1057
+ throw new UpdateStepDefinitionsError({
1058
+ type: SaveJobErrorType.STEP_DEFINITION_UPDATE_FAILED,
1059
+ message: "Failed to update step definition",
1060
+ meta: {
1061
+ stepIndex: index,
1062
+ stepText: step.text,
1063
+ reason: getErrorMessage(error),
1064
+ },
1065
+ });
1066
+ }
1067
+ }
1068
+
1069
+ writeFileSync(utilsFilePath, utilsContent, UTF8_ENCODING);
1070
+ } catch (error) {
1071
+ logger.error(`❌ updateStepDefinitions() failed: ${error?.message ?? String(error)}`);
1072
+ throw error instanceof UpdateStepDefinitionsError
1073
+ ? error
1074
+ : new UpdateStepDefinitionsError({
1075
+ type: SaveJobErrorType.INTERNAL_ERROR,
1076
+ message: error?.message ?? "Unknown error",
1077
+ });
1078
+ }
1079
+ }
1080
+
948
1081
  export function saveRoutes({ step, folderPath }, logger) {
949
1082
  const routeItems = step.routeItems;
950
1083
  if (!routeItems || routeItems.length === 0) {
@@ -978,8 +1111,8 @@ export function saveRoutes({ step, folderPath }, logger) {
978
1111
  mkdirSync(folderPath, { recursive: true });
979
1112
  }
980
1113
  try {
981
- writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), "utf8");
1114
+ writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), UTF8_ENCODING);
982
1115
  } catch (error) {
983
- logger.error(`Error saving routes to ${routesFilePath}: ${getErrorMessage(error)}`);
1116
+ logger.error(`❌ Error saving routes to ${routesFilePath}: ${getErrorMessage(error)}`);
984
1117
  }
985
1118
  }
@@ -0,0 +1,74 @@
1
+ import { getErrorMessage } from "../utils/socket_logger.js";
2
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import {
5
+ FIXED_FILE_NAMES,
6
+ FIXED_FOLDER_NAMES,
7
+ SaveJobErrorType,
8
+ UpdateStepDefinitionsError,
9
+ UTF8_ENCODING,
10
+ } from "./constants.js";
11
+
12
+ export function handleFileInitOps(projectDir) {
13
+ try {
14
+ const stepDefinitionFolderPath = path.join(
15
+ projectDir,
16
+ FIXED_FOLDER_NAMES.FEATURES,
17
+ FIXED_FOLDER_NAMES.STEP_DEFINITIONS
18
+ );
19
+ if (!existsSync(stepDefinitionFolderPath)) {
20
+ mkdirSync(stepDefinitionFolderPath, { recursive: true });
21
+ }
22
+
23
+ const utilsFilePath = path.join(
24
+ projectDir,
25
+ FIXED_FOLDER_NAMES.FEATURES,
26
+ FIXED_FOLDER_NAMES.STEP_DEFINITIONS,
27
+ FIXED_FILE_NAMES.UTILS
28
+ );
29
+
30
+ const utilsTemplateFilePath = path.join(
31
+ __dirname,
32
+ `../../${FIXED_FOLDER_NAMES.ASSETS}`,
33
+ FIXED_FOLDER_NAMES.TEMPLATES,
34
+ FIXED_FILE_NAMES.UTILS_TEMPLATE
35
+ );
36
+ const utilsContent = readFileSync(utilsTemplateFilePath, UTF8_ENCODING);
37
+ writeFileSync(utilsFilePath, utilsContent, UTF8_ENCODING);
38
+
39
+ const hooksTemplateFilePath = path.join(
40
+ __dirname,
41
+ `../../${FIXED_FOLDER_NAMES.ASSETS}`,
42
+ FIXED_FOLDER_NAMES.TEMPLATES,
43
+ FIXED_FILE_NAMES.HOOKS_TEMPLATE
44
+ );
45
+ if (existsSync(hooksTemplateFilePath)) {
46
+ const hooksFilePath = path.join(stepDefinitionFolderPath, FIXED_FILE_NAMES.HOOKS);
47
+ const hooksContent = readFileSync(hooksTemplateFilePath, UTF8_ENCODING);
48
+ writeFileSync(hooksFilePath, hooksContent, UTF8_ENCODING);
49
+ }
50
+
51
+ const featureFolder = path.join(projectDir, FIXED_FOLDER_NAMES.FEATURES);
52
+
53
+ return { featureFolder, utilsFilePath, utilsContent };
54
+ } catch (error) {
55
+ throw new UpdateStepDefinitionsError({
56
+ type: SaveJobErrorType.FILE_SYSTEM_ERROR,
57
+ message: "Failed to initialize step definition folder structure",
58
+ meta: { reason: getErrorMessage(error) },
59
+ });
60
+ }
61
+ }
62
+
63
+ export async function potentialErrorWrapper(fn, errorMessage, type, logger) {
64
+ try {
65
+ return await fn();
66
+ } catch (error) {
67
+ logger.error(`❌ ${errorMessage}: ${getErrorMessage(error)}`);
68
+ throw new UpdateStepDefinitionsError({
69
+ type: type,
70
+ message: errorMessage,
71
+ meta: { reason: getErrorMessage(error) },
72
+ });
73
+ }
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-blinq/cucumber_client",
3
- "version": "1.0.1469-stage",
3
+ "version": "1.0.1470-stage",
4
4
  "description": " ",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",