@dev-blinq/cucumber_client 1.0.1431-dev → 1.0.1431-stage

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +73 -73
  2. package/bin/assets/preload/css_gen.js +10 -10
  3. package/bin/assets/preload/toolbar.js +27 -29
  4. package/bin/assets/preload/unique_locators.js +1 -1
  5. package/bin/assets/preload/yaml.js +288 -275
  6. package/bin/assets/scripts/aria_snapshot.js +223 -220
  7. package/bin/assets/scripts/dom_attr.js +329 -329
  8. package/bin/assets/scripts/dom_parent.js +169 -174
  9. package/bin/assets/scripts/event_utils.js +94 -94
  10. package/bin/assets/scripts/pw.js +2050 -1949
  11. package/bin/assets/scripts/recorder.js +70 -45
  12. package/bin/assets/scripts/snapshot_capturer.js +147 -147
  13. package/bin/assets/scripts/unique_locators.js +170 -49
  14. package/bin/assets/scripts/yaml.js +796 -783
  15. package/bin/assets/templates/_hooks_template.txt +6 -2
  16. package/bin/assets/templates/utils_template.txt +16 -16
  17. package/bin/client/code_cleanup/find_step_definition_references.js +0 -1
  18. package/bin/client/code_gen/api_codegen.js +2 -2
  19. package/bin/client/code_gen/code_inversion.js +63 -2
  20. package/bin/client/code_gen/function_signature.js +4 -0
  21. package/bin/client/code_gen/page_reflection.js +52 -11
  22. package/bin/client/code_gen/playwright_codeget.js +28 -22
  23. package/bin/client/cucumber/feature_data.js +2 -2
  24. package/bin/client/cucumber/project_to_document.js +8 -2
  25. package/bin/client/cucumber/steps_definitions.js +19 -3
  26. package/bin/client/local_agent.js +3 -2
  27. package/bin/client/parse_feature_file.js +23 -26
  28. package/bin/client/playground/projects/env.json +2 -2
  29. package/bin/client/recorderv3/bvt_init.js +363 -0
  30. package/bin/client/recorderv3/bvt_recorder.js +1009 -47
  31. package/bin/client/recorderv3/implemented_steps.js +2 -0
  32. package/bin/client/recorderv3/index.js +3 -283
  33. package/bin/client/recorderv3/scriptTest.js +1 -1
  34. package/bin/client/recorderv3/services.js +818 -142
  35. package/bin/client/recorderv3/step_runner.js +28 -8
  36. package/bin/client/recorderv3/step_utils.js +514 -39
  37. package/bin/client/recorderv3/update_feature.js +32 -13
  38. package/bin/client/recorderv3/wbr_entry.js +61 -0
  39. package/bin/client/recording.js +1 -0
  40. package/bin/client/upload-service.js +4 -2
  41. package/bin/client/utils/socket_logger.js +1 -1
  42. package/bin/index.js +4 -1
  43. package/package.json +6 -4
@@ -1,37 +1,34 @@
1
- import {
2
- AstBuilder,
3
- GherkinClassicTokenMatcher,
4
- Parser,
5
- } from '@cucumber/gherkin'
6
- import { readFileSync, writeFileSync } from 'fs'
7
- import { loadArgs, showUsage, validateCLIArg } from './cli_helpers.js'
8
- let id =0;
9
- const uuidFn = () => (++id).toString(16)
10
- const builder = new AstBuilder(uuidFn)
11
- const matcher = new GherkinClassicTokenMatcher()
1
+ import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherkin";
2
+ import { readFileSync, writeFileSync } from "fs";
3
+ import { loadArgs, showUsage, validateCLIArg } from "./cli_helpers.js";
4
+ let id = 0;
5
+ const uuidFn = () => (++id).toString(16);
6
+ const builder = new AstBuilder(uuidFn);
7
+ const matcher = new GherkinClassicTokenMatcher();
12
8
 
13
- const parser = new Parser(builder, matcher)
9
+ const parser = new Parser(builder, matcher);
14
10
 
15
11
  const parseFeatureFile = (featureFilePath) => {
16
- const source = readFileSync(featureFilePath, 'utf8')
17
- const gherkinDocument = parser.parse(source)
18
- return gherkinDocument
19
- }
12
+ const source = readFileSync(featureFilePath, "utf8");
13
+ const gherkinDocument = parser.parse(source);
14
+ return gherkinDocument;
15
+ };
20
16
 
