@percy/playwright 1.0.10-alpha.0 → 1.0.10
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/index.js +5 -75
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -8,78 +8,13 @@ const CLIENT_INFO = `${sdkPkg.name}/${sdkPkg.version}`;
|
|
|
8
8
|
const ENV_INFO = `${playwrightPkg.name}/${playwrightPkg.version}`;
|
|
9
9
|
const log = utils.logger('playwright');
|
|
10
10
|
|
|
11
|
-
// This function is executed in the browser context to handle dynamic resources.
|
|
12
|
-
/* istanbul ignore next: browser-executed function difficult to instrument */
|
|
13
|
-
const handleDynamicResources = async () => {
|
|
14
|
-
// Handle lazy-loaded images
|
|
15
|
-
document.querySelectorAll('img').forEach(img => {
|
|
16
|
-
const dataSrc = img.getAttribute('data-src');
|
|
17
|
-
if (dataSrc) {
|
|
18
|
-
try {
|
|
19
|
-
// Only allow http, https, data, or blob URLs
|
|
20
|
-
const url = new URL(dataSrc, window.location.origin);
|
|
21
|
-
if (
|
|
22
|
-
url.protocol === 'http:' ||
|
|
23
|
-
url.protocol === 'https:' ||
|
|
24
|
-
url.protocol === 'data:' ||
|
|
25
|
-
url.protocol === 'blob:'
|
|
26
|
-
) {
|
|
27
|
-
img.src = url.href;
|
|
28
|
-
} else {
|
|
29
|
-
// Ignored unsafe data-src value
|
|
30
|
-
}
|
|
31
|
-
} catch (e) {
|
|
32
|
-
// If dataSrc is not a valid URL, ignore it
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Handle blob background images
|
|
38
|
-
const elements = Array.from(document.querySelectorAll('*'));
|
|
39
|
-
const promises = [];
|
|
40
|
-
|
|
41
|
-
for (const el of elements) {
|
|
42
|
-
const style = window.getComputedStyle(el);
|
|
43
|
-
const backgroundImage = style.getPropertyValue('background-image');
|
|
44
|
-
|
|
45
|
-
if (backgroundImage && backgroundImage.includes('blob:')) {
|
|
46
|
-
const blobUrlMatch = backgroundImage.match(/url\("?(blob:.+?)"?\)/);
|
|
47
|
-
if (blobUrlMatch && blobUrlMatch[1]) {
|
|
48
|
-
const blobUrl = blobUrlMatch[1];
|
|
49
|
-
|
|
50
|
-
/* eslint-disable-next-line no-undef */
|
|
51
|
-
const promise = fetch(blobUrl)
|
|
52
|
-
.then(res => res.blob())
|
|
53
|
-
.then(blob => new Promise((resolve, reject) => {
|
|
54
|
-
/* eslint-disable-next-line no-undef */
|
|
55
|
-
const reader = new FileReader();
|
|
56
|
-
reader.onloadend = () => {
|
|
57
|
-
el.style.backgroundImage = style.getPropertyValue('background-image').replace(blobUrl, reader.result);
|
|
58
|
-
resolve();
|
|
59
|
-
};
|
|
60
|
-
reader.onerror = reject;
|
|
61
|
-
reader.readAsDataURL(blob);
|
|
62
|
-
}))
|
|
63
|
-
.catch(err => {
|
|
64
|
-
log.warn(`Failed to process blob URL "${blobUrl}": ${err.message}`);
|
|
65
|
-
// Silently handle errors
|
|
66
|
-
});
|
|
67
|
-
promises.push(promise);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
await Promise.all(promises);
|
|
72
|
-
};
|
|
73
|
-
|
|
74
11
|
// Processes a single cross-origin frame to capture its snapshot and resources.
|
|
75
12
|
async function processFrame(page, frame, options, percyDOM) {
|
|
76
13
|
const frameUrl = frame.url();
|
|
77
14
|
|
|
78
|
-
// Execute pre-serialization transformations in the iframe
|
|
79
|
-
/* istanbul ignore next: browser-executed function call */
|
|
80
|
-
await frame.evaluate(handleDynamicResources);
|
|
81
|
-
|
|
82
15
|
/* istanbul ignore next: browser-executed iframe serialization */
|
|
16
|
+
// enableJavaScript: true prevents the standard iframe serialization logic from running.
|
|
17
|
+
// This is necessary because we're manually handling cross-origin iframe serialization here.
|
|
83
18
|
const iframeSnapshot = await frame.evaluate((opts) => {
|
|
84
19
|
/* eslint-disable-next-line no-undef */
|
|
85
20
|
return PercyDOM.serialize(opts);
|
|
@@ -123,14 +58,6 @@ const percySnapshot = async function(page, name, options) {
|
|
|
123
58
|
const percyDOM = await utils.fetchPercyDOM();
|
|
124
59
|
await page.evaluate(percyDOM);
|
|
125
60
|
|
|
126
|
-
// Execute pre-serialization transformations on the main page
|
|
127
|
-
try {
|
|
128
|
-
/* istanbul ignore next: browser-executed function call */
|
|
129
|
-
await page.evaluate(handleDynamicResources);
|
|
130
|
-
} catch (error) {
|
|
131
|
-
// Silently handle any errors from handleDynamicResources to not disrupt snapshots
|
|
132
|
-
}
|
|
133
|
-
|
|
134
61
|
// Serialize and capture the DOM
|
|
135
62
|
/* istanbul ignore next: no instrumenting injected code */
|
|
136
63
|
let domSnapshot = await page.evaluate((options) => {
|
|
@@ -139,6 +66,9 @@ const percySnapshot = async function(page, name, options) {
|
|
|
139
66
|
}, options);
|
|
140
67
|
|
|
141
68
|
// Process CORS IFrames
|
|
69
|
+
// Note: Blob URL handling (data-src images, blob background images) is now handled
|
|
70
|
+
// in the CLI via async DOM serialization. See: percy/cli packages/dom/src/serialize-blob-urls.js
|
|
71
|
+
// This section only handles cross-origin iframe serialization and resource merging.
|
|
142
72
|
const pageUrl = new URL(page.url());
|
|
143
73
|
const crossOriginFrames = page.frames()
|
|
144
74
|
.filter(frame => frame.url() !== 'about:blank' && new URL(frame.url()).origin !== pageUrl.origin);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/playwright",
|
|
3
3
|
"description": "Playwright client library for visual testing with Percy",
|
|
4
|
-
"version": "1.0.10
|
|
4
|
+
"version": "1.0.10",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Perceptual Inc.",
|
|
7
7
|
"repository": "https://github.com/percy/percy-playwright",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public",
|
|
32
|
-
"tag": "
|
|
32
|
+
"tag": "latest"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"playwright-core": ">=1"
|