@empiricalrun/playwright-utils 0.7.8 → 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,17 @@
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
+
3
15
  ## 0.7.8
4
16
 
5
17
  ### 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);
@@ -185,7 +185,7 @@ class HtmlReporter {
185
185
  }
186
186
  }
187
187
  async onExit() {
188
- if ("true" || !this._buildResult)
188
+ if (process.env.CI || !this._buildResult)
189
189
  return;
190
190
  const { ok, singleTestId } = this._buildResult;
191
191
  const shouldOpen = !this._options._isTestServer &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.7.8",
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
+ }