@dev-blinq/cucumber_client 1.0.1597-dev โ†’ 1.0.1599-dev

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.
@@ -154,7 +154,9 @@ export class PublishService {
154
154
  this.TOKEN = TOKEN;
155
155
  }
156
156
  async saveScenario({ scenario, featureName, override, branch, isEditing, projectId }) {
157
- const url = path.join(`${getRunsServiceBaseURL()}`, "..", "workspace/publish-recording");
157
+ const runsURL = getRunsServiceBaseURL();
158
+ const workspaceURL = runsURL.replace("/runs", "/workspace");
159
+ const url = `${workspaceURL}/publish-recording`;
158
160
  const result = await axiosClient({
159
161
  url,
160
162
  method: "POST",
@@ -216,10 +218,12 @@ export class RemoteBrowserService extends EventEmitter {
216
218
  context;
217
219
  pages = new Map();
218
220
  _selectedPageId = null;
221
+ wsUrlBase; // Store the base URL
219
222
  constructor({ CDP_CONNECT_URL, context }) {
220
223
  super();
221
224
  this.CDP_CONNECT_URL = CDP_CONNECT_URL;
222
225
  this.context = context;
226
+ this.wsUrlBase = this.CDP_CONNECT_URL.replace(/^http/, "ws") + "/devtools/page/";
223
227
  this.log("๐Ÿš€ RemoteBrowserService initialized", { CDP_CONNECT_URL });
224
228
  this.initializeListeners();
225
229
  }
@@ -227,9 +231,16 @@ export class RemoteBrowserService extends EventEmitter {
227
231
  const timestamp = new Date().toISOString();
228
232
  console.log(`[${timestamp}] [RemoteBrowserService] ${message}`, data ? JSON.stringify(data, null, 2) : "");
229
233
  }
230
- // Simplified: Get the ID directly from the page
234
+ /**
235
+ * Gets the CDP Target ID for a page *directly* from the page.
236
+ * This is the only reliable method during restarts.
237
+ */
231
238
  async getCdpTargetId(page) {
232
239
  try {
240
+ if (page.isClosed()) {
241
+ this.log("โš ๏ธ Attempted to get CDP ID from a closed page");
242
+ return null;
243
+ }
233
244
  const cdpSession = await page.context().newCDPSession(page);
234
245
  const { targetInfo } = await cdpSession.send("Target.getTargetInfo");
235
246
  await cdpSession.detach();
@@ -244,38 +255,27 @@ export class RemoteBrowserService extends EventEmitter {
244
255
  return null;
245
256
  }
246
257
  }
247
- async getDebugURLs() {
248
- const url = `${this.CDP_CONNECT_URL}/json?t=${Date.now()}`; // Cache-busting
249
- try {
250
- const response = await fetch(url, { cache: "no-store" });
251
- if (!response.ok) {
252
- this.log("โŒ Failed to fetch debug URLs", { status: response.status });
253
- throw new Error("Error while fetching debug URL");
254
- }
255
- return await response.json();
256
- }
257
- catch (error) {
258
- this.log("โŒ Exception while fetching debug URLs", { error });
259
- return [];
260
- }
261
- }
262
258
  async initializeListeners() {
263
259
  this.log("๐Ÿ“ก Initializing listeners");
264
260
  this.context.on("page", async (page) => {
265
261
  const stableTabId = uuidv4();
266
262
  this.log("๐Ÿ†• New page event triggered", { stableTabId, url: page.url() });
263
+ // We get the ID immediately, but it might be null if the page is too new
267
264
  const cdpTargetId = await this.getCdpTargetId(page);
268
265
  this.pages.set(stableTabId, { page, cdpTargetId });
269
266
  if (cdpTargetId) {
270
267
  this.log("โœ… Page mapped to CDP ID", { stableTabId, cdpTargetId });
271
268
  }
272
269
  else {
273
- this.log("โš ๏ธ Could not find CDP ID for new page", { stableTabId });
270
+ this.log("โš ๏ธ Could not find CDP ID for new page yet", { stableTabId });
274
271
  }
275
- if (this.pages.size === 1) {
272
+ if (!this._selectedPageId) {
273
+ // Select the first page that opens
276
274
  this._selectedPageId = stableTabId;
275
+ this.log("๐ŸŽฏ Initial selected page set", { selectedPageId: this._selectedPageId });
277
276
  }
278
277
  await this.syncState();
278
+ // Add listeners
279
279
  page.on("load", () => this.syncState());
280
280
  page.on("framenavigated", () => this.syncState());
281
281
  page.on("close", async () => {
@@ -315,36 +315,46 @@ export class RemoteBrowserService extends EventEmitter {
315
315
  }
316
316
  async getState() {
317
317
  this.log("๐Ÿ“Š Getting current state");
318
- // Get the *live* list of debuggable pages
319
- const debugData = await this.getDebugURLs();
320
- const debugMap = new Map(debugData.map((d) => [d.id, d]));
321
318
  const pagesData = [];
319
+ const pagesToDelete = []; // To clean up closed pages
322
320
  for (const [stableTabId, pageInfo] of this.pages.entries()) {
323
321
  try {
324
- // Re-verify the CDP ID in case it changed
322
+ if (pageInfo.page.isClosed()) {
323
+ this.log("๐Ÿงน Found closed page during getState, marking for deletion", { stableTabId });
324
+ pagesToDelete.push(stableTabId);
325
+ continue;
326
+ }
327
+ // Get the one, true, live CDP ID
325
328
  const currentCdpId = await this.getCdpTargetId(pageInfo.page);
326
329
  if (currentCdpId && pageInfo.cdpTargetId !== currentCdpId) {
327
330
  this.log("๐Ÿ”„ CDP ID changed", { stableTabId, old: pageInfo.cdpTargetId, new: currentCdpId });
328
- pageInfo.cdpTargetId = currentCdpId;
331
+ pageInfo.cdpTargetId = currentCdpId; // Update our internal reference
332
+ }
333
+ // Manually construct the WebSocket URL
334
+ const wsDebuggerUrl = currentCdpId ? `${this.wsUrlBase}${currentCdpId}` : "";
335
+ if (!wsDebuggerUrl) {
336
+ this.log("โš ๏ธ Could not get CDP ID, wsDebuggerUrl will be empty", { stableTabId });
329
337
  }
330
- // Get the debug info from the live map
331
- const debugInfo = currentCdpId ? debugMap.get(currentCdpId) : undefined;
332
338
  pagesData.push({
333
339
  id: stableTabId,
334
340
  title: await pageInfo.page.title(),
335
341
  url: pageInfo.page.url(),
336
- wsDebuggerUrl: debugInfo?.webSocketDebuggerUrl || "",
342
+ wsDebuggerUrl: wsDebuggerUrl, // Use the constructed URL
337
343
  });
338
344
  }
339
345
  catch (error) {
340
- // This likely means the page was closed during the loop
341
- this.log("โŒ Error getting page data (page might be closed)", { stableTabId });
342
- this.pages.delete(stableTabId); // Clean up dead page
346
+ this.log("โŒ Error getting page data", { stableTabId, error });
347
+ pagesToDelete.push(stableTabId); // Mark for deletion
343
348
  }
344
349
  }
345
- // Ensure selectedPageId is valid
350
+ pagesToDelete.forEach((id) => this.pages.delete(id));
346
351
  if (this._selectedPageId && !this.pages.has(this._selectedPageId)) {
347
352
  this._selectedPageId = pagesData.length > 0 ? pagesData[0].id : null;
353
+ this.log("๐Ÿ”„ Corrected selectedPageId", { new: this._selectedPageId });
354
+ }
355
+ if (!this._selectedPageId && pagesData.length > 0) {
356
+ this._selectedPageId = pagesData[0].id;
357
+ this.log("๐ŸŽฏ Set default selectedPageId", { new: this._selectedPageId });
348
358
  }
349
359
  const state = {
350
360
  pages: pagesData,
@@ -356,11 +366,10 @@ export class RemoteBrowserService extends EventEmitter {
356
366
  async createTab(url = "about:blank") {
357
367
  try {
358
368
  this.log("๐Ÿ†• Creating new tab", { url });
359
- const page = await this.context.newPage(); // Triggers 'page' event
369
+ const page = await this.context.newPage(); // This will trigger the 'page' event
360
370
  if (url !== "about:blank") {
361
371
  await page.goto(url, { waitUntil: "domcontentloaded" });
362
372
  }
363
- // Find the stableTabId that was just created by the 'page' event
364
373
  for (const [stableTabId, pageInfo] of this.pages.entries()) {
365
374
  if (pageInfo.page === page) {
366
375
  this._selectedPageId = stableTabId;
@@ -379,7 +388,7 @@ export class RemoteBrowserService extends EventEmitter {
379
388
  this.log("๐Ÿ—‘๏ธ Closing tab", { stableTabId });
380
389
  const pageInfo = this.pages.get(stableTabId);
381
390
  if (pageInfo) {
382
- await pageInfo.page.close(); // Triggers 'close' event
391
+ await pageInfo.page.close(); // This will trigger the 'close' event
383
392
  }
384
393
  else {
385
394
  this.log("โš ๏ธ Page not found for closing", { stableTabId });
@@ -409,16 +418,21 @@ export class RemoteBrowserService extends EventEmitter {
409
418
  }
410
419
  getSelectedPage() {
411
420
  const pageInfo = this._selectedPageId ? this.pages.get(this._selectedPageId) : null;
421
+ this.log("๐Ÿ” Getting selected page", {
422
+ selectedPageId: this._selectedPageId,
423
+ found: !!pageInfo,
424
+ url: pageInfo?.page.url(),
425
+ });
412
426
  return pageInfo?.page || null;
413
427
  }
414
428
  destroy() {
415
429
  this.log("๐Ÿ’ฅ Destroying RemoteBrowserService");
416
430
  this.context.removeAllListeners("page");
417
431
  for (const [, pageInfo] of this.pages.entries()) {
418
- pageInfo.page.removeAllListeners();
432
+ pageInfo.page.removeAllListeners(); // Remove all listeners from each page
419
433
  }
420
434
  this.pages.clear();
421
435
  this._selectedPageId = null;
422
- this.removeAllListeners();
436
+ this.removeAllListeners(); // Remove listeners on the emitter itself
423
437
  }
424
438
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-blinq/cucumber_client",
3
- "version": "1.0.1597-dev",
3
+ "version": "1.0.1599-dev",
4
4
  "description": " ",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",