commit 65449da7109a4ab14eb8372cc6da2f8581e98b99
parent ed0ed50b99780b6f2784065b1da385b3230c7c51
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Tue, 29 Sep 2026 21:39:34 -0400
export: restore-no-refire covers a second mount — a tg= link, then another page and Back, and a ch= link, then the header's Search link, each leave the stored query held with no shard fetched (review M1)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
1 file changed, 73 insertions(+), 2 deletions(-)
diff --git a/export/e2e/restore-no-refire.spec.ts b/export/e2e/restore-no-refire.spec.ts
@@ -1,5 +1,6 @@
import { expect, test, type Page } from "@playwright/test";
-import { installRoutes } from "./helpers";
+import { TAG_TOPIC } from "./fixtures/data";
+import { installRoutes, installTagRoutes } from "./helpers";
// Release 8 slice E. The search session restored from localStorage loads the
// query and the filters but does NOT run the search on first load: a restored
@@ -8,7 +9,9 @@ import { installRoutes } from "./helpers";
// asked for this time. The visitor runs it — Search / Enter. A query on the
// URL (`qt=`) is a shared link, i.e. the visitor asking, and still runs.
// Release 14: until then the page shows no results area at all — the held
-// query no longer sits over a browse listing.
+// query no longer sits over a browse listing. A link that carries only a
+// filter (`tg=`, `ch=`) shows its results but runs no query, so a stored one
+// stays held on that load AND on every later mount in the same visit.
const STORAGE_KEY = "ytdlp-tb:export-filters";
const SHARD = /\/transcripts\/[^/]+\/page-\d+\.json$/;
@@ -53,6 +56,24 @@ async function seedStoredSearch(page: Page) {
);
}
+// A route outside the workspace unmounts the search session; coming back
+// mounts it again in the same page life.
+async function leaveForUseWithAi(page: Page) {
+ await page
+ .getByRole("banner")
+ .getByRole("link", { name: "Use with AI", exact: true })
+ .click();
+ await expect(page).toHaveURL(/use-with-ai/, { timeout: 20_000 });
+}
+
+async function expectHeld(page: Page) {
+ await expect(leafInput(page)).toHaveValue("alpha");
+ await expect(page.getByTestId("search-submit")).toHaveAttribute(
+ "data-dirty",
+ "true",
+ );
+}
+
test.describe("restored search waits for the visitor", () => {
test.beforeEach(async ({ page }) => {
await installRoutes(page);
@@ -124,4 +145,54 @@ test.describe("restored search waits for the visitor", () => {
"false",
);
});
+
+ test("a filter-only link shows its results and leaves a stored query held, then and after Back", async ({
+ page,
+ }) => {
+ await installTagRoutes(page);
+ const shards = countShards(page);
+ await seedStoredSearch(page);
+
+ shards.n = 0;
+ await page.goto(`/?tg=${TAG_TOPIC}`);
+ // The link asked: its results show, under its filter…
+ await expect(page.getByTestId("results-summary")).toHaveText("All videos (1)");
+ // …and the stored query is in the box, held.
+ await expectHeld(page);
+
+ await leaveForUseWithAi(page);
+ await page.goBack();
+ await expect(page).not.toHaveURL(/use-with-ai/);
+ // A second mount in the same visit: still held, still the listing.
+ await expectHeld(page);
+ await expect(page.getByTestId("results-summary")).toHaveText("All videos (1)");
+ await page.waitForTimeout(1_500);
+ expect(shards.n).toBe(0);
+ });
+
+ test("a filter-only link, then the header's Search link: the stored query stays held", async ({
+ page,
+ }) => {
+ const shards = countShards(page);
+ await seedStoredSearch(page);
+
+ shards.n = 0;
+ // Under a filter link the stored session is not read at all.
+ await page.goto(`/?ch=${encodeURIComponent("Nobody")}`);
+ await expect(page.getByTestId("results-summary")).toContainText("All videos");
+ await expect(leafInput(page)).toHaveValue("");
+
+ await leaveForUseWithAi(page);
+ await page
+ .getByRole("banner")
+ .getByRole("link", { name: "Search", exact: true })
+ .click();
+ await expect(page).not.toHaveURL(/use-with-ai/, { timeout: 20_000 });
+ // The plain search page reads the stored session: the query is held, and
+ // the listing shows because the visitor asked earlier in this visit.
+ await expectHeld(page);
+ await expect(page.getByTestId("results-summary")).toHaveText("All videos (3)");
+ await page.waitForTimeout(1_500);
+ expect(shards.n).toBe(0);
+ });
});