@skyramp/mcp 0.1.8 → 0.2.0-rc.1

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 (60) hide show
  1. package/build/playwright/registerPlaywrightTools.js +12 -0
  2. package/build/playwright/traceRecordingPrompt.js +15 -0
  3. package/build/prompts/test-recommendation/diffExecutionPlan.js +31 -0
  4. package/build/prompts/test-recommendation/recommendationSections.js +1 -2
  5. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +94 -0
  6. package/build/prompts/testbot/testbot-prompts.js +115 -11
  7. package/build/prompts/testbot/testbot-prompts.test.js +79 -0
  8. package/build/resources/testbotResource.js +1 -1
  9. package/build/services/ScenarioGenerationService.integration.test.js +158 -0
  10. package/build/services/ScenarioGenerationService.js +36 -3
  11. package/build/services/ScenarioGenerationService.test.js +158 -22
  12. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +16 -4
  13. package/build/tools/generate-tests/generateIntegrationRestTool.js +2 -0
  14. package/build/tools/generate-tests/generateUIRestTool.js +2 -0
  15. package/build/tools/test-management/analyzeChangesTool.js +7 -1
  16. package/build/utils/routeParsers.js +12 -0
  17. package/node_modules/playwright/ThirdPartyNotices.txt +6 -6
  18. package/node_modules/playwright/lib/dom-analyzer/analyze.js +111 -0
  19. package/node_modules/playwright/lib/dom-analyzer/blueprint.js +1161 -0
  20. package/node_modules/playwright/lib/dom-analyzer/blueprint.test.js +396 -0
  21. package/node_modules/playwright/lib/dom-analyzer/blueprintCache.js +57 -0
  22. package/node_modules/playwright/lib/dom-analyzer/blueprintCache.test.js +57 -0
  23. package/node_modules/playwright/lib/dom-analyzer/blueprintDiff.js +250 -0
  24. package/node_modules/playwright/lib/dom-analyzer/blueprintDiff.test.js +298 -0
  25. package/node_modules/playwright/lib/dom-analyzer/crawler.js +384 -0
  26. package/node_modules/playwright/lib/dom-analyzer/curatedWidgets.js +73 -0
  27. package/node_modules/playwright/lib/dom-analyzer/dynamicId.js +43 -0
  28. package/node_modules/playwright/lib/dom-analyzer/dynamicId.test.js +85 -0
  29. package/node_modules/playwright/lib/dom-analyzer/fingerprint.js +90 -0
  30. package/node_modules/playwright/lib/dom-analyzer/fingerprint.test.js +231 -0
  31. package/node_modules/playwright/lib/dom-analyzer/fingerprintAblation.fixtures.js +145 -0
  32. package/node_modules/playwright/lib/dom-analyzer/fingerprintAblation.test.js +41 -0
  33. package/node_modules/playwright/lib/dom-analyzer/graph.js +36 -0
  34. package/node_modules/playwright/lib/dom-analyzer/liveFingerprints.js +43 -0
  35. package/node_modules/playwright/lib/dom-analyzer/logicalNameResolver.js +72 -0
  36. package/node_modules/playwright/lib/dom-analyzer/logicalNameResolver.test.js +182 -0
  37. package/node_modules/playwright/lib/dom-analyzer/sectionGrouper.js +169 -0
  38. package/node_modules/playwright/lib/dom-analyzer/sectionGrouper.test.js +269 -0
  39. package/node_modules/playwright/lib/dom-analyzer/serialization.js +75 -0
  40. package/node_modules/playwright/lib/dom-analyzer/slug.js +30 -0
  41. package/node_modules/playwright/lib/dom-analyzer/slug.test.js +84 -0
  42. package/node_modules/playwright/lib/dom-analyzer/widgetContract.js +127 -0
  43. package/node_modules/playwright/lib/dom-analyzer/widgetContract.test.js +212 -0
  44. package/node_modules/playwright/lib/mcp/browser/browserContextFactory.js +3 -1
  45. package/node_modules/playwright/lib/mcp/browser/config.js +1 -1
  46. package/node_modules/playwright/lib/mcp/browser/context.js +17 -1
  47. package/node_modules/playwright/lib/mcp/browser/tab.js +38 -0
  48. package/node_modules/playwright/lib/mcp/browser/tools/domAnalyzer.js +261 -0
  49. package/node_modules/playwright/lib/mcp/browser/tools/keyboard.js +3 -3
  50. package/node_modules/playwright/lib/mcp/browser/tools/pageBlueprint.js +129 -0
  51. package/node_modules/playwright/lib/mcp/browser/tools/pageBlueprint.test.js +137 -0
  52. package/node_modules/playwright/lib/mcp/browser/tools/sitemap.js +226 -0
  53. package/node_modules/playwright/lib/mcp/browser/tools/snapshot.js +2 -2
  54. package/node_modules/playwright/lib/mcp/browser/tools/widgetContract.js +168 -0
  55. package/node_modules/playwright/lib/mcp/browser/tools.js +6 -0
  56. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +52 -12
  57. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +64 -13
  58. package/node_modules/playwright/package.json +1 -1
  59. package/node_modules/playwright/skyramp-playwright-1.58.2-skyramp.8.9.3.tgz +0 -0
  60. package/package.json +2 -2
