@dev-blinq/cucumber_client 1.0.1366-stage → 1.0.1367-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/client/recorderv3/bvt_init.js +325 -0
- package/bin/client/recorderv3/bvt_recorder.js +62 -4
- package/bin/client/recorderv3/index.js +4 -308
- package/bin/client/recorderv3/services.js +426 -204
- package/bin/client/recorderv3/step_utils.js +3 -9
- package/bin/client/recorderv3/wbr_entry.js +29 -0
- package/bin/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,325 @@
|
|
|
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: ${event}`, 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
|
+
const promisifiedSocketServer = new PromisifiedSocketServer(socket, {
|
|
123
|
+
"recorderWindow.openBrowser": async (input) => {
|
|
124
|
+
return recorder
|
|
125
|
+
.openBrowser(input)
|
|
126
|
+
.then(() => {
|
|
127
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
128
|
+
console.info("BVTRecorder.browserOpened");
|
|
129
|
+
socket.emit("BVTRecorder.browserOpened", { roomId, window: "cucumber_client/bvt_recorder" });
|
|
130
|
+
})
|
|
131
|
+
.catch((e) => {
|
|
132
|
+
socketLogger.error("Error opening browser", e);
|
|
133
|
+
console.error("BVTRecorder.browserLaunchFailed", e);
|
|
134
|
+
socket.emit("BVTRecorder.browserLaunchFailed", { roomId, window: "cucumber_client/bvt_recorder" });
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
"recorderWindow.closeBrowser": async (input) => {
|
|
138
|
+
return recorder.closeBrowser(input);
|
|
139
|
+
},
|
|
140
|
+
"recorderWindow.reOpenBrowser": async (input) => {
|
|
141
|
+
return recorder
|
|
142
|
+
.reOpenBrowser(input)
|
|
143
|
+
.then(() => {
|
|
144
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
145
|
+
console.log("BVTRecorder.browserOpened");
|
|
146
|
+
socket.emit("BVTRecorder.browserOpened", null, roomId);
|
|
147
|
+
})
|
|
148
|
+
.catch((e) => {
|
|
149
|
+
socketLogger.info("BVTRecorder.browserLaunchFailed");
|
|
150
|
+
console.error("BVTRecorder.browserLaunchFailed", e);
|
|
151
|
+
socket.emit("BVTRecorder.browserLaunchFailed", null, roomId);
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
"recorderWindow.startRecordingInput": async (input) => {
|
|
155
|
+
return timeOutForFunction(recorder.startRecordingInput(input));
|
|
156
|
+
},
|
|
157
|
+
"recorderWindow.stopRecordingInput": async (input) => {
|
|
158
|
+
return timeOutForFunction(recorder.stopRecordingInput(input));
|
|
159
|
+
},
|
|
160
|
+
"recorderWindow.startRecordingText": async (input) => {
|
|
161
|
+
// console.log("--- {{ }} -- : recorderWindow.startRecordingText", input);
|
|
162
|
+
return timeOutForFunction(recorder.startRecordingText(input));
|
|
163
|
+
},
|
|
164
|
+
"recorderWindow.stopRecordingText": async (input) => {
|
|
165
|
+
return timeOutForFunction(recorder.stopRecordingText(input));
|
|
166
|
+
},
|
|
167
|
+
"recorderWindow.startRecordingContext": async (input) => {
|
|
168
|
+
return timeOutForFunction(recorder.startRecordingContext(input));
|
|
169
|
+
},
|
|
170
|
+
"recorderWindow.stopRecordingContext": async (input) => {
|
|
171
|
+
return timeOutForFunction(recorder.stopRecordingContext(input));
|
|
172
|
+
},
|
|
173
|
+
"recorderWindow.runStep": async (input) => {
|
|
174
|
+
return recorder.runStep(input);
|
|
175
|
+
},
|
|
176
|
+
"recorderWindow.saveScenario": async (input) => {
|
|
177
|
+
return recorder.saveScenario(input);
|
|
178
|
+
},
|
|
179
|
+
"recorderWindow.getImplementedSteps": async (input) => {
|
|
180
|
+
// console.log("recorderWindow.getImplementedSteps", input);
|
|
181
|
+
return (await recorder.getImplementedSteps(input)).implementedSteps;
|
|
182
|
+
},
|
|
183
|
+
"recorderWindow.getImplementedScenarios": async (input) => {
|
|
184
|
+
// console.log("recorderWindow.getImplementedScenarios", input);
|
|
185
|
+
return (await recorder.getImplementedSteps(input)).scenarios;
|
|
186
|
+
},
|
|
187
|
+
"recorderWindow.getCurrentChromiumPath": async () => {
|
|
188
|
+
// console.log("recorderWindow.getCurrentChromiumPath");
|
|
189
|
+
return await recorder.getCurrentChromiumPath();
|
|
190
|
+
},
|
|
191
|
+
"recorderWindow.overwriteTestData": async (input) => {
|
|
192
|
+
// console.log("recorderWindow.overwriteTestData");
|
|
193
|
+
return await recorder.overwriteTestData(input);
|
|
194
|
+
},
|
|
195
|
+
"recorderWindow.generateStepName": async (input) => {
|
|
196
|
+
return recorder.generateStepName(input);
|
|
197
|
+
},
|
|
198
|
+
"recorderWindow.getFeatureAndScenario": async (input) => {
|
|
199
|
+
return recorder.generateScenarioAndFeatureNames(input);
|
|
200
|
+
},
|
|
201
|
+
"recorderWindow.generateCommandName": async (input) => {
|
|
202
|
+
return recorder.generateCommandName(input);
|
|
203
|
+
},
|
|
204
|
+
"recorderWindow.loadTestData": async (input) => {
|
|
205
|
+
return recorder.loadTestData(input);
|
|
206
|
+
},
|
|
207
|
+
"recorderWindow.discard": async (input) => {
|
|
208
|
+
return await recorder.discardTestData(input);
|
|
209
|
+
},
|
|
210
|
+
"recorderWindow.addToTestData": async (input) => {
|
|
211
|
+
return await recorder.addToTestData(input);
|
|
212
|
+
},
|
|
213
|
+
"recorderWindow.getScenarios": async () => {
|
|
214
|
+
return recorder.getScenarios();
|
|
215
|
+
},
|
|
216
|
+
"recorderWindow.setShouldTakeScreenshot": async (input) => {
|
|
217
|
+
return recorder.setShouldTakeScreenshot(input);
|
|
218
|
+
},
|
|
219
|
+
"recorderWindow.compareWithScenario": async ({ projectDir, scenario }, roomId) => {
|
|
220
|
+
return await compareWithScenario(getAppDataDir(projectDir), scenario);
|
|
221
|
+
},
|
|
222
|
+
"recorderWindow.getCommandsForImplementedStep": async (input) => {
|
|
223
|
+
return recorder.getCommandsForImplementedStep(input);
|
|
224
|
+
},
|
|
225
|
+
"recorderWindow.getNumberOfOccurrences": async (input) => {
|
|
226
|
+
return recorder.getNumberOfOccurrences(input);
|
|
227
|
+
},
|
|
228
|
+
"recorderWindow.getFakeParams": async ({ parametersMap }) => {
|
|
229
|
+
return recorder.fakeParams(parametersMap);
|
|
230
|
+
},
|
|
231
|
+
"recorderWindow.abortExecution": async (input) => {
|
|
232
|
+
return recorder.abortExecution(input);
|
|
233
|
+
},
|
|
234
|
+
"recorderWindow.pauseExecution": async (input) => {
|
|
235
|
+
return recorder.pauseExecution(input);
|
|
236
|
+
},
|
|
237
|
+
"recorderWindow.resumeExecution": async (input) => {
|
|
238
|
+
return recorder.resumeExecution(input);
|
|
239
|
+
},
|
|
240
|
+
"recorderWindow.loadExistingScenario": async (input) => {
|
|
241
|
+
return recorder.loadExistingScenario(input);
|
|
242
|
+
},
|
|
243
|
+
"recorderWindow.findRelatedTextInAllFrames": async (input) => {
|
|
244
|
+
return recorder.findRelatedTextInAllFrames(input);
|
|
245
|
+
},
|
|
246
|
+
"recorderWindow.getReportFolder": async (input) => {
|
|
247
|
+
return recorder.getReportFolder();
|
|
248
|
+
},
|
|
249
|
+
"recorderWindow.getSnapshotFiles": async (input) => {
|
|
250
|
+
const snapshotFolder = recorder.getSnapshotFolder();
|
|
251
|
+
if (snapshotFolder) {
|
|
252
|
+
const files = await readdir(snapshotFolder);
|
|
253
|
+
const ymlFiles = files.filter((file) => file.endsWith(".yml") || file.endsWith(".yaml"));
|
|
254
|
+
return { folder: snapshotFolder, files: ymlFiles };
|
|
255
|
+
} else return { folder: null, files: [] };
|
|
256
|
+
},
|
|
257
|
+
"recorderWindow.getCurrentPageTitle": async (input) => {
|
|
258
|
+
return await recorder.getCurrentPageTitle();
|
|
259
|
+
},
|
|
260
|
+
"recorderWindow.getCurrentPageUrl": async (input) => {
|
|
261
|
+
return await recorder.getCurrentPageUrl();
|
|
262
|
+
},
|
|
263
|
+
"recorderWindow.sendAriaSnapshot": async (input) => {
|
|
264
|
+
const snapshot = input?.snapshot;
|
|
265
|
+
const deselect = input?.deselect;
|
|
266
|
+
if (deselect === true) {
|
|
267
|
+
return await recorder.deselectAriaElements();
|
|
268
|
+
}
|
|
269
|
+
if (snapshot !== null) {
|
|
270
|
+
return await recorder.processAriaSnapshot(snapshot);
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
"recorderWindow.revertMode": async (input) => {
|
|
274
|
+
await recorder.revertMode();
|
|
275
|
+
},
|
|
276
|
+
"recorderWindow.setMode": async (input) => {
|
|
277
|
+
const mode = input?.mode;
|
|
278
|
+
return recorder.setMode(mode);
|
|
279
|
+
},
|
|
280
|
+
"recorderWindow.getStepsAndCommandsForScenario": async (input) => {
|
|
281
|
+
return await recorder.getStepsAndCommandsForScenario(input);
|
|
282
|
+
},
|
|
283
|
+
"recorderWindow.getNetworkEvents": async (input) => {
|
|
284
|
+
return await recorder.getNetworkEvents(input);
|
|
285
|
+
},
|
|
286
|
+
"recorderWindow.initExecution": async (input) => {
|
|
287
|
+
return await recorder.initExecution(input);
|
|
288
|
+
},
|
|
289
|
+
"recorderWindow.cleanupExecution": async (input) => {
|
|
290
|
+
return await recorder.cleanupExecution(input);
|
|
291
|
+
},
|
|
292
|
+
"recorderWindow.resetExecution": async (input) => {
|
|
293
|
+
return await recorder.resetExecution(input);
|
|
294
|
+
},
|
|
295
|
+
"recorderWindow.stopRecordingNetwork": async (input) => {
|
|
296
|
+
return recorder.stopRecordingNetwork(input);
|
|
297
|
+
},
|
|
298
|
+
"browserUI.requestState": async (input) => {
|
|
299
|
+
console.log("Received browserUI.requestState");
|
|
300
|
+
await recorder.getBrowserState();
|
|
301
|
+
},
|
|
302
|
+
"browserUI.createTab": async (input) => {
|
|
303
|
+
console.log("Received browserUI.createTab", input);
|
|
304
|
+
await recorder.createTab(input);
|
|
305
|
+
},
|
|
306
|
+
"browserUI.closeTab": async (input) => {
|
|
307
|
+
console.log("Received browserUI.closeTab", input);
|
|
308
|
+
await recorder.closeTab(input);
|
|
309
|
+
},
|
|
310
|
+
"browserUI.selectTab": async (input) => {
|
|
311
|
+
console.log("Received browserUI.selectTab", input);
|
|
312
|
+
await recorder.selectTab(input);
|
|
313
|
+
},
|
|
314
|
+
"recorderWindow.cleanup": async (input) => {
|
|
315
|
+
return recorder.cleanup(input);
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
socket.on("targetBrowser.command.event", async (input) => {
|
|
320
|
+
return recorder.onAction(input);
|
|
321
|
+
});
|
|
322
|
+
promisifiedSocketServer.init();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export { BVTRecorderInit };
|
|
@@ -205,7 +205,6 @@ export class BVTRecorder {
|
|
|
205
205
|
this.shouldTakeScreenshot = true;
|
|
206
206
|
this.watcher = null;
|
|
207
207
|
this.networkEventsFolder = path.join(tmpdir(), "blinq_network_events");
|
|
208
|
-
|
|
209
208
|
this.tempProjectFolder = `${tmpdir()}/bvt_temp_project_${Math.floor(Math.random() * 1000000)}`;
|
|
210
209
|
this.tempSnapshotsFolder = path.join(this.tempProjectFolder, "data/snapshots");
|
|
211
210
|
|
|
@@ -228,6 +227,8 @@ export class BVTRecorder {
|
|
|
228
227
|
interceptResults: "BVTRecorder.interceptResults",
|
|
229
228
|
onDebugURLChange: "BVTRecorder.onDebugURLChange",
|
|
230
229
|
updateCommand: "BVTRecorder.updateCommand",
|
|
230
|
+
browserStateSync: "BrowserService.stateSync",
|
|
231
|
+
browserStateError: "BrowserService.stateError",
|
|
231
232
|
};
|
|
232
233
|
bindings = {
|
|
233
234
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
@@ -365,12 +366,21 @@ export class BVTRecorder {
|
|
|
365
366
|
},
|
|
366
367
|
bvtContext: this.bvtContext,
|
|
367
368
|
});
|
|
368
|
-
|
|
369
|
-
this.context = context;
|
|
369
|
+
this.context = bvtContext.playContext;
|
|
370
370
|
this.web = bvtContext.stable || bvtContext.web;
|
|
371
371
|
this.web.tryAllStrategies = true;
|
|
372
372
|
this.page = bvtContext.page;
|
|
373
373
|
this.pageSet.add(this.page);
|
|
374
|
+
if (process.env.REMOTE_RECORDER === "true") {
|
|
375
|
+
this.browserEmitter = new RemoteBrowserService({
|
|
376
|
+
CDP_CONNECT_URL: `http://localhost:${this.#remoteDebuggerPort}`,
|
|
377
|
+
context: this.context,
|
|
378
|
+
});
|
|
379
|
+
this.browserEmitter.on(this.events.browserStateSync, (state) => {
|
|
380
|
+
this.page = this.browserEmitter.getSelectedPage();
|
|
381
|
+
this.sendEvent(this.events.browserStateSync, state);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
374
384
|
this.lastKnownUrlPath = this._updateUrlPath();
|
|
375
385
|
const browser = await this.context.browser();
|
|
376
386
|
this.browser = browser;
|
|
@@ -818,7 +828,6 @@ export class BVTRecorder {
|
|
|
818
828
|
this.previousHistoryLength = null;
|
|
819
829
|
this.previousUrl = null;
|
|
820
830
|
this.previousEntries = null;
|
|
821
|
-
|
|
822
831
|
await closeContext();
|
|
823
832
|
this.pageSet.clear();
|
|
824
833
|
}
|
|
@@ -1353,4 +1362,53 @@ export class BVTRecorder {
|
|
|
1353
1362
|
|
|
1354
1363
|
return newFakeParams;
|
|
1355
1364
|
}
|
|
1365
|
+
|
|
1366
|
+
async getBrowserState() {
|
|
1367
|
+
try {
|
|
1368
|
+
const state = await this.browserEmitter?.getState();
|
|
1369
|
+
this.sendEvent(this.events.browserStateSync, state);
|
|
1370
|
+
} catch (error) {
|
|
1371
|
+
this.logger.error("Error getting browser state:", error);
|
|
1372
|
+
this.sendEvent(this.events.browserStateError, {
|
|
1373
|
+
message: "Error getting browser state",
|
|
1374
|
+
code: "GET_STATE_ERROR",
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
async createTab({ url }) {
|
|
1380
|
+
try {
|
|
1381
|
+
await this.browserEmitter?.createTab(url);
|
|
1382
|
+
} catch (error) {
|
|
1383
|
+
this.logger.error("Error creating tab:", error);
|
|
1384
|
+
this.sendEvent(this.events.browserStateError, {
|
|
1385
|
+
message: "Error creating tab",
|
|
1386
|
+
code: "CREATE_TAB_ERROR",
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
async closeTab({ pageId }) {
|
|
1392
|
+
try {
|
|
1393
|
+
await this.browserEmitter?.closeTab(pageId);
|
|
1394
|
+
} catch (error) {
|
|
1395
|
+
this.logger.error("Error closing tab:", error);
|
|
1396
|
+
this.sendEvent(this.events.browserStateError, {
|
|
1397
|
+
message: "Error closing tab",
|
|
1398
|
+
code: "CLOSE_TAB_ERROR",
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
async selectTab({ pageId }) {
|
|
1404
|
+
try {
|
|
1405
|
+
await this.browserEmitter?.selectTab(pageId);
|
|
1406
|
+
} catch (error) {
|
|
1407
|
+
this.logger.error("Error selecting tab:", error);
|
|
1408
|
+
this.sendEvent(this.events.browserStateError, {
|
|
1409
|
+
message: "Error selecting tab",
|
|
1410
|
+
code: "SELECT_TAB_ERROR",
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1356
1414
|
}
|