@empiricalrun/playwright-utils 0.58.5 → 0.58.6

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.
@@ -20,6 +20,25 @@ const useCache = (data) => {
20
20
  }
21
21
  fs_1.default.writeFileSync(cache_1.CACHE_FILE, JSON.stringify(cacheValue, null, 2), "utf8");
22
22
  };
23
+ // Unsets env vars for the duration of a test and puts them back exactly as they
24
+ // were — assigning `undefined` to process.env would store the string
25
+ // "undefined", which reads as a present (and truthy) credential.
26
+ function clearEnv(names) {
27
+ const saved = names.map((name) => [name, process.env[name]]);
28
+ for (const name of names) {
29
+ delete process.env[name];
30
+ }
31
+ return () => {
32
+ for (const [name, value] of saved) {
33
+ if (value === undefined) {
34
+ delete process.env[name];
35
+ }
36
+ else {
37
+ process.env[name] = value;
38
+ }
39
+ }
40
+ };
41
+ }
23
42
  fixtures_1.test.beforeEach(async ({ page }) => {
24
43
  (0, test_1.injectLocatorHighlightScripts)(page, fixtures_1.test);
25
44
  });
@@ -39,9 +58,12 @@ fixtures_1.test.afterEach(() => {
39
58
  ]);
40
59
  await page.goto(`${server.baseURL}/glass-pane.html`);
41
60
  let error;