@@ -66,6 +66,16 @@ function jsonlHeader(browserName, harPath) {
66
66
  });
67
67
  }
68
68
  function extractLocatorFromCode(code) {
69
+ const extensionFrameMatch = code.match(
70
+ /await\s+page\.frames\(\)\.find\(\s*f\s*=>\s*f\.url\(\)\.includes\(\s*(['"])([^'"]+)\1\s*\)\s*\)!?\.(.*?)\.(click|dblclick|fill|pressSequentially|check|uncheck|selectOption|hover|dragTo)\s*\(/s
71
+ );
72
+ if (extensionFrameMatch) {
73
+ return {
74
+ locatorExpr: extensionFrameMatch[3].trim(),
75
+ framePath: [],
76
+ frameUrlMatch: extensionFrameMatch[2]
77
+ };
78
+ }
69
79
  const contentFrameMatch = code.match(/await\s+page\.locator\((['"])(iframe[^\n]*?)\1\)(?:\.contentFrame\(\))+\.(.*?)\.(click|dblclick|fill|pressSequentially|check|uncheck|selectOption|hover|dragTo)\s*\(/s);
70
80
  if (contentFrameMatch) {
71
81
  return { locatorExpr: contentFrameMatch[3].trim(), framePath: [contentFrameMatch[2]] };
@@ -206,10 +216,13 @@ function trackedActionToJsonl(action, pageGuid, timestamp) {
206
216
  if (toolName === "browser_wait_for") {
207
217
  const text = args.text;
208
218
  const textGone = args.textGone;
219
+ const time = args.time;
209
220
  if (text)
210
221
  return JSON.stringify({ name: "waitForSelector", selector: `text=${text}`, ...base });
211
222
  if (textGone)
212
223
  return JSON.stringify({ name: "waitForSelector", selector: `text=${textGone}`, state: "hidden", ...base });
224
+ if (typeof time === "number")
225
+ return JSON.stringify({ name: "waitForTimeout", duration: time * 1e3, ...base });
213
226
  return null;
214
227
  }
215
228
  if (toolName === "browser_press_key")
@@ -219,9 +232,11 @@ function trackedActionToJsonl(action, pageGuid, timestamp) {
219
232
  const extracted = extractLocatorFromCode(code);
220
233
  if (!extracted)
221
234
  return null;
222
- const { locatorExpr, framePath: codeFramePath } = extracted;
235
+ const { locatorExpr, framePath: codeFramePath, frameUrlMatch } = extracted;
223
236
  if (codeFramePath.length > 0)
224
237
  base.framePath = codeFramePath;
238
+ if (frameUrlMatch)
239
+ base.frameUrlMatch = frameUrlMatch;
225
240
  const parsed = locatorToJsonl(locatorExpr);
226
241
  if (!parsed)
227
242
  return null;
@@ -373,18 +388,51 @@ function removeRedundantClicks(actions) {
373
388
  });
374
389
  }
375
390
  function deduplicateRetries(actions) {
376
- const firstNavigate = actions.find((a) => a.toolName === "browser_navigate");
377
- if (!firstNavigate)
378
- return actions;
379
- const startUrl = firstNavigate.args.url;
380
- let lastRestartIdx = 0;
381
- for (let i = 1; i < actions.length; i++) {
382
- if (actions[i].toolName === "browser_navigate" && actions[i].args.url === startUrl)
383
- lastRestartIdx = i;
391
+ const result = [];
392
+ let lastNavIdx = -1;
393
+ for (const action of actions) {
394
+ if (action.toolName !== "browser_navigate") {
395
+ result.push(action);
396
+ continue;
397
+ }
398
+ const url = action.args.url;
399
+ if (lastNavIdx >= 0 && result[lastNavIdx].args.url === url) {
400
+ result.length = lastNavIdx;
401
+ lastNavIdx = -1;
402
+ for (let k = result.length - 1; k >= 0; k--) {
403
+ if (result[k].toolName === "browser_navigate") {
404
+ lastNavIdx = k;
405
+ break;
406
+ }
407
+ }
408
+ }
409
+ result.push(action);
410
+ lastNavIdx = result.length - 1;
411
+ }
412
+ return result;
413
+ }
414
+ function normalizePrimaryPageAlias(actions) {
415
+ const DEFAULT = DEFAULT_PAGE_ALIAS;
416
+ const counts = /* @__PURE__ */ new Map();
417
+ for (const a of actions) {
418
+ const alias = a.pageAlias ?? DEFAULT;
419
+ counts.set(alias, (counts.get(alias) ?? 0) + 1);
420
+ }
421
+ if ((counts.get(DEFAULT) ?? 0) > 0)
422
+ return;
423
+ const candidates = [...counts.keys()].filter((a) => /^page\d+$/.test(a));
424
+ if (candidates.length !== 1)
425
+ return;
426
+ const from = candidates[0];
427
+ for (const a of actions) {
428
+ if (a.pageAlias === from)
429
+ a.pageAlias = DEFAULT;
430
+ if (a.popupAlias === from)
431
+ a.popupAlias = DEFAULT;
384
432
  }
385
- return lastRestartIdx > 0 ? actions.slice(lastRestartIdx) : actions;
386
433
  }
387
434
  function buildJsonlContent(actions, browserName, harPath) {
435
+ normalizePrimaryPageAlias(actions);
388
436
  const deduplicated = removeRedundantClicks(deduplicateRetries(actions));
389
437
  const startTime = deduplicated[0]?.timestamp ?? Date.now();
390
438
  const pageGuids = /* @__PURE__ */ new Map();
@@ -416,7 +464,9 @@ function buildJsonlContent(actions, browserName, harPath) {
416
464
  const obj = JSON.parse(lines[i]);
417
465
  if (obj.name === "openPage" || obj.name === "closePage")
418
466
  continue;
419
- if (!obj.pageAlias || obj.pageAlias !== alias) {
467
+ if (!obj.pageAlias)
468
+ continue;
469
+ if (obj.pageAlias !== alias) {
420
470
  obj.signals = [...obj.signals || [], { name: "popup", popupAlias: alias }];
421
471
  lines[i] = JSON.stringify(obj);
422
472
  break;
@@ -453,7 +503,7 @@ function buildJsonlContent(actions, browserName, harPath) {
453
503
  }
454
504
  const parsed = extractLocatorFromCode(action.code);
455
505
  if (parsed) {
456
- const { locatorExpr, framePath } = parsed;
506
+ const { locatorExpr, framePath, frameUrlMatch } = parsed;
457
507
  const locatorInfo = locatorToJsonl(locatorExpr);
458
508
  if (locatorInfo) {
459
509
  const { selector, locator: locatorObj } = locatorInfo;
@@ -466,7 +516,8 @@ function buildJsonlContent(actions, browserName, harPath) {
466
516
  timestamp: String(action.timestamp + 100),
467
517
  pageGuid,
468
518
  pageAlias: alias,
469
- framePath
519
+ framePath,
520
+ ...frameUrlMatch ? { frameUrlMatch } : {}
470
521
  });
471
522
  lines.push(pressLine);
472
523
  actionCount++;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyramp/playwright",
3
- "version": "1.58.2-skyramp.8.9.0",
3
+ "version": "1.58.2-skyramp.8.9.4",
4
4
  "description": "Skyramp's fork of Playwright with trace recording for UI test generation",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyramp/mcp",
3
- "version": "0.1.8",
3
+ "version": "0.2.0-rc.1",
4
4
  "main": "build/index.js",
5
5
  "exports": {
6
6
  ".": "./build/index.js",
@@ -59,7 +59,7 @@
59
59
  "dockerode": "^5.0.0",
60
60
  "fast-glob": "^3.3.3",
61
61
  "js-yaml": "^4.1.1",
62
- "playwright": "file:vendor/skyramp-playwright-1.58.2-skyramp.8.9.0.tgz",
62
+ "playwright": "file:vendor/skyramp-playwright-1.58.2-skyramp.8.9.4.tgz",
63
63
  "simple-git": "^3.30.0",
64
64
  "zod": "^3.25.3"
65
65
  },