@percy/core 1.31.6-beta.5 → 1.31.6-beta.7
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/dist/config.js +21 -0
- package/dist/discovery.js +1 -0
- package/dist/network.js +7 -2
- package/dist/snapshot.js +2 -1
- package/dist/utils.js +55 -0
- package/package.json +8 -8
package/dist/config.js
CHANGED
|
@@ -508,6 +508,24 @@ export const configSchema = {
|
|
|
508
508
|
default: true
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
|
+
},
|
|
512
|
+
fontDomains: {
|
|
513
|
+
type: 'array',
|
|
514
|
+
default: [],
|
|
515
|
+
items: {
|
|
516
|
+
type: 'string',
|
|
517
|
+
allOf: [{
|
|
518
|
+
not: {
|
|
519
|
+
pattern: '[^/]/'
|
|
520
|
+
},
|
|
521
|
+
error: 'must not include a pathname'
|
|
522
|
+
}, {
|
|
523
|
+
not: {
|
|
524
|
+
pattern: '^([a-zA-Z]+:)?//'
|
|
525
|
+
},
|
|
526
|
+
error: 'must not include a protocol'
|
|
527
|
+
}]
|
|
528
|
+
}
|
|
511
529
|
}
|
|
512
530
|
}
|
|
513
531
|
}
|
|
@@ -635,6 +653,9 @@ export const snapshotSchema = {
|
|
|
635
653
|
},
|
|
636
654
|
scrollToBottom: {
|
|
637
655
|
$ref: '/config/discovery#/properties/scrollToBottom'
|
|
656
|
+
},
|
|
657
|
+
fontDomains: {
|
|
658
|
+
$ref: '/config/discovery#/properties/fontDomains'
|
|
638
659
|
}
|
|
639
660
|
}
|
|
640
661
|
}
|
package/dist/discovery.js
CHANGED
|
@@ -492,6 +492,7 @@ export function createDiscoveryQueue(percy) {
|
|
|
492
492
|
requestHeaders: snapshot.discovery.requestHeaders,
|
|
493
493
|
authorization: snapshot.discovery.authorization,
|
|
494
494
|
userAgent: snapshot.discovery.userAgent,
|
|
495
|
+
fontDomains: snapshot.discovery.fontDomains,
|
|
495
496
|
captureMockedServiceWorker: snapshot.discovery.captureMockedServiceWorker,
|
|
496
497
|
meta: {
|
|
497
498
|
...snapshot.meta,
|
package/dist/network.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { request as makeRequest } from '@percy/client/utils';
|
|
2
2
|
import logger from '@percy/logger';
|
|
3
3
|
import mime from 'mime-types';
|
|
4
|
-
import { DefaultMap, createResource, hostnameMatches, normalizeURL, waitFor, decodeAndEncodeURLWithLogging } from './utils.js';
|
|
4
|
+
import { DefaultMap, createResource, hostnameMatches, normalizeURL, waitFor, decodeAndEncodeURLWithLogging, handleIncorrectFontMimeType } from './utils.js';
|
|
5
5
|
const MAX_RESOURCE_SIZE = 25 * 1024 ** 2 * 0.63; // 25MB, 0.63 factor for accounting for base64 encoding
|
|
6
6
|
const ALLOWED_STATUSES = [200, 201, 301, 302, 304, 307, 308];
|
|
7
7
|
const ALLOWED_RESOURCES = ['Document', 'Stylesheet', 'Image', 'Media', 'Font', 'Other'];
|
|
@@ -38,6 +38,7 @@ export class Network {
|
|
|
38
38
|
this.userAgent = options.userAgent ??
|
|
39
39
|
// by default, emulate a non-headless browser
|
|
40
40
|
page.session.browser.version.userAgent.replace('Headless', '');
|
|
41
|
+
this.fontDomains = options.fontDomains || [];
|
|
41
42
|
this.intercept = options.intercept;
|
|
42
43
|
this.meta = options.meta;
|
|
43
44
|
this._initializeNetworkIdleWaitTimeout();
|
|
@@ -516,6 +517,7 @@ async function saveResponseResource(network, request, session) {
|
|
|
516
517
|
let resource = network.intercept.getResource(url);
|
|
517
518
|
if (!resource || !resource.root && !resource.provided && disableCache) {
|
|
518
519
|
try {
|
|
520
|
+
var _mimeType;
|
|
519
521
|
// Don't rename the below log line as it is used in getting network logs in api
|
|
520
522
|
log.debug(`Processing resource: ${url}`, meta);
|
|
521
523
|
let shouldCapture = response && hostnameMatches(allowedHostnames, url);
|
|
@@ -546,11 +548,14 @@ async function saveResponseResource(network, request, session) {
|
|
|
546
548
|
// ensure the mimetype is correct for text/plain responses
|
|
547
549
|
response.mimeType === 'text/plain' && detectedMime || response.mimeType;
|
|
548
550
|
|
|
551
|
+
// Handle Google Fonts MIME type detection and override
|
|
552
|
+
mimeType = handleIncorrectFontMimeType(urlObj, mimeType, body, network.fontDomains, meta);
|
|
553
|
+
|
|
549
554
|
// if we detect a font mime, we dont want to override it as different browsers may behave
|
|
550
555
|
// differently for incorrect mimetype in font response, but we want to treat it as a
|
|
551
556
|
// font anyway as font responses from the browser may not be properly encoded,
|
|
552
557
|
// so request them directly.
|
|
553
|
-
if (mimeType !== null &&
|
|
558
|
+
if ((_mimeType = mimeType) !== null && _mimeType !== void 0 && _mimeType.includes('font') || detectedMime && detectedMime.includes('font')) {
|
|
554
559
|
log.debug('- Requesting asset directly', meta);
|
|
555
560
|
body = await makeDirectRequest(network, request, session);
|
|
556
561
|
log.debug('- Got direct response', meta);
|
package/dist/snapshot.js
CHANGED
|
@@ -152,7 +152,8 @@ function getSnapshotOptions(options, {
|
|
|
152
152
|
captureSrcset: config.discovery.captureSrcset,
|
|
153
153
|
userAgent: config.discovery.userAgent,
|
|
154
154
|
retry: config.discovery.retry,
|
|
155
|
-
scrollToBottom: config.discovery.scrollToBottom
|
|
155
|
+
scrollToBottom: config.discovery.scrollToBottom,
|
|
156
|
+
fontDomains: config.discovery.fontDomains
|
|
156
157
|
}
|
|
157
158
|
}, options], (path, prev, next) => {
|
|
158
159
|
var _next, _next2, _next3;
|
package/dist/utils.js
CHANGED
|
@@ -26,6 +26,61 @@ export function normalizeURL(url) {
|
|
|
26
26
|
return `${protocol}//${host}${pathname}${search}`;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Detects font MIME type from file content by checking magic bytes.
|
|
31
|
+
* Handles string-based signatures (WOFF, OTTO) and binary signatures (TTF).
|
|
32
|
+
*/
|
|
33
|
+
export function detectFontMimeType(buffer) {
|
|
34
|
+
try {
|
|
35
|
+
if (!buffer || buffer.length < 4) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Convert the first 4 bytes into two formats for matching:
|
|
40
|
+
// 1. A lowercase string for text-based signatures (e.g., 'otto')
|
|
41
|
+
// 2. A hex string for binary/null-byte signatures (e.g., '00010000')
|
|
42
|
+
const headerString = buffer.slice(0, 4).toString('binary').toLowerCase();
|
|
43
|
+
const headerHex = buffer.slice(0, 4).toString('hex');
|
|
44
|
+
const mimeMap = {
|
|
45
|
+
woff: 'font/woff',
|
|
46
|
+
wof2: 'font/woff2',
|
|
47
|
+
otto: 'font/otf',
|
|
48
|
+
'00010000': 'font/ttf'
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Return the match if it exists in our map for either format
|
|
52
|
+
return mimeMap[headerString] || mimeMap[headerHex] || null;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
// Fail silently and return null if buffer reading fails
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const KNOWN_PROBLEMATIC_FONT_DOMAINS = ['fonts.gstatic.com'];
|
|
59
|
+
function isKnownFontDomain(hostname, userConfiguredFontDomains = []) {
|
|
60
|
+
return KNOWN_PROBLEMATIC_FONT_DOMAINS.includes(hostname) || userConfiguredFontDomains.includes(hostname);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handles Inncorrect Fonts MIME type detection and override
|
|
64
|
+
// Google Fonts sometimes returns font files with text/html mime type
|
|
65
|
+
// This function detects the actual font format from the file content
|
|
66
|
+
export function handleIncorrectFontMimeType(urlObj, mimeType, body, userConfiguredFontDomains, meta) {
|
|
67
|
+
// Check if this is a Google Fonts request with incorrect mime type
|
|
68
|
+
const log = logger('core:utils');
|
|
69
|
+
let isFontDomain = isKnownFontDomain(urlObj.hostname, userConfiguredFontDomains);
|
|
70
|
+
if (isFontDomain && mimeType === 'text/html') {
|
|
71
|
+
const detectedFontMime = detectFontMimeType(body);
|
|
72
|
+
if (detectedFontMime) {
|
|
73
|
+
mimeType = detectedFontMime;
|
|
74
|
+
log.warn(`- Detected Google Font as ${detectedFontMime} from content, overriding mime type`, meta);
|
|
75
|
+
} else {
|
|
76
|
+
// Fallback to generic font mime type if we can't detect the specific format
|
|
77
|
+
mimeType = 'application/font-woff2';
|
|
78
|
+
log.warn('- Google Font detected but format unclear, treating as font', meta);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return mimeType;
|
|
82
|
+
}
|
|
83
|
+
|
|
29
84
|
/* istanbul ignore next: tested, but coverage is stripped */
|
|
30
85
|
// Returns the body for automateScreenshot in structure
|
|
31
86
|
export function percyAutomateRequestHandler(req, percy) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/core",
|
|
3
|
-
"version": "1.31.6-beta.
|
|
3
|
+
"version": "1.31.6-beta.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"test:types": "tsd"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@percy/client": "1.31.6-beta.
|
|
47
|
-
"@percy/config": "1.31.6-beta.
|
|
48
|
-
"@percy/dom": "1.31.6-beta.
|
|
49
|
-
"@percy/logger": "1.31.6-beta.
|
|
50
|
-
"@percy/monitoring": "1.31.6-beta.
|
|
51
|
-
"@percy/webdriver-utils": "1.31.6-beta.
|
|
46
|
+
"@percy/client": "1.31.6-beta.7",
|
|
47
|
+
"@percy/config": "1.31.6-beta.7",
|
|
48
|
+
"@percy/dom": "1.31.6-beta.7",
|
|
49
|
+
"@percy/logger": "1.31.6-beta.7",
|
|
50
|
+
"@percy/monitoring": "1.31.6-beta.7",
|
|
51
|
+
"@percy/webdriver-utils": "1.31.6-beta.7",
|
|
52
52
|
"content-disposition": "^0.5.4",
|
|
53
53
|
"cross-spawn": "^7.0.3",
|
|
54
54
|
"extract-zip": "^2.0.1",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"ws": "^8.17.1",
|
|
62
62
|
"yaml": "^2.4.1"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "55a4ac55d8a7a41f2d66bc5887ce8631a8e5ffd7"
|
|
65
65
|
}
|