42
- // Overwriting API key to ensure we don't call OpenAI
43
- const originalApiKey = process.env.OPENAI_API_KEY;
44
- process.env.OPENAI_API_KEY = undefined;
61
+ // The only two routes the browser agent has to a model: the project API key
62
+ // (api-worker's proxy) and a sandbox's OPENAI_BASE_URL. Clearing both makes
63
+ // llmProxyOpenAIConfig throw before any request — which matters here more
64
+ // than elsewhere, because this is the recursive case and every extra
65
+ // dismissal would spawn another agent and another set of screenshots.
66
+ const restoreEnv = clearEnv(["EMPIRICALRUN_API_KEY", "OPENAI_BASE_URL"]);
45
67
  try {
46
68
  // Target element click will trigger the cache - which will invoke another
47
69
  // click to the same element (recursive overlay dismissal)
@@ -50,7 +72,9 @@ fixtures_1.test.afterEach(() => {
50
72
  catch (e) {
51
73
  error = e;
52
74
  }
75
+ finally {
76
+ restoreEnv();
77
+ }
53
78
  (0, fixtures_1.expect)(error).toBeDefined();
54
- process.env.OPENAI_API_KEY = originalApiKey;
55
79
  (0, fixtures_1.expect)(error.message).toContain('<div class="glass-pane"></div> intercepts pointer events');
56
80
  });
@@ -1,28 +1,5 @@
1
+ import type { TestCaseSyncManifest } from "@empiricalrun/shared-types/playwright-utils";
1
2
  import type { FullConfig, Suite } from "@playwright/test/reporter";
2
- export interface TestCaseSyncTestCase {
3
- id: string;
4
- name: string;
5
- file_path: string;
6
- suites: string[];
7
- playwright_project: string;
8
- tags: string[];
9
- }
10
- export interface TestCaseDependencyGroupMember {
11
- test_case_id: string;
12
- dependency_order: number;
13
- }
14
- export interface TestCaseDependencyGroup {
15
- id: string;
16
- kind: "playwright_serial";
17
- file_path: string;
18
- title_path: string[];
19
- playwright_project: string;
20
- members: TestCaseDependencyGroupMember[];
21
- }
22
- export interface TestCaseSyncManifest {
23
- version: 1;
24
- test_cases: TestCaseSyncTestCase[];
25
- dependency_groups: TestCaseDependencyGroup[];
26
- }
3
+ export type { TestCaseDependencyGroup, TestCaseDependencyGroupMember, TestCaseSyncManifest, TestCaseSyncTestCase, } from "@empiricalrun/shared-types/playwright-utils";
27
4
  export declare function collectTestCaseSyncManifest(config: FullConfig, rootSuite: Suite): TestCaseSyncManifest;
28
5
  //# sourceMappingURL=test-case-sync.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-case-sync.d.ts","sourceRoot":"","sources":["../../src/reporter/test-case-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAEV,KAAK,EAEN,MAAM,2BAA2B,CAAC;AAMnC,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,mBAAmB,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,6BAA6B,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,oBAAoB,EAAE,CAAC;IACnC,iBAAiB,EAAE,uBAAuB,EAAE,CAAC;CAC9C;AA+JD,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,KAAK,GACf,oBAAoB,CAuBtB"}
1
+ {"version":3,"file":"test-case-sync.d.ts","sourceRoot":"","sources":["../../src/reporter/test-case-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EACV,UAAU,EAEV,KAAK,EAEN,MAAM,2BAA2B,CAAC;AAUnC,YAAY,EACV,uBAAuB,EACvB,6BAA6B,EAC7B,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,6CAA6C,CAAC;AA+JrD,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,KAAK,GACf,oBAAoB,CAuBtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"visual.d.ts","sourceRoot":"","sources":["../../../src/test/expect/visual.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAY,MAAM,kBAAkB,CAAC;AAShE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA0E7C,wBAAsB,WAAW,CAC/B,MAAM,EAAE,IAAI,GAAG,OAAO,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,aAAa,CAAC,CAyFxB"}
1
+ {"version":3,"file":"visual.d.ts","sourceRoot":"","sources":["../../../src/test/expect/visual.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAY,MAAM,kBAAkB,CAAC;AAUhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA0E7C,wBAAsB,WAAW,CAC/B,MAAM,EAAE,IAAI,GAAG,OAAO,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,aAAa,CAAC,CA2FxB"}
@@ -10,6 +10,7 @@ const fs_1 = __importDefault(require("fs"));
10
10
  const openai_1 = __importDefault(require("openai"));
11
11
  const os_1 = __importDefault(require("os"));
12
12
  const path_1 = __importDefault(require("path"));
13
+ const api_worker_client_1 = require("../../api-worker-client");
13
14
  const mouse_pointer_1 = require("../scripts/mouse-pointer");
14
15
  function getCallerLine() {
15
16
  const stack = new Error().stack;
@@ -85,7 +86,9 @@ async function toLookRight(target, pageDescription) {
85
86
  const base64Image = screenshot.toString("base64");
86
87
  await (0, mouse_pointer_1.addHighlighterScriptsToPage)(page);
87
88
  const model = "gpt-4o";
88
- const openai = new openai_1.default({ maxRetries: 5 });
89
+ // Same api-worker proxy the overlay-dismissal agent uses, so a test run needs
90
+ // no OpenAI key of its own; undefined falls back to the SDK's env defaults.
91
+ const openai = new openai_1.default({ maxRetries: 5, ...(0, api_worker_client_1.llmProxyOpenAIConfig)() });
89
92
  const completion = await openai.chat.completions.create({
90
93
  model,
91
94
  messages: [
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/dismiss-overlays/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAGxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK9C,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,WAKhE;AAED,qBAAa,mBAAmB;IAOlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,OAAO,CAAC,iBAAiB,CAIhB;IAET,YAA6B,IAAI,EAAE,IAAI,EAAI;IAErC,WAAW,kBAIhB;IAEK,GAAG,CACP,aAAa,EAAE,GAAG,EAClB,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,EACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAuDf;YAEa,QAAQ;CAiCvB;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,cAAc,GAAG,SAAS,CAiC5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/dismiss-overlays/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAIxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK9C,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,WAKhE;AAED,qBAAa,mBAAmB;IAOlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,OAAO,CAAC,iBAAiB,CAIhB;IAET,YAA6B,IAAI,EAAE,IAAI,EAAI;IAErC,WAAW,kBAIhB;IAEK,GAAG,CACP,aAAa,EAAE,GAAG,EAClB,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,EACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAuDf;YAEa,QAAQ;CAqCvB;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,cAAc,GAAG,SAAS,CAiC5B"}
@@ -4,6 +4,7 @@ exports.OverlayDismissAgent = void 0;
4
4
  exports.isErrorSupported = isErrorSupported;
5
5
  exports.extractInterceptingElement = extractInterceptingElement;
6
6
  const cua_1 = require("@empiricalrun/cua");
7
+ const api_worker_client_1 = require("../../../../api-worker-client");
7
8
  const telemetry_1 = require("../../../../telemetry");
8
9
  const cache_1 = require("./cache");
9
10
  const prompt_1 = require("./prompt");
@@ -99,6 +100,10 @@ class OverlayDismissAgent {
99
100
  // already on the current page. Including page_goto causes the model
100
101
  // to waste turns trying to navigate instead of clicking dismiss.
101
102
  includePageGotoTool: false,
103
+ // Route the model call through api-worker (Cloudflare AI Gateway) on the
104
+ // project API key, so test-run containers carry no OpenAI key. Undefined
105
+ // on a dev machine or in a pi sandbox — see the helper.
106
+ openAIClientConfig: (0, api_worker_client_1.llmProxyOpenAIConfig)(),
102
107
  });
103
108
  this.cachingCandidates.push({
104
109
  dom: element?.interceptor,
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/vision/query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,wBAAgB,UAAU,CAAC,YAAY,EAAE,QAAQ,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,QAOzE"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/vision/query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIhD,wBAAgB,UAAU,CAAC,YAAY,EAAE,QAAQ,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,QASzE"}
@@ -2,11 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.patchQuery = patchQuery;
4
4
  const vision_1 = require("@empiricalrun/llm/vision");
5
+ const api_worker_client_1 = require("../../../../api-worker-client");
5
6
  function patchQuery(LocatorClass) {
6
7
  LocatorClass.prototype.query = async function (instruction) {
7
8
  await this.waitFor({ state: "visible" });
8
9
  const screenshot = await this.screenshot();
9
- const answer = await (0, vision_1.query)(screenshot.toString("base64"), instruction);
10
+ const answer = await (0, vision_1.query)(screenshot.toString("base64"), instruction, {
11
+ clientConfig: (0, api_worker_client_1.llmProxyOpenAIConfig)(),
12
+ });
10
13
  return answer;
11
14
  };
12
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.58.5",
3
+ "version": "0.58.6",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -54,10 +54,10 @@
54
54
  "puppeteer-extra-plugin-recaptcha": "^3.6.8",
55
55
  "rimraf": "^6.0.1",
56
56
  "ts-morph": "^23.0.0",
57
- "@empiricalrun/cua": "^0.4.1",
58
- "@empiricalrun/llm": "^0.27.0",
57
+ "@empiricalrun/cua": "^0.4.2",
58
+ "@empiricalrun/llm": "^0.27.1",
59
59
  "@empiricalrun/r2-uploader": "^0.10.2",
60
- "@empiricalrun/reporter": "^0.29.1"
60
+ "@empiricalrun/reporter": "^0.30.0"
61
61
  },
62
62
  "scripts": {
63
63
  "dev": "pnpm gen:api-worker-openapi && tsgo --build --watch",