@empiricalrun/playwright-utils 0.25.23 → 0.25.24
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 +6 -0
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/cache.js +1 -1
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/index.d.ts +8 -1
- 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 +69 -75
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/utils.d.ts +1 -0
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/utils.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/utils.js +20 -1
- package/dist/test/scripts/pw-locator-patch/highlight/click.js +6 -3
- package/dist/test/scripts/pw-locator-patch/highlight/hover.js +5 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -63,7 +63,7 @@ async function executeFromCache({ page, dom, text, }) {
|
|
|
63
63
|
return { success: false };
|
|
64
64
|
}
|
|
65
65
|
try {
|
|
66
|
-
console.log(`Executing "${match.code}" for element: ${dom}`);
|
|
66
|
+
console.log(`Executing from cache: "${match.code}" for element: ${dom}`);
|
|
67
67
|
// Ref: https://davidwalsh.name/async-function-class
|
|
68
68
|
const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
|
|
69
69
|
const exec = new AsyncFunction("page", match.code);
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { Page } from "@playwright/test";
|
|
2
2
|
import { OverlayElement } from "./types";
|
|
3
3
|
export declare function isErrorSupported(errorMessage: string | undefined): boolean;
|
|
4
|
+
export declare class OverlayDismissAgent {
|
|
5
|
+
private readonly page;
|
|
6
|
+
private cachingCandidates;
|
|
7
|
+
constructor(page: Page);
|
|
8
|
+
saveToCache(): Promise<void>;
|
|
9
|
+
run(originalError: any, reporter: (description: string) => void): Promise<void>;
|
|
10
|
+
private runAgent;
|
|
11
|
+
}
|
|
4
12
|
export declare function extractInterceptingElement(errorMessage: string): OverlayElement | undefined;
|
|
5
|
-
export declare function attemptToDismissOverlay(originalError: any, page: Page, reporter: (description: string) => void): Promise<void>;
|
|
6
13
|
//# 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":"
|
|
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;AAED,qBAAa,mBAAmB;IAOlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,OAAO,CAAC,iBAAiB,CAIhB;gBAEoB,IAAI,EAAE,IAAI;IAEjC,WAAW;IAMX,GAAG,CACP,aAAa,EAAE,GAAG,EAClB,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,GACtC,OAAO,CAAC,IAAI,CAAC;YA4BF,QAAQ;CAgCvB;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,cAAc,GAAG,SAAS,CAiC5B"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const llm_1 = require("@empiricalrun/llm");
|
|
3
|
+
exports.extractInterceptingElement = exports.OverlayDismissAgent = exports.isErrorSupported = void 0;
|
|
5
4
|
const run_1 = require("@empiricalrun/test-gen/agent/master/run");
|
|
6
5
|
const cache_1 = require("./cache");
|
|
7
6
|
const prompt_1 = require("./prompt");
|
|
@@ -15,62 +14,76 @@ function isErrorSupported(errorMessage) {
|
|
|
15
14
|
return errorMessage.includes(ERROR_SUBSTRING_INTERCEPTION);
|
|
16
15
|
}
|
|
17
16
|
exports.isErrorSupported = isErrorSupported;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
17
|
+
class OverlayDismissAgent {
|
|
18
|
+
page;
|
|
19
|
+
cachingCandidates = [];
|
|
20
|
+
constructor(page) {
|
|
21
|
+
this.page = page;
|
|
22
|
+
}
|
|
23
|
+
async saveToCache() {
|
|
24
|
+
for (const candidate of this.cachingCandidates) {
|
|
25
|
+
await (0, cache_1.setCodeToCache)(candidate);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async run(originalError, reporter) {
|
|
29
|
+
let element;
|
|
30
|
+
try {
|
|
31
|
+
element = extractInterceptingElement(originalError.message);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
// Ignoring this error
|
|
35
|
+
}
|
|
36
|
+
const description = (0, utils_1.overlayDescription)(element);
|
|
37
|
+
reporter(`Attempting to auto-dismiss overlay: ${description}`);
|
|
38
|
+
try {
|
|
39
|
+
const text = await (0, utils_1.textContent)(this.page, element);
|
|
40
|
+
const { success } = await (0, cache_1.executeFromCache)({
|
|
41
|
+
page: this.page,
|
|
42
|
+
dom: element?.interceptor,
|
|
43
|
+
text,
|
|
44
|
+
});
|
|
45
|
+
if (success) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
await this.runAgent(element, text);
|
|
49
|
+
}
|
|
50
|
+
catch (agentError) {
|
|
51
|
+
reporter(`Error during overlay dismissal agent execution: ${agentError.toString()}`);
|
|
52
|
+
throw originalError;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async runAgent(element, text) {
|
|
56
|
+
const task = await (0, prompt_1.getTask)(this.page, element, text);
|
|
57
|
+
if (PREFERRED_AGENT === "inhouse-master") {
|
|
58
|
+
const result = await (0, run_1.createTestUsingMasterAgent)({
|
|
59
|
+
task,
|
|
60
|
+
page: this.page,
|
|
61
|
+
options: {
|
|
62
|
+
useActionSpecificAnnotations: true,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
this.cachingCandidates.push({
|
|
66
|
+
dom: element?.interceptor,
|
|
67
|
+
text,
|
|
68
|
+
code: result.code,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else if (PREFERRED_AGENT === "openai-cua") {
|
|
72
|
+
const trace = (0, utils_1.traceThis)(task);
|
|
73
|
+
const result = await (0, run_1.createTestUsingComputerUseAgent)({
|
|
74
|
+
page: this.page,
|
|
75
|
+
task,
|
|
76
|
+
trace,
|
|
77
|
+
});
|
|
78
|
+
this.cachingCandidates.push({
|
|
79
|
+
dom: element?.interceptor,
|
|
80
|
+
text,
|
|
81
|
+
code: result.code,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
72
84
|
}
|
|
73
85
|
}
|
|
86
|
+
exports.OverlayDismissAgent = OverlayDismissAgent;
|
|
74
87
|
function extractInterceptingElement(errorMessage) {
|
|
75
88
|
// This extract element and parent info from interception error message
|
|
76
89
|
// Note that error message from the last retry is returned.
|
|
@@ -128,22 +141,3 @@ function findAllMatches(str, regex) {
|
|
|
128
141
|
}
|
|
129
142
|
return matches;
|
|
130
143
|
}
|
|
131
|
-
async function attemptToDismissOverlay(originalError, page, reporter) {
|
|
132
|
-
let overlayElement;
|
|
133
|
-
try {
|
|
134
|
-
overlayElement = extractInterceptingElement(originalError.message);
|
|
135
|
-
}
|
|
136
|
-
catch (err) {
|
|
137
|
-
// Ignoring this error
|
|
138
|
-
}
|
|
139
|
-
const description = (0, utils_1.overlayDescription)(overlayElement);
|
|
140
|
-
reporter(`Attempting to auto-dismiss overlay: ${description}`);
|
|
141
|
-
try {
|
|
142
|
-
await runAgentOnOverlay(page, overlayElement);
|
|
143
|
-
}
|
|
144
|
-
catch (agentError) {
|
|
145
|
-
reporter(`Error during overlay dismissal agent execution: ${agentError.toString()}`);
|
|
146
|
-
throw originalError;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
exports.attemptToDismissOverlay = attemptToDismissOverlay;
|
|
@@ -5,4 +5,5 @@ export declare function overlayDescription(element: OverlayElement | undefined):
|
|
|
5
5
|
export declare function isProductFruitsOverlay(element: OverlayElement | undefined): boolean | undefined;
|
|
6
6
|
export declare function textContent(pageRef: Page, element: OverlayElement | undefined): Promise<string | undefined>;
|
|
7
7
|
export declare function annotateForReport(testFn: TestFn, description: string): void;
|
|
8
|
+
export declare function traceThis(task: string): import("@empiricalrun/llm").TraceClient | undefined;
|
|
8
9
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/dismiss-overlays/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/dismiss-overlays/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,sBASrE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,uBAKzE;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,IAAI,EACb,OAAO,EAAE,cAAc,GAAG,SAAS,+BAiDpC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAMpE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,uDAgBrC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.annotateForReport = exports.textContent = exports.isProductFruitsOverlay = exports.overlayDescription = void 0;
|
|
3
|
+
exports.traceThis = exports.annotateForReport = exports.textContent = exports.isProductFruitsOverlay = exports.overlayDescription = void 0;
|
|
4
|
+
const llm_1 = require("@empiricalrun/llm");
|
|
4
5
|
function overlayDescription(element) {
|
|
5
6
|
if (element) {
|
|
6
7
|
const { interceptor, parent } = element;
|
|
@@ -75,3 +76,21 @@ function annotateForReport(testFn, description) {
|
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
78
|
exports.annotateForReport = annotateForReport;
|
|
79
|
+
function traceThis(task) {
|
|
80
|
+
const metadata = {
|
|
81
|
+
projectName: process.env.PROJECT_NAME ?? "",
|
|
82
|
+
testRunId: process.env.TEST_RUN_GITHUB_ACTION_ID ?? "",
|
|
83
|
+
};
|
|
84
|
+
const trace = (0, llm_1.createLangfuseTrace)({
|
|
85
|
+
name: "overlay_dismiss",
|
|
86
|
+
input: task,
|
|
87
|
+
tags: ["overlay_dismiss"],
|
|
88
|
+
metadata,
|
|
89
|
+
});
|
|
90
|
+
if (trace) {
|
|
91
|
+
const traceUrl = trace.getTraceUrl();
|
|
92
|
+
console.log(`Starting computer use agent: ${traceUrl}`);
|
|
93
|
+
}
|
|
94
|
+
return trace;
|
|
95
|
+
}
|
|
96
|
+
exports.traceThis = traceThis;
|
|
@@ -12,17 +12,20 @@ function patchClick(LocatorClass, testFn) {
|
|
|
12
12
|
}
|
|
13
13
|
const reporter = (description) => (0, utils_1.annotateForReport)(testFn, description);
|
|
14
14
|
const originalClick = LocatorClass.prototype.click;
|
|
15
|
-
//ref: github.com/microsoft/playwright/blob/69287f26bc514b740eac40160503d6fac8185d37/packages/playwright-core/src/client/locator.ts#L255
|
|
15
|
+
// ref: github.com/microsoft/playwright/blob/69287f26bc514b740eac40160503d6fac8185d37/packages/playwright-core/src/client/locator.ts#L255
|
|
16
16
|
LocatorClass.prototype.click = async function (options) {
|
|
17
17
|
const stepName = `locator.click(${(0, utils_2.description)(this)})`;
|
|
18
18
|
return await testFn.step(stepName, async () => {
|
|
19
19
|
let overlayAttemptsRemaining = 2;
|
|
20
20
|
let originalError;
|
|
21
|
+
const overlayDismiss = new dismiss_overlays_1.OverlayDismissAgent(this._frame._page);
|
|
21
22
|
while (overlayAttemptsRemaining >= 0) {
|
|
22
23
|
overlayAttemptsRemaining--;
|
|
23
24
|
try {
|
|
24
25
|
let result = await originalClick.apply(this, [options]);
|
|
25
|
-
|
|
26
|
+
// If click is successful, we can save overlay dismissal code to cache and return
|
|
27
|
+
await overlayDismiss.saveToCache();
|
|
28
|
+
return result;
|
|
26
29
|
}
|
|
27
30
|
catch (error) {
|
|
28
31
|
originalError = error;
|
|
@@ -36,7 +39,7 @@ function patchClick(LocatorClass, testFn) {
|
|
|
36
39
|
// This will cause our overlay dismissal to not run.
|
|
37
40
|
throw originalError;
|
|
38
41
|
}
|
|
39
|
-
await
|
|
42
|
+
await overlayDismiss.run(originalError, reporter);
|
|
40
43
|
// Dismissal attempt finished (implicitly successful if no error thrown)
|
|
41
44
|
reporter(`Overlay dismissal attempted, retrying original action.`);
|
|
42
45
|
}
|
|
@@ -16,12 +16,15 @@ function patchHover(LocatorClass, testFn) {
|
|
|
16
16
|
return await testFn.step(stepName, async () => {
|
|
17
17
|
let overlayAttemptsRemaining = 2;
|
|
18
18
|
let originalError;
|
|
19
|
+
const overlayDismiss = new dismiss_overlays_1.OverlayDismissAgent(this._frame._page);
|
|
19
20
|
while (overlayAttemptsRemaining >= 0) {
|
|
20
21
|
overlayAttemptsRemaining--;
|
|
21
22
|
try {
|
|
22
23
|
let result = await originalHover.apply(this, [options]);
|
|
23
24
|
await (0, utils_2.highlight)(this);
|
|
24
|
-
|
|
25
|
+
// If hover is successful, we can save overlay dismissal code to cache and return
|
|
26
|
+
await overlayDismiss.saveToCache();
|
|
27
|
+
return result;
|
|
25
28
|
}
|
|
26
29
|
catch (error) {
|
|
27
30
|
originalError = error;
|
|
@@ -31,7 +34,7 @@ function patchHover(LocatorClass, testFn) {
|
|
|
31
34
|
if (!(0, dismiss_overlays_1.isErrorSupported)(originalError.message)) {
|
|
32
35
|
throw originalError;
|
|
33
36
|
}
|
|
34
|
-
await
|
|
37
|
+
await overlayDismiss.run(originalError, reporter);
|
|
35
38
|
reporter(`Overlay dismissal attempted, retrying original action.`);
|
|
36
39
|
}
|
|
37
40
|
}
|