feat(web): filter tabs and recent strip by status bucket

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 12:56:12 +07:00
parent f783b72a81
commit 5aae678668
2 changed files with 115 additions and 16 deletions
+86
View File
@@ -513,3 +513,89 @@ func TestUIListNewTab(t *testing.T) {
t.Fatal("new tab included a series already caught up")
}
}
// seedStatusRows puts one series in each bucket, the archived one also
// favourited and with a new chapter out, so a leak into any reading-bucket tab
// shows up as a failure rather than passing by accident.
func seedStatusRows(t *testing.T, store *Store) {
t.Helper()
// floatPtr already exists in store_test.go — same package, reuse it.
rows := []Bookmark{
{Key: "asura:reading", Site: "asura", SeriesID: "reading", Title: "ReadingOne",
Status: statusReading, LastChapterNum: 10, Favorite: true,
LatestChapter: "11", LatestChapterNum: floatPtr(11)},
{Key: "asura:archived", Site: "asura", SeriesID: "archived", Title: "ArchivedOne",
Status: statusArchived, LastChapterNum: 5, Favorite: true,
LatestChapter: "99", LatestChapterNum: floatPtr(99)},
{Key: "asura:finished", Site: "asura", SeriesID: "finished", Title: "FinishedOne",
Status: statusFinished, LastChapterNum: 200, Favorite: true},
}
for _, b := range rows {
b.UpdatedAt = time.Now().UnixMilli()
if _, err := store.Upsert(b); err != nil {
t.Fatalf("seed %s: %v", b.Key, err)
}
}
}
func TestTabsShowOnlyTheirBucket(t *testing.T) {
cfg := webConfig()
srv, store := newWebTestServer(t, cfg)
seedStatusRows(t, store)
cases := []struct {
tab string
want, dontWant []string
}{
{"all", []string{"ReadingOne"}, []string{"ArchivedOne", "FinishedOne"}},
{"new", []string{"ReadingOne"}, []string{"ArchivedOne", "FinishedOne"}},
{"fav", []string{"ReadingOne"}, []string{"ArchivedOne", "FinishedOne"}},
{"archived", []string{"ArchivedOne"}, []string{"ReadingOne", "FinishedOne"}},
{"finished", []string{"FinishedOne"}, []string{"ReadingOne", "ArchivedOne"}},
}
for _, tc := range cases {
t.Run(tc.tab, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/ui/list?tab="+tc.tab, nil)
req.AddCookie(sessionCookie(t, cfg))
rr := httptest.NewRecorder()
srv.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("status = %d, want 200", rr.Code)
}
body := rr.Body.String()
for _, w := range tc.want {
if !strings.Contains(body, w) {
t.Fatalf("tab %s missing %s", tc.tab, w)
}
}
for _, d := range tc.dontWant {
if strings.Contains(body, d) {
t.Fatalf("tab %s leaked %s", tc.tab, d)
}
}
})
}
}
func TestRecentStripExcludesArchivedAndFinished(t *testing.T) {
cfg := webConfig()
srv, store := newWebTestServer(t, cfg)
seedStatusRows(t, store)
req := httptest.NewRequest(http.MethodGet, "/?tab=archived", nil)
req.AddCookie(sessionCookie(t, cfg))
rr := httptest.NewRecorder()
srv.ServeHTTP(rr, req)
strip := rr.Body.String()
if i := strings.Index(strip, `id="list"`); i >= 0 {
strip = strip[:i] // everything above the list is the recent section
}
if strings.Contains(strip, "ArchivedOne") || strings.Contains(strip, "FinishedOne") {
t.Fatal("recent strip included an archived or finished series")
}
if !strings.Contains(strip, "ReadingOne") {
t.Fatal("recent strip dropped the reading series")
}
}