@empiricalrun/playwright-utils 0.7.8 → 0.8.1

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.1
4
+
5
+ ### Patch Changes
6
+
7
+ - f6dd07c: fix: add logs before starting report building
8
+
9
+ ## 0.8.0
10
+
11
+ ### Minor Changes
12
+
13
+ - ea4085d: feat: add util method to get stable chrome path
14
+ - 1c4780e: feat: add recaptcha solver
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [1c4780e]
19
+ - @empiricalrun/llm@0.8.0
20
+
3
21
  ## 0.7.8
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;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"}
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;IAkFxB,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"}
@@ -126,6 +126,7 @@ class HtmlReporter {
126
126
  this._topLevelErrors.push(error);
127
127
  }
128
128
  async onEnd(result) {
129
+ console.log(`Tests ended in ${result.duration / (1000 * 60)} mins`);
129
130
  const projectSuites = this.suite.suites;
130
131
  // Commenting out this line causes the outputs to not get deleted
131
132
  // await removeFolders([this._outputFolder]);
@@ -185,7 +186,7 @@ class HtmlReporter {
185
186
  }
186
187
  }
187
188
  async onExit() {
188
- if ("true" || !this._buildResult)
189
+ if (process.env.CI || !this._buildResult)
189
190
  return;
190
191
  const { ok, singleTestId } = this._buildResult;
191
192
  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.1",
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
+ }