@dev-blinq/cucumber_client 1.0.1361-dev → 1.0.1361-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 +107 -107
- 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 +13 -23
- package/bin/assets/scripts/snapshot_capturer.js +147 -147
- package/bin/assets/scripts/unique_locators.js +163 -44
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +41 -0
- package/bin/assets/templates/utils_template.txt +2 -45
- package/bin/client/apiTest/apiTest.js +6 -0
- package/bin/client/code_cleanup/utils.js +5 -1
- package/bin/client/code_gen/api_codegen.js +2 -2
- package/bin/client/code_gen/code_inversion.js +107 -2
- package/bin/client/code_gen/function_signature.js +4 -0
- package/bin/client/code_gen/page_reflection.js +846 -906
- package/bin/client/code_gen/playwright_codeget.js +25 -11
- package/bin/client/cucumber/feature.js +4 -0
- package/bin/client/cucumber/feature_data.js +2 -2
- package/bin/client/cucumber/project_to_document.js +9 -3
- package/bin/client/cucumber/steps_definitions.js +6 -3
- package/bin/client/cucumber_selector.js +17 -1
- package/bin/client/local_agent.js +4 -3
- package/bin/client/parse_feature_file.js +23 -26
- package/bin/client/playground/projects/env.json +2 -2
- package/bin/client/project.js +186 -196
- package/bin/client/recorderv3/bvt_recorder.js +213 -90
- package/bin/client/recorderv3/implemented_steps.js +8 -0
- package/bin/client/recorderv3/index.js +59 -54
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +315 -205
- package/bin/client/recorderv3/step_utils.js +475 -16
- package/bin/client/recorderv3/update_feature.js +9 -5
- package/bin/client/recording.js +1 -0
- package/bin/client/upload-service.js +3 -2
- package/bin/client/utils/socket_logger.js +132 -0
- package/bin/index.js +1 -0
- package/bin/logger.js +3 -2
- package/bin/min/consoleApi.min.cjs +2 -3
- package/bin/min/injectedScript.min.cjs +16 -16
- package/package.json +20 -10
|
@@ -12,11 +12,12 @@ 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";
|
|
18
|
+
import { tmpdir } from "os";
|
|
19
|
+
import { faker } from "@faker-js/faker/locale/en_US";
|
|
20
|
+
import { chromium } from "playwright-core";
|
|
20
21
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
21
22
|
|
|
22
23
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -45,7 +46,6 @@ async function evaluate(frame, script) {
|
|
|
45
46
|
async function findNestedFrameSelector(frame, obj) {
|
|
46
47
|
try {
|
|
47
48
|
const parent = frame.parentFrame();
|
|
48
|
-
if (parent) console.log(`Parent frame: ${JSON.stringify(parent)}`);
|
|
49
49
|
if (!parent) return { children: obj };
|
|
50
50
|
const frameElement = await frame.frameElement();
|
|
51
51
|
if (!frameElement) return;
|
|
@@ -54,6 +54,7 @@ async function findNestedFrameSelector(frame, obj) {
|
|
|
54
54
|
}, frameElement);
|
|
55
55
|
return findNestedFrameSelector(parent, { children: obj, selectors });
|
|
56
56
|
} catch (e) {
|
|
57
|
+
socketLogger.error(`Error in findNestedFrameSelector: ${e}`);
|
|
57
58
|
console.error(e);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -150,17 +151,30 @@ const transformAction = (action, el, isVerify, isPopupCloseClick, isInHoverMode,
|
|
|
150
151
|
};
|
|
151
152
|
}
|
|
152
153
|
default: {
|
|
154
|
+
socketLogger.error(`Action not supported: ${action.name}`);
|
|
153
155
|
console.log("action not supported", action);
|
|
154
156
|
throw new Error("action not supported");
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
159
|
};
|
|
160
|
+
const diffPaths = (currentPath, newPath) => {
|
|
161
|
+
const currentDomain = new URL(currentPath).hostname;
|
|
162
|
+
const newDomain = new URL(newPath).hostname;
|
|
163
|
+
if (currentDomain !== newDomain) {
|
|
164
|
+
return true;
|
|
165
|
+
} else {
|
|
166
|
+
const currentRoute = new URL(currentPath).pathname;
|
|
167
|
+
const newRoute = new URL(newPath).pathname;
|
|
168
|
+
return currentRoute !== newRoute;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
158
171
|
/**
|
|
159
172
|
* @typedef {Object} BVTRecorderInput
|
|
160
173
|
* @property {string} envName
|
|
161
174
|
* @property {string} projectDir
|
|
162
175
|
* @property {string} TOKEN
|
|
163
176
|
* @property {(name:string, data:any)=> void} sendEvent
|
|
177
|
+
* @property {Object} logger
|
|
164
178
|
*/
|
|
165
179
|
export class BVTRecorder {
|
|
166
180
|
#currentURL = "";
|
|
@@ -174,7 +188,6 @@ export class BVTRecorder {
|
|
|
174
188
|
*/
|
|
175
189
|
constructor(initialState) {
|
|
176
190
|
Object.assign(this, initialState);
|
|
177
|
-
this.logger = logger;
|
|
178
191
|
this.screenshotMap = new Map();
|
|
179
192
|
this.snapshotMap = new Map();
|
|
180
193
|
this.scenariosStepsMap = new Map();
|
|
@@ -184,40 +197,16 @@ export class BVTRecorder {
|
|
|
184
197
|
projectDir: this.projectDir,
|
|
185
198
|
logger: this.logger,
|
|
186
199
|
});
|
|
187
|
-
this.stepRunner = new BVTStepRunner({
|
|
188
|
-
projectDir: this.projectDir,
|
|
189
|
-
sendExecutionStatus: (data) => {
|
|
190
|
-
if (data && data.type) {
|
|
191
|
-
switch (data.type) {
|
|
192
|
-
case "cmdExecutionStart":
|
|
193
|
-
console.log("Sending cmdExecutionStart event for cmdId:", data);
|
|
194
|
-
this.sendEvent(this.events.cmdExecutionStart, data);
|
|
195
|
-
break;
|
|
196
|
-
case "cmdExecutionSuccess":
|
|
197
|
-
console.log("Sending cmdExecutionSuccess event for cmdId:", data);
|
|
198
|
-
this.sendEvent(this.events.cmdExecutionSuccess, data);
|
|
199
|
-
break;
|
|
200
|
-
case "cmdExecutionError":
|
|
201
|
-
console.log("Sending cmdExecutionError event for cmdId:", data);
|
|
202
|
-
this.sendEvent(this.events.cmdExecutionError, data);
|
|
203
|
-
break;
|
|
204
|
-
case "interceptResults":
|
|
205
|
-
console.log("Sending interceptResults event");
|
|
206
|
-
this.sendEvent(this.events.interceptResults, data);
|
|
207
|
-
break;
|
|
208
|
-
default:
|
|
209
|
-
console.warn("Unknown command execution status type:", data.type);
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
});
|
|
215
200
|
this.pageSet = new Set();
|
|
201
|
+
this.pageMetaDataSet = new Set();
|
|
216
202
|
this.lastKnownUrlPath = "";
|
|
217
|
-
// TODO: what is world?
|
|
218
203
|
this.world = { attach: () => {} };
|
|
219
204
|
this.shouldTakeScreenshot = true;
|
|
220
205
|
this.watcher = null;
|
|
206
|
+
this.networkEventsFolder = path.join(tmpdir(), "blinq_network_events");
|
|
207
|
+
if (existsSync(this.networkEventsFolder)) {
|
|
208
|
+
rmSync(this.networkEventsFolder, { recursive: true, force: true });
|
|
209
|
+
}
|
|
221
210
|
}
|
|
222
211
|
events = {
|
|
223
212
|
onFrameNavigate: "BVTRecorder.onFrameNavigate",
|
|
@@ -232,12 +221,14 @@ export class BVTRecorder {
|
|
|
232
221
|
cmdExecutionSuccess: "BVTRecorder.cmdExecutionSuccess",
|
|
233
222
|
cmdExecutionError: "BVTRecorder.cmdExecutionError",
|
|
234
223
|
interceptResults: "BVTRecorder.interceptResults",
|
|
224
|
+
onDebugURLChange: "BVTRecorder.onDebugURLChange",
|
|
225
|
+
updateCommand: "BVTRecorder.updateCommand",
|
|
235
226
|
};
|
|
236
227
|
bindings = {
|
|
237
228
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
238
229
|
this.#activeFrame = frame;
|
|
239
230
|
const nestFrmLoc = await findNestedFrameSelector(frame);
|
|
240
|
-
|
|
231
|
+
this.logger.info(`Time taken for action: ${event.statistics.time}`);
|
|
241
232
|
await this.onAction({ ...event, nestFrmLoc });
|
|
242
233
|
},
|
|
243
234
|
__bvt_getMode: async () => {
|
|
@@ -256,8 +247,7 @@ export class BVTRecorder {
|
|
|
256
247
|
await this.onClosePopup();
|
|
257
248
|
},
|
|
258
249
|
__bvt_log: async (src, message) => {
|
|
259
|
-
|
|
260
|
-
console.log(`Inside Browser: ${message}`);
|
|
250
|
+
this.logger.info(`Inside Browser: ${message}`);
|
|
261
251
|
},
|
|
262
252
|
__bvt_getObject: (_src, obj) => {
|
|
263
253
|
this.processObject(obj);
|
|
@@ -319,10 +309,11 @@ export class BVTRecorder {
|
|
|
319
309
|
}
|
|
320
310
|
|
|
321
311
|
async _initBrowser({ url }) {
|
|
312
|
+
socketLogger.info("Only present in 1.0.1293-stage");
|
|
322
313
|
this.#remoteDebuggerPort = await findAvailablePort();
|
|
323
314
|
process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
|
|
324
315
|
|
|
325
|
-
this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
316
|
+
// this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
326
317
|
this.world = { attach: () => {} };
|
|
327
318
|
|
|
328
319
|
const ai_config_file = path.join(this.projectDir, "ai_config.json");
|
|
@@ -331,7 +322,7 @@ export class BVTRecorder {
|
|
|
331
322
|
try {
|
|
332
323
|
ai_config = JSON.parse(readFileSync(ai_config_file, "utf8"));
|
|
333
324
|
} catch (error) {
|
|
334
|
-
|
|
325
|
+
this.logger.error("Error reading ai_config.json", error);
|
|
335
326
|
}
|
|
336
327
|
}
|
|
337
328
|
this.config = ai_config;
|
|
@@ -343,16 +334,37 @@ export class BVTRecorder {
|
|
|
343
334
|
],
|
|
344
335
|
};
|
|
345
336
|
|
|
346
|
-
let startTime = Date.now();
|
|
347
337
|
const bvtContext = await initContext(url, false, false, this.world, 450, initScripts, this.envName);
|
|
348
|
-
let stopTime = Date.now();
|
|
349
|
-
this.logger.info(`Browser launched in ${(stopTime - startTime) / 1000} s`);
|
|
350
338
|
this.bvtContext = bvtContext;
|
|
339
|
+
this.stepRunner = new BVTStepRunner({
|
|
340
|
+
projectDir: this.projectDir,
|
|
341
|
+
sendExecutionStatus: (data) => {
|
|
342
|
+
if (data && data.type) {
|
|
343
|
+
switch (data.type) {
|
|
344
|
+
case "cmdExecutionStart":
|
|
345
|
+
this.sendEvent(this.events.cmdExecutionStart, data);
|
|
346
|
+
break;
|
|
347
|
+
case "cmdExecutionSuccess":
|
|
348
|
+
this.sendEvent(this.events.cmdExecutionSuccess, data);
|
|
349
|
+
break;
|
|
350
|
+
case "cmdExecutionError":
|
|
351
|
+
this.sendEvent(this.events.cmdExecutionError, data);
|
|
352
|
+
break;
|
|
353
|
+
case "interceptResults":
|
|
354
|
+
this.sendEvent(this.events.interceptResults, data);
|
|
355
|
+
break;
|
|
356
|
+
default:
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
bvtContext: this.bvtContext,
|
|
362
|
+
});
|
|
351
363
|
const context = bvtContext.playContext;
|
|
352
364
|
this.context = context;
|
|
353
365
|
this.web = bvtContext.stable || bvtContext.web;
|
|
366
|
+
this.web.tryAllStrategies = true;
|
|
354
367
|
this.page = bvtContext.page;
|
|
355
|
-
|
|
356
368
|
this.pageSet.add(this.page);
|
|
357
369
|
this.lastKnownUrlPath = this._updateUrlPath();
|
|
358
370
|
const browser = await this.context.browser();
|
|
@@ -366,6 +378,14 @@ export class BVTRecorder {
|
|
|
366
378
|
this.web.onRestoreSaveState = (url) => {
|
|
367
379
|
this._initBrowser({ url });
|
|
368
380
|
};
|
|
381
|
+
|
|
382
|
+
// create a second browser for locator generation
|
|
383
|
+
this.backgroundBrowser = await chromium.launch({
|
|
384
|
+
headless: true,
|
|
385
|
+
});
|
|
386
|
+
this.backgroundContext = await this.backgroundBrowser.newContext({});
|
|
387
|
+
await this.backgroundContext.addInitScript({ content: this.getInitScripts(this.config) });
|
|
388
|
+
await this.backgroundContext.newPage();
|
|
369
389
|
}
|
|
370
390
|
async onClosePopup() {
|
|
371
391
|
// console.log("close popups");
|
|
@@ -380,13 +400,15 @@ export class BVTRecorder {
|
|
|
380
400
|
}
|
|
381
401
|
return;
|
|
382
402
|
} catch (error) {
|
|
383
|
-
console.error("Error evaluting in context:", error);
|
|
403
|
+
// console.error("Error evaluting in context:", error);
|
|
404
|
+
this.logger.error("Error evaluating in context:", error);
|
|
384
405
|
}
|
|
385
406
|
}
|
|
386
407
|
}
|
|
387
408
|
|
|
388
409
|
getMode() {
|
|
389
|
-
console.log("getMode", this.#mode);
|
|
410
|
+
// console.log("getMode", this.#mode);
|
|
411
|
+
this.logger.info("Current mode:", this.#mode);
|
|
390
412
|
return this.#mode;
|
|
391
413
|
}
|
|
392
414
|
|
|
@@ -411,7 +433,7 @@ export class BVTRecorder {
|
|
|
411
433
|
|
|
412
434
|
// eval init script on current tab
|
|
413
435
|
// await this._initPage(this.page);
|
|
414
|
-
this.#currentURL =
|
|
436
|
+
this.#currentURL = url;
|
|
415
437
|
|
|
416
438
|
await this.page.dispatchEvent("html", "scroll");
|
|
417
439
|
await delay(1000);
|
|
@@ -428,6 +450,8 @@ export class BVTRecorder {
|
|
|
428
450
|
this.sendEvent(this.events.onBrowserClose);
|
|
429
451
|
}
|
|
430
452
|
} catch (error) {
|
|
453
|
+
this.logger.error("Error in page close event");
|
|
454
|
+
this.logger.error(error);
|
|
431
455
|
console.error("Error in page close event");
|
|
432
456
|
console.error(error);
|
|
433
457
|
}
|
|
@@ -438,8 +462,10 @@ export class BVTRecorder {
|
|
|
438
462
|
if (frame !== page.mainFrame()) return;
|
|
439
463
|
this.handlePageTransition();
|
|
440
464
|
} catch (error) {
|
|
465
|
+
this.logger.error("Error in handlePageTransition event");
|
|
466
|
+
this.logger.error(error);
|
|
441
467
|
console.error("Error in handlePageTransition event");
|
|
442
|
-
|
|
468
|
+
console.error(error);
|
|
443
469
|
}
|
|
444
470
|
try {
|
|
445
471
|
if (frame !== this.#activeFrame) return;
|
|
@@ -449,15 +475,18 @@ export class BVTRecorder {
|
|
|
449
475
|
element: { inputID: "frame" },
|
|
450
476
|
});
|
|
451
477
|
|
|
452
|
-
const
|
|
478
|
+
const newUrl = frame.url();
|
|
479
|
+
const newPath = new URL(newUrl).pathname;
|
|
453
480
|
const newTitle = await frame.title();
|
|
454
|
-
|
|
481
|
+
const changed = diffPaths(this.#currentURL, newUrl);
|
|
482
|
+
|
|
483
|
+
if (changed) {
|
|
455
484
|
this.sendEvent(this.events.onFrameNavigate, { url: newPath, title: newTitle });
|
|
456
|
-
this.#currentURL =
|
|
485
|
+
this.#currentURL = newUrl;
|
|
457
486
|
}
|
|
458
|
-
// await this._setRecordingMode(frame);
|
|
459
|
-
// await this._initPage(page);
|
|
460
487
|
} catch (error) {
|
|
488
|
+
this.logger.error("Error in frame navigate event");
|
|
489
|
+
this.logger.error(error);
|
|
461
490
|
console.error("Error in frame navigate event");
|
|
462
491
|
// console.error(error);
|
|
463
492
|
}
|
|
@@ -540,13 +569,9 @@ export class BVTRecorder {
|
|
|
540
569
|
|
|
541
570
|
try {
|
|
542
571
|
const result = await client.send("Page.getNavigationHistory");
|
|
543
|
-
// console.log("Navigation History:", result);
|
|
544
572
|
const entries = result.entries;
|
|
545
573
|
const currentIndex = result.currentIndex;
|
|
546
574
|
|
|
547
|
-
// ignore if currentIndex is not the last entry
|
|
548
|
-
// if (currentIndex !== entries.length - 1) return;
|
|
549
|
-
|
|
550
575
|
const currentEntry = entries[currentIndex];
|
|
551
576
|
const transitionInfo = this.analyzeTransitionType(entries, currentIndex, currentEntry);
|
|
552
577
|
this.previousIndex = currentIndex;
|
|
@@ -559,6 +584,8 @@ export class BVTRecorder {
|
|
|
559
584
|
navigationAction: transitionInfo.action,
|
|
560
585
|
};
|
|
561
586
|
} catch (error) {
|
|
587
|
+
this.logger.error("Error in getCurrentTransition event");
|
|
588
|
+
this.logger.error(error);
|
|
562
589
|
console.error("Error in getTransistionType event", error);
|
|
563
590
|
} finally {
|
|
564
591
|
await client.detach();
|
|
@@ -627,6 +654,8 @@ export class BVTRecorder {
|
|
|
627
654
|
// add listener for frame navigation on new tab
|
|
628
655
|
this._addFrameNavigateListener(page);
|
|
629
656
|
} catch (error) {
|
|
657
|
+
this.logger.error("Error in page event");
|
|
658
|
+
this.logger.error(error);
|
|
630
659
|
console.error("Error in page event");
|
|
631
660
|
console.error(error);
|
|
632
661
|
}
|
|
@@ -668,6 +697,7 @@ export class BVTRecorder {
|
|
|
668
697
|
const { data } = await client.send("Page.captureScreenshot", { format: "png" });
|
|
669
698
|
return data;
|
|
670
699
|
} catch (error) {
|
|
700
|
+
this.logger.error("Error in taking browser screenshot");
|
|
671
701
|
console.error("Error in taking browser screenshot", error);
|
|
672
702
|
} finally {
|
|
673
703
|
await client.detach();
|
|
@@ -683,6 +713,52 @@ export class BVTRecorder {
|
|
|
683
713
|
console.error("Error in saving screenshot: ", error);
|
|
684
714
|
}
|
|
685
715
|
}
|
|
716
|
+
async generateLocators(event) {
|
|
717
|
+
const snapshotDetails = event.snapshotDetails;
|
|
718
|
+
if (!snapshotDetails) {
|
|
719
|
+
throw new Error("No snapshot details found");
|
|
720
|
+
}
|
|
721
|
+
const mode = event.mode;
|
|
722
|
+
const inputID = event.element.inputID;
|
|
723
|
+
|
|
724
|
+
const { id, contextId, doc } = snapshotDetails;
|
|
725
|
+
// const selector = `[data-blinq-id="${id}"]`;
|
|
726
|
+
const newPage = await this.backgroundContext.newPage();
|
|
727
|
+
await newPage.setContent(doc, { waitUntil: "domcontentloaded" });
|
|
728
|
+
const locatorsObj = await newPage.evaluate(
|
|
729
|
+
([id, contextId, mode]) => {
|
|
730
|
+
const recorder = window.__bvt_Recorder;
|
|
731
|
+
const contextElement = document.querySelector(`[data-blinq-context-id="${contextId}"]`);
|
|
732
|
+
const el = document.querySelector(`[data-blinq-id="${id}"]`);
|
|
733
|
+
if (contextElement) {
|
|
734
|
+
const result = recorder.locatorGenerator.toContextLocators(el, contextElement);
|
|
735
|
+
return result;
|
|
736
|
+
}
|
|
737
|
+
const isRecordingText = mode === "recordingText";
|
|
738
|
+
return recorder.locatorGenerator.getElementLocators(el, {
|
|
739
|
+
excludeText: isRecordingText,
|
|
740
|
+
});
|
|
741
|
+
},
|
|
742
|
+
[id, contextId, mode]
|
|
743
|
+
);
|
|
744
|
+
|
|
745
|
+
console.log(`Generated locators: for ${inputID}: `, JSON.stringify(locatorsObj));
|
|
746
|
+
await newPage.close();
|
|
747
|
+
if (event.nestFrmLoc?.children) {
|
|
748
|
+
locatorsObj.nestFrmLoc = event.nestFrmLoc.children;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
this.sendEvent(this.events.updateCommand, {
|
|
752
|
+
locators: {
|
|
753
|
+
locators: locatorsObj.locators,
|
|
754
|
+
nestFrmLoc: locatorsObj.nestFrmLoc,
|
|
755
|
+
iframe_src: !event.frame.isTop ? event.frame.url : undefined,
|
|
756
|
+
},
|
|
757
|
+
allStrategyLocators: locatorsObj.allStrategyLocators,
|
|
758
|
+
inputID,
|
|
759
|
+
});
|
|
760
|
+
// const
|
|
761
|
+
}
|
|
686
762
|
async onAction(event) {
|
|
687
763
|
this._updateUrlPath();
|
|
688
764
|
// const locators = this.overlayLocators(event);
|
|
@@ -696,25 +772,26 @@ export class BVTRecorder {
|
|
|
696
772
|
event.mode === "recordingHover",
|
|
697
773
|
event.mode === "multiInspecting"
|
|
698
774
|
),
|
|
699
|
-
locators: {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
},
|
|
703
|
-
allStrategyLocators: event.allStrategyLocators,
|
|
775
|
+
// locators: {
|
|
776
|
+
// locators: event.locators,
|
|
777
|
+
// iframe_src: !event.frame.isTop ? event.frame.url : undefined,
|
|
778
|
+
// },
|
|
779
|
+
// allStrategyLocators: event.allStrategyLocators,
|
|
704
780
|
url: event.frame.url,
|
|
705
781
|
title: event.frame.title,
|
|
706
782
|
extract: {},
|
|
707
783
|
lastKnownUrlPath: this.lastKnownUrlPath,
|
|
708
784
|
};
|
|
709
|
-
if (event.nestFrmLoc?.children) {
|
|
710
|
-
|
|
711
|
-
}
|
|
785
|
+
// if (event.nestFrmLoc?.children) {
|
|
786
|
+
// cmdEvent.locators.nestFrmLoc = event.nestFrmLoc.children;
|
|
787
|
+
// }
|
|
712
788
|
// this.logger.info({ event });
|
|
713
789
|
if (this.shouldTakeScreenshot) {
|
|
714
790
|
await this.storeScreenshot(event);
|
|
715
791
|
}
|
|
716
792
|
this.sendEvent(this.events.onNewCommand, cmdEvent);
|
|
717
793
|
this._updateUrlPath();
|
|
794
|
+
await this.generateLocators(event);
|
|
718
795
|
}
|
|
719
796
|
_updateUrlPath() {
|
|
720
797
|
try {
|
|
@@ -788,7 +865,6 @@ export class BVTRecorder {
|
|
|
788
865
|
}
|
|
789
866
|
|
|
790
867
|
async startRecordingInput() {
|
|
791
|
-
console.log("startRecordingInput");
|
|
792
868
|
await this.setMode("recordingInput");
|
|
793
869
|
}
|
|
794
870
|
async stopRecordingInput() {
|
|
@@ -812,9 +888,17 @@ export class BVTRecorder {
|
|
|
812
888
|
}
|
|
813
889
|
|
|
814
890
|
async abortExecution() {
|
|
815
|
-
this.bvtContext.web.abortedExecution = true;
|
|
816
891
|
await this.stepRunner.abortExecution();
|
|
817
892
|
}
|
|
893
|
+
|
|
894
|
+
async pauseExecution({ cmdId }) {
|
|
895
|
+
await this.stepRunner.pauseExecution(cmdId);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
async resumeExecution({ cmdId }) {
|
|
899
|
+
await this.stepRunner.resumeExecution(cmdId);
|
|
900
|
+
}
|
|
901
|
+
|
|
818
902
|
async dealyedRevertMode() {
|
|
819
903
|
const timerId = setTimeout(async () => {
|
|
820
904
|
await this.revertMode();
|
|
@@ -828,13 +912,15 @@ export class BVTRecorder {
|
|
|
828
912
|
TEMP_RUN: true,
|
|
829
913
|
REPORT_FOLDER: this.bvtContext.reportFolder,
|
|
830
914
|
BLINQ_ENV: this.envName,
|
|
831
|
-
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
832
|
-
CURRENT_STEP_ID: step.id,
|
|
833
915
|
};
|
|
834
916
|
|
|
835
917
|
this.bvtContext.navigate = true;
|
|
836
918
|
this.bvtContext.loadedRoutes = null;
|
|
837
|
-
|
|
919
|
+
if (listenNetwork) {
|
|
920
|
+
this.bvtContext.STORE_DETAILED_NETWORK_DATA = true;
|
|
921
|
+
} else {
|
|
922
|
+
this.bvtContext.STORE_DETAILED_NETWORK_DATA = false;
|
|
923
|
+
}
|
|
838
924
|
for (const [key, value] of Object.entries(_env)) {
|
|
839
925
|
process.env[key] = value;
|
|
840
926
|
}
|
|
@@ -959,10 +1045,11 @@ export class BVTRecorder {
|
|
|
959
1045
|
if (existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
960
1046
|
try {
|
|
961
1047
|
const testData = JSON.parse(readFileSync(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
|
|
962
|
-
this.logger.info("Test data", testData);
|
|
1048
|
+
// this.logger.info("Test data", testData);
|
|
963
1049
|
this.sendEvent(this.events.getTestData, testData);
|
|
964
1050
|
} catch (e) {
|
|
965
|
-
this.logger.error("Error reading test data file", e);
|
|
1051
|
+
// this.logger.error("Error reading test data file", e);
|
|
1052
|
+
console.log("Error reading test data file", e);
|
|
966
1053
|
}
|
|
967
1054
|
}
|
|
968
1055
|
|
|
@@ -971,10 +1058,12 @@ export class BVTRecorder {
|
|
|
971
1058
|
this.watcher.on("all", async (event, path) => {
|
|
972
1059
|
try {
|
|
973
1060
|
const testData = JSON.parse(await readFile(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
|
|
974
|
-
this.logger.info("Test data", testData);
|
|
1061
|
+
// this.logger.info("Test data", testData);
|
|
1062
|
+
console.log("Test data changed", testData);
|
|
975
1063
|
this.sendEvent(this.events.getTestData, testData);
|
|
976
1064
|
} catch (e) {
|
|
977
|
-
this.logger.error("Error reading test data file", e);
|
|
1065
|
+
// this.logger.error("Error reading test data file", e);
|
|
1066
|
+
console.log("Error reading test data file", e);
|
|
978
1067
|
}
|
|
979
1068
|
});
|
|
980
1069
|
}
|
|
@@ -1007,7 +1096,7 @@ export class BVTRecorder {
|
|
|
1007
1096
|
.filter((file) => file.endsWith(".feature"))
|
|
1008
1097
|
.map((file) => path.join(this.projectDir, "features", file));
|
|
1009
1098
|
try {
|
|
1010
|
-
const parsedFiles = featureFiles.map((file) => parseFeatureFile(file));
|
|
1099
|
+
const parsedFiles = featureFiles.map((file) => this.parseFeatureFile(file));
|
|
1011
1100
|
const output = {};
|
|
1012
1101
|
parsedFiles.forEach((file) => {
|
|
1013
1102
|
if (!file.feature) return;
|
|
@@ -1035,7 +1124,7 @@ export class BVTRecorder {
|
|
|
1035
1124
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
1036
1125
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
1037
1126
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
1038
|
-
const gherkinDoc = parseFeatureFile(featureFilePath);
|
|
1127
|
+
const gherkinDoc = this.parseFeatureFile(featureFilePath);
|
|
1039
1128
|
const scenario = gherkinDoc.feature.children.find((child) => child.scenario.name === scenarioName)?.scenario;
|
|
1040
1129
|
|
|
1041
1130
|
const steps = [];
|
|
@@ -1194,20 +1283,54 @@ export class BVTRecorder {
|
|
|
1194
1283
|
await this.cleanupExecution({ tags });
|
|
1195
1284
|
await this.initExecution({ tags });
|
|
1196
1285
|
}
|
|
1197
|
-
}
|
|
1198
1286
|
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1287
|
+
parseFeatureFile(featureFilePath) {
|
|
1288
|
+
try {
|
|
1289
|
+
let id = 0;
|
|
1290
|
+
const uuidFn = () => (++id).toString(16);
|
|
1291
|
+
const builder = new AstBuilder(uuidFn);
|
|
1292
|
+
const matcher = new GherkinClassicTokenMatcher();
|
|
1293
|
+
const parser = new Parser(builder, matcher);
|
|
1294
|
+
const source = readFileSync(featureFilePath, "utf8");
|
|
1295
|
+
const gherkinDocument = parser.parse(source);
|
|
1296
|
+
return gherkinDocument;
|
|
1297
|
+
} catch (e) {
|
|
1298
|
+
this.logger.error(`Error parsing feature file: ${featureFilePath}`);
|
|
1299
|
+
console.log(e);
|
|
1300
|
+
}
|
|
1301
|
+
return {};
|
|
1211
1302
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1303
|
+
|
|
1304
|
+
stopRecordingNetwork(input) {
|
|
1305
|
+
if (this.bvtContext) {
|
|
1306
|
+
this.bvtContext.STORE_DETAILED_NETWORK_DATA = false;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
async fakeParams(params) {
|
|
1311
|
+
const newFakeParams = {};
|
|
1312
|
+
Object.keys(params).forEach((key) => {
|
|
1313
|
+
if (!params[key].startsWith("{{") || !params[key].endsWith("}}")) {
|
|
1314
|
+
newFakeParams[key] = params[key];
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
try {
|
|
1319
|
+
const value = params[key].substring(2, params[key].length - 2).trim();
|
|
1320
|
+
const faking = value.split("(")[0].split(".");
|
|
1321
|
+
let argument = value.substring(value.indexOf("(") + 1, value.lastIndexOf(")"));
|
|
1322
|
+
argument = isNaN(Number(argument)) || argument === "" ? argument : Number(argument);
|
|
1323
|
+
let fakeFunc = faker;
|
|
1324
|
+
faking.forEach((f) => {
|
|
1325
|
+
fakeFunc = fakeFunc[f];
|
|
1326
|
+
});
|
|
1327
|
+
const newValue = fakeFunc(argument);
|
|
1328
|
+
newFakeParams[key] = newValue;
|
|
1329
|
+
} catch (error) {
|
|
1330
|
+
newFakeParams[key] = params[key];
|
|
1331
|
+
}
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1334
|
+
return newFakeParams;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
@@ -116,6 +116,12 @@ export const getImplementedSteps = async (projectDir) => {
|
|
|
116
116
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
117
117
|
//console.log({ utilsContent });
|
|
118
118
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
119
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
120
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
121
|
+
const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
|
|
122
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
123
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
124
|
+
}
|
|
119
125
|
} catch (error) {
|
|
120
126
|
foundErrors.push({ error });
|
|
121
127
|
}
|
|
@@ -229,6 +235,7 @@ export const getImplementedSteps = async (projectDir) => {
|
|
|
229
235
|
pattern: template.pattern,
|
|
230
236
|
paths: template.paths,
|
|
231
237
|
routeItems: step.routeItems,
|
|
238
|
+
isApiStep: template.source === "api",
|
|
232
239
|
};
|
|
233
240
|
|
|
234
241
|
implementedSteps.push(implementedStep);
|
|
@@ -254,6 +261,7 @@ export const getImplementedSteps = async (projectDir) => {
|
|
|
254
261
|
mjsFile: template.mjsFile,
|
|
255
262
|
pattern: template.pattern,
|
|
256
263
|
paths: template.paths,
|
|
264
|
+
isApiStep: template.source === "api",
|
|
257
265
|
};
|
|
258
266
|
// reconstruct the parameters
|
|
259
267
|
const parameters = [];
|