21
- const args = loadArgs()
22
- const featureFilePath = args[0]
23
- const outputFilePath = args[1]
24
- const usage = 'Usage: node parse_feature_file.js <featureFilePath> [<outputFilePath>] \n\nExample: node parseFeatureFile.js ./features/my.feature ./features/my.feature.json\n\n'
17
+ const args = loadArgs();
18
+ const featureFilePath = args[0];
19
+ const outputFilePath = args[1];
20
+ const usage =
21
+ "Usage: node parse_feature_file.js <featureFilePath> [<outputFilePath>] \n\nExample: node parseFeatureFile.js ./features/my.feature ./features/my.feature.json\n\n";
25
22
  try {
26
- validateCLIArg(featureFilePath, 'featureFilePath')
23
+ validateCLIArg(featureFilePath, "featureFilePath");
27
24
  } catch (error) {
28
- showUsage(error, usage)
25
+ showUsage(error, usage);
29
26
  }
30
- const gherkinDocument = parseFeatureFile(featureFilePath)
27
+ const gherkinDocument = parseFeatureFile(featureFilePath);
31
28
  if (outputFilePath) {
32
- writeFileSync(outputFilePath, JSON.stringify(gherkinDocument, null, 2))
29
+ writeFileSync(outputFilePath, JSON.stringify(gherkinDocument, null, 2));
33
30
  } else {
34
- console.log(JSON.stringify(gherkinDocument, null, 2))
31
+ console.log(JSON.stringify(gherkinDocument, null, 2));
35
32
  }
36
33
 
