commit 6e6ec9cae2d090a0b36ebee08c51c2e4f1dda4bd
parent bfdb702aefdf9d1a7db08e8b7459b48c07136e8d
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Tue, 6 Oct 2026 14:37:17 -0400
editor: the site picker stamps data-hydrated, and site-scope.spec's charts test waits for it (a pick before hydration was lost: two long-run failures)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/editor/app/components/SiteScopeSelect.tsx b/editor/app/components/SiteScopeSelect.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState } from "react";
+import { useEffect, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import {
ALL_SITES,
@@ -22,6 +22,8 @@ export type SiteScopeOption = { siteId: string; siteTitle: string };
// navigation it starts lands), the site a /sites/<id>/… path names, a valid
// `?site=` on the URL (a link's scope for that page), the stored selection.
export function SiteScopeSelect({ sites }: { sites: SiteScopeOption[] }) {
+ const [hydrated, setHydrated] = useState(false);
+ useEffect(() => setHydrated(true), []);
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
@@ -95,6 +97,10 @@ export function SiteScopeSelect({ sites }: { sites: SiteScopeOption[] }) {
value={resolved.value}
onChange={(e) => void onChange(e.target.value)}
aria-label="Active site"
+ // A TESTING AFFORDANCE, as on the operation lanes: a change that lands
+ // before React hydrates is lost (the server-rendered value already
+ // reads right), so a spec waits for this before it picks a site.
+ data-hydrated={hydrated ? "true" : undefined}
className="rounded border border-border bg-card px-2 py-1 text-sm"
>
{multi && <option value={ALL_SITES}>All sites</option>}
diff --git a/editor/e2e/site-scope.spec.ts b/editor/e2e/site-scope.spec.ts
@@ -71,6 +71,9 @@ test("charts is a site's tab, and the picker follows the path", async ({
await page.goto("/sites/alpha/charts");
await expect(page.getByText(/author the default dashboard/i)).toBeVisible();
await expect(page.getByLabel("Active site")).toHaveValue("alpha");
+ // Hydrated first: a pick before React attaches is lost (it failed this way
+ // in long runs, release 18).
+ await expect(page.getByLabel("Active site")).toHaveAttribute("data-hydrated", "true");
await page.getByLabel("Active site").selectOption("beta");
await expect(page).toHaveURL(/\/sites\/beta\/charts$/);
await expect(page.getByText(/author the default dashboard/i)).toContainText(
@@ -84,6 +87,7 @@ test("charts is a site's tab, and the picker follows the path", async ({
await expectNoSiteParam(page);
// "All sites" is the family page.
await page.goto("/sites/beta/charts");
+ await expect(page.getByLabel("Active site")).toHaveAttribute("data-hydrated", "true");
await page.getByLabel("Active site").selectOption("__all__");
await expect(page).toHaveURL(/\/sites$/);
});