@empiricalrun/test-gen 0.42.4 → 0.42.9

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 (52) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/agent/browsing/utils.d.ts.map +1 -1
  3. package/dist/agent/browsing/utils.js +1 -0
  4. package/dist/agent/codegen/create-test-block.d.ts.map +1 -1
  5. package/dist/agent/codegen/create-test-block.js +4 -2
  6. package/dist/agent/codegen/lexical-scoped-vars.d.ts.map +1 -1
  7. package/dist/agent/codegen/lexical-scoped-vars.js +4 -6
  8. package/dist/agent/codegen/promptBuilder.d.ts +3 -0
  9. package/dist/agent/codegen/promptBuilder.d.ts.map +1 -0
  10. package/dist/agent/codegen/promptBuilder.js +44 -0
  11. package/dist/agent/codegen/repo-edit.js +1 -1
  12. package/dist/agent/master/action-tool-calls.d.ts +40 -0
  13. package/dist/agent/master/action-tool-calls.d.ts.map +1 -0
  14. package/dist/agent/master/action-tool-calls.js +83 -0
  15. package/dist/agent/master/element-annotation.d.ts +7 -2
  16. package/dist/agent/master/element-annotation.d.ts.map +1 -1
  17. package/dist/agent/master/element-annotation.js +13 -3
  18. package/dist/agent/master/next-action.d.ts +12 -14
  19. package/dist/agent/master/next-action.d.ts.map +1 -1
  20. package/dist/agent/master/next-action.js +62 -63
  21. package/dist/agent/master/run.d.ts.map +1 -1
  22. package/dist/agent/master/run.js +68 -51
  23. package/dist/agent/master/scroller.d.ts +15 -0
  24. package/dist/agent/master/scroller.d.ts.map +1 -0
  25. package/dist/agent/master/scroller.js +371 -0
  26. package/dist/agent/master/with-hints.d.ts.map +1 -1
  27. package/dist/agent/master/with-hints.js +4 -1
  28. package/dist/agent/utils.d.ts +2 -0
  29. package/dist/agent/utils.d.ts.map +1 -0
  30. package/dist/agent/utils.js +12 -0
  31. package/dist/bin/utils/platform/web/index.d.ts.map +1 -1
  32. package/dist/bin/utils/platform/web/index.js +2 -0
  33. package/dist/browser-injected-scripts/annotate-elements.js +122 -74
  34. package/dist/browser-injected-scripts/annotate-elements.spec.d.ts +2 -0
  35. package/dist/browser-injected-scripts/annotate-elements.spec.d.ts.map +1 -0
  36. package/dist/browser-injected-scripts/annotate-elements.spec.js +186 -0
  37. package/dist/browser-injected-scripts/annotate-elements.spec.ts +52 -26
  38. package/dist/evals/master-agent.evals.d.ts.map +1 -1
  39. package/dist/evals/master-agent.evals.js +5 -4
  40. package/dist/prompts/lib/ts-transformer.d.ts +4 -0
  41. package/dist/prompts/lib/ts-transformer.d.ts.map +1 -0
  42. package/dist/prompts/lib/ts-transformer.js +90 -0
  43. package/dist/prompts/lib/vitest-plugin.d.ts +8 -0
  44. package/dist/prompts/lib/vitest-plugin.d.ts.map +1 -0
  45. package/dist/prompts/lib/vitest-plugin.js +20 -0
  46. package/dist/session/index.d.ts.map +1 -1
  47. package/dist/session/index.js +4 -0
  48. package/package.json +10 -8
  49. package/playwright.config.ts +1 -1
  50. package/vitest.config.ts +5 -0
  51. package/browser-injected-scripts/annotate-elements.js +0 -491
  52. package/browser-injected-scripts/annotate-elements.spec.ts +0 -277
@@ -1,4 +1,4 @@
1
- /* eslint-disable no-undef */
1
+ /* eslint-disable autofix/no-unused-vars */
2
2
  /**
3
3
  * Annotates all clickable elements on the page with unique hint markers.
4
4
  * Returns an object containing annotations and methods to enable/disable them.
@@ -9,7 +9,10 @@
9
9
  * @param {string} options.markerClass - CSS class to apply to hint markers.
10
10
  * @returns {Object} An object containing annotations map and enable/disable methods.
11
11
  */