37
- export { parseFeatureFile }
34
+ export { parseFeatureFile };
@@ -1,3 +1,3 @@
1
1
  {
2
- "baseUrl": "https://google.com"
3
- }
2
+ "baseUrl": "https://google.com"
3
+ }
@@ -0,0 +1,363 @@
1
+ import { io } from "socket.io-client";
2
+ import { BVTRecorder } from "./bvt_recorder.js";
3
+ import { compareWithScenario } from "../code_gen/duplication_analysis.js";
4
+ import { getAppDataDir } from "./app_dir.js";
5
+ import { readdir } from "fs/promises";
6
+ import socketLogger from "../utils/socket_logger.js";
7
+
8
+ let port = process.env.EDITOR_PORT || 3003;
9
+ const WS_URL = process.env.WORKER_WS_SERVER_URL || "http://localhost:" + port;
10
+
11
+ const responseSize = (response) => {
12
+ try {
13
+ if (typeof response !== "string") {
14
+ return new Blob([JSON.stringify(response)]).size;
15
+ } else {
16
+ return new Blob([response]).size;
17
+ }
18
+ } catch {
19
+ return -1;
20
+ }
21
+ };
22
+
23
+ class PromisifiedSocketServer {
24
+ constructor(socket, routes) {
25
+ this.socket = socket;
26
+ this.routes = routes;
27
+ }
28
+ init() {
29
+ this.socket.on("request", async (data) => {
30
+ const { event, input, id, roomId, socketId } = data;
31
+ if (event !== "recorderWindow.getCurrentChromiumPath") {
32
+ socketLogger.info("Received request", { event, input, id, roomId, socketId });
33
+ }
34
+ try {
35
+ const handler = this.routes[event];
36
+ if (!handler) {
37
+ console.error(`No handler found for event: ${event}`);
38
+ return;
39
+ }
40
+ const response = await handler(input);
41
+ if (event !== "recorderWindow.getCurrentChromiumPath") {
42
+ socketLogger.info(`Sending response for ${event}, ${responseSize(response)} bytes`);
43
+ }
44
+ this.socket.emit("response", { id, value: response, roomId, socketId });
45
+ } catch (error) {
46
+ console.error(`Error handling request for event: ${JSON.stringify(event, null, 2)}`, error);
47
+ socketLogger.error("Error handling request", {
48
+ event,
49
+ input,
50
+ id,
51
+ roomId,
52
+ socketId,
53
+ error: error instanceof Error ? `${error.message}\n${error.stack}` : error,
54
+ });
55
+ this.socket.emit("response", {
56
+ id,
57
+ error: {
58
+ message: error?.message,
59
+ code: error?.code,
60
+ info: error?.info,
61
+ stack: error?.stack,
62
+ },
63
+ roomId,
64
+ socketId,
65
+ });
66
+ }
67
+ });
68
+ }
69
+ }
70
+
71
+ const timeOutForFunction = async (promise, timeout = 5000) => {
72
+ const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(), timeout));
73
+
74
+ try {
75
+ const res = await Promise.race([promise, timeoutPromise]);
76
+ return res;
77
+ } catch (error) {
78
+ console.error(error);
79
+ socketLogger.error(error);
80
+ throw error;
81
+ }
82
+ };
83
+
84
+ async function BVTRecorderInit({ envName, projectDir, roomId, TOKEN, socket = null }) {
85
+ console.log("Connecting to " + WS_URL);
86
+ socket = socket || io(WS_URL);
87
+ socketLogger.init(socket, { context: "BVTRecorder", eventName: "BVTRecorder.log" });
88
+ socket.on("connect", () => {
89
+ socketLogger.info(`${roomId} Connected to BVTRecorder server`);
90
+ console.log(`${roomId} Connected to BVTRecorder server`);
91
+ });
92
+ socket.on("disconnect", () => {
93
+ socketLogger.info(`${roomId} Disconnected from server`);
94
+ console.log(`${roomId} Disconnected from server`);
95
+ });
96
+ socket.emit("joinRoom", { id: roomId, window: "cucumber_client/bvt_recorder" });
97
+ const recorder = new BVTRecorder({
98
+ envName,
99
+ projectDir,
100
+ TOKEN,
101
+ sendEvent: (event, data) => {
102
+ socketLogger.info("Sending event", { event, data, roomId });
103
+ socket.emit(event, data, roomId);
104
+ },
105
+ logger: socketLogger,
106
+ });
107
+ // try {
108
+ // await recorder.openBrowser();
109
+ // socketLogger.info("BVTRecorder.browserOpened");
110
+ // socket.emit("BVTRecorder.browserOpened", null, roomId);
111
+ // } catch (e) {
112
+ // if (e instanceof Error) {
113
+ // socketLogger.error("BVTRecorder.browserLaunchFailed", e);
114
+ // socket.emit("BVTRecorder.browserLaunchFailed", e, roomId);
115
+ // } else {
116
+ // socketLogger.error("BVTRecorder.browserLaunchFailed", JSON.stringify(e));
117
+ // socket.emit("BVTRecorder.browserLaunchFailed", JSON.stringify(e), roomId);
118
+ // }
119
+ // console.error("Browser launch failed", e);
120
+ // }
121
+
122
+ // emit connected event for every 50 ms until connection_ack message is recieved
123
+ let connected = false;
124
+ const interval = setInterval(() => {
125
+ if (connected) {
126
+ clearInterval(interval);
127
+ return;
128
+ }
129
+ socket.emit("BVTRecorder.connected", { roomId, window: "cucumber_client/bvt_recorder" }, roomId);
130
+ }, 50);
131
+
132
+ const promisifiedSocketServer = new PromisifiedSocketServer(socket, {
133
+ "recorderWindow.connectionAck": async (input) => {
134
+ connected = true;
135
+ clearInterval(interval);
136
+ },
137
+ "recorderWindow.openBrowser": async (input) => {
138
+ return recorder
139
+ .openBrowser(input)
140
+ .then(() => {
141
+ socketLogger.info("BVTRecorder.browserOpened");
142
+ console.info("BVTRecorder.browserOpened");
143
+ socket.emit("BVTRecorder.browserOpened", { roomId, window: "cucumber_client/bvt_recorder" });
144
+ })
145
+ .catch((e) => {
146
+ socketLogger.error("Error opening browser", e);
147
+ console.error("BVTRecorder.browserLaunchFailed", e);
148
+ socket.emit("BVTRecorder.browserLaunchFailed", { roomId, window: "cucumber_client/bvt_recorder" });
149
+ });
150
+ },
151
+ "recorderWindow.closeBrowser": async (input) => {
152
+ return recorder.closeBrowser(input);
153
+ },
154
+ "recorderWindow.reOpenBrowser": async (input) => {
155
+ return recorder
156
+ .reOpenBrowser(input)
157
+ .then(() => {
158
+ socketLogger.info("BVTRecorder.browserOpened");
159
+ console.log("BVTRecorder.browserOpened");
160
+ socket.emit("BVTRecorder.browserOpened", null, roomId);
161
+ })
162
+ .catch((e) => {
163
+ socketLogger.info("BVTRecorder.browserLaunchFailed");
164
+ console.error("BVTRecorder.browserLaunchFailed", e);
165
+ socket.emit("BVTRecorder.browserLaunchFailed", null, roomId);
166
+ });
167
+ },
168
+ "recorderWindow.startRecordingInput": async (input) => {
169
+ return timeOutForFunction(recorder.startRecordingInput(input));
170
+ },
171
+ "recorderWindow.stopRecordingInput": async (input) => {
172
+ return timeOutForFunction(recorder.stopRecordingInput(input));
173
+ },
174
+ "recorderWindow.startRecordingText": async (input) => {
175
+ // console.log("--- {{ }} -- : recorderWindow.startRecordingText", input);
176
+ return timeOutForFunction(recorder.startRecordingText(input));
177
+ },
178
+ "recorderWindow.stopRecordingText": async (input) => {
179
+ return timeOutForFunction(recorder.stopRecordingText(input));
180
+ },
181
+ "recorderWindow.startRecordingContext": async (input) => {
182
+ return timeOutForFunction(recorder.startRecordingContext(input));
183
+ },
184
+ "recorderWindow.stopRecordingContext": async (input) => {
185
+ return timeOutForFunction(recorder.stopRecordingContext(input));
186
+ },
187
+ "recorderWindow.runStep": async (input) => {
188
+ return recorder.runStep(input);
189
+ },
190
+ "recorderWindow.saveScenario": async (input) => {
191
+ return recorder.saveScenario(input);
192
+ },
193
+ "recorderWindow.getImplementedSteps": async (input) => {
194
+ // console.log("recorderWindow.getImplementedSteps", input);
195
+ return (await recorder.getImplementedSteps(input)).implementedSteps;
196
+ },
197
+ "recorderWindow.getImplementedScenarios": async (input) => {
198
+ // console.log("recorderWindow.getImplementedScenarios", input);
199
+ return (await recorder.getImplementedSteps(input)).scenarios;
200
+ },
201
+ "recorderWindow.getCurrentChromiumPath": async () => {
202
+ // console.log("recorderWindow.getCurrentChromiumPath");
203
+ return await recorder.getCurrentChromiumPath();
204
+ },
205
+ "recorderWindow.overwriteTestData": async (input) => {
206
+ // console.log("recorderWindow.overwriteTestData");
207
+ return await recorder.overwriteTestData(input);
208
+ },
209
+ "recorderWindow.generateStepName": async (input) => {
210
+ return recorder.generateStepName(input);
211
+ },
212
+ "recorderWindow.getFeatureAndScenario": async (input) => {
213
+ return recorder.generateScenarioAndFeatureNames(input);
214
+ },
215
+ "recorderWindow.generateCommandName": async (input) => {
216
+ return recorder.generateCommandName(input);
217
+ },
218
+ "recorderWindow.loadTestData": async (input) => {
219
+ return recorder.loadTestData(input);
220
+ },
221
+ "recorderWindow.discard": async (input) => {
222
+ return await recorder.discardTestData(input);
223
+ },
224
+ "recorderWindow.addToTestData": async (input) => {
225
+ return await recorder.addToTestData(input);
226
+ },
227
+ "recorderWindow.getScenarios": async () => {
228
+ return recorder.getScenarios();
229
+ },
230
+ "recorderWindow.setShouldTakeScreenshot": async (input) => {
231
+ return recorder.setShouldTakeScreenshot(input);
232
+ },
233
+ "recorderWindow.compareWithScenario": async ({ projectDir, scenario }, roomId) => {
234
+ return await compareWithScenario(getAppDataDir(projectDir), scenario);
235
+ },
236
+ "recorderWindow.getCommandsForImplementedStep": async (input) => {
237
+ return recorder.getCommandsForImplementedStep(input);
238
+ },
239
+ "recorderWindow.getNumberOfOccurrences": async (input) => {
240
+ return recorder.getNumberOfOccurrences(input);
241
+ },
242
+ "recorderWindow.getFakeParams": async ({ parametersMap }) => {
243
+ return recorder.fakeParams(parametersMap);
244
+ },
245
+ "recorderWindow.abortExecution": async (input) => {
246
+ return recorder.abortExecution(input);
247
+ },
248
+ "recorderWindow.pauseExecution": async (input) => {
249
+ return recorder.pauseExecution(input);
250
+ },
251
+ "recorderWindow.resumeExecution": async (input) => {
252
+ return recorder.resumeExecution(input);
253
+ },
254
+ "recorderWindow.loadExistingScenario": async (input) => {
255
+ return recorder.loadExistingScenario(input);
256
+ },
257
+ "recorderWindow.findRelatedTextInAllFrames": async (input) => {
258
+ return recorder.findRelatedTextInAllFrames(input);
259
+ },
260
+ "recorderWindow.getReportFolder": async (input) => {
261
+ return recorder.getReportFolder();
262
+ },
263
+ "recorderWindow.getSnapshotFiles": async (input) => {
264
+ const snapshotFolder = recorder.getSnapshotFolder();
265
+ if (snapshotFolder) {
266
+ const files = await readdir(snapshotFolder);
267
+ const ymlFiles = files.filter((file) => file.endsWith(".yml") || file.endsWith(".yaml"));
268
+ return { folder: snapshotFolder, files: ymlFiles };
269
+ } else return { folder: null, files: [] };
270
+ },
271
+ "recorderWindow.getCurrentPageTitle": async (input) => {
272
+ return await recorder.getCurrentPageTitle();
273
+ },
274
+ "recorderWindow.getCurrentPageUrl": async (input) => {
275
+ return await recorder.getCurrentPageUrl();
276
+ },
277
+ "recorderWindow.sendAriaSnapshot": async (input) => {
278
+ const snapshot = input?.snapshot;
279
+ const deselect = input?.deselect;
280
+ if (deselect === true) {
281
+ return await recorder.deselectAriaElements();
282
+ }
283
+ if (snapshot !== null) {
284
+ return await recorder.processAriaSnapshot(snapshot);
285
+ }
286
+ },
287
+ "recorderWindow.revertMode": async (input) => {
288
+ await recorder.revertMode();
289
+ },
290
+ "recorderWindow.setMode": async (input) => {
291
+ const mode = input?.mode;
292
+ return recorder.setMode(mode);
293
+ },
294
+ "recorderWindow.getStepsAndCommandsForScenario": async (input) => {
295
+ return await recorder.getStepsAndCommandsForScenario(input);
296
+ },
297
+ "recorderWindow.getNetworkEvents": async (input) => {
298
+ return await recorder.getNetworkEvents(input);
299
+ },
300
+ "recorderWindow.initExecution": async (input) => {
301
+ return await recorder.initExecution(input);
302
+ },
303
+ "recorderWindow.cleanupExecution": async (input) => {
304
+ return await recorder.cleanupExecution(input);
305
+ },
306
+ "recorderWindow.resetExecution": async (input) => {
307
+ return await recorder.resetExecution(input);
308
+ },
309
+ "recorderWindow.stopRecordingNetwork": async (input) => {
310
+ return recorder.stopRecordingNetwork(input);
311
+ },
312
+ "browserUI.requestState": async (input) => {
313
+ console.log("Received browserUI.requestState");
314
+ await recorder.getBrowserState();
315
+ },
316
+ "browserUI.createTab": async (input) => {
317
+ console.log("Received browserUI.createTab", input);
318
+ await recorder.createTab(input);
319
+ },
320
+ "browserUI.closeTab": async (input) => {
321
+ console.log("Received browserUI.closeTab", input);
322
+ await recorder.closeTab(input);
323
+ },
324
+ "browserUI.selectTab": async (input) => {
325
+ console.log("Received browserUI.selectTab", input);
326
+ await recorder.selectTab(input);
327
+ },
328
+ "browserUI.navigateTab": async (input) => {
329
+ console.log("Received browserUI.navigateTab", input);
330
+ await recorder.navigateTab(input);
331
+ },
332
+ "browserUI.reloadTab": async (input) => {
333
+ console.log("Received browserUI.reloadTab", input);
334
+ await recorder.reloadTab(input);
335
+ },
336
+ "browserUI.goBack": async (input) => {
337
+ console.log("Received browserUI.goBack", input);
338
+ await recorder.goBack(input);
339
+ },
340
+ "browserUI.goForward": async (input) => {
341
+ console.log("Received browserUI.goForward", input);
342
+ await recorder.goForward(input);
343
+ },
344
+ "browserUI.writeToClipboard": async (input) => {
345
+ console.log("Received browserUI.writeToClipboard");
346
+ await recorder.applyClipboardPayload(input);
347
+ },
348
+ "browserUI.readToClipboard": async (input) => {
349
+ console.log("Received browserUI.readToClipboard");
350
+ await recorder.readClipboardPayload(input);
351
+ },
352
+ "recorderWindow.cleanup": async (input) => {
353
+ return recorder.cleanup(input);
354
+ },
355
+ });
356
+
357
+ socket.on("targetBrowser.command.event", async (input) => {
358
+ return recorder.onAction(input);
359
+ });
360
+ promisifiedSocketServer.init();
361
+ }
362
+
363
+ export { BVTRecorderInit };