@empiricalrun/playwright-utils 0.24.2 → 0.25.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 +26 -0
- package/dist/overlay-tests/click.spec.js +6 -1
- package/dist/overlay-tests/fixtures.d.ts.map +1 -1
- package/dist/overlay-tests/fixtures.js +6 -3
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/index.d.ts +1 -3
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/index.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/index.js +9 -51
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/prompt.d.ts +3 -0
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/prompt.d.ts.map +1 -0
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/prompt.js +55 -0
- package/dist/test/scripts/pw-locator-patch/highlight/click.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/click.js +32 -19
- package/dist/test/scripts/pw-locator-patch/highlight/hover.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/hover.js +28 -20
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @empiricalrun/playwright-utils
|
|
2
2
|
|
|
3
|
+
## 0.25.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [c490603]
|
|
8
|
+
- Updated dependencies [68640d2]
|
|
9
|
+
- Updated dependencies [486264f]
|
|
10
|
+
- Updated dependencies [ae91e37]
|
|
11
|
+
- Updated dependencies [0704b28]
|
|
12
|
+
- Updated dependencies [3ed20a3]
|
|
13
|
+
- Updated dependencies [02a2439]
|
|
14
|
+
- Updated dependencies [01fa143]
|
|
15
|
+
- @empiricalrun/test-gen@0.52.2
|
|
16
|
+
- @empiricalrun/llm@0.13.0
|
|
17
|
+
|
|
18
|
+
## 0.25.0
|
|
19
|
+
|
|
20
|
+
### Minor Changes
|
|
21
|
+
|
|
22
|
+
- be00f0b: feat: update overlay dismissal to support multiple overlays at once
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- Updated dependencies [be00f0b]
|
|
27
|
+
- @empiricalrun/test-gen@0.52.1
|
|
28
|
+
|
|
3
29
|
## 0.24.2
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
|
@@ -29,7 +29,7 @@ fixtures_1.test.beforeEach(async ({ page }) => {
|
|
|
29
29
|
await (0, fixtures_1.expect)(page.getByRole("heading", { name: "Terms of Service" })).not.toBeVisible();
|
|
30
30
|
});
|
|
31
31
|
(0, fixtures_1.test)("should choose and dismiss the correct overlay", async ({ page, server, }) => {
|
|
32
|
-
await page.goto(`${server.baseURL}/
|
|
32
|
+
await page.goto(`${server.baseURL}/choose-an-overlay.html`);
|
|
33
33
|
// Assert that button and overlays load
|
|
34
34
|
await (0, fixtures_1.expect)(page.getByRole("button", { name: "Target" })).toBeVisible();
|
|
35
35
|
await (0, fixtures_1.expect)(page.getByText("This is a toast message")).toBeVisible();
|
|
@@ -66,3 +66,8 @@ fixtures_1.test.beforeEach(async ({ page }) => {
|
|
|
66
66
|
await page.getByRole("button", { name: "Target" }).click();
|
|
67
67
|
await (0, fixtures_1.expect)(page.getByText("Target was clicked")).toBeVisible();
|
|
68
68
|
});
|
|
69
|
+
(0, fixtures_1.test)("should be able to dismiss multiple overlays", async ({ page, server, }) => {
|
|
70
|
+
await page.goto(`${server.baseURL}/loop-to-dismiss.html`);
|
|
71
|
+
await page.getByRole("button", { name: "Target" }).click();
|
|
72
|
+
await (0, fixtures_1.expect)(page.getByText("Clicked!")).toBeVisible();
|
|
73
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/overlay-tests/fixtures.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/overlay-tests/fixtures.ts"],"names":[],"mappings":"AAKA,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,MAAM,uCAAc,CAAC;AAClC,eAAO,MAAM,IAAI;YAA6B,aAAa;EAwBzD,CAAC"}
|
|
@@ -5,16 +5,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.test = exports.expect = void 0;
|
|
7
7
|
const test_1 = require("@playwright/test");
|
|
8
|
-
const
|
|
8
|
+
const http_1 = __importDefault(require("http"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const serve_handler_1 = __importDefault(require("serve-handler"));
|
|
10
11
|
exports.expect = test_1.test.expect;
|
|
11
12
|
exports.test = test_1.test.extend({
|
|
12
13
|
server: [
|
|
13
14
|
// eslint-disable-next-line no-empty-pattern
|
|
14
15
|
async ({}, use, workerInfo) => {
|
|
15
16
|
const port = 1234 + workerInfo.workerIndex;
|
|
16
|
-
const server =
|
|
17
|
-
|
|
17
|
+
const server = http_1.default.createServer((request, response) => {
|
|
18
|
+
return (0, serve_handler_1.default)(request, response, {
|
|
19
|
+
public: path_1.default.join(process.cwd(), "test-data"),
|
|
20
|
+
});
|
|
18
21
|
});
|
|
19
22
|
await new Promise((resolve) => {
|
|
20
23
|
server.listen(port, () => {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { Page } from "@playwright/test";
|
|
2
|
-
import type { TestFn } from "../../types";
|
|
3
2
|
import { OverlayElement } from "./types";
|
|
4
3
|
export declare function isErrorSupported(errorMessage: string | undefined): boolean;
|
|
5
|
-
export declare function runAgentOnOverlay(pageRef: Page, element: OverlayElement | undefined): Promise<void>;
|
|
6
4
|
export declare function extractInterceptingElement(errorMessage: string): OverlayElement | undefined;
|
|
7
|
-
export declare function
|
|
5
|
+
export declare function attemptToDismissOverlay(originalError: any, page: Page, reporter: (description: string) => void): Promise<void>;
|
|
8
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/dismiss-overlays/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/dismiss-overlays/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAIxC,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAOzC,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,WAKhE;AA0CD,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,cAAc,GAAG,SAAS,CAiC5B;AAwBD,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,GAAG,EAClB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,GACtC,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.attemptToDismissOverlay = exports.extractInterceptingElement = exports.isErrorSupported = void 0;
|
|
4
4
|
const run_1 = require("@empiricalrun/test-gen/agent/master/run");
|
|
5
5
|
const cache_1 = require("./cache");
|
|
6
|
+
const prompt_1 = require("./prompt");
|
|
6
7
|
const utils_1 = require("./utils");
|
|
7
8
|
const ERROR_SUBSTRING_INTERCEPTION = "intercepts pointer events";
|
|
8
9
|
const PREFERRED_AGENT = "openai-cua";
|
|
@@ -15,48 +16,7 @@ function isErrorSupported(errorMessage) {
|
|
|
15
16
|
exports.isErrorSupported = isErrorSupported;
|
|
16
17
|
async function runAgentOnOverlay(pageRef, element) {
|
|
17
18
|
const text = await (0, utils_1.textContent)(pageRef, element);
|
|
18
|
-
const
|
|
19
|
-
? `
|
|
20
|
-
In this case, the popup can be identified with its text content:
|
|
21
|
-
|
|
22
|
-
<popup_text_content>
|
|
23
|
-
${text}
|
|
24
|
-
</popup_text_content>
|
|
25
|
-
`
|
|
26
|
-
: ``;
|
|
27
|
-
let task = `
|
|
28
|
-
Find a way to dismiss the popup. If the popup is non dismissible or there is no popup then return immediately.
|
|
29
|
-
Do all actions required to dismiss the popup - don't ask for user confirmation.
|
|
30
|
-
|
|
31
|
-
Note that you just need to dismiss popup and DO NOTHING ELSE. If you do more steps, the remainder
|
|
32
|
-
of the workflow will fail, because ONLY the popup is expected to be dismissed by your actions.
|
|
33
|
-
|
|
34
|
-
Examples of typical popups:
|
|
35
|
-
1. Feature announcements, which can be generally dismissed by close/dismiss buttons.
|
|
36
|
-
2. Product tours which might require going through the tour steps.
|
|
37
|
-
3. Consents for cookies or updated terms of service, which can be dismissed by clicking on the accept/continue button.
|
|
38
|
-
4. Forms that capture traffic sources or persona information. Make up content for the input fields, if that's required to dismiss the popup.
|
|
39
|
-
5. Anything else that can be dismissed by taking a few user actions.
|
|
40
|
-
|
|
41
|
-
${promptAddition}`;
|
|
42
|
-
if ((0, utils_1.isProductFruitsOverlay)(element)) {
|
|
43
|
-
// Special handling for product fruits overlay: Overwrite the task
|
|
44
|
-
task = `
|
|
45
|
-
We are attempting to do a click action on Target element.
|
|
46
|
-
|
|
47
|
-
This action is failing because our Target element is covered with another element (called Overlapper).
|
|
48
|
-
|
|
49
|
-
The Overlapper element can be identifed with the following text content:
|
|
50
|
-
|
|
51
|
-
<overlapper_element_text_content>
|
|
52
|
-
${text}
|
|
53
|
-
</overlapper_element_text_content>
|
|
54
|
-
|
|
55
|
-
The only way to work around this is to Click on any other sidebar link element.
|
|
56
|
-
|
|
57
|
-
Don't reattempt the click on Target element, your job is done after the first click.
|
|
58
|
-
`;
|
|
59
|
-
}
|
|
19
|
+
const task = (0, prompt_1.getTask)(element, text);
|
|
60
20
|
const { success } = await (0, cache_1.executeFromCache)({
|
|
61
21
|
page: pageRef,
|
|
62
22
|
dom: element?.interceptor,
|
|
@@ -91,7 +51,6 @@ Don't reattempt the click on Target element, your job is done after the first cl
|
|
|
91
51
|
});
|
|
92
52
|
}
|
|
93
53
|
}
|
|
94
|
-
exports.runAgentOnOverlay = runAgentOnOverlay;
|
|
95
54
|
function extractInterceptingElement(errorMessage) {
|
|
96
55
|
// This extract element and parent info from interception error message
|
|
97
56
|
// Note that error message from the last retry is returned.
|
|
@@ -149,23 +108,22 @@ function findAllMatches(str, regex) {
|
|
|
149
108
|
}
|
|
150
109
|
return matches;
|
|
151
110
|
}
|
|
152
|
-
async function
|
|
153
|
-
let overlayElement
|
|
111
|
+
async function attemptToDismissOverlay(originalError, page, reporter) {
|
|
112
|
+
let overlayElement;
|
|
154
113
|
try {
|
|
155
114
|
overlayElement = extractInterceptingElement(originalError.message);
|
|
156
115
|
}
|
|
157
116
|
catch (err) {
|
|
158
117
|
// Ignoring this error
|
|
159
118
|
}
|
|
160
|
-
|
|
119
|
+
const description = (0, utils_1.overlayDescription)(overlayElement);
|
|
120
|
+
reporter(`Attempting to auto-dismiss overlay: ${description}`);
|
|
161
121
|
try {
|
|
162
122
|
await runAgentOnOverlay(page, overlayElement);
|
|
163
123
|
}
|
|
164
124
|
catch (agentError) {
|
|
165
|
-
(
|
|
125
|
+
reporter(`Error during overlay dismissal agent execution: ${agentError.toString()}`);
|
|
166
126
|
throw originalError;
|
|
167
127
|
}
|
|
168
|
-
(0, utils_1.annotateForReport)(testFn, `Overlay was dismissed, retrying original ${actionName} action`);
|
|
169
|
-
return await retryAction();
|
|
170
128
|
}
|
|
171
|
-
exports.
|
|
129
|
+
exports.attemptToDismissOverlay = attemptToDismissOverlay;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/dismiss-overlays/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGzC,wBAAgB,OAAO,CACrB,OAAO,EAAE,cAAc,GAAG,SAAS,EACnC,IAAI,EAAE,MAAM,GAAG,SAAS,UAkCzB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTask = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
function getTask(element, text) {
|
|
6
|
+
if ((0, utils_1.isProductFruitsOverlay)(element)) {
|
|
7
|
+
// TODO: Remove this special handling with app knowledge
|
|
8
|
+
return promptForPFScenario(text);
|
|
9
|
+
}
|
|
10
|
+
const promptAddition = text
|
|
11
|
+
? `
|
|
12
|
+
In this case, the popup can be identified with its text content:
|
|
13
|
+
|
|
14
|
+
<popup_text_content>
|
|
15
|
+
${text}
|
|
16
|
+
</popup_text_content>
|
|
17
|
+
`
|
|
18
|
+
: ``;
|
|
19
|
+
let task = `
|
|
20
|
+
Find a way to dismiss the popup. If the popup is non dismissible or there is no popup then return immediately.
|
|
21
|
+
Do all actions required to dismiss the popup - don't ask for user confirmation.
|
|
22
|
+
|
|
23
|
+
Note that you just need to dismiss popup and DO NOTHING ELSE. If you do more steps, the remainder
|
|
24
|
+
of the workflow will fail, because ONLY the popup is expected to be dismissed by your actions.
|
|
25
|
+
|
|
26
|
+
Examples of typical popups:
|
|
27
|
+
1. Feature announcements, which can be generally dismissed by close/dismiss buttons.
|
|
28
|
+
2. Product tours which might require going through the tour steps.
|
|
29
|
+
3. Consents for cookies or updated terms of service, which can be dismissed by clicking on the accept/continue button.
|
|
30
|
+
4. Forms that capture traffic sources or persona information. Make up content for the input fields, if that's required to dismiss the popup.
|
|
31
|
+
5. Anything else that can be dismissed by taking a few user actions.
|
|
32
|
+
|
|
33
|
+
${promptAddition}`;
|
|
34
|
+
return task;
|
|
35
|
+
}
|
|
36
|
+
exports.getTask = getTask;
|
|
37
|
+
function promptForPFScenario(text) {
|
|
38
|
+
const promptAddition = text
|
|
39
|
+
? `The Overlapper element can be identifed with the following text content:
|
|
40
|
+
|
|
41
|
+
<overlapper_element_text_content>
|
|
42
|
+
${text}
|
|
43
|
+
</overlapper_element_text_content>`
|
|
44
|
+
: undefined;
|
|
45
|
+
return `
|
|
46
|
+
We are attempting to do a click action on Target element.
|
|
47
|
+
|
|
48
|
+
This action is failing because our Target element is covered with another element (called Overlapper).
|
|
49
|
+
${promptAddition || ""}
|
|
50
|
+
|
|
51
|
+
The only way to work around this is to Click on some other sidebar link element.
|
|
52
|
+
|
|
53
|
+
Don't reattempt the click on Target element, your job is done after the first click.
|
|
54
|
+
`;
|
|
55
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/highlight/click.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/highlight/click.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,wBAAgB,UAAU,CACxB,YAAY,EAAE,QAAQ,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,EAC/C,MAAM,EAAE,MAAM,QA0Df"}
|
|
@@ -2,38 +2,51 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.patchClick = void 0;
|
|
4
4
|
const dismiss_overlays_1 = require("../dismiss-overlays");
|
|
5
|
-
const utils_1 = require("../utils");
|
|
5
|
+
const utils_1 = require("../dismiss-overlays/utils");
|
|
6
|
+
const utils_2 = require("../utils");
|
|
6
7
|
// Static flag to track if click has been patched
|
|
7
8
|
const isClickPatched = new WeakMap();
|
|
8
9
|
function patchClick(LocatorClass, testFn) {
|
|
9
10
|
if (isClickPatched.get(LocatorClass)) {
|
|
10
11
|
return;
|
|
11
12
|
}
|
|
13
|
+
const reporter = (description) => (0, utils_1.annotateForReport)(testFn, description);
|
|
12
14
|
const originalClick = LocatorClass.prototype.click;
|
|
13
15
|
//ref: github.com/microsoft/playwright/blob/69287f26bc514b740eac40160503d6fac8185d37/packages/playwright-core/src/client/locator.ts#L255
|
|
14
16
|
LocatorClass.prototype.click = async function (options) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
if (process.env.TEST_GEN_TOKEN) {
|
|
26
|
-
// Happening during test-gen, we ignore this
|
|
27
|
-
throw originalError;
|
|
17
|
+
const stepName = `locator.click(${(0, utils_2.description)(this)})`;
|
|
18
|
+
return await testFn.step(stepName, async () => {
|
|
19
|
+
let overlayAttemptsRemaining = 2;
|
|
20
|
+
let originalError;
|
|
21
|
+
while (overlayAttemptsRemaining >= 0) {
|
|
22
|
+
overlayAttemptsRemaining--;
|
|
23
|
+
try {
|
|
24
|
+
let result = await originalClick.apply(this, [options]);
|
|
25
|
+
return result; // If click is successful, we're done -- just return
|
|
28
26
|
}
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
catch (error) {
|
|
28
|
+
originalError = error;
|
|
29
|
+
if (originalError instanceof Error) {
|
|
30
|
+
// Overwrite the stack trace to show the original click (remove patch)
|
|
31
|
+
Error.captureStackTrace(originalError, LocatorClass.prototype.click);
|
|
32
|
+
}
|
|
33
|
+
if (process.env.TEST_GEN_TOKEN) {
|
|
34
|
+
// We skip overlay dismissal if its happening during test-gen
|
|
35
|
+
throw originalError;
|
|
36
|
+
}
|
|
37
|
+
if (!(0, dismiss_overlays_1.isErrorSupported)(originalError.message)) {
|
|
38
|
+
// TODO: Playwright actionability checks have precedence: if an overlay blocks a
|
|
39
|
+
// disabled button, the error will not show interception -- it will focus on "not enabled".
|
|
40
|
+
// This will cause our overlay dismissal to not run.
|
|
41
|
+
throw originalError;
|
|
42
|
+
}
|
|
43
|
+
await (0, dismiss_overlays_1.attemptToDismissOverlay)(originalError, this._frame._page, reporter);
|
|
44
|
+
// Dismissal attempt finished (implicitly successful if no error thrown)
|
|
45
|
+
reporter(`Overlay dismissal attempted, retrying original action.`);
|
|
31
46
|
}
|
|
32
|
-
// Now that we've confirmed this is an overlay-related error, delegate to handleOverlayDismissal
|
|
33
|
-
result = await (0, dismiss_overlays_1.handleOverlayDismissal)(originalError, this._frame._page, "click", testFn, () => originalClick.apply(this, [options]));
|
|
34
47
|
}
|
|
48
|
+
throw originalError;
|
|
35
49
|
}, { box: true });
|
|
36
|
-
return result;
|
|
37
50
|
};
|
|
38
51
|
isClickPatched.set(LocatorClass, true);
|
|
39
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hover.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/highlight/hover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"hover.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/highlight/hover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAOrC,wBAAgB,UAAU,CACxB,YAAY,EAAE,QAAQ,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,EAC/C,MAAM,EAAE,MAAM,QAmDf"}
|
|
@@ -2,37 +2,45 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.patchHover = void 0;
|
|
4
4
|
const dismiss_overlays_1 = require("../dismiss-overlays");
|
|
5
|
-
const utils_1 = require("../utils");
|
|
5
|
+
const utils_1 = require("../dismiss-overlays/utils");
|
|
6
|
+
const utils_2 = require("../utils");
|
|
6
7
|
const isHoverPatched = new WeakMap();
|
|
7
8
|
function patchHover(LocatorClass, testFn) {
|
|
8
9
|
if (isHoverPatched.get(LocatorClass)) {
|
|
9
10
|
return;
|
|
10
11
|
}
|
|
12
|
+
const reporter = (description) => (0, utils_1.annotateForReport)(testFn, description);
|
|
11
13
|
const originalHover = LocatorClass.prototype.hover;
|
|
12
14
|
LocatorClass.prototype.hover = async function (options) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (process.env.TEST_GEN_TOKEN) {
|
|
24
|
-
// Happening during test-gen, we ignore this
|
|
25
|
-
throw originalError;
|
|
15
|
+
const stepName = `locator.hover(${(0, utils_2.description)(this)})`;
|
|
16
|
+
return await testFn.step(stepName, async () => {
|
|
17
|
+
let overlayAttemptsRemaining = 2;
|
|
18
|
+
let originalError;
|
|
19
|
+
while (overlayAttemptsRemaining >= 0) {
|
|
20
|
+
overlayAttemptsRemaining--;
|
|
21
|
+
try {
|
|
22
|
+
let result = await originalHover.apply(this, [options]);
|
|
23
|
+
await (0, utils_2.highlight)(this);
|
|
24
|
+
return result; // If hover is successful, we're done -- just return
|
|
26
25
|
}
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
catch (error) {
|
|
27
|
+
originalError = error;
|
|
28
|
+
if (originalError instanceof Error) {
|
|
29
|
+
Error.captureStackTrace(originalError, LocatorClass.prototype.hover);
|
|
30
|
+
}
|
|
31
|
+
if (process.env.TEST_GEN_TOKEN) {
|
|
32
|
+
// We skip overlay dismissal if its happening during test-gen
|
|
33
|
+
throw originalError;
|
|
34
|
+
}
|
|
35
|
+
if (!(0, dismiss_overlays_1.isErrorSupported)(originalError.message)) {
|
|
36
|
+
throw originalError;
|
|
37
|
+
}
|
|
38
|
+
await (0, dismiss_overlays_1.attemptToDismissOverlay)(originalError, this._frame._page, reporter);
|
|
39
|
+
reporter(`Overlay dismissal attempted, retrying original action.`);
|
|
29
40
|
}
|
|
30
|
-
// Now that we've confirmed this is an overlay-related error, delegate to handleOverlayDismissal
|
|
31
|
-
result = await (0, dismiss_overlays_1.handleOverlayDismissal)(originalError, this._frame._page, "hover", testFn, () => originalHover.apply(this, [options]));
|
|
32
41
|
}
|
|
33
|
-
|
|
42
|
+
throw originalError;
|
|
34
43
|
}, { box: true });
|
|
35
|
-
return result;
|
|
36
44
|
};
|
|
37
45
|
isHoverPatched.set(LocatorClass, true);
|
|
38
46
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/playwright-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
},
|
|
23
23
|
"author": "Empirical Team <hey@empirical.run>",
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"playwright-core": "1.47.1",
|
|
26
25
|
"@playwright/test": "1.47.1",
|
|
27
26
|
"@types/async-retry": "^1.4.8",
|
|
28
27
|
"@types/babel__code-frame": "^7.0.6",
|
|
29
28
|
"@types/console-log-level": "^1.4.5",
|
|
30
|
-
"@types/http-server": "^0.12.4",
|
|
31
29
|
"@types/md5": "^2.3.5",
|
|
32
30
|
"@types/mime": "3.0.0",
|
|
33
31
|
"@types/node": "^20.14.9",
|
|
34
|
-
"
|
|
32
|
+
"@types/serve-handler": "^6.1.4",
|
|
33
|
+
"playwright-core": "1.47.1",
|
|
34
|
+
"serve-handler": "^6.1.6"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@babel/code-frame": "^7.24.7",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"mime": "3.0.0",
|
|
43
43
|
"puppeteer-extra-plugin-recaptcha": "^3.6.8",
|
|
44
44
|
"rimraf": "^6.0.1",
|
|
45
|
-
"@empiricalrun/llm": "^0.
|
|
45
|
+
"@empiricalrun/llm": "^0.13.0",
|
|
46
46
|
"@empiricalrun/r2-uploader": "^0.3.8",
|
|
47
|
-
"@empiricalrun/test-gen": "^0.52.
|
|
47
|
+
"@empiricalrun/test-gen": "^0.52.2"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"dev": "tsc --build --watch",
|