@empiricalrun/playwright-utils 0.61.3 → 0.62.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 +16 -0
- package/dist/generated/api-worker-openapi.d.ts +835 -221
- package/dist/generated/api-worker-openapi.d.ts.map +1 -1
- package/dist/test/expect/visual.d.ts.map +1 -1
- package/dist/test/expect/visual.js +0 -7
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +10 -8
- package/dist/test/scripts/index.d.ts.map +1 -1
- package/dist/test/scripts/index.js +1 -6
- package/dist/test/scripts/pw-locator-patch/highlight/expect.js +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/hover.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/hover.js +0 -1
- package/dist/test/scripts/pw-locator-patch/highlight/inner-text.js +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/input-value.js +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/is-checked.js +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/is-disabled.js +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/is-editable.js +1 -1
- package/dist/test/scripts/pw-locator-patch/highlight/text-content.js +1 -1
- package/dist/test/scripts/pw-locator-patch/utils/index.d.ts +1 -2
- package/dist/test/scripts/pw-locator-patch/utils/index.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/utils/index.js +3 -25
- package/dist/test/types.d.ts +1 -0
- package/dist/test/types.d.ts.map +1 -1
- package/docs/fixtures.md +10 -8
- package/package.json +3 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/test/scripts/mouse-pointer.d.ts +0 -5
- package/dist/test/scripts/mouse-pointer.d.ts.map +0 -1
- package/dist/test/scripts/mouse-pointer.js +0 -125
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual.d.ts","sourceRoot":"","sources":["../../../src/test/expect/visual.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAY,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"visual.d.ts","sourceRoot":"","sources":["../../../src/test/expect/visual.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAY,MAAM,kBAAkB,CAAC;AAOhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAsE7C,wBAAsB,WAAW,CAC/B,MAAM,EAAE,IAAI,GAAG,OAAO,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,aAAa,CAAC,CAwFxB"}
|
|
@@ -11,7 +11,6 @@ const os_1 = __importDefault(require("os"));
|
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const api_worker_client_1 = require("../../api-worker-client");
|
|
13
13
|
const telemetry_1 = require("../../telemetry");
|
|
14
|
-
const mouse_pointer_1 = require("../scripts/mouse-pointer");
|
|
15
14
|
function getCallerLine() {
|
|
16
15
|
const stack = new Error().stack;
|
|
17
16
|
if (!stack) {
|
|
@@ -75,16 +74,10 @@ issues or page loading bugs.
|
|
|
75
74
|
You are to respond to your visual evaluation with a Pass or Fail, and provide
|
|
76
75
|
a reason for your evaluation.
|
|
77
76
|
`;
|
|
78
|
-
function isLocator(target) {
|
|
79
|
-
return "page" in target && typeof target.page === "function";
|
|
80
|
-
}
|
|
81
77
|
async function toLookRight(target, pageDescription) {
|
|
82
|
-
const page = isLocator(target) ? target.page() : target;
|
|
83
|
-
await (0, mouse_pointer_1.removeMousePointerHighlighter)(page);
|
|
84
78
|
const screenshot = await target.screenshot();
|
|
85
79
|
attachScreenshot(screenshot, pageDescription);
|
|
86
80
|
const base64Image = screenshot.toString("base64");
|
|
87
|
-
await (0, mouse_pointer_1.addHighlighterScriptsToPage)(page);
|
|
88
81
|
const model = "gpt-4o";
|
|
89
82
|
// Same api-worker proxy the overlay-dismissal agent uses, so a test run needs
|
|
90
83
|
// no OpenAI key of its own; undefined falls back to the SDK's env defaults.
|
package/dist/test/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,IAAI,EACJ,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,KAAK,mBAAmB,EAAwB,MAAM,SAAS,CAAC;AACzE,OAAO,EAA8B,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,cAAc,CAAC;QACvB,UAAU,QAAQ,CAAC,CAAC;YAClB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC7C,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;SACnE;KACF;CACF;AAED,QAAA,MAAM,YAAY,mBAA6B,OAAO,MAAM,0CAG3D,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,QAAQ,CAAC;IACb,yBAAyB,EAAE,CACzB,OAAO,CAAC,EAAE,qBAAqB,KAC5B,OAAO,CAAC;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAYF,QAAA,MAAM,eAAe,WACX,QAAQ,CACd,kBAAkB,GAAG,qBAAqB,EAC1C,oBAAoB,GAAG,uBAAuB,CAC/C,YACQ,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,IAAI,EACJ,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,KAAK,mBAAmB,EAAwB,MAAM,SAAS,CAAC;AACzE,OAAO,EAA8B,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,cAAc,CAAC;QACvB,UAAU,QAAQ,CAAC,CAAC;YAClB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC7C,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;SACnE;KACF;CACF;AAED,QAAA,MAAM,YAAY,mBAA6B,OAAO,MAAM,0CAG3D,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,QAAQ,CAAC;IACb,yBAAyB,EAAE,CACzB,OAAO,CAAC,EAAE,qBAAqB,KAC5B,OAAO,CAAC;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAYF,QAAA,MAAM,eAAe,WACX,QAAQ,CACd,kBAAkB,GAAG,qBAAqB,EAC1C,oBAAoB,GAAG,uBAAuB,CAC/C,YACQ,mBAAmB,uHAwH7B,CAAC;AAEF,OAAO,EACL,eAAe,EACf,YAAY,EACZ,6BAA6B,EAC7B,aAAa,GACd,CAAC"}
|
package/dist/test/index.js
CHANGED
|
@@ -27,13 +27,18 @@ const defaultOptions = {
|
|
|
27
27
|
};
|
|
28
28
|
const baseTestFixture = function (testFn, options = defaultOptions) {
|
|
29
29
|
const coverageEnabled = options.collectCoverage ?? false;
|
|
30
|
+
// Playwright draws the cursor, target box and action title into the video.
|
|
31
|
+
// 100ms per action keeps them visible without the default 500ms slowdown.
|
|
32
|
+
const showActions = options.mousePointerHighlighter === false ? undefined : { duration: 100 };
|
|
33
|
+
const recordVideoOptions = (dir) => ({
|
|
34
|
+
dir,
|
|
35
|
+
size: { width: 1280, height: 720 },
|
|
36
|
+
showActions,
|
|
37
|
+
});
|
|
30
38
|
const extendedTestFn = testFn.extend({
|
|
31
39
|
context: async ({ browser }, use, testInfo) => {
|
|
32
40
|
const context = await browser.newContext({
|
|
33
|
-
recordVideo:
|
|
34
|
-
dir: testInfo.outputDir,
|
|
35
|
-
size: { width: 1280, height: 720 },
|
|
36
|
-
},
|
|
41
|
+
recordVideo: recordVideoOptions(testInfo.outputDir),
|
|
37
42
|
});
|
|
38
43
|
const pages = [];
|
|
39
44
|
context.on("page", (page) => pages.push(page));
|
|
@@ -67,10 +72,7 @@ const baseTestFixture = function (testFn, options = defaultOptions) {
|
|
|
67
72
|
async function createContext(contextOptions = {}) {
|
|
68
73
|
const pageContext = await browser.newContext({
|
|
69
74
|
...contextOptions,
|
|
70
|
-
recordVideo:
|
|
71
|
-
dir: testInfo.outputDir,
|
|
72
|
-
size: { width: 1280, height: 720 },
|
|
73
|
-
},
|
|
75
|
+
recordVideo: recordVideoOptions(testInfo.outputDir),
|
|
74
76
|
});
|
|
75
77
|
const pages = [];
|
|
76
78
|
pageContext.on("page", (page) => pages.push(page));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/test/scripts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/test/scripts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAI3C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAQjC,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAgC,QAmB1C"}
|
|
@@ -5,9 +5,7 @@ const logger_1 = require("../../logger");
|
|
|
5
5
|
const agent_capabilities_1 = require("./agent-capabilities");
|
|
6
6
|
const locator_highlights_1 = require("./locator-highlights");
|
|
7
7
|
const locator_vision_1 = require("./locator-vision");
|
|
8
|
-
const mouse_pointer_1 = require("./mouse-pointer");
|
|
9
8
|
const defaultOptions = {
|
|
10
|
-
mousePointerHighlighter: true,
|
|
11
9
|
locatorHighlighter: true,
|
|
12
10
|
visionMethods: true,
|
|
13
11
|
agentCapabilities: true,
|
|
@@ -18,9 +16,6 @@ function injectLocatorHighlightScripts(page, testFn, options = defaultOptions) {
|
|
|
18
16
|
...options,
|
|
19
17
|
};
|
|
20
18
|
try {
|
|
21
|
-
if (opts.mousePointerHighlighter) {
|
|
22
|
-
(0, mouse_pointer_1.addMousePointerHighlighter)(page);
|
|
23
|
-
}
|
|
24
19
|
if (opts.locatorHighlighter) {
|
|
25
20
|
(0, locator_highlights_1.addLocatorHighlights)(page, testFn);
|
|
26
21
|
}
|
|
@@ -32,6 +27,6 @@ function injectLocatorHighlightScripts(page, testFn, options = defaultOptions) {
|
|
|
32
27
|
}
|
|
33
28
|
}
|
|
34
29
|
catch (e) {
|
|
35
|
-
logger_1.logger.debug("Failed to
|
|
30
|
+
logger_1.logger.debug("Failed to inject locator highlight scripts", e);
|
|
36
31
|
}
|
|
37
32
|
}
|
|
@@ -15,7 +15,7 @@ function patchExpect(LocatorClass) {
|
|
|
15
15
|
LocatorClass.prototype._expect = async function (expression, options) {
|
|
16
16
|
const result = await originalExpect.apply(this, [expression, options]);
|
|
17
17
|
if (result.matches) {
|
|
18
|
-
await (0, utils_1.
|
|
18
|
+
await (0, utils_1.scrollIntoView)(this);
|
|
19
19
|
}
|
|
20
20
|
return result;
|
|
21
21
|
};
|
|
@@ -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;AAOrC,wBAAgB,UAAU,CACxB,YAAY,EAAE,QAAQ,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,EAC/C,MAAM,EAAE,MAAM,
|
|
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"}
|
|
@@ -21,7 +21,6 @@ function patchHover(LocatorClass, testFn) {
|
|
|
21
21
|
overlayAttemptsRemaining--;
|
|
22
22
|
try {
|
|
23
23
|
let result = await originalHover.apply(this, [options]);
|
|
24
|
-
await (0, utils_2.highlight)(this);
|
|
25
24
|
// If hover is successful, we can save overlay dismissal code to cache and return
|
|
26
25
|
await overlayDismiss.saveToCache();
|
|
27
26
|
return result;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Locator } from "playwright-core";
|
|
2
2
|
export declare function description(locator: Locator): string;
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function highlight(locator: Locator): Promise<void>;
|
|
3
|
+
export declare function scrollIntoView(locator: Locator): Promise<void>;
|
|
5
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK1C,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,UA0B3C;AAED,wBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/test/scripts/pw-locator-patch/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK1C,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,UA0B3C;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,OAAO,iBAgBpD"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.description = description;
|
|
4
|
-
exports.
|
|
5
|
-
exports.highlight = highlight;
|
|
4
|
+
exports.scrollIntoView = scrollIntoView;
|
|
6
5
|
const logger_1 = require("../../../../logger");
|
|
7
6
|
const constants_1 = require("../../../constants");
|
|
8
7
|
function description(locator) {
|
|
@@ -26,7 +25,7 @@ function description(locator) {
|
|
|
26
25
|
return fallbackDescription;
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
|
-
async function
|
|
28
|
+
async function scrollIntoView(locator) {
|
|
30
29
|
try {
|
|
31
30
|
await locator.evaluate((node) => {
|
|
32
31
|
if (node.scrollIntoViewIfNeeded) {
|
|
@@ -35,30 +34,9 @@ async function scrollAndHighlight(locator) {
|
|
|
35
34
|
else {
|
|
36
35
|
node.scrollIntoView();
|
|
37
36
|
}
|
|
38
|
-
node.classList.add("empirical-element-grab-highlight");
|
|
39
|
-
setTimeout(() => {
|
|
40
|
-
if (node && node.isConnected && node.classList) {
|
|
41
|
-
node.classList.remove("empirical-element-grab-highlight");
|
|
42
|
-
}
|
|
43
|
-
}, 2000);
|
|
44
37
|
}, undefined, { timeout: constants_1.DEFAULT_SCRIPT_EXECUTION_TIMEOUT });
|
|
45
38
|
}
|
|
46
39
|
catch {
|
|
47
|
-
logger_1.logger.debug("Failed to scroll
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
async function highlight(locator) {
|
|
51
|
-
try {
|
|
52
|
-
await locator.evaluate((node) => {
|
|
53
|
-
node.classList.add("empirical-element-grab-highlight");
|
|
54
|
-
setTimeout(() => {
|
|
55
|
-
if (node && node.isConnected && node.classList) {
|
|
56
|
-
node.classList.remove("empirical-element-grab-highlight");
|
|
57
|
-
}
|
|
58
|
-
}, 2000);
|
|
59
|
-
}, undefined, { timeout: constants_1.DEFAULT_SCRIPT_EXECUTION_TIMEOUT });
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
logger_1.logger.debug("Failed to add highlight for locator method");
|
|
40
|
+
logger_1.logger.debug("Failed to scroll into view for locator method");
|
|
63
41
|
}
|
|
64
42
|
}
|
package/dist/test/types.d.ts
CHANGED
package/dist/test/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/test/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG;IAClD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/test/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,iFAAiF;IACjF,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG;IAClD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC"}
|
package/docs/fixtures.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Fixtures
|
|
2
2
|
|
|
3
3
|
The playwright-utils package provides fixtures that wrap around Playwright's built-in
|
|
4
|
-
`page`, `context` fixtures to
|
|
5
|
-
see actions taken in a video
|
|
4
|
+
`page`, `context` fixtures to record videos with Playwright's action annotations
|
|
5
|
+
(cursor, target box and action title), which make it easier to see actions taken in a video.
|
|
6
6
|
|
|
7
7
|
To use this, you can use the `baseTestFixture` and `extendExpect` imports
|
|
8
8
|
in your fixtures file.
|
|
@@ -17,8 +17,8 @@ export const expect = extendExpect(baseExpect);
|
|
|
17
17
|
|
|
18
18
|
## Highlighters and agentic behaviors
|
|
19
19
|
|
|
20
|
-
`baseTestFixture` patches the playwright page object to add
|
|
21
|
-
|
|
20
|
+
`baseTestFixture` patches the playwright page object to add locator helpers.
|
|
21
|
+
Pass `mousePointerHighlighter: false` to turn off the action annotations in videos.
|
|
22
22
|
|
|
23
23
|
These methods also enable agentic behaviors like dismissing overlays.
|
|
24
24
|
|
|
@@ -49,7 +49,7 @@ a fresh, new browser context, and a page inside it.
|
|
|
49
49
|
|
|
50
50
|
There are two benefits of using this to create contexts or pages:
|
|
51
51
|
1. Videos get recorded and attached to the test report
|
|
52
|
-
2.
|
|
52
|
+
2. Action annotations are shown in the video
|
|
53
53
|
|
|
54
54
|
```ts
|
|
55
55
|
import { test, expect } from "./fixtures";
|
|
@@ -61,12 +61,14 @@ test("Example test", async ({ page: builtInPage, customContextPageProvider }) =>
|
|
|
61
61
|
});
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
### Inject
|
|
64
|
+
### Inject locator scripts manually
|
|
65
65
|
|
|
66
|
-
In some cases, you want to
|
|
66
|
+
In some cases, you want to patch a page you created yourself. This is useful if the test
|
|
67
67
|
requires `launchPersistentContext`, which means the browser context is created manually.
|
|
68
68
|
|
|
69
|
-
With `injectLocatorHighlightScripts`, you
|
|
69
|
+
With `injectLocatorHighlightScripts`, you still get the locator helpers in any page. For
|
|
70
|
+
action annotations in the video, pass `recordVideo: { dir, showActions: { duration: 100 } }`
|
|
71
|
+
when you create the context.
|
|
70
72
|
|
|
71
73
|
```ts
|
|
72
74
|
import { injectLocatorHighlightScripts, baseTestFixture } from "@empiricalrun/playwright-utils/test";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/playwright-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.62.1",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22"
|
|
6
6
|
},
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"openapi-typescript": "7.6.1",
|
|
46
46
|
"playwright-core": "1.63.0",
|
|
47
47
|
"serve-handler": "^6.1.6",
|
|
48
|
-
"@empiricalrun/shared-types": "0.20.
|
|
48
|
+
"@empiricalrun/shared-types": "0.20.6"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@babel/code-frame": "^7.24.7",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"ts-morph": "^23.0.0",
|
|
61
61
|
"@empiricalrun/cua": "^0.5.1",
|
|
62
62
|
"@empiricalrun/llm": "^0.28.1",
|
|
63
|
-
"@empiricalrun/r2-uploader": "^0.11.
|
|
63
|
+
"@empiricalrun/r2-uploader": "^0.11.2",
|
|
64
64
|
"@empiricalrun/reporter": "^0.30.2"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"7.0.0-dev.20260623.1","root":["./src/api-worker-client.ts","./src/email.ts","./src/inbox-client.ts","./src/index.ts","./src/kv.ts","./src/logger.ts","./src/mailosaur-client.ts","./src/playwright-extensions.ts","./src/telemetry.ts","./src/webhook.ts","./src/auth/google.ts","./src/auth/index.ts","./src/auth/types.ts","./src/captcha/index.ts","./src/config/index.ts","./src/config/proxy.ts","./src/config/devices/types.ts","./src/generated/api-worker-openapi.ts","./src/overlay-tests/cache.spec.ts","./src/overlay-tests/click.spec.ts","./src/overlay-tests/fixtures.ts","./src/overlay-tests/patch.spec.ts","./src/overlay-tests/visual.spec.ts","./src/reporter/attachment-cleanup-test-reporter.ts","./src/reporter/attachment-cleanup.ts","./src/reporter/blob-utils.ts","./src/reporter/empirical-reporter.ts","./src/reporter/failing-line.ts","./src/reporter/harness.ts","./src/reporter/ibr-utils.ts","./src/reporter/incremental-blob-reporter.ts","./src/reporter/lifecycle-events.ts","./src/reporter/local-test.ts","./src/reporter/parity-utils.ts","./src/reporter/reporter-state.ts","./src/reporter/test-case-sync-reporter.ts","./src/reporter/test-case-sync.ts","./src/reporter/uploader.ts","./src/reporter/util.ts","./src/test/constants.ts","./src/test/coverage.ts","./src/test/index.ts","./src/test/types.ts","./src/test/video-labels.ts","./src/test/expect/index.ts","./src/test/expect/types.ts","./src/test/expect/visual.ts","./src/test/expect/webhook.ts","./src/test/scripts/agent-capabilities.ts","./src/test/scripts/index.ts","./src/test/scripts/locator-highlights.ts","./src/test/scripts/locator-vision.ts","./src/test/scripts/
|
|
1
|
+
{"version":"7.0.0-dev.20260623.1","root":["./src/api-worker-client.ts","./src/email.ts","./src/inbox-client.ts","./src/index.ts","./src/kv.ts","./src/logger.ts","./src/mailosaur-client.ts","./src/playwright-extensions.ts","./src/telemetry.ts","./src/webhook.ts","./src/auth/google.ts","./src/auth/index.ts","./src/auth/types.ts","./src/captcha/index.ts","./src/config/index.ts","./src/config/proxy.ts","./src/config/devices/types.ts","./src/generated/api-worker-openapi.ts","./src/overlay-tests/cache.spec.ts","./src/overlay-tests/click.spec.ts","./src/overlay-tests/fixtures.ts","./src/overlay-tests/patch.spec.ts","./src/overlay-tests/visual.spec.ts","./src/reporter/attachment-cleanup-test-reporter.ts","./src/reporter/attachment-cleanup.ts","./src/reporter/blob-utils.ts","./src/reporter/empirical-reporter.ts","./src/reporter/failing-line.ts","./src/reporter/harness.ts","./src/reporter/ibr-utils.ts","./src/reporter/incremental-blob-reporter.ts","./src/reporter/lifecycle-events.ts","./src/reporter/local-test.ts","./src/reporter/parity-utils.ts","./src/reporter/reporter-state.ts","./src/reporter/test-case-sync-reporter.ts","./src/reporter/test-case-sync.ts","./src/reporter/uploader.ts","./src/reporter/util.ts","./src/test/constants.ts","./src/test/coverage.ts","./src/test/index.ts","./src/test/types.ts","./src/test/video-labels.ts","./src/test/expect/index.ts","./src/test/expect/types.ts","./src/test/expect/visual.ts","./src/test/expect/webhook.ts","./src/test/scripts/agent-capabilities.ts","./src/test/scripts/index.ts","./src/test/scripts/locator-highlights.ts","./src/test/scripts/locator-vision.ts","./src/test/scripts/types.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/cache.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/index.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/prompt.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/types.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/utils.ts","./src/test/scripts/pw-locator-patch/highlight/click.ts","./src/test/scripts/pw-locator-patch/highlight/expect.ts","./src/test/scripts/pw-locator-patch/highlight/hover.ts","./src/test/scripts/pw-locator-patch/highlight/inner-text.ts","./src/test/scripts/pw-locator-patch/highlight/input-value.ts","./src/test/scripts/pw-locator-patch/highlight/is-checked.ts","./src/test/scripts/pw-locator-patch/highlight/is-disabled.ts","./src/test/scripts/pw-locator-patch/highlight/is-editable.ts","./src/test/scripts/pw-locator-patch/highlight/text-content.ts","./src/test/scripts/pw-locator-patch/utils/index.ts","./src/test/scripts/pw-locator-patch/vision/query.ts"]}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { Page } from "@playwright/test";
|
|
2
|
-
export declare function addHighlighterScriptsToPage(page: Page): Promise<void>;
|
|
3
|
-
export declare function removeMousePointerHighlighter(page: Page): Promise<void>;
|
|
4
|
-
export declare function addMousePointerHighlighter(page: Page): void;
|
|
5
|
-
//# sourceMappingURL=mouse-pointer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mouse-pointer.d.ts","sourceRoot":"","sources":["../../../src/test/scripts/mouse-pointer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAmD7C,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,IAAI,iBAqD3D;AAED,wBAAsB,6BAA6B,CAAC,IAAI,EAAE,IAAI,iBA6B7D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,IAAI,QAUpD"}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.addHighlighterScriptsToPage = addHighlighterScriptsToPage;
|
|
4
|
-
exports.removeMousePointerHighlighter = removeMousePointerHighlighter;
|
|
5
|
-
exports.addMousePointerHighlighter = addMousePointerHighlighter;
|
|
6
|
-
const logger_1 = require("../../logger");
|
|
7
|
-
const STYLES_FOR_MOUSE_POINTER = `
|
|
8
|
-
.empirical-mouse-pointer {
|
|
9
|
-
pointer-events: none;
|
|
10
|
-
position: absolute;
|
|
11
|
-
top: 0;
|
|
12
|
-
z-index: 10000;
|
|
13
|
-
left: 0;
|
|
14
|
-
width: 20px;
|
|
15
|
-
height: 20px;
|
|
16
|
-
background: rgba(0,0,0,.4);
|
|
17
|
-
border: 1px dashed #FF000D;
|
|
18
|
-
border-radius: 10px;
|
|
19
|
-
margin: -10px 0 0 -10px;
|
|
20
|
-
padding: 0;
|
|
21
|
-
transition: background .2s, border-radius .2s, border-color .2s;
|
|
22
|
-
}
|
|
23
|
-
.empirical-mouse-pointer.button-1 {
|
|
24
|
-
transition: none;
|
|
25
|
-
background: rgba(0,0,0,0.9);
|
|
26
|
-
}
|
|
27
|
-
.empirical-mouse-pointer.button-2 {
|
|
28
|
-
transition: none;
|
|
29
|
-
border-color: rgba(0,0,255,0.9);
|
|
30
|
-
}
|
|
31
|
-
.empirical-mouse-pointer.button-3 {
|
|
32
|
-
transition: none;
|
|
33
|
-
border-radius: 4px;
|
|
34
|
-
}
|
|
35
|
-
.empirical-mouse-pointer.button-4 {
|
|
36
|
-
transition: none;
|
|
37
|
-
border-color: rgba(255,0,0,0.9);
|
|
38
|
-
}
|
|
39
|
-
.empirical-mouse-pointer.button-5 {
|
|
40
|
-
transition: none;
|
|
41
|
-
border-color: rgba(0,255,0,0.9);
|
|
42
|
-
}
|
|
43
|
-
.empirical-element-grab-highlight {
|
|
44
|
-
outline: 2px dashed cyan !important;
|
|
45
|
-
}
|
|
46
|
-
*:focus {
|
|
47
|
-
outline: 2px dashed #FF000D !important;
|
|
48
|
-
}
|
|
49
|
-
*:focus-visible {
|
|
50
|
-
outline: 2px dashed #FF000D !important;
|
|
51
|
-
}
|
|
52
|
-
`;
|
|
53
|
-
async function addHighlighterScriptsToPage(page) {
|
|
54
|
-
try {
|
|
55
|
-
await page.evaluate((stylesString) => {
|
|
56
|
-
const mouseBox = document.createElement("div");
|
|
57
|
-
mouseBox.classList.add("empirical-mouse-pointer");
|
|
58
|
-
const styleElement = document.createElement("style");
|
|
59
|
-
styleElement.textContent = stylesString;
|
|
60
|
-
document.head.appendChild(styleElement);
|
|
61
|
-
document.body.appendChild(mouseBox);
|
|
62
|
-
document.addEventListener("mousemove", (event) => {
|
|
63
|
-
mouseBox.style.left = `${event.pageX}px`;
|
|
64
|
-
mouseBox.style.top = `${event.pageY}px`;
|
|
65
|
-
updateButtons(event.buttons);
|
|
66
|
-
}, true);
|
|
67
|
-
document.addEventListener("mousedown", (event) => {
|
|
68
|
-
updateButtons(event.buttons);
|
|
69
|
-
mouseBox.classList.add(`button-${event.button + 1}`);
|
|
70
|
-
}, true);
|
|
71
|
-
document.addEventListener("mouseup", (event) => {
|
|
72
|
-
updateButtons(event.buttons);
|
|
73
|
-
mouseBox.classList.remove(`button-${event.button + 1}`);
|
|
74
|
-
}, true);
|
|
75
|
-
// @ts-ignore
|
|
76
|
-
function updateButtons(buttons) {
|
|
77
|
-
for (let i = 0; i < 5; i++) {
|
|
78
|
-
mouseBox.classList.toggle(`button-${i + 1}`, (buttons / Math.pow(2, i)) % 2 >= 1);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}, STYLES_FOR_MOUSE_POINTER);
|
|
82
|
-
}
|
|
83
|
-
catch (e) {
|
|
84
|
-
logger_1.logger.debug(`Error adding mouse pointer highlighter`, e);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
async function removeMousePointerHighlighter(page) {
|
|
88
|
-
try {
|
|
89
|
-
await page.evaluate(() => {
|
|
90
|
-
// check if any element has the class empirical-element-grab-highlight
|
|
91
|
-
// if so, remove the class
|
|
92
|
-
const hasHighlight = document.querySelectorAll(".empirical-element-grab-highlight");
|
|
93
|
-
if (hasHighlight) {
|
|
94
|
-
hasHighlight.forEach((highlight) => {
|
|
95
|
-
highlight.classList.remove("empirical-element-grab-highlight");
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
// find div.empirical-mouse-pointer and remove it
|
|
99
|
-
const mousePointer = document.querySelector(".empirical-mouse-pointer");
|
|
100
|
-
if (mousePointer) {
|
|
101
|
-
mousePointer.remove();
|
|
102
|
-
}
|
|
103
|
-
// find style element with text content of STYLE_FOR_MOUSE_POINTER
|
|
104
|
-
const styleElements = document.querySelectorAll("style");
|
|
105
|
-
styleElements.forEach((styleElement) => {
|
|
106
|
-
if (styleElement.textContent?.includes("empirical-mouse-pointer")) {
|
|
107
|
-
styleElement.remove();
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
catch (e) {
|
|
113
|
-
logger_1.logger.debug(`Error removing mouse pointer highlighter`, e);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function addMousePointerHighlighter(page) {
|
|
117
|
-
page.on("load", async () => {
|
|
118
|
-
await addHighlighterScriptsToPage(page);
|
|
119
|
-
});
|
|
120
|
-
page.context().on("page", async (newPage) => {
|
|
121
|
-
newPage?.on("load", async () => {
|
|
122
|
-
await addHighlighterScriptsToPage(newPage);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
}
|