Files
hyperframes/packages/engine/src/services/frameCapture.test.ts
T
James RussoandClaude Opus 4.7 686e45dac0 fix(engine): suppress font-load 404s by checking console location URL (#313)
Chrome's "Failed to load resource" message text does not include the failing
URL — it's only on msg.location().url. The previous filter in frameCapture.ts
only checked msg.text(), so every font 404 (e.g. Google Fonts <link> tags
in sandboxed render environments) fell through to the "[non-blocking]"
prefix instead of being suppressed.

Extract the classifier into isFontResourceError() and match against both
text and location.url, and extend the extension match to .ttf/.otf. Adds
a unit test covering the URL-in-location, URL-in-text, and non-font cases.

This is a targeted fix for the render-output noise that PR #311 attempted
to address by adding a ~120-entry SYSTEM_FONTS skip list. That approach
silently shadowed existing FONT_ALIASES (arial→inter, helvetica→inter,
courier new→jetbrains-mono, segoe ui→roboto, etc.) and changed render
output on Linux fleets that don't have those fonts installed. Fixing the
console-log filter here suppresses the noise without changing any font
resolution behavior.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:38:46 -07:00

113 lines
3.2 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { isFontResourceError } from "./frameCapture.js";
describe("isFontResourceError", () => {
it("matches Google Fonts CSS load failures via location.url", () => {
expect(
isFontResourceError(
"error",
"Failed to load resource: net::ERR_FAILED",
"https://fonts.googleapis.com/css2?family=Inter",
),
).toBe(true);
});
it("matches gstatic font binaries via location.url", () => {
expect(
isFontResourceError(
"error",
"Failed to load resource: the server responded with a status of 404 (Not Found)",
"https://fonts.gstatic.com/s/inter/v12/foo.woff2",
),
).toBe(true);
});
it("matches self-hosted woff2 failures", () => {
expect(
isFontResourceError(
"error",
"Failed to load resource: net::ERR_CONNECTION_REFUSED",
"http://localhost:9999/font.woff2",
),
).toBe(true);
});
it("matches .ttf and .otf URLs", () => {
expect(
isFontResourceError("error", "Failed to load resource: 404", "http://example.com/a.ttf"),
).toBe(true);
expect(
isFontResourceError("error", "Failed to load resource: 404", "http://example.com/b.otf"),
).toBe(true);
});
it("does NOT match non-font resources (images, scripts, videos)", () => {
expect(
isFontResourceError("error", "Failed to load resource: 404", "https://example.com/img.png"),
).toBe(false);
expect(
isFontResourceError(
"error",
"Failed to load resource: 404",
"https://cdn.example.com/bundle.js",
),
).toBe(false);
expect(
isFontResourceError("error", "Failed to load resource: 404", "https://example.com/video.mp4"),
).toBe(false);
});
it("does NOT match when location.url is missing and text has no URL (safe default)", () => {
expect(isFontResourceError("error", "Failed to load resource: 404", "")).toBe(false);
});
it("still matches when URL appears in text (older Chrome formats)", () => {
expect(
isFontResourceError(
"error",
"Failed to load resource: https://fonts.googleapis.com/... 404",
"",
),
).toBe(true);
});
it("does NOT match non-error console messages", () => {
expect(
isFontResourceError(
"warn",
"Failed to load resource: 404",
"https://fonts.googleapis.com/css2",
),
).toBe(false);
expect(
isFontResourceError(
"info",
"Failed to load resource: 404",
"https://fonts.googleapis.com/css2",
),
).toBe(false);
});
it("does NOT match unrelated error messages", () => {
expect(isFontResourceError("error", "Uncaught ReferenceError: x is not defined", "")).toBe(
false,
);
expect(
isFontResourceError("error", "Some other error", "https://fonts.googleapis.com/css2"),
).toBe(false);
});
it("is case-insensitive for URL matching", () => {
expect(
isFontResourceError(
"error",
"Failed to load resource: 404",
"https://FONTS.GOOGLEAPIS.COM/css2",
),
).toBe(true);
expect(
isFontResourceError("error", "Failed to load resource: 404", "http://example.com/FONT.WOFF2"),
).toBe(true);
});
});