@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 +12 -0
- package/dist/captcha.d.ts +3 -0
- package/dist/captcha.d.ts.map +1 -0
- package/dist/captcha.js +83 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +32 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/reporter/custom.js +1 -1
- package/package.json +3 -2
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 @@
|
|
|
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"}
|
package/dist/captcha.js
ADDED
|
@@ -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
package/dist/config.d.ts.map
CHANGED
|
@@ -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;
|
|
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:
|
|
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
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,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);
|
package/dist/reporter/custom.js
CHANGED
|
@@ -185,7 +185,7 @@ class HtmlReporter {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
async onExit() {
|
|
188
|
-
if (
|
|
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.
|
|
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
|
+
}
|