authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-05 00:28:48-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-05 00:28:48-07:00
log3e544f8cda371dc565c806508a9ab38b80c96ff7
treea151e167784c34865b091e23caf2eb9c1ed1c705
parent4e59b06b84fdfa36f78b4fc9079dff88b4ff3dc4
signature Signed by PGP key B5690EEEBB952194

refactor(shared): test favicon selection through public API (#10005)


2 files changed, 18 insertions(+), 13 deletions(-)

packages/shared/src/favicon.test.ts+16-11
......@@ -1,11 +1,6 @@
11import { describe, expect, it } from "@effect/vitest";
22
3import {
4 explicitFaviconUrl,
5 faviconUrlForOrigin,
6 faviconUrlForPage,
7 toolActivityFaviconUrl,
8} from "./favicon.ts";
3import { faviconUrlForOrigin, toolActivityFaviconUrl } from "./favicon.ts";
94
105describe("faviconUrlForOrigin", () => {
116 it.each([
......@@ -46,12 +41,12 @@ describe("faviconUrlForOrigin", () => {
4641 );
4742});
4843
49describe("faviconUrlForPage", () => {
44describe("toolActivityFaviconUrl", () => {
5045 it("uses the page origin instead of a third-party favicon service", () => {
51 expect(faviconUrlForPage("https://example.com/docs/page?q=1")).toBe(
46 expect(toolActivityFaviconUrl({ pageUrl: "https://example.com/docs/page?q=1" }, "light")).toBe(
5247 "https://example.com/favicon.ico",
5348 );
54 expect(faviconUrlForPage("http://localhost:5173/app")).toBe(
49 expect(toolActivityFaviconUrl({ pageUrl: "http://localhost:5173/app" }, "light")).toBe(
5550 "http://localhost:5173/favicon.ico",
5651 );
5752 });
......@@ -86,7 +81,17 @@ describe("faviconUrlForPage", () => {
8681 });
8782
8883 it("accepts provider-supplied image URLs but rejects extension URLs", () => {
89 expect(explicitFaviconUrl("https://example.com/icon.png")).toBe("https://example.com/icon.png");
90 expect(explicitFaviconUrl("chrome-extension://example/_favicon/")).toBeNull();
84 expect(
85 toolActivityFaviconUrl(
86 { pageUrl: "https://example.com/docs", faviconUrl: "https://example.com/icon.png" },
87 "light",
88 ),
89 ).toBe("https://example.com/icon.png");
90 expect(
91 toolActivityFaviconUrl(
92 { pageUrl: "https://example.com/docs", faviconUrl: "chrome-extension://example/_favicon/" },
93 "light",
94 ),
95 ).toBe("https://example.com/favicon.ico");
9196 });
9297});
packages/shared/src/favicon.ts+2-2
......@@ -5,7 +5,7 @@ import { isPublicFaviconHost } from "./hostClassification.ts";
55 * conventional favicon and let the image element fall back to a browser glyph.
66 * Chrome-backed tools can pass their tab's explicit favicon URL separately.
77 */
8export function faviconUrlForPage(rawUrl: string | null | undefined, _size = 32): string | null {
8function faviconUrlForPage(rawUrl: string | null | undefined, _size = 32): string | null {
99 if (!rawUrl || rawUrl.length > 4096) return null;
1010 try {
1111 const pageUrl = new URL(rawUrl);
......@@ -40,7 +40,7 @@ function themedFaviconUrlForPage(
4040}
4141
4242/** Accepts image URLs supplied by a trusted provider event. */
43export function explicitFaviconUrl(rawUrl: string | null | undefined): string | null {
43function explicitFaviconUrl(rawUrl: string | null | undefined): string | null {
4444 if (!rawUrl || rawUrl.length > 4096) return null;
4545 try {
4646 const url = new URL(rawUrl);