@dev-blinq/cucumber_client 1.0.1341-dev → 1.0.1341-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 +110 -110
- package/bin/assets/preload/css_gen.js +10 -10
- package/bin/assets/preload/recorderv3.js +3 -1
- 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 +5 -17
- package/bin/assets/scripts/snapshot_capturer.js +153 -146
- package/bin/assets/scripts/unique_locators.js +940 -815
- 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/cli_helpers.js +11 -13
- 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 +112 -4
- package/bin/client/code_gen/page_reflection.js +839 -906
- package/bin/client/code_gen/playwright_codeget.js +26 -18
- package/bin/client/cucumber/feature.js +89 -27
- 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 +6 -5
- 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 +136 -81
- package/bin/client/recorderv3/implemented_steps.js +24 -14
- package/bin/client/recorderv3/index.js +59 -54
- package/bin/client/recorderv3/network.js +22 -5
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +318 -209
- package/bin/client/recorderv3/step_utils.js +476 -17
- package/bin/client/recorderv3/update_feature.js +32 -30
- package/bin/client/recording.js +1 -0
- package/bin/client/run_cucumber.js +1 -1
- package/bin/client/scenario_report.js +0 -5
- package/bin/client/test_scenario.js +0 -1
- 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 +21 -12
|
@@ -12,11 +12,11 @@ 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";
|
|
20
20
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
21
21
|
|
|
22
22
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -45,15 +45,15 @@ async function evaluate(frame, script) {
|
|
|
45
45
|
async function findNestedFrameSelector(frame, obj) {
|
|
46
46
|
try {
|
|
47
47
|
const parent = frame.parentFrame();
|
|
48
|
-
if (parent) console.log(`Parent frame: ${JSON.stringify(parent)}`);
|
|
49
48
|
if (!parent) return { children: obj };
|
|
50
49
|
const frameElement = await frame.frameElement();
|
|
51
50
|
if (!frameElement) return;
|
|
52
51
|
const selectors = await parent.evaluate((element) => {
|
|
53
|
-
return window.
|
|
52
|
+
return window.__bvt_Recorder.locatorGenerator.getElementLocators(element, { excludeText: true }).locators;
|
|
54
53
|
}, frameElement);
|
|
55
54
|
return findNestedFrameSelector(parent, { children: obj, selectors });
|
|
56
55
|
} catch (e) {
|
|
56
|
+
socketLogger.error(`Error in findNestedFrameSelector: ${e}`);
|
|
57
57
|
console.error(e);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -150,6 +150,7 @@ const transformAction = (action, el, isVerify, isPopupCloseClick, isInHoverMode,
|
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
default: {
|
|
153
|
+
socketLogger.error(`Action not supported: ${action.name}`);
|
|
153
154
|
console.log("action not supported", action);
|
|
154
155
|
throw new Error("action not supported");
|
|
155
156
|
}
|
|
@@ -161,6 +162,7 @@ const transformAction = (action, el, isVerify, isPopupCloseClick, isInHoverMode,
|
|
|
161
162
|
* @property {string} projectDir
|
|
162
163
|
* @property {string} TOKEN
|
|
163
164
|
* @property {(name:string, data:any)=> void} sendEvent
|
|
165
|
+
* @property {Object} logger
|
|
164
166
|
*/
|
|
165
167
|
export class BVTRecorder {
|
|
166
168
|
#currentURL = "";
|
|
@@ -174,7 +176,6 @@ export class BVTRecorder {
|
|
|
174
176
|
*/
|
|
175
177
|
constructor(initialState) {
|
|
176
178
|
Object.assign(this, initialState);
|
|
177
|
-
this.logger = logger;
|
|
178
179
|
this.screenshotMap = new Map();
|
|
179
180
|
this.snapshotMap = new Map();
|
|
180
181
|
this.scenariosStepsMap = new Map();
|
|
@@ -184,40 +185,16 @@ export class BVTRecorder {
|
|
|
184
185
|
projectDir: this.projectDir,
|
|
185
186
|
logger: this.logger,
|
|
186
187
|
});
|
|
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
188
|
this.pageSet = new Set();
|
|
189
|
+
this.pageMetaDataSet = new Set();
|
|
216
190
|
this.lastKnownUrlPath = "";
|
|
217
|
-
// TODO: what is world?
|
|
218
191
|
this.world = { attach: () => {} };
|
|
219
192
|
this.shouldTakeScreenshot = true;
|
|
220
193
|
this.watcher = null;
|
|
194
|
+
this.networkEventsFolder = path.join(tmpdir(), "blinq_network_events");
|
|
195
|
+
if (existsSync(this.networkEventsFolder)) {
|
|
196
|
+
rmSync(this.networkEventsFolder, { recursive: true, force: true });
|
|
197
|
+
}
|
|
221
198
|
}
|
|
222
199
|
events = {
|
|
223
200
|
onFrameNavigate: "BVTRecorder.onFrameNavigate",
|
|
@@ -237,7 +214,7 @@ export class BVTRecorder {
|
|
|
237
214
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
238
215
|
this.#activeFrame = frame;
|
|
239
216
|
const nestFrmLoc = await findNestedFrameSelector(frame);
|
|
240
|
-
|
|
217
|
+
this.logger.info(`Time taken for action: ${event.statistics.time}`);
|
|
241
218
|
await this.onAction({ ...event, nestFrmLoc });
|
|
242
219
|
},
|
|
243
220
|
__bvt_getMode: async () => {
|
|
@@ -256,8 +233,7 @@ export class BVTRecorder {
|
|
|
256
233
|
await this.onClosePopup();
|
|
257
234
|
},
|
|
258
235
|
__bvt_log: async (src, message) => {
|
|
259
|
-
|
|
260
|
-
console.log(`Inside Browser: ${message}`);
|
|
236
|
+
this.logger.info(`Inside Browser: ${message}`);
|
|
261
237
|
},
|
|
262
238
|
__bvt_getObject: (_src, obj) => {
|
|
263
239
|
this.processObject(obj);
|
|
@@ -269,7 +245,6 @@ export class BVTRecorder {
|
|
|
269
245
|
const locator = await this.web.page.locator(selector);
|
|
270
246
|
const snapshot = await locator.ariaSnapshot();
|
|
271
247
|
return snapshot;
|
|
272
|
-
// Triggering workflow
|
|
273
248
|
};
|
|
274
249
|
|
|
275
250
|
processObject = async ({ type, action, value }) => {
|
|
@@ -320,10 +295,11 @@ export class BVTRecorder {
|
|
|
320
295
|
}
|
|
321
296
|
|
|
322
297
|
async _initBrowser({ url }) {
|
|
298
|
+
socketLogger.info("Only present in 1.0.1293-stage");
|
|
323
299
|
this.#remoteDebuggerPort = await findAvailablePort();
|
|
324
300
|
process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
|
|
325
301
|
|
|
326
|
-
this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
302
|
+
// this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
327
303
|
this.world = { attach: () => {} };
|
|
328
304
|
|
|
329
305
|
const ai_config_file = path.join(this.projectDir, "ai_config.json");
|
|
@@ -332,9 +308,10 @@ export class BVTRecorder {
|
|
|
332
308
|
try {
|
|
333
309
|
ai_config = JSON.parse(readFileSync(ai_config_file, "utf8"));
|
|
334
310
|
} catch (error) {
|
|
335
|
-
|
|
311
|
+
this.logger.error("Error reading ai_config.json", error);
|
|
336
312
|
}
|
|
337
313
|
}
|
|
314
|
+
this.config = ai_config;
|
|
338
315
|
const initScripts = {
|
|
339
316
|
// recorderCjs: injectedScriptSource,
|
|
340
317
|
scripts: [
|
|
@@ -343,16 +320,37 @@ export class BVTRecorder {
|
|
|
343
320
|
],
|
|
344
321
|
};
|
|
345
322
|
|
|
346
|
-
let startTime = Date.now();
|
|
347
323
|
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
324
|
this.bvtContext = bvtContext;
|
|
325
|
+
this.stepRunner = new BVTStepRunner({
|
|
326
|
+
projectDir: this.projectDir,
|
|
327
|
+
sendExecutionStatus: (data) => {
|
|
328
|
+
if (data && data.type) {
|
|
329
|
+
switch (data.type) {
|
|
330
|
+
case "cmdExecutionStart":
|
|
331
|
+
this.sendEvent(this.events.cmdExecutionStart, data);
|
|
332
|
+
break;
|
|
333
|
+
case "cmdExecutionSuccess":
|
|
334
|
+
this.sendEvent(this.events.cmdExecutionSuccess, data);
|
|
335
|
+
break;
|
|
336
|
+
case "cmdExecutionError":
|
|
337
|
+
this.sendEvent(this.events.cmdExecutionError, data);
|
|
338
|
+
break;
|
|
339
|
+
case "interceptResults":
|
|
340
|
+
this.sendEvent(this.events.interceptResults, data);
|
|
341
|
+
break;
|
|
342
|
+
default:
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
bvtContext: this.bvtContext,
|
|
348
|
+
});
|
|
351
349
|
const context = bvtContext.playContext;
|
|
352
350
|
this.context = context;
|
|
353
351
|
this.web = bvtContext.stable || bvtContext.web;
|
|
352
|
+
this.web.tryAllStrategies = true;
|
|
354
353
|
this.page = bvtContext.page;
|
|
355
|
-
|
|
356
354
|
this.pageSet.add(this.page);
|
|
357
355
|
this.lastKnownUrlPath = this._updateUrlPath();
|
|
358
356
|
const browser = await this.context.browser();
|
|
@@ -380,13 +378,15 @@ export class BVTRecorder {
|
|
|
380
378
|
}
|
|
381
379
|
return;
|
|
382
380
|
} catch (error) {
|
|
383
|
-
console.error("Error evaluting in context:", error);
|
|
381
|
+
// console.error("Error evaluting in context:", error);
|
|
382
|
+
this.logger.error("Error evaluating in context:", error);
|
|
384
383
|
}
|
|
385
384
|
}
|
|
386
385
|
}
|
|
387
386
|
|
|
388
387
|
getMode() {
|
|
389
|
-
console.log("getMode", this.#mode);
|
|
388
|
+
// console.log("getMode", this.#mode);
|
|
389
|
+
this.logger.info("Current mode:", this.#mode);
|
|
390
390
|
return this.#mode;
|
|
391
391
|
}
|
|
392
392
|
|
|
@@ -428,6 +428,8 @@ export class BVTRecorder {
|
|
|
428
428
|
this.sendEvent(this.events.onBrowserClose);
|
|
429
429
|
}
|
|
430
430
|
} catch (error) {
|
|
431
|
+
this.logger.error("Error in page close event");
|
|
432
|
+
this.logger.error(error);
|
|
431
433
|
console.error("Error in page close event");
|
|
432
434
|
console.error(error);
|
|
433
435
|
}
|
|
@@ -438,8 +440,10 @@ export class BVTRecorder {
|
|
|
438
440
|
if (frame !== page.mainFrame()) return;
|
|
439
441
|
this.handlePageTransition();
|
|
440
442
|
} catch (error) {
|
|
443
|
+
this.logger.error("Error in handlePageTransition event");
|
|
444
|
+
this.logger.error(error);
|
|
441
445
|
console.error("Error in handlePageTransition event");
|
|
442
|
-
|
|
446
|
+
console.error(error);
|
|
443
447
|
}
|
|
444
448
|
try {
|
|
445
449
|
if (frame !== this.#activeFrame) return;
|
|
@@ -458,6 +462,8 @@ export class BVTRecorder {
|
|
|
458
462
|
// await this._setRecordingMode(frame);
|
|
459
463
|
// await this._initPage(page);
|
|
460
464
|
} catch (error) {
|
|
465
|
+
this.logger.error("Error in frame navigate event");
|
|
466
|
+
this.logger.error(error);
|
|
461
467
|
console.error("Error in frame navigate event");
|
|
462
468
|
// console.error(error);
|
|
463
469
|
}
|
|
@@ -540,13 +546,9 @@ export class BVTRecorder {
|
|
|
540
546
|
|
|
541
547
|
try {
|
|
542
548
|
const result = await client.send("Page.getNavigationHistory");
|
|
543
|
-
// console.log("Navigation History:", result);
|
|
544
549
|
const entries = result.entries;
|
|
545
550
|
const currentIndex = result.currentIndex;
|
|
546
551
|
|
|
547
|
-
// ignore if currentIndex is not the last entry
|
|
548
|
-
// if (currentIndex !== entries.length - 1) return;
|
|
549
|
-
|
|
550
552
|
const currentEntry = entries[currentIndex];
|
|
551
553
|
const transitionInfo = this.analyzeTransitionType(entries, currentIndex, currentEntry);
|
|
552
554
|
this.previousIndex = currentIndex;
|
|
@@ -559,6 +561,8 @@ export class BVTRecorder {
|
|
|
559
561
|
navigationAction: transitionInfo.action,
|
|
560
562
|
};
|
|
561
563
|
} catch (error) {
|
|
564
|
+
this.logger.error("Error in getCurrentTransition event");
|
|
565
|
+
this.logger.error(error);
|
|
562
566
|
console.error("Error in getTransistionType event", error);
|
|
563
567
|
} finally {
|
|
564
568
|
await client.detach();
|
|
@@ -623,9 +627,12 @@ export class BVTRecorder {
|
|
|
623
627
|
this.pageSet.add(page);
|
|
624
628
|
|
|
625
629
|
await page.waitForLoadState("domcontentloaded");
|
|
630
|
+
|
|
626
631
|
// add listener for frame navigation on new tab
|
|
627
632
|
this._addFrameNavigateListener(page);
|
|
628
633
|
} catch (error) {
|
|
634
|
+
this.logger.error("Error in page event");
|
|
635
|
+
this.logger.error(error);
|
|
629
636
|
console.error("Error in page event");
|
|
630
637
|
console.error(error);
|
|
631
638
|
}
|
|
@@ -667,6 +674,7 @@ export class BVTRecorder {
|
|
|
667
674
|
const { data } = await client.send("Page.captureScreenshot", { format: "png" });
|
|
668
675
|
return data;
|
|
669
676
|
} catch (error) {
|
|
677
|
+
this.logger.error("Error in taking browser screenshot");
|
|
670
678
|
console.error("Error in taking browser screenshot", error);
|
|
671
679
|
} finally {
|
|
672
680
|
await client.detach();
|
|
@@ -712,7 +720,6 @@ export class BVTRecorder {
|
|
|
712
720
|
if (this.shouldTakeScreenshot) {
|
|
713
721
|
await this.storeScreenshot(event);
|
|
714
722
|
}
|
|
715
|
-
|
|
716
723
|
this.sendEvent(this.events.onNewCommand, cmdEvent);
|
|
717
724
|
this._updateUrlPath();
|
|
718
725
|
}
|
|
@@ -788,7 +795,6 @@ export class BVTRecorder {
|
|
|
788
795
|
}
|
|
789
796
|
|
|
790
797
|
async startRecordingInput() {
|
|
791
|
-
console.log("startRecordingInput");
|
|
792
798
|
await this.setMode("recordingInput");
|
|
793
799
|
}
|
|
794
800
|
async stopRecordingInput() {
|
|
@@ -812,9 +818,17 @@ export class BVTRecorder {
|
|
|
812
818
|
}
|
|
813
819
|
|
|
814
820
|
async abortExecution() {
|
|
815
|
-
this.bvtContext.web.abortedExecution = true;
|
|
816
821
|
await this.stepRunner.abortExecution();
|
|
817
822
|
}
|
|
823
|
+
|
|
824
|
+
async pauseExecution({ cmdId }) {
|
|
825
|
+
await this.stepRunner.pauseExecution(cmdId);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
async resumeExecution({ cmdId }) {
|
|
829
|
+
await this.stepRunner.resumeExecution(cmdId);
|
|
830
|
+
}
|
|
831
|
+
|
|
818
832
|
async dealyedRevertMode() {
|
|
819
833
|
const timerId = setTimeout(async () => {
|
|
820
834
|
await this.revertMode();
|
|
@@ -828,13 +842,15 @@ export class BVTRecorder {
|
|
|
828
842
|
TEMP_RUN: true,
|
|
829
843
|
REPORT_FOLDER: this.bvtContext.reportFolder,
|
|
830
844
|
BLINQ_ENV: this.envName,
|
|
831
|
-
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
832
|
-
CURRENT_STEP_ID: step.id,
|
|
833
845
|
};
|
|
834
846
|
|
|
835
847
|
this.bvtContext.navigate = true;
|
|
836
848
|
this.bvtContext.loadedRoutes = null;
|
|
837
|
-
|
|
849
|
+
if (listenNetwork) {
|
|
850
|
+
this.bvtContext.STORE_DETAILED_NETWORK_DATA = true;
|
|
851
|
+
} else {
|
|
852
|
+
this.bvtContext.STORE_DETAILED_NETWORK_DATA = false;
|
|
853
|
+
}
|
|
838
854
|
for (const [key, value] of Object.entries(_env)) {
|
|
839
855
|
process.env[key] = value;
|
|
840
856
|
}
|
|
@@ -852,6 +868,7 @@ export class BVTRecorder {
|
|
|
852
868
|
parametersMap,
|
|
853
869
|
envPath: this.envName,
|
|
854
870
|
tags,
|
|
871
|
+
config: this.config,
|
|
855
872
|
},
|
|
856
873
|
this.bvtContext,
|
|
857
874
|
{
|
|
@@ -906,6 +923,7 @@ export class BVTRecorder {
|
|
|
906
923
|
// map: this.scenariosStepsMap,
|
|
907
924
|
// });
|
|
908
925
|
}
|
|
926
|
+
|
|
909
927
|
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
910
928
|
return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
|
|
911
929
|
}
|
|
@@ -957,10 +975,11 @@ export class BVTRecorder {
|
|
|
957
975
|
if (existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
958
976
|
try {
|
|
959
977
|
const testData = JSON.parse(readFileSync(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
|
|
960
|
-
this.logger.info("Test data", testData);
|
|
978
|
+
// this.logger.info("Test data", testData);
|
|
961
979
|
this.sendEvent(this.events.getTestData, testData);
|
|
962
980
|
} catch (e) {
|
|
963
|
-
this.logger.error("Error reading test data file", e);
|
|
981
|
+
// this.logger.error("Error reading test data file", e);
|
|
982
|
+
console.log("Error reading test data file", e);
|
|
964
983
|
}
|
|
965
984
|
}
|
|
966
985
|
|
|
@@ -969,10 +988,12 @@ export class BVTRecorder {
|
|
|
969
988
|
this.watcher.on("all", async (event, path) => {
|
|
970
989
|
try {
|
|
971
990
|
const testData = JSON.parse(await readFile(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
|
|
972
|
-
this.logger.info("Test data", testData);
|
|
991
|
+
// this.logger.info("Test data", testData);
|
|
992
|
+
console.log("Test data changed", testData);
|
|
973
993
|
this.sendEvent(this.events.getTestData, testData);
|
|
974
994
|
} catch (e) {
|
|
975
|
-
this.logger.error("Error reading test data file", e);
|
|
995
|
+
// this.logger.error("Error reading test data file", e);
|
|
996
|
+
console.log("Error reading test data file", e);
|
|
976
997
|
}
|
|
977
998
|
});
|
|
978
999
|
}
|
|
@@ -1005,7 +1026,7 @@ export class BVTRecorder {
|
|
|
1005
1026
|
.filter((file) => file.endsWith(".feature"))
|
|
1006
1027
|
.map((file) => path.join(this.projectDir, "features", file));
|
|
1007
1028
|
try {
|
|
1008
|
-
const parsedFiles = featureFiles.map((file) => parseFeatureFile(file));
|
|
1029
|
+
const parsedFiles = featureFiles.map((file) => this.parseFeatureFile(file));
|
|
1009
1030
|
const output = {};
|
|
1010
1031
|
parsedFiles.forEach((file) => {
|
|
1011
1032
|
if (!file.feature) return;
|
|
@@ -1033,7 +1054,7 @@ export class BVTRecorder {
|
|
|
1033
1054
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
1034
1055
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
1035
1056
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
1036
|
-
const gherkinDoc = parseFeatureFile(featureFilePath);
|
|
1057
|
+
const gherkinDoc = this.parseFeatureFile(featureFilePath);
|
|
1037
1058
|
const scenario = gherkinDoc.feature.children.find((child) => child.scenario.name === scenarioName)?.scenario;
|
|
1038
1059
|
|
|
1039
1060
|
const steps = [];
|
|
@@ -1189,23 +1210,57 @@ export class BVTRecorder {
|
|
|
1189
1210
|
}
|
|
1190
1211
|
async resetExecution({ tags = [] }) {
|
|
1191
1212
|
// run after hooks followed by before hooks
|
|
1192
|
-
await this.
|
|
1193
|
-
await this.
|
|
1213
|
+
await this.cleanupExecution({ tags });
|
|
1214
|
+
await this.initExecution({ tags });
|
|
1194
1215
|
}
|
|
1195
|
-
}
|
|
1196
1216
|
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1217
|
+
parseFeatureFile(featureFilePath) {
|
|
1218
|
+
try {
|
|
1219
|
+
let id = 0;
|
|
1220
|
+
const uuidFn = () => (++id).toString(16);
|
|
1221
|
+
const builder = new AstBuilder(uuidFn);
|
|
1222
|
+
const matcher = new GherkinClassicTokenMatcher();
|
|
1223
|
+
const parser = new Parser(builder, matcher);
|
|
1224
|
+
const source = readFileSync(featureFilePath, "utf8");
|
|
1225
|
+
const gherkinDocument = parser.parse(source);
|
|
1226
|
+
return gherkinDocument;
|
|
1227
|
+
} catch (e) {
|
|
1228
|
+
this.logger.error(`Error parsing feature file: ${featureFilePath}`);
|
|
1229
|
+
console.log(e);
|
|
1230
|
+
}
|
|
1231
|
+
return {};
|
|
1209
1232
|
}
|
|
1210
|
-
|
|
1211
|
-
|
|
1233
|
+
|
|
1234
|
+
stopRecordingNetwork(input) {
|
|
1235
|
+
if (this.bvtContext) {
|
|
1236
|
+
this.bvtContext.STORE_DETAILED_NETWORK_DATA = false;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
async fakeParams(params) {
|
|
1241
|
+
const newFakeParams = {};
|
|
1242
|
+
Object.keys(params).forEach((key) => {
|
|
1243
|
+
if (!params[key].startsWith("{{") || !params[key].endsWith("}}")) {
|
|
1244
|
+
newFakeParams[key] = params[key];
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
try {
|
|
1249
|
+
const value = params[key].substring(2, params[key].length - 2).trim();
|
|
1250
|
+
const faking = value.split("(")[0].split(".");
|
|
1251
|
+
let argument = value.substring(value.indexOf("(") + 1, value.lastIndexOf(")"));
|
|
1252
|
+
argument = isNaN(Number(argument)) || argument === "" ? argument : Number(argument);
|
|
1253
|
+
let fakeFunc = faker;
|
|
1254
|
+
faking.forEach((f) => {
|
|
1255
|
+
fakeFunc = fakeFunc[f];
|
|
1256
|
+
});
|
|
1257
|
+
const newValue = fakeFunc(argument);
|
|
1258
|
+
newFakeParams[key] = newValue;
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
newFakeParams[key] = params[key];
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
return newFakeParams;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
@@ -13,7 +13,6 @@ const uuidFn = () => (++id).toString(16);
|
|
|
13
13
|
const builder = new AstBuilder(uuidFn);
|
|
14
14
|
const matcher = new GherkinClassicTokenMatcher();
|
|
15
15
|
const parser = new Parser(builder, matcher);
|
|
16
|
-
|
|
17
16
|
let i = 0;
|
|
18
17
|
const getImplId = () => {
|
|
19
18
|
return `I-${i++}`;
|
|
@@ -61,6 +60,11 @@ export function parseRouteFiles(projectDir, step) {
|
|
|
61
60
|
const routeFolder = path.join(projectDir, "data", "routes");
|
|
62
61
|
const templateRouteMap = new Map();
|
|
63
62
|
|
|
63
|
+
if (!existsSync(routeFolder)) {
|
|
64
|
+
step.routeItems = null;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
64
68
|
// Go over all the files in the route folder and parse them
|
|
65
69
|
const routeFiles = readdirSync(routeFolder).filter((file) => file.endsWith(".json"));
|
|
66
70
|
for (const file of routeFiles) {
|
|
@@ -87,8 +91,8 @@ export function parseRouteFiles(projectDir, step) {
|
|
|
87
91
|
const filters = item.filters || {};
|
|
88
92
|
const queryParams = filters?.queryParams || {};
|
|
89
93
|
const queryParamsArray = Object.keys(queryParams).map((key) => ({
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
key: key,
|
|
95
|
+
value: queryParams[key],
|
|
92
96
|
}));
|
|
93
97
|
filters.queryParams = queryParamsArray || [];
|
|
94
98
|
});
|
|
@@ -112,6 +116,12 @@ export const getImplementedSteps = async (projectDir) => {
|
|
|
112
116
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
113
117
|
//console.log({ utilsContent });
|
|
114
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
|
+
}
|
|
115
125
|
} catch (error) {
|
|
116
126
|
foundErrors.push({ error });
|
|
117
127
|
}
|
|
@@ -284,17 +294,17 @@ export const getImplementedSteps = async (projectDir) => {
|
|
|
284
294
|
for (const tag of scenario.tags) {
|
|
285
295
|
delete tag.location;
|
|
286
296
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
297
|
+
for (const scenario of scenarios) {
|
|
298
|
+
for (const step of scenario.steps) {
|
|
299
|
+
if (step.templateIndex === undefined) {
|
|
300
|
+
const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
|
|
301
|
+
const index = implementedSteps.findIndex((istep) => {
|
|
302
|
+
return cleanStepName === istep.pattern;
|
|
303
|
+
});
|
|
304
|
+
step.templateIndex = index;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
298
308
|
}
|
|
299
309
|
if (foundErrors.length > 0) {
|
|
300
310
|
console.log("foundErrors", foundErrors);
|