feat(ui-mode): add font preview to network tab (#32209)

Resolves https://github.com/microsoft/playwright/issues/32218

Currently, fonts are displayed as a raw binary file which does not give
any information to the users.
I replaced it with a simple font preview similar to the one found in the
dev tools of web browsers.
It is not a major feature but I think it is a nice addition and it might
be useful to somebody.

<img width="1043" alt="Screenshot 2024-08-17 at 18 33 46"
src="https://github.com/user-attachments/assets/a6cc7b57-7ea8-4a54-869d-57a44712597b">


https://github.com/user-attachments/assets/e52d9a72-fb2c-43c7-bfee-3d6d6edc6b6a
This commit is contained in:
Kuba Janik 2024-08-20 08:28:02 +02:00 committed by GitHub
parent 5271c26af1
commit f7e0bd3098
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 1 deletions

View file

@ -48,6 +48,22 @@
overflow: hidden;
}
.network-font-preview {
font-family: font-preview;
font-size: 30px;
line-height: 40px;
padding: 16px;
padding-left: 6px;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
}
.network-font-preview-error {
margin-top: 8px;
text-align: center;
}
.tab-network .toolbar {
min-height: 30px !important;
background-color: initial !important;

View file

@ -101,12 +101,13 @@ const ResponseTab: React.FunctionComponent<{
const BodyTab: React.FunctionComponent<{
resource: ResourceSnapshot;
}> = ({ resource }) => {
const [responseBody, setResponseBody] = React.useState<{ dataUrl?: string, text?: string, mimeType?: string } | null>(null);
const [responseBody, setResponseBody] = React.useState<{ dataUrl?: string, text?: string, mimeType?: string, font?: BinaryData } | null>(null);
React.useEffect(() => {
const readResources = async () => {
if (resource.response.content._sha1) {
const useBase64 = resource.response.content.mimeType.includes('image');
const isFont = resource.response.content.mimeType.includes('font');
const response = await fetch(`sha1/${resource.response.content._sha1}`);
if (useBase64) {
const blob = await response.blob();
@ -114,6 +115,9 @@ const BodyTab: React.FunctionComponent<{
const eventPromise = new Promise<any>(f => reader.onload = f);
reader.readAsDataURL(blob);
setResponseBody({ dataUrl: (await eventPromise).target.result });
} else if (isFont) {
const font = await response.arrayBuffer();
setResponseBody({ font });
} else {
const formattedBody = formatBody(await response.text(), resource.response.content.mimeType);
setResponseBody({ text: formattedBody, mimeType: resource.response.content.mimeType });
@ -128,11 +132,48 @@ const BodyTab: React.FunctionComponent<{
return <div className='network-request-details-tab'>
{!resource.response.content._sha1 && <div>Response body is not available for this request.</div>}
{responseBody && responseBody.font && <FontPreview font={responseBody.font} />}
{responseBody && responseBody.dataUrl && <img draggable='false' src={responseBody.dataUrl} />}
{responseBody && responseBody.text && <CodeMirrorWrapper text={responseBody.text} mimeType={responseBody.mimeType} readOnly lineNumbers={true}/>}
</div>;
};
const FontPreview: React.FunctionComponent<{
font: BinaryData;
}> = ({ font }) => {
const [isError, setIsError] = React.useState(false);
React.useEffect(() => {
let fontFace: FontFace;
try {
// note: constant font family name will lead to bugs
// when displaying two font previews.
fontFace = new FontFace('font-preview', font);
if (fontFace.status === 'loaded')
document.fonts.add(fontFace);
if (fontFace.status === 'error')
setIsError(true);
} catch {
setIsError(true);
}
return () => {
document.fonts.delete(fontFace);
};
}, [font]);
if (isError)
return <div className='network-font-preview-error'>Could not load font preview</div>;
return <div className='network-font-preview'>
ABCDEFGHIJKLM<br />
NOPQRSTUVWXYZ<br />
abcdefghijklm<br />
nopqrstuvwxyz<br />
1234567890
</div>;
};
function statusClass(statusCode: number): string {
if (statusCode < 300 || statusCode === 304)
return 'green-circle';