@empiricalrun/playwright-utils 0.7.7 → 0.8.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,23 @@
1
1
  # @empiricalrun/playwright-utils
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ea4085d: feat: add util method to get stable chrome path
8
+ - 1c4780e: feat: add recaptcha solver
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [1c4780e]
13
+ - @empiricalrun/llm@0.8.0
14
+
15
+ ## 0.7.8
16
+
17
+ ### Patch Changes
18
+
19
+ - ab9e911: fix: handle errors for final uploads and improve upload failure logging
20
+
3
21
  ## 0.7.7
4
22
 
5
23
  ### Patch Changes
@@ -0,0 +1,3 @@
1
+ import { Page } from "@playwright/test";
2
+ export declare function solveRecaptcha(page: Page): Promise<void>;
3
+ //# sourceMappingURL=captcha.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captcha.d.ts","sourceRoot":"","sources":["../src/captcha.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAyExD,wBAAsB,cAAc,CAAC,IAAI,EAAE,IAAI,iBAiB9C"}
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.solveRecaptcha = void 0;
4
+ const vision_1 = require("@empiricalrun/llm/vision");
5
+ const RECAPTCHA_FRAME_URL = "https://www.google.com/recaptcha/api2";
6
+ const MAX_ATTEMPTS = 5;
7
+ async function isVisible(locator) {
8
+ const isVisibleAccordingToPlaywright = await locator.isVisible();
9
+ if (isVisibleAccordingToPlaywright) {
10
+ const bbox = await locator.boundingBox();
11
+ const isValidBbox = !!bbox && bbox.width > 0 && bbox.height > 0 && bbox.x > 0 && bbox.y > 0;
12
+ return isValidBbox;
13
+ }
14
+ return false;
15
+ }
16
+ async function isVerifyCaptchaVisible(page) {
17
+ const frames = page.frames();
18
+ for (const frame of frames) {
19
+ if (frame.url().includes(RECAPTCHA_FRAME_URL)) {
20
+ if (await isVisible(frame.getByText("Select all images"))) {
21
+ return { frame, type: "images" };
22
+ }
23
+ else if (await isVisible(frame.getByText("Select all squares"))) {
24
+ return { frame, type: "squares" };
25
+ }
26
+ }
27
+ }
28
+ }
29
+ async function getObjectiveCaptcha(capFrame) {
30
+ const { frame, type } = capFrame;
31
+ const text = await frame.getByText(`Select all ${type}`).textContent();
32
+ return text
33
+ ?.replace(`Select all ${type} with`, "")
34
+ .replace(`Click verify once there are none left`, "")
35
+ .replace(`If there are none, click skip`, "")
36
+ .trim();
37
+ }
38
+ async function clickImageTile(frame, nth) {
39
+ const image = frame.locator(".rc-imageselect-tile").nth(nth);
40
+ await image.dispatchEvent("click");
41
+ }
42
+ async function handleCaptcha(cf) {
43
+ const gridLocator = cf.frame.locator(".rc-imageselect-challenge");
44
+ const screenshot = await cf.frame.page().screenshot();
45
+ const grid = await (0, vision_1.solveRecaptchaGrid)({
46
+ captchaType: cf.type,
47
+ pageScreenshotBase64: screenshot.toString("base64"),
48
+ captchaBoundingBox: (await gridLocator.boundingBox()),
49
+ captchaObject: (await getObjectiveCaptcha(cf)),
50
+ });
51
+ for (const n of grid) {
52
+ await clickImageTile(cf.frame, n - 1);
53
+ }
54
+ const verifyButton = cf.frame.getByRole("button", { name: "Verify" });
55
+ const nextButton = cf.frame.getByRole("button", { name: "Next" });
56
+ if (await isVisible(verifyButton)) {
57
+ await verifyButton.dispatchEvent("click");
58
+ }
59
+ else if (await isVisible(nextButton)) {
60
+ await nextButton.dispatchEvent("click");
61
+ }
62
+ await cf.frame.waitForTimeout(3000);
63
+ }
64
+ async function solveRecaptcha(page) {
65
+ const frame = page.frameLocator('iframe[title="reCAPTCHA"]');
66
+ await frame.getByLabel("not a robot").click();
67
+ await page.waitForTimeout(2000);
68
+ for (let i = 0; i < MAX_ATTEMPTS; i++) {
69
+ const cf = await isVerifyCaptchaVisible(page);
70
+ if (cf) {
71
+ await handleCaptcha(cf);
72
+ }
73
+ else {
74
+ break;
75
+ }
76
+ if (i === MAX_ATTEMPTS - 1) {
77
+ if (await isVerifyCaptchaVisible(page)) {
78
+ throw new Error(`Failed to solve captcha in ${MAX_ATTEMPTS} attempts.`);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ exports.solveRecaptcha = solveRecaptcha;
package/dist/config.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { type PlaywrightTestConfig } from "@playwright/test";
2
+ export declare function chromeStablePath(): string;
2
3
  export declare const baseConfig: PlaywrightTestConfig;
3
4
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,eAAO,MAAM,UAAU,EAAE,oBAwBxB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAa7D,wBAAgB,gBAAgB,IAAI,MAAM,CAazC;AAED,eAAO,MAAM,UAAU,EAAE,oBAwBxB,CAAC"}
package/dist/config.js CHANGED
@@ -1,12 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.baseConfig = void 0;
3
+ exports.baseConfig = exports.chromeStablePath = void 0;
4
+ function getPlatformOS() {
5
+ const platform = process.platform;
6
+ if (platform === "win32") {
7
+ return "win";
8
+ }
9
+ else if (platform === "darwin") {
10
+ return "mac";
11
+ }
12
+ else {
13
+ return "linux";
14
+ }
15
+ }
16
+ function chromeStablePath() {
17
+ if (process.env.CHROMIUM_PATH) {
18
+ return process.env.CHROMIUM_PATH;
19
+ }
20
+ else {
21
+ const platform = getPlatformOS();
22
+ if (platform === "win") {
23
+ return "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
24
+ }
25
+ else if (platform === "mac") {
26
+ return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
27
+ }
28
+ else {
29
+ return "/usr/bin/google-chrome-stable";
30
+ }
31
+ }
32
+ }
33
+ exports.chromeStablePath = chromeStablePath;
4
34
  exports.baseConfig = {
5
35
  testDir: "./tests",
6
36
  outputDir: "./playwright-report/data", // to store default playwright artifacts (during and post test run)
7
37
  fullyParallel: true,
8
38
  forbidOnly: false,
9
- retries: "true" ? 2 : 0,
39
+ retries: process.env.CI ? 2 : 0,
10
40
  workers: undefined,
11
41
  reporter: [
12
42
  ["list"], // For real-time reporting on CI terminal (vs. the default "dot" reporter)
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- export { baseConfig } from "./config";
1
+ export { solveRecaptcha } from "./captcha";
2
+ export { baseConfig, chromeStablePath } from "./config";
2
3
  export * from "./email";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACxD,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -14,7 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.baseConfig = void 0;
17
+ exports.chromeStablePath = exports.baseConfig = exports.solveRecaptcha = void 0;
18
+ var captcha_1 = require("./captcha");
19
+ Object.defineProperty(exports, "solveRecaptcha", { enumerable: true, get: function () { return captcha_1.solveRecaptcha; } });
18
20
  var config_1 = require("./config");
19
21
  Object.defineProperty(exports, "baseConfig", { enumerable: true, get: function () { return config_1.baseConfig; } });
22
+ Object.defineProperty(exports, "chromeStablePath", { enumerable: true, get: function () { return config_1.chromeStablePath; } });
20
23
  __exportStar(require("./email"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/reporter/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EAEV,KAAK,EACL,QAAQ,IAAI,cAAc,EAC1B,SAAS,EACT,UAAU,IAAI,gBAAgB,EAE/B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAML,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAgBnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAkC/C,QAAA,MAAM,iBAAiB,UAAoC,CAAC;AAC5D,KAAK,oBAAoB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAM/D,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,cAAM,YAAa,YAAW,UAAU;IACtC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,YAAY,CAEN;IACd,OAAO,CAAC,eAAe,CAAmB;gBAE9B,OAAO,EAAE,mBAAmB;IAIxC,aAAa;IAIb,QAAQ;IAER,QAAQ;IAER,WAAW;IAEX,SAAS;IAET,OAAO,IAAI,IAAI;IAIf,WAAW;IAEX,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB;IA+BxD,WAAW,CAAC,MAAM,EAAE,UAAU;IAI9B,OAAO,CAAC,KAAK,EAAE,KAAK;IAYpB,eAAe,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B;IAsBD,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IASxD,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIzB,KAAK,CAAC,MAAM,EAAE,UAAU;IA6ExB,MAAM;CA8Bb;AAkCD,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,GAAE,MAAoB,EAC1B,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,iBAqBhB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsBhE;AAqiBD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/reporter/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EAEV,KAAK,EACL,QAAQ,IAAI,cAAc,EAC1B,SAAS,EACT,UAAU,IAAI,gBAAgB,EAE/B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAML,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAgBnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAkC/C,QAAA,MAAM,iBAAiB,UAAoC,CAAC;AAC5D,KAAK,oBAAoB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAM/D,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,cAAM,YAAa,YAAW,UAAU;IACtC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,YAAY,CAEN;IACd,OAAO,CAAC,eAAe,CAAmB;gBAE9B,OAAO,EAAE,mBAAmB;IAIxC,aAAa;IAIb,QAAQ;IAER,QAAQ;IAER,WAAW;IAEX,SAAS;IAET,OAAO,IAAI,IAAI;IAIf,WAAW;IAEX,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB;IA+BxD,WAAW,CAAC,MAAM,EAAE,UAAU;IAI9B,OAAO,CAAC,KAAK,EAAE,KAAK;IAYpB,eAAe,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B;IAsBD,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IASxD,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIzB,KAAK,CAAC,MAAM,EAAE,UAAU;IAiFxB,MAAM;CA8Bb;AAkCD,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,GAAE,MAAoB,EAC1B,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,iBAqBhB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsBhE;AAqiBD,eAAe,YAAY,CAAC"}
@@ -141,46 +141,51 @@ class HtmlReporter {
141
141
  minute: "2-digit",
142
142
  second: "2-digit",
143
143
  }).format(startTime));
144
- await Promise.allSettled([
145
- (0, upload_1.uploadDirectory)({
146
- sourceDir: this._outputFolder + "/trace",
147
- destinationDir: process.env.PROJECT_NAME +
148
- "/" +
149
- process.env.TEST_RUN_GITHUB_ACTION_ID +
150
- "/trace",
151
- uploadBucket: "test-report",
152
- }),
153
- // upload index.html
154
- (0, upload_1.uploadDirectory)({
155
- sourceDir: this._outputFolder,
156
- fileList: [path_1.default.join(this._outputFolder, "index.html")],
157
- destinationDir: process.env.PROJECT_NAME +
158
- "/" +
159
- process.env.TEST_RUN_GITHUB_ACTION_ID,
160
- uploadBucket: "test-report",
161
- }),
162
- // upload summary.json
163
- (0, upload_1.uploadDirectory)({
164
- sourceDir: this._outputFolder,
165
- fileList: [path_1.default.join(this._outputFolder, "summary.json")],
166
- destinationDir: process.env.PROJECT_NAME +
167
- "/" +
168
- process.env.TEST_RUN_GITHUB_ACTION_ID,
169
- uploadBucket: "test-report",
170
- }),
171
- ]);
172
- const endTime = new Date().getTime();
173
- console.log("Finished final report upload at: ", new Intl.DateTimeFormat("en-US", {
174
- hour: "2-digit",
175
- minute: "2-digit",
176
- second: "2-digit",
177
- }).format(endTime));
178
- // time difference
179
- const timeDiff = endTime - startTime;
180
- console.log("Time taken to upload after tests ended: ", timeDiff, "ms");
144
+ try {
145
+ await Promise.allSettled([
146
+ (0, upload_1.uploadDirectory)({
147
+ sourceDir: this._outputFolder + "/trace",
148
+ destinationDir: process.env.PROJECT_NAME +
149
+ "/" +
150
+ process.env.TEST_RUN_GITHUB_ACTION_ID +
151
+ "/trace",
152
+ uploadBucket: "test-report",
153
+ }),
154
+ // upload index.html
155
+ (0, upload_1.uploadDirectory)({
156
+ sourceDir: this._outputFolder,
157
+ fileList: [path_1.default.join(this._outputFolder, "index.html")],
158
+ destinationDir: process.env.PROJECT_NAME +
159
+ "/" +
160
+ process.env.TEST_RUN_GITHUB_ACTION_ID,
161
+ uploadBucket: "test-report",
162
+ }),
163
+ // upload summary.json
164
+ (0, upload_1.uploadDirectory)({
165
+ sourceDir: this._outputFolder,
166
+ fileList: [path_1.default.join(this._outputFolder, "summary.json")],
167
+ destinationDir: process.env.PROJECT_NAME +
168
+ "/" +
169
+ process.env.TEST_RUN_GITHUB_ACTION_ID,
170
+ uploadBucket: "test-report",
171
+ }),
172
+ ]);
173
+ const endTime = new Date().getTime();
174
+ console.log("Finished final report upload at: ", new Intl.DateTimeFormat("en-US", {
175
+ hour: "2-digit",
176
+ minute: "2-digit",
177
+ second: "2-digit",
178
+ }).format(endTime));
179
+ // time difference
180
+ const timeDiff = endTime - startTime;
181
+ console.log("Time taken to upload after tests ended: ", timeDiff, "ms");
182
+ }
183
+ catch (e) {
184
+ // tests shouldn't stop no matter whatever error we get
185
+ }
181
186
  }
182
187
  async onExit() {
183
- if ("true" || !this._buildResult)
188
+ if (process.env.CI || !this._buildResult)
184
189
  return;
185
190
  const { ok, singleTestId } = this._buildResult;
186
191
  const shouldOpen = !this._options._isTestServer &&
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/reporter/upload.ts"],"names":[],"mappings":"AAsBA,UAAU,OAAO;IACf,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAyGD,wBAAsB,eAAe,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,cAAc,EACd,YAAY,GACb,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,OAAO,CAAC,CAYnB"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/reporter/upload.ts"],"names":[],"mappings":"AAsBA,UAAU,OAAO;IACf,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AA+GD,wBAAsB,eAAe,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,cAAc,EACd,YAAY,GACb,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,OAAO,CAAC,CAYnB"}
@@ -110,6 +110,7 @@ const run = async (config) => {
110
110
  if (error["$metadata"]) {
111
111
  if (error.$metadata.httpStatusCode !== 412) {
112
112
  console.log(`R2 Error - ${file} ${config.sourceDir} ${config.destinationDir} \nError: ${error}`);
113
+ console.log("Upload response", error.$response, "with status", error.$metadata.httpStatusCode);
113
114
  throw error;
114
115
  }
115
116
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.7.7",
3
+ "version": "0.8.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -34,6 +34,7 @@
34
34
  "@types/node": "^20.14.9"
35
35
  },
36
36
  "dependencies": {
37
+ "@empiricalrun/llm": "workspace:^",
37
38
  "@aws-sdk/client-s3": "^3.614.0",
38
39
  "@aws-sdk/s3-request-presigner": "^3.614.0",
39
40
  "@babel/code-frame": "^7.24.7",
@@ -45,4 +46,4 @@
45
46
  "mime": "3.0.0",
46
47
  "playwright-core": "^1.46.1"
47
48
  }
48
- }
49
+ }