@empiricalrun/test-gen 0.8.2 → 0.9.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @empiricalrun/test-gen
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a6067de: feat: generate better playwright locators using playwright
8
+
3
9
  ## 0.8.2
4
10
 
5
11
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"assertTextVisibility.d.ts","sourceRoot":"","sources":["../../src/actions/assertTextVisibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAErD,eAAO,MAAM,6CAA6C,2BAChC,CAAC;AAE3B,eAAO,MAAM,mCAAmC,EAAE,yBA0CjD,CAAC"}
1
+ {"version":3,"file":"assertTextVisibility.d.ts","sourceRoot":"","sources":["../../src/actions/assertTextVisibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAGrD,eAAO,MAAM,6CAA6C,2BAChC,CAAC;AAE3B,eAAO,MAAM,mCAAmC,EAAE,yBA8DjD,CAAC"}
@@ -1,18 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertTextVisibilityActionGenerator = exports.PLAYWRIGHT_ASSERT_TEXT_VISIBILITY_ACTION_NAME = void 0;
4
+ const utils_1 = require("./utils");
4
5
  exports.PLAYWRIGHT_ASSERT_TEXT_VISIBILITY_ACTION_NAME = "assert_text_visibility";
5
6
  const assertTextVisibilityActionGenerator = (page) => {
6
7
  return {
7
8
  execute: async (args) => {
9
+ const css = args.css_selector;
10
+ const locator = await (0, utils_1.getPlaywrightLocatorUsingCssSelector)(args.css_selector, page, {
11
+ hasText: args.text,
12
+ });
8
13
  await page
9
- .locator(args.css_selector)
14
+ .locator(css)
10
15
  .filter({ hasText: args.text })
11
16
  .first()
12
17
  .isVisible({ timeout: 3000 });
18
+ return {
19
+ locator,
20
+ };
13
21
  },
14
22
  // TODO: args transformer to be kept at a single place
15
- template: (args) => `await expect(page.locator("${args.css_selector}").filter({ hasText: "${args.text}"}).first()).toBeVisible();`,
23
+ template: (args, options) => {
24
+ const css = args.css_selector;
25
+ const assertStr = `await expect(page.locator("${css}").filter({ hasText: "${args.text}"}).first()).toBeVisible();`;
26
+ if (options?.locator) {
27
+ return `
28
+ // ${assertStr}
29
+ await expect(page.${options.locator}).toBeVisible();
30
+ `;
31
+ }
32
+ return assertStr;
33
+ },
16
34
  name: exports.PLAYWRIGHT_ASSERT_TEXT_VISIBILITY_ACTION_NAME,
17
35
  schema: {
18
36
  type: "function",
@@ -1 +1 @@
1
- {"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../src/actions/click.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAErD,eAAO,MAAM,4BAA4B,kBAAkB,CAAC;AAE5D,eAAO,MAAM,oBAAoB,EAAE,yBAoClC,CAAC"}
1
+ {"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../src/actions/click.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAGrD,eAAO,MAAM,4BAA4B,kBAAkB,CAAC;AAE5D,eAAO,MAAM,oBAAoB,EAAE,yBAkDlC,CAAC"}
@@ -1,18 +1,31 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.clickActionGenerator = exports.PLAYWRIGHT_CLICK_ACTION_NAME = void 0;
4
+ const utils_1 = require("./utils");
4
5
  exports.PLAYWRIGHT_CLICK_ACTION_NAME = "click_element";
5
6
  const clickActionGenerator = (page) => {
6
7
  return {
7
8
  execute: async (args) => {
8
- await page
9
- .locator(args.css_selector.split(" ")[0].replaceAll("\\", ""))
10
- .first()
11
- .click({ timeout: 3000 });
9
+ const selector = args.css_selector;
10
+ const locator = await (0, utils_1.getPlaywrightLocatorUsingCssSelector)(selector, page);
11
+ await page.locator(selector).first().click({ timeout: 3000 });
12
12
  await page.waitForTimeout(3000);
13
+ return {
14
+ locator,
15
+ };
13
16
  },
14
17
  // TODO: args transformer to be kept at a single place
15
- template: (args) => `await page.locator("${args.css_selector.split(" ")[0].replaceAll("\\", "")}").first().click();`,
18
+ template: (args, options) => {
19
+ const css = args.css_selector;
20
+ const templ = `await page.locator("${css}").first().click();`;
21
+ if (options?.locator) {
22
+ return `
23
+ // ${templ}
24
+ await page.${options.locator}.click();
25
+ `;
26
+ }
27
+ return templ;
28
+ },
16
29
  name: exports.PLAYWRIGHT_CLICK_ACTION_NAME,
17
30
  schema: {
18
31
  type: "function",
@@ -1 +1 @@
1
- {"version":3,"file":"fill.d.ts","sourceRoot":"","sources":["../../src/actions/fill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAErD,eAAO,MAAM,2BAA2B,uBAAuB,CAAC;AAEhE,eAAO,MAAM,mBAAmB,EAAE,yBAsCjC,CAAC"}
1
+ {"version":3,"file":"fill.d.ts","sourceRoot":"","sources":["../../src/actions/fill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAGrD,eAAO,MAAM,2BAA2B,uBAAuB,CAAC;AAEhE,eAAO,MAAM,mBAAmB,EAAE,yBAkDjC,CAAC"}
@@ -1,16 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fillActionGenerator = exports.PLAYWRIGHT_FILL_ACTION_NAME = void 0;
4
+ const utils_1 = require("./utils");
4
5
  exports.PLAYWRIGHT_FILL_ACTION_NAME = "fill_input_element";
5
6
  const fillActionGenerator = (page) => {
6
7
  return {
7
8
  execute: async (args) => {
8
- await page
9
- .locator(args.css_selector.split(" ")[0])
10
- .fill(args.text, { timeout: 3000 });
9
+ const css = args.css_selector;
10
+ const locator = await (0, utils_1.getPlaywrightLocatorUsingCssSelector)(css, page);
11
+ await page.locator(css).fill(args.text, { timeout: 3000 });
12
+ return {
13
+ locator,
14
+ };
11
15
  },
12
16
  // TODO: args transformer to be kept at a single place
13
- template: (args) => `await page.locator("${args.css_selector.split(" ")[0]}").fill("${args.text}");`,
17
+ template: (args, options) => {
18
+ const css = args.css_selector;
19
+ const templ = `await page.locator("${css}").fill("${args.text}");`;
20
+ if (options?.locator) {
21
+ return `
22
+ // ${templ}
23
+ await page.${options?.locator}.fill("${args.text}");
24
+ `;
25
+ }
26
+ return templ;
27
+ },
14
28
  name: exports.PLAYWRIGHT_FILL_ACTION_NAME,
15
29
  schema: {
16
30
  type: "function",
@@ -24,9 +24,9 @@ class PlaywrightActions {
24
24
  }
25
25
  try {
26
26
  console.log("executing:", name, "\nreason:", args.reason);
27
- await action.execute(args);
27
+ const templateOptions = (await action.execute(args)) || undefined;
28
28
  // record successful actions
29
- const code = action.template(args);
29
+ const code = action.template(args, templateOptions);
30
30
  this.recordedActions.push({ name, code });
31
31
  console.log(`code: ${code}`, "\n\n");
32
32
  }
@@ -0,0 +1,8 @@
1
+ import { Page } from "playwright";
2
+ declare global {
3
+ interface Window {
4
+ playwright: any;
5
+ }
6
+ }
7
+ export declare function getPlaywrightLocatorUsingCssSelector(cssSelector: string, page: Page, filter?: Record<string, any>): Promise<any>;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/actions/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,EAAE,GAAG,CAAC;KACjB;CACF;AAED,wBAAsB,oCAAoC,CACxD,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,gBAsB7B"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPlaywrightLocatorUsingCssSelector = void 0;
4
+ async function getPlaywrightLocatorUsingCssSelector(cssSelector, page, filter) {
5
+ return await page.evaluate((locator) => {
6
+ const elements = document.querySelectorAll(locator.css);
7
+ let element = elements[0];
8
+ if (locator.filter?.hasText) {
9
+ element = Array.from(elements).find((el) => el.textContent?.trim().replaceAll(" ", "") ===
10
+ locator.filter?.hasText.trim().replaceAll(" ", ""));
11
+ }
12
+ if (!element) {
13
+ throw Error(`Unable to find element, css: ${locator.css}, filter ${JSON.stringify(locator.filter)}`);
14
+ }
15
+ return window.playwright.generateLocator(element);
16
+ }, { css: cssSelector, filter });
17
+ }
18
+ exports.getPlaywrightLocatorUsingCssSelector = getPlaywrightLocatorUsingCssSelector;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQlC,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,EACV,OAAO,GAAE;IACP,YAAY,CAAC,EAAE;QACb,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC9B,CAAC;CACE,mBAsDP"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQlC,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,EACV,OAAO,GAAE;IACP,YAAY,CAAC,EAAE;QACb,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC9B,CAAC;CACE,mBAgEP"}
@@ -15,6 +15,13 @@ async function browsingAgent(task, page, options = {}) {
15
15
  const tools = actions.getActionSchemas();
16
16
  let isTaskDone = false;
17
17
  const previousActions = [];
18
+ const resp = await fetch("https://assets-test.empirical.run/pw-selector.js");
19
+ const script = await resp.text();
20
+ await page.addScriptTag({
21
+ content: script,
22
+ });
23
+ let lastActionErrors = [];
24
+ // await page.waitForTimeout(3_00_000)
18
25
  while (!isTaskDone) {
19
26
  trace.update({ input: { task } });
20
27
  const pageContentSpan = trace.startSpan("page-content");
@@ -28,8 +35,10 @@ async function browsingAgent(task, page, options = {}) {
28
35
  pageSnapshot,
29
36
  previousActions,
30
37
  task,
38
+ lastActionErrors,
31
39
  });
32
40
  promptSpan.end({ output: { messages } });
41
+ lastActionErrors = [];
33
42
  const completion = await (0, ai_1.getLLMResult)({
34
43
  messages,
35
44
  tools,
@@ -44,6 +53,7 @@ async function browsingAgent(task, page, options = {}) {
44
53
  }
45
54
  catch (e) {
46
55
  // TODO: implement feedback loop to llm
56
+ lastActionErrors.push(e.message);
47
57
  console.error(e);
48
58
  }
49
59
  }
@@ -1,8 +1,9 @@
1
1
  import OpenAI from "openai";
2
2
  export declare function getPrompt(name: string, vars: any): Promise<OpenAI.Chat.Completions.ChatCompletionMessageParam[]>;
3
- export declare function getPromptForNextAction({ pageSnapshot, task, previousActions, }: {
3
+ export declare function getPromptForNextAction({ pageSnapshot, task, previousActions, lastActionErrors, }: {
4
4
  pageSnapshot: string;
5
5
  task: string;
6
6
  previousActions: string[];
7
+ lastActionErrors: string[];
7
8
  }): Promise<OpenAI.Chat.Completions.ChatCompletionMessageParam[]>;
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/bin/ai/prompts/provider/index.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAS5B,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,GAAG,GACR,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAC,CAI/D;AAGD,wBAAsB,sBAAsB,CAAC,EAC3C,YAAiB,EACjB,IAAS,EACT,eAAoB,GACrB,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,iEAQA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/bin/ai/prompts/provider/index.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAS5B,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,GAAG,GACR,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAC,CAI/D;AAGD,wBAAsB,sBAAsB,CAAC,EAC3C,YAAiB,EACjB,IAAS,EACT,eAAoB,EACpB,gBAAqB,GACtB,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,iEASA"}
@@ -15,12 +15,13 @@ async function getPrompt(name, vars) {
15
15
  }
16
16
  exports.getPrompt = getPrompt;
17
17
  // TODO: move this prompt to langfuse
18
- async function getPromptForNextAction({ pageSnapshot = "", task = "", previousActions = [], }) {
18
+ async function getPromptForNextAction({ pageSnapshot = "", task = "", previousActions = [], lastActionErrors = [], }) {
19
19
  const previousActionsStr = previousActions.join("\n\n ---- \n\n");
20
20
  const prompt = await getPrompt("browsing-agent-next-action", {
21
21
  pageSnapshot,
22
22
  previousActionsStr,
23
23
  task,
24
+ lastActionErrors,
24
25
  });
25
26
  return prompt;
26
27
  }
@@ -19,7 +19,11 @@ export type ActionSchema = OpenAI.Chat.Completions.ChatCompletionTool;
19
19
  export type Action = {
20
20
  name: string;
21
21
  schema: ActionSchema;
22
- execute: (args: Record<string, any>) => Promise<void>;
23
- template: (args: Record<string, any>) => string;
22
+ execute: (args: Record<string, any>) => Promise<{
23
+ locator: string;
24
+ } | void | undefined>;
25
+ template: (args: Record<string, any>, options?: {
26
+ locator: string;
27
+ }) => string;
24
28
  };
25
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAEtE,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,MAAM,CAAC;CACjD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAEtE,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACtB,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACrD,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAC1B,MAAM,CAAC;CACb,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-gen",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"