12
- function annotateClickableElements({ options = {}, preference } = {}) {
12
+ function annotateElementsWithPreference({
13
+ options = {},
14
+ preference = {},
15
+ } = {}) {
13
16
  const {
14
17
  hintCharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", // Default set of characters for hints
15
18
  maxHints = 1000, // Maximum number of hints to generate
@@ -35,38 +38,18 @@ function annotateClickableElements({ options = {}, preference } = {}) {
35
38
  if (
36
39
  centerX < 0 ||
37
40
  centerY < 0 ||
38
- centerX > (windowToAnnotate.innerWidth || document.documentElement.clientWidth) ||
39
- centerY > (windowToAnnotate.innerHeight || document.documentElement.clientHeight)
41
+ centerX >
42
+ (windowToAnnotate.innerWidth || document.documentElement.clientWidth) ||
43
+ centerY >
44
+ (windowToAnnotate.innerHeight || document.documentElement.clientHeight)
40
45
  ) {
41
- // Determine the viewport dimensions
42
- const viewportWidth =
43
- windowToAnnotate.innerWidth || document.documentElement.clientWidth;
44
- const viewportHeight =
45
- windowToAnnotate.innerHeight || document.documentElement.clientHeight;
46
-
47
- // Calculate the new scroll positions to bring the element into the center of the viewport
48
- const newScrollX = centerX - viewportWidth / 2;
49
- const newScrollY = centerY - viewportHeight / 2;
50
-
51
- // Scroll the window to the new positions
52
- windowToAnnotate.scrollTo({
53
- top: newScrollY,
54
- left: newScrollX,
55
- });
56
-
57
- const newRect = element.getBoundingClientRect();
58
- const newCenterX = newRect.left + newRect.width / 2;
59
- const newCenterY = newRect.top + newRect.height / 2;
60
- const topElement = document.elementFromPoint(newCenterX, newCenterY);
61
- const doesElementContainTopElement = element.contains(topElement);
62
-
63
-
64
- // Restore the original scroll positions
65
- windowToAnnotate.scrollTo(originalScrollX, originalScrollY);
66
- return doesElementContainTopElement;
46
+ return false;
67
47
  }
68
48
 
69
- const topElement = windowToAnnotate.document.elementFromPoint(centerX, centerY);
49
+ const topElement = windowToAnnotate.document.elementFromPoint(
50
+ centerX,
51
+ centerY,
52
+ );
70
53
 
71
54
  // Check if the topmost element is the target element or one of its descendants
72
55
  return element.contains(topElement);
@@ -98,7 +81,7 @@ function annotateClickableElements({ options = {}, preference } = {}) {
98
81
  acc
99
82
  .map((a) => curr.map((b) => a.concat([b])))
100
83
  .reduce((a, b) => a.concat(b), []),
101
- [[]]
84
+ [[]],
102
85
  );
103
86
  }
104
87
 
@@ -121,7 +104,7 @@ function annotateClickableElements({ options = {}, preference } = {}) {
121
104
  style.display === "none" ||
122
105
  style.visibility === "hidden" ||
123
106
  // This is done for cases where opacity is undefined
124
- // parseFloat(style.opacity) === 0
107
+ // parseFloat(style.opacity) === 0
125
108
  style.pointerEvents === "none"
126
109
  ) {
127
110
  return false;
@@ -173,11 +156,11 @@ function annotateClickableElements({ options = {}, preference } = {}) {
173
156
  // Check for onclick attribute or listener
174
157
  if (
175
158
  (element.hasAttribute("onclick") ||
176
- typeof element.onclick === "function")
159
+ typeof element.onclick === "function") &&
177
160
  // check for parent element having same on click
178
- && element.parentNode.onclick !== element.onclick
161
+ element.parentNode.onclick !== element.onclick &&
179
162
  // parent element should not be a focusable tag like button
180
- && focusableTags.indexOf(element.parentNode.tagName.toLowerCase()) === -1
163
+ focusableTags.indexOf(element.parentNode.tagName.toLowerCase()) === -1
181
164
  ) {
182
165
  isClickable = true;
183
166
  }
@@ -227,7 +210,6 @@ function annotateClickableElements({ options = {}, preference } = {}) {
227
210
  }
228
211
  }
229
212
 
230
-
231
213
  if (focusableTags.includes(tagName)) {
232
214
  switch (tagName) {
233
215
  case "a":
@@ -321,7 +303,7 @@ function annotateClickableElements({ options = {}, preference } = {}) {
321
303
  // Create a hint marker
322
304
  function createHintMarker(el, hint, parentElement, windowToAnnotate) {
323
305
  const rect = el.getBoundingClientRect();
324
-
306
+
325
307
  // Create the marker element
326
308
  const marker = document.createElement("div");
327
309
  marker.textContent = hint;
@@ -350,13 +332,12 @@ function annotateClickableElements({ options = {}, preference } = {}) {
350
332
  fontWeight: "bold",
351
333
  textShadow: "rgba(255, 255, 255, 0.6) 0px 1px 0px",
352
334
  });
353
-
335
+
354
336
  // Attach the marker to the specified parent element
355
337
  parentElement.appendChild(marker);
356
338
  parentElements.push(parentElement);
357
339
  return marker;
358
340
  }
359
-
360
341
 
361
342
  // Clear existing annotations
362
343
  //TODO: Handle clearing annotations
@@ -371,51 +352,113 @@ function annotateClickableElements({ options = {}, preference } = {}) {
371
352
  function isInputElement(el) {
372
353
  // Check if it's an input with a text-like type
373
354
  if (el instanceof HTMLInputElement) {
374
- const textTypes = ['text', 'email', 'number', 'password', 'search', 'tel', 'url', 'checkbox'];
355
+ const textTypes = [
356
+ "text",
357
+ "email",
358
+ "number",
359
+ "password",
360
+ "search",
361
+ "tel",
362
+ "url",
363
+ "checkbox",
364
+ ];
375
365
  return textTypes.includes(el.type.toLowerCase());
376
366
  }
377
-
367
+
378
368
  // Check if it's a textarea
379
369
  if (el instanceof HTMLTextAreaElement) {
380
370
  return true;
381
371
  }
382
-
372
+
383
373
  // Check if it's contentEditable
384
374
  return el.isContentEditable;
385
375
  }
386
376
 
377
+ function isRequiredTextPresent(el, assertionText) {
378
+ assertionText = assertionText?.trim().toLowerCase();
379
+ if (assertionText) {
380
+ let elementText = el.innerText?.trim().toLowerCase();
381
+ let placeHolderText = el.placeholder?.trim().toLowerCase();
382
+ if (elementText === assertionText || placeHolderText === assertionText) {
383
+ //Check if the text for parent and child is same or not, if its same don't annotate again
384
+ if (el.parentNode.innerText?.toLowerCase() !== elementText) {
385
+ return true;
386
+ }
387
+ }
388
+ return false;
389
+ }
390
+ return true;
391
+ }
392
+
393
+ // This checks if the element is scrollable or not
394
+ function isElementScrollable(elem) {
395
+ function getComputedStyle(elem) {
396
+ return window.getComputedStyle(elem, null);
397
+ }
398
+
399
+ function getActualCss(elem, style) {
400
+ return getComputedStyle(elem)[style];
401
+ }
402
+
403
+ function isYScrollable(elem) {
404
+ return (
405
+ elem.offsetHeight < elem.scrollHeight &&
406
+ autoOrScroll(getActualCss(elem, "overflow-y"))
407
+ );
408
+ }
409
+
410
+ function autoOrScroll(text) {
411
+ return text == "scroll" || text == "auto";
412
+ }
413
+
414
+ // This doesn't annotate the elements with horizontal scroll
415
+ return isYScrollable(elem);
416
+ }
417
+
387
418
  // Initialize annotations for a given window (including iframes)
388
419
  function initializeAnnotations(windowToAnnotate, parentHints, depth) {
389
420
  const container =
390
- parentHints?.nodeName === "IFRAME"
391
- ? parentHints.contentWindow.document.body
392
- : annotationsContainer;
421
+ parentHints?.nodeName === "IFRAME"
422
+ ? parentHints.contentWindow.document.body
423
+ : annotationsContainer;
393
424
 
394
425
  // Ensure the container exists
395
426
  if (!container) return;
396
-
427
+
397
428
  // Filter for clickable elements
398
- const clickableElements = Array.from(windowToAnnotate.document.querySelectorAll("*")).filter((el) => {
429
+ const elementsToAnnotate = Array.from(
430
+ windowToAnnotate.document.querySelectorAll("*"),
431
+ ).filter((el) => {
432
+ // Here based on the action type we filter the elements
433
+ // and annotate only those elements
434
+ switch (preference.actionType) {
435
+ case "fill":
436
+ return isInputElement(el);
399
437
 
400
- //If preference is fill then it should only annotate input elements
401
- if(preference === "fill"){
402
- if (!isInputElement(el)) {
403
- return false;
404
- }
405
- }
438
+ case "assert_text":
439
+ return isRequiredTextPresent(el, preference.assertionText);
440
+
441
+ case "scroll":
442
+ return isElementScrollable(el);
406
443
 
407
- const isClickable = isElementClickable(el, windowToAnnotate);
408
- const isClickNotBlocked = isElementClickNotBlocked(el, windowToAnnotate);
409
- return isClickable && isClickNotBlocked;
410
- });
444
+ default:
445
+ return (
446
+ isElementClickable(el, windowToAnnotate) &&
447
+ isElementClickNotBlocked(el, windowToAnnotate)
448
+ );
449
+ }
450
+ });
411
451
  // Generate hint strings for the clickable elements
412
- const hints = generateHintStrings(hintCharacterSet, Math.min(maxHints, clickableElements.length));
413
-
452
+ const hints = generateHintStrings(
453
+ hintCharacterSet,
454
+ Math.min(maxHints, elementsToAnnotate.length),
455
+ );
456
+
414
457
  // Create markers for the elements
415
- clickableElements.slice(0, maxHints).forEach((el, index) => {
458
+ elementsToAnnotate.slice(0, maxHints).forEach((el, index) => {
416
459
  const hint = hints[index];
417
460
  const rect = el.getBoundingClientRect();
418
-
461
+
419
462
  // Use createHintMarker with the specified container
420
463
  createHintMarker(el, hint, container, windowToAnnotate);
421
464
  el.style.boxShadow = `inset 0 0 0px 2px red`;
@@ -429,23 +472,28 @@ function annotateClickableElements({ options = {}, preference } = {}) {
429
472
  width: rect.width,
430
473
  height: rect.height,
431
474
  },
432
- depth: [...depth ]
475
+ depth: [...depth],
433
476
  };
434
477
  });
435
-
478
+
436
479
  // Process iframes recursively
437
- Array.from(windowToAnnotate.document.querySelectorAll("iframe")).forEach((iframe) => {
438
- try {
439
- const frameWindow = iframe.contentWindow;
440
- if (frameWindow && iframe.offsetWidth > 0 && iframe.offsetHeight > 0) {
441
- initializeAnnotations(frameWindow, iframe, [...depth, iframe]);
480
+ Array.from(windowToAnnotate.document.querySelectorAll("iframe")).forEach(
481
+ (iframe) => {
482
+ try {
483
+ const frameWindow = iframe.contentWindow;
484
+ if (
485
+ frameWindow &&
486
+ iframe.offsetWidth > 0 &&
487
+ iframe.offsetHeight > 0
488
+ ) {
489
+ initializeAnnotations(frameWindow, iframe, [...depth, iframe]);
490
+ }
491
+ } catch (e) {
492
+ console.warn("Cannot access iframe:", e);
442
493
  }
443
- } catch (e) {
444
- console.warn("Cannot access iframe:", e);
445
- }
446
- });
494
+ },
495
+ );
447
496
  }
448
-
449
497
 
450
498
  // Initialize and enable annotations
451
499
  function enable() {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=annotate-elements.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotate-elements.spec.d.ts","sourceRoot":"","sources":["../../src/browser-injected-scripts/annotate-elements.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // @ts-nocheck
7
+ const test_1 = require("@playwright/test");
8
+ const path_1 = __importDefault(require("path"));
9
+ const action_tool_calls_1 = require("../agent/master/action-tool-calls");
10
+ (0, test_1.test)("should annotate all links on empirical landing page", async ({ page, }) => {
11
+ await page.goto("https://assets-test.empirical.run/selector-hints-testing/dom-1.html");
12
+ await page.addScriptTag({
13
+ path: path_1.default.resolve(__dirname, "./annotate-elements.js"),
14
+ });
15
+ const annotations = await page.evaluate(() => {
16
+ // eslint-disable-next-line no-undef
17
+ const { annotations } = annotateElementsWithPreference();
18
+ return Object.entries(annotations).map(([, config]) => ({
19
+ innerText: config.node.innerText,
20
+ tagName: config.node.tagName,
21
+ href: config.node.href,
22
+ }));
23
+ });
24
+ test_1.test.expect(annotations).toEqual([
25
+ {
26
+ innerText: "Empirical",
27
+ tagName: "A",
28
+ href: "https://assets-test.empirical.run/",
29
+ },
30
+ {
31
+ innerText: "Blog",
32
+ tagName: "A",
33
+ href: "https://assets-test.empirical.run/blog",
34
+ },
35
+ {
36
+ innerText: "Contact us",
37
+ tagName: "A",
38
+ href: "https://assets-test.empirical.run/contact",
39
+ },
40
+ {
41
+ href: "https://dash.empirical.run/",
42
+ innerText: "Login ↗\n(opens in a new tab)",
43
+ tagName: "A",
44
+ },
45
+ {
46
+ innerText: "Get early access",
47
+ tagName: "A",
48
+ href: "https://assets-test.empirical.run/contact",
49
+ },
50
+ ]);
51
+ });
52
+ (0, test_1.test)("should annotate all important items on quizizz page", async ({ page, }) => {
53
+ await page.goto("https://assets-test.empirical.run/selector-hints-testing/dom-2/index.html");
54
+ await page.addScriptTag({
55
+ path: path_1.default.resolve(__dirname, "./annotate-elements.js"),
56
+ });
57
+ const annotations = await page.evaluate(() => {
58
+ // eslint-disable-next-line no-undef
59
+ const { annotations } = annotateElementsWithPreference();
60
+ return Object.entries(annotations).map(([hint, config]) => ({
61
+ hint,
62
+ innerText: config.node.innerText.toLowerCase().trim(),
63
+ tagName: config.node.tagName,
64
+ testId: config.node.getAttribute("data-testid"),
65
+ href: config.node.href,
66
+ }));
67
+ });
68
+ test_1.test
69
+ .expect(annotations.find((item) => item.innerText.includes("enter code")))
70
+ .toBeTruthy();
71
+ test_1.test
72
+ .expect(annotations.find((item) => item.innerText.includes("get help")))
73
+ .toBeTruthy();
74
+ test_1.test
75
+ .expect(annotations.find((item) => item.innerText.includes("create") &&
76
+ item.testId === "create-content-button"))
77
+ .toBeTruthy();
78
+ test_1.test
79
+ .expect(annotations.find((item) => item.innerText.includes("explore") &&
80
+ item.href === "https://quizizz.com/admin"))
81
+ .toBeTruthy();
82
+ test_1.test
83
+ .expect(annotations.find((item) => item.innerText.includes("library") &&
84
+ item.href === "https://quizizz.com/admin/my-library/createdByMe"))
85
+ .toBeTruthy();
86
+ test_1.test
87
+ .expect(annotations.find((item) => item.innerText.includes("reports") &&
88
+ item.href === "https://quizizz.com/admin/reports"))
89
+ .toBeTruthy();
90
+ test_1.test
91
+ .expect(annotations.find((item) => item.innerText.includes("classes") &&
92
+ item.href === "https://quizizz.com/admin/classes"))
93
+ .toBeTruthy();
94
+ test_1.test
95
+ .expect(annotations.find((item) => item.innerText.includes("accommodations") &&
96
+ item.href ===
97
+ "https://quizizz.com/admin/differentiation/accommodations"))
98
+ .toBeTruthy();
99
+ test_1.test
100
+ .expect(annotations.find((item) => item.innerText.includes("quizizz ai") &&
101
+ item.href === "https://quizizz.com/admin/quizizz-ai"))
102
+ .toBeTruthy();
103
+ test_1.test
104
+ .expect(annotations.find((item) => item.innerText.includes("start your free trial") &&
105
+ item.href === "https://quizizz.com/super-pricing"))
106
+ .toBeTruthy();
107
+ test_1.test
108
+ .expect(annotations.find((item) => item.innerText.includes("upgrade") &&
109
+ item.href === "https://quizizz.com/super-pricing?backto=/admin"))
110
+ .toBeTruthy();
111
+ test_1.test
112
+ .expect(annotations.find((item) => item.tagName === "INPUT" &&
113
+ item.testId === "emphasized-search-bar-input"))
114
+ .toBeTruthy();
115
+ test_1.test
116
+ .expect(annotations.find((item) => item.tagName === "BUTTON" &&
117
+ item.innerText.includes("verify details") &&
118
+ item.testId === "verify-profile-cta"))
119
+ .toBeTruthy();
120
+ test_1.test
121
+ .expect(annotations.find((item) => item.tagName === "BUTTON" && item.innerText.includes("for you")))
122
+ .toBeTruthy();
123
+ test_1.test
124
+ .expect(annotations.find((item) => item.tagName === "BUTTON" && item.innerText.includes("assessments")))
125
+ .toBeTruthy();
126
+ test_1.test
127
+ .expect(annotations.find((item) => item.tagName === "BUTTON" && item.innerText.includes("lessons")))
128
+ .toBeTruthy();
129
+ test_1.test
130
+ .expect(annotations.find((item) => item.tagName === "BUTTON" &&
131
+ item.innerText.includes("interactive videos")))
132
+ .toBeTruthy();
133
+ test_1.test
134
+ .expect(annotations.find((item) => item.tagName === "BUTTON" && item.innerText.includes("passages")))
135
+ .toBeTruthy();
136
+ });
137
+ (0, test_1.test)("should only annotate input fields on quizizz page", async ({ page }) => {
138
+ await page.goto("https://assets-test.empirical.run/selector-hints-testing/dom-2/index.html");
139
+ await page.addScriptTag({
140
+ path: path_1.default.resolve(__dirname, "./annotate-elements.js"),
141
+ });
142
+ const preference = {
143
+ actionType: action_tool_calls_1.ActionType.FILL,
144
+ };
145
+ const annotations = await page.evaluate((preference) => {
146
+ // eslint-disable-next-line no-undef
147
+ const { annotations } = annotateElementsWithPreference({
148
+ preference: preference,
149
+ });
150
+ return Object.entries(annotations).map(([hint, config]) => ({
151
+ hint,
152
+ innerText: config.node.innerText.toLowerCase().trim(),
153
+ tagName: config.node.tagName,
154
+ testId: config.node.getAttribute("data-testid"),
155
+ href: config.node.href,
156
+ }));
157
+ }, preference);
158
+ test_1.test.expect(annotations.length).toBe(1);
159
+ test_1.test.expect(annotations[0].testId).toBe("emphasized-search-bar-input");
160
+ });
161
+ (0, test_1.test)("should only annotate given text on quizziz page", async ({ page }) => {
162
+ await page.goto("https://assets-test.empirical.run/selector-hints-testing/dom-2/index.html");
163
+ await page.addScriptTag({
164
+ path: path_1.default.resolve(__dirname, "./annotate-elements.js"),
165
+ });
166
+ const preference = {
167
+ actionType: action_tool_calls_1.ActionType.ASSERT_TEXT,
168
+ assertionText: "What are you teaching today?",
169
+ };
170
+ const annotations = await page.evaluate((preference) => {
171
+ // eslint-disable-next-line no-undef
172
+ const { annotations } = annotateElementsWithPreference({
173
+ preference: preference,
174
+ });
175
+ return Object.entries(annotations).map(([hint, config]) => ({
176
+ hint,
177
+ innerText: config.node.innerText?.toLowerCase().trim(),
178
+ tagName: config.node.tagName,
179
+ testId: config.node.getAttribute("data-testid"),
180
+ href: config.node.href,
181
+ }));
182
+ }, preference);
183
+ console.log("Annotations:", annotations);
184
+ test_1.test.expect(annotations.length).toBe(1);
185
+ test_1.test.expect(annotations[0]?.tagName).toBe("DIV");
186
+ });
@@ -3,6 +3,9 @@
3
3
  import { test } from "@playwright/test";
4
4
  import path from "path";
5
5
 
6
+ import { ActionType } from "../agent/master/action-tool-calls";
7
+ import { AnnotationPreference } from "../agent/master/element-annotation";
8
+
6
9
  test("should annotate all links on empirical landing page", async ({
7
10
  page,
8
11
  }) => {
@@ -15,9 +18,10 @@ test("should annotate all links on empirical landing page", async ({
15
18
  });
16
19
 
17
20
  const annotations = await page.evaluate(() => {
18
- const { annotations } = annotateClickableElements();
21
+ // eslint-disable-next-line no-undef
22
+ const { annotations } = annotateElementsWithPreference();
19
23
 
20
- return Object.entries(annotations).map(([hint, config]) => ({
24
+ return Object.entries(annotations).map(([, config]) => ({
21
25
  innerText: config.node.innerText,
22
26
  tagName: config.node.tagName,
23
27
  href: config.node.href,
@@ -50,21 +54,6 @@ test("should annotate all links on empirical landing page", async ({
50
54
  tagName: "A",
51
55
  href: "https://assets-test.empirical.run/contact",
52
56
  },
53
- {
54
- innerText: "Playwright\n(opens in a new tab)",
55
- tagName: "A",
56
- href: "https://github.com/microsoft/playwright",
57
- },
58
- {
59
- innerText: "Meet with us",
60
- tagName: "A",
61
- href: "https://assets-test.empirical.run/contact",
62
- },
63
- {
64
- innerText: "Privacy Policy",
65
- tagName: "A",
66
- href: "https://assets-test.empirical.run/privacy.html",
67
- },
68
57
  ]);
69
58
  });
70
59
 
@@ -80,7 +69,8 @@ test("should annotate all important items on quizizz page", async ({
80
69
  });
81
70
 
82
71
  const annotations = await page.evaluate(() => {
83
- const { annotations } = annotateClickableElements();
72
+ // eslint-disable-next-line no-undef
73
+ const { annotations } = annotateElementsWithPreference();
84
74
 
85
75
  return Object.entries(annotations).map(([hint, config]) => ({
86
76
  hint,
@@ -148,7 +138,7 @@ test("should annotate all important items on quizizz page", async ({
148
138
  (item) =>
149
139
  item.innerText.includes("accommodations") &&
150
140
  item.href ===
151
- "https://quizizz.com/admin/differentiation/accommodations",
141
+ "https://quizizz.com/admin/differentiation/accommodations",
152
142
  ),
153
143
  )
154
144
  .toBeTruthy();
@@ -248,9 +238,7 @@ test("should annotate all important items on quizizz page", async ({
248
238
  .toBeTruthy();
249
239
  });
250
240
 
251
- test("should only annotate input fields on quizizz page", async ({
252
- page,
253
- }) => {
241
+ test("should only annotate input fields on quizizz page", async ({ page }) => {
254
242
  await page.goto(
255
243
  "https://assets-test.empirical.run/selector-hints-testing/dom-2/index.html",
256
244
  );
@@ -259,9 +247,14 @@ test("should only annotate input fields on quizizz page", async ({
259
247
  path: path.resolve(__dirname, "./annotate-elements.js"),
260
248
  });
261
249
 
262
- const preference = "fill";
250
+ const preference = {
251
+ actionType: ActionType.FILL,
252
+ };
263
253
  const annotations = await page.evaluate((preference) => {
264
- const { annotations } = annotateClickableElements({preference: preference});
254
+ // eslint-disable-next-line no-undef
255
+ const { annotations } = annotateElementsWithPreference({
256
+ preference: preference,
257
+ });
265
258
 
266
259
  return Object.entries(annotations).map(([hint, config]) => ({
267
260
  hint,
@@ -270,8 +263,41 @@ test("should only annotate input fields on quizizz page", async ({
270
263
  testId: config.node.getAttribute("data-testid"),
271
264
  href: config.node.href,
272
265
  }));
273
- },preference);
266
+ }, preference);
267
+
268
+ test.expect(annotations.length).toBe(1);
269
+ test.expect(annotations[0].testId).toBe("emphasized-search-bar-input");
270
+ });
271
+
272
+ test("should only annotate given text on quizziz page", async ({ page }) => {
273
+ await page.goto(
274
+ "https://assets-test.empirical.run/selector-hints-testing/dom-2/index.html",
275
+ );
276
+
277
+ await page.addScriptTag({
278
+ path: path.resolve(__dirname, "./annotate-elements.js"),
279
+ });
280
+
281
+ const preference: AnnotationPreference = {
282
+ actionType: ActionType.ASSERT_TEXT,
283
+ assertionText: "What are you teaching today?",
284
+ };
285
+ const annotations = await page.evaluate((preference) => {
286
+ // eslint-disable-next-line no-undef
287
+ const { annotations } = annotateElementsWithPreference({
288
+ preference: preference,
289
+ });
290
+
291
+ return Object.entries(annotations).map(([hint, config]) => ({
292
+ hint,
293
+ innerText: config.node.innerText?.toLowerCase().trim(),
294
+ tagName: config.node.tagName,
295
+ testId: config.node.getAttribute("data-testid"),
296
+ href: config.node.href,
297
+ }));
298
+ }, preference);
274
299
 
300
+ console.log("Annotations:", annotations);
275
301
  test.expect(annotations.length).toBe(1);
276
- test.expect(annotations[0].testId).toBe('emphasized-search-bar-input');
302
+ test.expect(annotations[0]?.tagName).toBe("DIV");
277
303
  });
@@ -1 +1 @@
1
- {"version":3,"file":"master-agent.evals.d.ts","sourceRoot":"","sources":["../../src/evals/master-agent.evals.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,eAAO,MAAM,4BAA4B,EAAE,UA0C1C,CAAC;AAEF,eAAe,4BAA4B,CAAC"}
1
+ {"version":3,"file":"master-agent.evals.d.ts","sourceRoot":"","sources":["../../src/evals/master-agent.evals.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,eAAO,MAAM,4BAA4B,EAAE,UAwC1C,CAAC;AAEF,eAAe,4BAA4B,CAAC"}
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.masterGetNextActionEvaluator = void 0;
4
4
  const actions_1 = require("../actions");
5
5
  const skill_1 = require("../actions/skill");
6
+ const action_tool_calls_1 = require("../agent/master/action-tool-calls");
6
7
  const next_action_1 = require("../agent/master/next-action");
7
8
  const page_1 = require("../page");
8
9
  const masterGetNextActionEvaluator = async ({ item, trace, }) => {
9
- const { task, executedActions, failedActions, pageUrl, options, pageScreenshot, annotatedPageScreenshot, disableSkills, skills = [], annotations, } = item.input;
10
+ const { task, executedActions, failedActions, pageUrl, options, pageScreenshot, disableSkills, skills = [], } = item.input;
10
11
  const page = {};
11
12
  skill_1.testCaseSkills.updateSkills(skills);
12
13
  const actions = new actions_1.PlaywrightActions(new page_1.TestGenPage(page, "page"));
@@ -18,16 +19,16 @@ const masterGetNextActionEvaluator = async ({ item, trace, }) => {
18
19
  trace,
19
20
  options,
20
21
  pageScreenshot,
21
- annotatedPageScreenshot,
22
22
  actions,
23
+ actionTypes: action_tool_calls_1.ActionType,
23
24
  disableSkills,
24
- annotations,
25
+ page,
25
26
  });
26
27
  return {
27
28
  scores: [
28
29
  {
29
30
  name: "action_correctness",
30
- value: item.expectedOutput.function.name === output?.function.name ? 1 : 0,
31
+ value: item.expectedOutput.function.name === output?.actionType ? 1 : 0,
31
32
  },
32
33
  ],
33
34
  output,
@@ -0,0 +1,4 @@
1
+ import * as ts from "typescript";
2
+ declare function createHandlebarsTransformer(): ts.TransformerFactory<ts.SourceFile>;
3
+ export default createHandlebarsTransformer;
4
+ //# sourceMappingURL=ts-transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-transformer.d.ts","sourceRoot":"","sources":["../../../src/prompts/lib/ts-transformer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,iBAAS,2BAA2B,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,UAAU,CAAC,CAkG3E;AAED,eAAe,2BAA2B,CAAC"}