@dev-blinq/cucumber_client 1.0.1438-dev → 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.
- package/bin/assets/bundled_scripts/recorder.js +73 -73
- package/bin/assets/preload/css_gen.js +10 -10
- package/bin/assets/preload/toolbar.js +27 -29
- package/bin/assets/preload/unique_locators.js +1 -1
- package/bin/assets/preload/yaml.js +288 -275
- package/bin/assets/scripts/aria_snapshot.js +223 -220
- package/bin/assets/scripts/dom_attr.js +329 -329
- package/bin/assets/scripts/dom_parent.js +169 -174
- package/bin/assets/scripts/event_utils.js +94 -94
- package/bin/assets/scripts/pw.js +2050 -1949
- package/bin/assets/scripts/recorder.js +70 -45
- package/bin/assets/scripts/snapshot_capturer.js +147 -147
- package/bin/assets/scripts/unique_locators.js +170 -49
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +6 -2
- package/bin/assets/templates/utils_template.txt +16 -16
- package/bin/client/code_cleanup/find_step_definition_references.js +0 -1
- package/bin/client/code_cleanup/utils.js +16 -7
- package/bin/client/code_gen/api_codegen.js +2 -2
- package/bin/client/code_gen/code_inversion.js +63 -2
- package/bin/client/code_gen/duplication_analysis.js +2 -1
- package/bin/client/code_gen/function_signature.js +4 -0
- package/bin/client/code_gen/page_reflection.js +52 -11
- package/bin/client/code_gen/playwright_codeget.js +46 -28
- package/bin/client/cucumber/feature.js +4 -17
- package/bin/client/cucumber/feature_data.js +2 -2
- package/bin/client/cucumber/project_to_document.js +8 -2
- package/bin/client/cucumber/steps_definitions.js +19 -3
- package/bin/client/local_agent.js +3 -2
- package/bin/client/parse_feature_file.js +23 -26
- package/bin/client/playground/projects/env.json +2 -2
- package/bin/client/recorderv3/bvt_init.js +305 -0
- package/bin/client/recorderv3/bvt_recorder.js +1025 -57
- package/bin/client/recorderv3/implemented_steps.js +2 -0
- package/bin/client/recorderv3/index.js +3 -283
- package/bin/client/recorderv3/services.js +818 -142
- package/bin/client/recorderv3/step_runner.js +21 -7
- package/bin/client/recorderv3/step_utils.js +540 -72
- package/bin/client/recorderv3/update_feature.js +86 -39
- package/bin/client/recorderv3/wbr_entry.js +61 -0
- package/bin/client/recording.js +1 -0
- package/bin/client/upload-service.js +4 -2
- package/bin/client/utils/app_dir.js +21 -0
- package/bin/client/utils/socket_logger.js +87 -125
- package/bin/index.js +4 -1
- package/package.json +11 -5
- package/bin/client/recorderv3/app_dir.js +0 -23
- package/bin/client/recorderv3/network.js +0 -299
- package/bin/client/recorderv3/scriptTest.js +0 -5
- package/bin/client/recorderv3/ws_server.js +0 -72
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,7 +110,18 @@ export function getCommandContent(command) {
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
function getExamplesContent(parametersMap, datasets) {
|
|
114
|
+
if (datasets && datasets.length > 0) {
|
|
115
|
+
let result = "";
|
|
116
|
+
const keys = Object.keys(parametersMap);
|
|
117
|
+
result += "\t\tExamples:\n";
|
|
118
|
+
|
|
119
|
+
result += `\t\t| ${keys.join(" | ")} |\n`;
|
|
120
|
+
for (const dataset of datasets) {
|
|
121
|
+
result += `\t\t| ${dataset.data.map((d) => escapeNonPrintables(d.value)).join(" | ")} |\n`;
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
112
125
|
const keys = Object.keys(parametersMap);
|
|
113
126
|
const l = keys.length;
|
|
114
127
|
let result = "\t\tExamples:\n";
|
|
@@ -144,19 +157,19 @@ function getTagsContent(scenario, featureFileObject) {
|
|
|
144
157
|
return tagsContent;
|
|
145
158
|
}
|
|
146
159
|
|
|
147
|
-
|
|
160
|
+
function getScenarioContent({ scenario }, featureFileObject) {
|
|
148
161
|
const prametersMap = scenario.parametersMap ?? {};
|
|
149
162
|
const isParmatersMapEmpty = Object.keys(prametersMap).length === 0;
|
|
150
163
|
let scenarioContent = isParmatersMapEmpty ? `Scenario: ${scenario.name}\n` : `Scenario Outline: ${scenario.name}\n`;
|
|
151
164
|
|
|
152
|
-
|
|
165
|
+
const tagsContent = getTagsContent(scenario, featureFileObject);
|
|
153
166
|
|
|
154
|
-
scenarioContent =
|
|
167
|
+
scenarioContent = `\t${tagsContent}\n${scenarioContent}`;
|
|
155
168
|
|
|
156
169
|
for (const step of scenario.steps) {
|
|
157
170
|
const commands = step.commands ?? [];
|
|
158
|
-
|
|
159
|
-
|
|
171
|
+
const commentContents = commands.map(getCommandContent).map(escapeNonPrintables);
|
|
172
|
+
const commentContent = commentContents.filter((content) => content.length > 0).join(", ");
|
|
160
173
|
|
|
161
174
|
if (commentContent) {
|
|
162
175
|
scenarioContent += `\t# ${commentContent}\n`;
|
|
@@ -164,18 +177,19 @@ export function getScenarioContent({ scenario }, featureFileObject) {
|
|
|
164
177
|
scenarioContent += `\t${step.keyword} ${escapeString(step.text)}\n`;
|
|
165
178
|
}
|
|
166
179
|
if (!isParmatersMapEmpty) {
|
|
167
|
-
scenarioContent += getExamplesContent(prametersMap);
|
|
180
|
+
scenarioContent += getExamplesContent(prametersMap, scenario.datasets);
|
|
168
181
|
}
|
|
169
182
|
return scenarioContent;
|
|
170
183
|
}
|
|
171
|
-
|
|
184
|
+
|
|
185
|
+
function escapeString(str) {
|
|
172
186
|
// Step 1: Replace all literal newline characters with a temporary placeholder
|
|
173
187
|
const placeholder = "\\n";
|
|
174
188
|
str = str.replace(/\n/g, placeholder);
|
|
175
189
|
return str;
|
|
176
|
-
}
|
|
190
|
+
}
|
|
177
191
|
|
|
178
|
-
|
|
192
|
+
function GherkinToObject(gherkin) {
|
|
179
193
|
const obj = {
|
|
180
194
|
featureName: "",
|
|
181
195
|
scenarios: [],
|
|
@@ -211,7 +225,7 @@ const GherkinToObject = (gherkin) => {
|
|
|
211
225
|
}
|
|
212
226
|
|
|
213
227
|
const getScenario = () => {
|
|
214
|
-
|
|
228
|
+
const scenario = {
|
|
215
229
|
name: "",
|
|
216
230
|
tags: [],
|
|
217
231
|
steps: [],
|
|
@@ -235,7 +249,7 @@ const GherkinToObject = (gherkin) => {
|
|
|
235
249
|
skipEmptyLines();
|
|
236
250
|
|
|
237
251
|
if (idx >= lines.length) {
|
|
238
|
-
return
|
|
252
|
+
return scenario;
|
|
239
253
|
}
|
|
240
254
|
|
|
241
255
|
while (
|
|
@@ -288,29 +302,50 @@ const GherkinToObject = (gherkin) => {
|
|
|
288
302
|
skipEmptyLines();
|
|
289
303
|
}
|
|
290
304
|
return obj;
|
|
291
|
-
}
|
|
305
|
+
}
|
|
292
306
|
|
|
293
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
|
|
294
308
|
// assumes that there are no multiple scenarios with the same name and having comments and tags in each scenario
|
|
295
|
-
function updateExistingScenario({
|
|
309
|
+
function updateExistingScenario({
|
|
310
|
+
featureFileContent,
|
|
311
|
+
scenarioName: newScenarioName,
|
|
312
|
+
scenarioContent: newScenarioContent,
|
|
313
|
+
}) {
|
|
296
314
|
const featureFileObject = GherkinToObject(featureFileContent);
|
|
297
315
|
if (featureFileObject.error) return "error";
|
|
316
|
+
|
|
298
317
|
const results = [];
|
|
299
|
-
let skipScenarioIndex = -1;
|
|
300
318
|
results.push(`Feature: ${featureFileObject.featureName}`);
|
|
319
|
+
|
|
320
|
+
let indexOfScenarioToUpdate = -1;
|
|
321
|
+
|
|
322
|
+
for (let i = 0; i < featureFileObject.scenarios.length; i++) {
|
|
323
|
+
if (featureFileObject.scenarios[i].name === newScenarioName) {
|
|
324
|
+
indexOfScenarioToUpdate = i;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
301
329
|
for (let i = 0; i < featureFileObject.scenarios.length; i++) {
|
|
302
330
|
const scenario = featureFileObject.scenarios[i];
|
|
303
|
-
|
|
304
|
-
|
|
331
|
+
|
|
332
|
+
if (i === indexOfScenarioToUpdate) {
|
|
333
|
+
results.push("");
|
|
334
|
+
results.push(newScenarioContent.trim());
|
|
335
|
+
results.push("");
|
|
305
336
|
continue;
|
|
306
337
|
}
|
|
307
|
-
|
|
338
|
+
|
|
339
|
+
const scenarioHeader = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
|
|
308
340
|
let tagsLine;
|
|
341
|
+
|
|
309
342
|
if (scenario.tags?.length > 0) {
|
|
310
|
-
tagsLine =
|
|
343
|
+
tagsLine = scenario.tags.map((t) => `@${t}`).join(" ");
|
|
311
344
|
}
|
|
312
|
-
|
|
313
|
-
results.push(`\t${
|
|
345
|
+
|
|
346
|
+
if (tagsLine) results.push(`\t${tagsLine}`);
|
|
347
|
+
results.push(`\t${scenarioHeader}`);
|
|
348
|
+
|
|
314
349
|
for (const step of scenario.steps) {
|
|
315
350
|
if (step.type === "examples") {
|
|
316
351
|
results.push(`\t\tExamples:`);
|
|
@@ -323,14 +358,12 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
|
|
|
323
358
|
}
|
|
324
359
|
results.push("");
|
|
325
360
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
finalContent = results.join("\n") + "\n" + scenarioContent;
|
|
329
|
-
}
|
|
330
|
-
return finalContent;
|
|
361
|
+
|
|
362
|
+
return results.join("\n");
|
|
331
363
|
}
|
|
332
|
-
|
|
333
|
-
|
|
364
|
+
|
|
365
|
+
async function updateFeatureFile({ featureName, scenario, override, projectDir, logger }) {
|
|
366
|
+
const featureFilePath = path.join(projectDir, "features", `${featureName}.feature`);
|
|
334
367
|
const isFeatureFileExists = existsSync(featureFilePath);
|
|
335
368
|
const scenarioContent = getScenarioContent(
|
|
336
369
|
{ scenario },
|
|
@@ -361,13 +394,13 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
|
|
|
361
394
|
plugins: ["prettier-plugin-gherkin"],
|
|
362
395
|
});
|
|
363
396
|
} catch (error) {
|
|
364
|
-
|
|
397
|
+
logger.error("Error formatting feature file content with Prettier:", error);
|
|
365
398
|
}
|
|
366
399
|
writeFileSync(featureFilePath, updatedFeatureFileContent);
|
|
367
400
|
return;
|
|
368
401
|
}
|
|
369
402
|
}
|
|
370
|
-
let updatedFeatureFileContent = featureFileContent
|
|
403
|
+
let updatedFeatureFileContent = `${featureFileContent}\n${scenarioContent}`;
|
|
371
404
|
try {
|
|
372
405
|
updatedFeatureFileContent = await prettier.format(updatedFeatureFileContent, {
|
|
373
406
|
...prettierConfig,
|
|
@@ -375,7 +408,7 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
|
|
|
375
408
|
plugins: ["prettier-plugin-gherkin"],
|
|
376
409
|
});
|
|
377
410
|
} catch (error) {
|
|
378
|
-
|
|
411
|
+
logger.error("Error formatting feature file content with Prettier:", error);
|
|
379
412
|
}
|
|
380
413
|
writeFileSync(featureFilePath, updatedFeatureFileContent);
|
|
381
414
|
} else {
|
|
@@ -387,8 +420,22 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
|
|
|
387
420
|
plugins: ["prettier-plugin-gherkin"],
|
|
388
421
|
});
|
|
389
422
|
} catch (error) {
|
|
390
|
-
|
|
423
|
+
logger.error("Error formatting feature file content with Prettier:", error);
|
|
391
424
|
}
|
|
392
425
|
writeFileSync(featureFilePath, featureFileContent);
|
|
393
426
|
}
|
|
394
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,61 @@
|
|
|
1
|
+
import { io } from "socket.io-client";
|
|
2
|
+
import { BVTRecorderInit } from "./bvt_init.js";
|
|
3
|
+
import { loadArgs, showUsage, validateCLIArg } from "../cli_helpers.js";
|
|
4
|
+
const requiredEnvVars = ["PROJECT_ID", "BLINQ_TOKEN", "SESSION_ID", "WORKER_WS_SERVER_URL", "REMOTE_ORIGINS_URL"];
|
|
5
|
+
function validateEnvVariables() {
|
|
6
|
+
const missingVars = requiredEnvVars.filter((varName) => !process.env[varName]);
|
|
7
|
+
if (missingVars.length > 0) {
|
|
8
|
+
throw new Error(`Missing required environment variables: ${missingVars.join(", ")}`);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
console.log("All required environment variables are set.");
|
|
12
|
+
requiredEnvVars.forEach((varName) => {
|
|
13
|
+
console.log(`${varName}: ${process.env[varName]}`);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function getEnvironmentConfig() {
|
|
18
|
+
const args = loadArgs();
|
|
19
|
+
const projectDir = args[0] || process.env.PROJECT_ID;
|
|
20
|
+
const envName = args[1]?.split("=")[1] || process.env.ENV_NAME;
|
|
21
|
+
const roomId = args[2] || process.env.SESSION_ID;
|
|
22
|
+
const shouldTakeScreenshot = args[3] || process.env.SHOULD_TAKE_SCREENSHOT;
|
|
23
|
+
const TOKEN = process.env.BLINQ_TOKEN;
|
|
24
|
+
try {
|
|
25
|
+
validateCLIArg(projectDir, "projectDir");
|
|
26
|
+
validateCLIArg(envName, "envName");
|
|
27
|
+
validateCLIArg(roomId, "roomId");
|
|
28
|
+
validateCLIArg(shouldTakeScreenshot, "shouldTakeScreenshot");
|
|
29
|
+
if (!TOKEN) {
|
|
30
|
+
throw new Error("BLINQ_TOKEN env variable not set");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const usage = `Usage: node bvt_recorder.js <projectDir> <envName> <roomId>`;
|
|
35
|
+
if (error instanceof Error) {
|
|
36
|
+
showUsage(error, usage);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const unknownError = new Error("An unknown error occurred");
|
|
40
|
+
showUsage(unknownError, usage);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { envName, projectDir, roomId, TOKEN };
|
|
44
|
+
}
|
|
45
|
+
function initWebBVTRecorder() {
|
|
46
|
+
const socket = io(process.env.WORKER_WS_SERVER_URL, {
|
|
47
|
+
path: "/ws",
|
|
48
|
+
transports: ["websocket", "polling"],
|
|
49
|
+
reconnection: true,
|
|
50
|
+
});
|
|
51
|
+
validateEnvVariables();
|
|
52
|
+
const { envName, projectDir, roomId, TOKEN } = getEnvironmentConfig();
|
|
53
|
+
BVTRecorderInit({
|
|
54
|
+
envName: envName,
|
|
55
|
+
projectDir,
|
|
56
|
+
roomId,
|
|
57
|
+
TOKEN,
|
|
58
|
+
socket: socket,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
initWebBVTRecorder();
|
package/bin/client/recording.js
CHANGED
|
@@ -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
|
|
|
@@ -107,6 +108,7 @@ class ScenarioUploadService {
|
|
|
107
108
|
{
|
|
108
109
|
scenarioId,
|
|
109
110
|
projectId,
|
|
111
|
+
testcase_id: process.env.TESTCASE_ID,
|
|
110
112
|
},
|
|
111
113
|
{
|
|
112
114
|
headers: {
|
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
72
|
-
|
|
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);
|
|
88
|
+
error(msg, ext, ctx) {
|
|
89
|
+
this.log("error", msg, ext, ctx);
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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/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,5 +14,7 @@ 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";
|
|
16
|
-
|
|
17
17
|
export * from "./client/code_cleanup/find_step_definition_references.js";
|
|
18
|
+
export * from "./client/recorderv3/step_utils.js";
|
|
19
|
+
export * from "./client/recorderv3/update_feature.js";
|
|
20
|
+
export * from "./client/recorderv3/bvt_init.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev-blinq/cucumber_client",
|
|
3
|
-
"version": "1.0.1438-
|
|
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",
|
|
@@ -37,9 +39,9 @@
|
|
|
37
39
|
"@babel/traverse": "^7.27.1",
|
|
38
40
|
"@babel/types": "^7.27.1",
|
|
39
41
|
"@cucumber/tag-expressions": "^6.1.1",
|
|
40
|
-
"@dev-blinq/cucumber-js": "1.0.
|
|
41
|
-
"@faker-js/faker": "^8.1
|
|
42
|
-
"automation_model": "1.0.
|
|
42
|
+
"@dev-blinq/cucumber-js": "1.0.121-stage",
|
|
43
|
+
"@faker-js/faker": "^8.4.1",
|
|
44
|
+
"automation_model": "1.0.798-stage",
|
|
43
45
|
"axios": "^1.7.4",
|
|
44
46
|
"chokidar": "^3.6.0",
|
|
45
47
|
"create-require": "^1.1.1",
|
|
@@ -57,6 +59,7 @@
|
|
|
57
59
|
"pureimage": "0.4.9",
|
|
58
60
|
"socket.io": "^4.7.5",
|
|
59
61
|
"socket.io-client": "^4.7.5",
|
|
62
|
+
"strip-comments": "^2.0.1",
|
|
60
63
|
"tunnel": "^0.0.6",
|
|
61
64
|
"unzipper": "^0.12.3",
|
|
62
65
|
"win-ca": "^3.5.1",
|
|
@@ -74,7 +77,10 @@
|
|
|
74
77
|
"mocha": "^10.2.0",
|
|
75
78
|
"ncp": "^2.0.0",
|
|
76
79
|
"readline-sync": "^1.4.10",
|
|
80
|
+
"ts-node": "^10.9.2",
|
|
77
81
|
"tsup": "^8.5.0",
|
|
78
|
-
"typescript": "^5.9.2"
|
|
82
|
+
"typescript": "^5.9.2",
|
|
83
|
+
"vite-tsconfig-paths": "^6.0.4",
|
|
84
|
+
"vitest": "^2.1.4"
|
|
79
85
|
}
|
|
80
86
|
}
|