commit 63dcce2d7579dc3bbc50a3ef382cd954eef41f23
parent eee3543c9e35953c9cb782e3d79d287df798ac79
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Sat, 26 Sep 2026 23:18:10 -0400
export(e2e): a site page and the hub have no link to ko-fi.com
The two Ko-fi mark tests become one negative check each: once the footer
is visible, no <a href*="ko-fi.com"> anywhere on the page. expectKofiMarkLast
and KOFI_SYMBOL_SHA256 are gone from e2e/helpers.ts, which is back to slice
O's parent byte for byte.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 8 insertions(+), 79 deletions(-)
diff --git a/export/e2e-hub/official-instances.spec.ts b/export/e2e-hub/official-instances.spec.ts
@@ -1,5 +1,4 @@
import { expect, test, type Page, type Route } from "@playwright/test";
-import { expectKofiMarkLast } from "../e2e/helpers";
// The hub's "Official Instances": one card per built-in member
// (hub-sites.json), carrying the homepage's own figures for it when the hub was
@@ -117,17 +116,14 @@ test.describe("hub official instances", () => {
).toHaveCount(0);
});
- test("the hub footer carries the Ko-fi mark, once, last in the social row", async ({
- page,
- }) => {
+ test("the hub has no link to ko-fi.com", async ({ page }) => {
await stubMember(page);
await page.route("**/hub-summary.json", (r) =>
r.fulfill({ status: 404, body: "" }),
);
await page.goto("/");
- // The same mark as every site (the operator's 2026-09-26 ruling). The
- // hub's own "Ko-fi" text link is gone: one Ko-fi per footer.
- await expectKofiMarkLast(page);
+ await expect(page.locator("footer")).toBeVisible();
+ await expect(page.locator('a[href*="ko-fi.com"]')).toHaveCount(0);
});
test("without hub-summary.json, the card renders with no figures", async ({
diff --git a/export/e2e/helpers.ts b/export/e2e/helpers.ts
@@ -1,6 +1,4 @@
-import { createHash } from "node:crypto";
-import { expect, type Page, type Route } from "@playwright/test";
-import { KOFI_URL } from "../../common/lib/project";
+import type { Page, Route } from "@playwright/test";
import {
channelSubsManifest,
channelTranscriptsManifest,
@@ -175,57 +173,3 @@ export async function closeModal(page: Page) {
.getByRole("button", { name: "Mark clip start at current time" })
.waitFor({ state: "detached" });
}
-
-// sha256 of Ko-fi's official `kofi_symbol.svg` (their brand-asset zip), which
-// the export vendors byte-for-byte as public/kofi-symbol.svg: a brand asset is
-// used as shipped, never recoloured or re-exported.
-export const KOFI_SYMBOL_SHA256 =
- "f5a2d5f1abb5c7f13392ecf6e7d5dffc8bef77917ab59c28a6080deab52f5078";
-
-// The footer's Ko-fi mark, on every build (site and hub): exactly one Ko-fi
-// link on the page, the LAST item of the footer's social row, opening Ko-fi in
-// a new tab, with no visible text — only the official symbol, which is drawn
-// (not a broken image) and served unmodified.
-export async function expectKofiMarkLast(page: Page) {
- const footer = page.locator("footer");
- const kofi = footer.getByRole("link", { name: "Ko-fi", exact: true });
- await expect(kofi).toHaveCount(1);
- // One per page: no second Ko-fi link anywhere (the hub's old text link).
- await expect(page.getByRole("link", { name: /ko-?fi/i })).toHaveCount(1);
- await expect(page.locator(`a[href="${KOFI_URL}"]`)).toHaveCount(1);
- await expect(kofi).toBeVisible();
- await expect(kofi).toHaveAttribute("href", KOFI_URL);
- await expect(kofi).toHaveAttribute("target", "_blank");
- await expect(kofi).toHaveAttribute("rel", "noopener noreferrer");
- // No copy: the mark is the whole link.
- expect((await kofi.innerText()).trim()).toBe("");
-
- const img = kofi.locator('img[src="/kofi-symbol.svg"]');
- await expect(img).toHaveCount(1);
- await expect(img).toHaveAttribute("alt", "");
- await expect
- .poll(() =>
- img.evaluate((el) => {
- const i = el as HTMLImageElement;
- return i.complete && i.naturalWidth > 0;
- }),
- )
- .toBe(true);
-
- // `has` is queried from each <ul>, so it takes a page-rooted locator: `kofi`
- // itself starts at <footer> and would look for a footer inside the list.
- const row = footer
- .locator("ul")
- .filter({ has: page.getByRole("link", { name: "Ko-fi", exact: true }) });
- await expect(row).toHaveCount(1);
- await expect(
- row.locator(":scope > li").last().getByRole("link"),
- ).toHaveAccessibleName("Ko-fi");
-
- const res = await page.request.get("/kofi-symbol.svg");
- expect(res.status()).toBe(200);
- expect(res.headers()["content-type"]).toMatch(/^image\/svg\+xml/);
- expect(createHash("sha256").update(await res.body()).digest("hex")).toBe(
- KOFI_SYMBOL_SHA256,
- );
-}
diff --git a/export/e2e/site-branding.spec.ts b/export/e2e/site-branding.spec.ts
@@ -1,6 +1,6 @@
import { test, expect } from "@playwright/test";
import { PROJECT_URL } from "../../common/lib/project";
-import { expectKofiMarkLast, installRoutes } from "./helpers";
+import { installRoutes } from "./helpers";
// The export app is built per-site; its SSR branding (document title, header,
// home tagline, footer social links) comes from currentSite() reading the
@@ -45,22 +45,11 @@ test("footer credits the project, ungated and in the same tab", async ({
await expect(footer).toContainText("Built with Archilyzer");
});
-test("every build carries the Ko-fi mark, last in the social row", async ({
- page,
-}) => {
+test("a site page has no link to ko-fi.com", async ({ page }) => {
await installRoutes(page);
await page.goto("/");
- // The operator's 2026-09-26 ruling replaced "hub and homepage only": the
- // project's Ko-fi is on every site, as Ko-fi's official symbol after the
- // site's own social links, with no copy around it.
- await expectKofiMarkLast(page);
- // The site's own links come first, in the same row.
- const row = page
- .locator("footer ul")
- .filter({ has: page.getByRole("link", { name: "Ko-fi", exact: true }) });
- const items = row.locator(":scope > li");
- await expect(items).toHaveCount(2);
- await expect(items.first().getByRole("link")).toHaveAccessibleName("GitHub");
+ await expect(page.locator("footer")).toBeVisible();
+ await expect(page.locator('a[href*="ko-fi.com"]')).toHaveCount(0);
});
test("the Downloads eyebrow appears only when something is behind it", async ({