package main import "testing" // Trimmed from https://asurascans.com/comics/chronicles-of-the-demon-faction-f886a8af // fetched 2026-07-26. The first anchor is the "First Chapter" shortcut: it is a // real chapter link with no "Chapter N" text, and it must not be mistaken for // the latest just because it parses. const asuraSeriesFixture = ` First Chapter Chapter 179 Chapter 181 Chapter 180 ` // A chapter link belonging to a different series, of the kind a "you might also // like" strip would introduce. Slug scoping must exclude it. const asuraCrossSeriesFixture = asuraSeriesFixture + ` Chapter 999 ` // Trimmed from https://demonicscans.org/manga/Catastrophic-Necromancer fetched // 2026-07-26. Note the raw "&", the doubled space after Chapter 0.5 Chapter 294 Chapter 296 Chapter 295 ` // What Cloudflare serves instead of the page when an IP's bot score flips. const challengeFixture = `Just a moment...
Checking your browser
` func TestLatestChapterFrom(t *testing.T) { const asuraURL = "https://asurascans.com/comics/chronicles-of-the-demon-faction-f886a8af" const demonicURL = "https://demonicscans.org/manga/Catastrophic-Necromancer" tests := []struct { name string site string seriesURL string body string wantOK bool wantNum float64 wantLabel string }{ { name: "asura takes the max, not the last listed", site: "asura", seriesURL: asuraURL, body: asuraSeriesFixture, wantOK: true, wantNum: 181, wantLabel: "Chapter 181", }, { name: "asura ignores another series' chapter links", site: "asura", seriesURL: asuraURL, body: asuraCrossSeriesFixture, wantOK: true, wantNum: 181, wantLabel: "Chapter 181", }, { name: "asura with an unparseable series url", site: "asura", seriesURL: "https://asurascans.com/", body: asuraSeriesFixture, wantOK: false, }, { name: "demonic takes the max across raw and escaped ampersands", site: "demonic", seriesURL: demonicURL, body: demonicSeriesFixture, wantOK: true, wantNum: 296, wantLabel: "Chapter 296", }, { name: "demonic keeps decimal chapters parseable", site: "demonic", seriesURL: demonicURL, body: `Chapter 0.5`, wantOK: true, wantNum: 0.5, wantLabel: "Chapter 0.5", }, { name: "empty body", site: "asura", seriesURL: asuraURL, body: "", wantOK: false, }, { name: "cloudflare challenge page", site: "asura", seriesURL: asuraURL, body: challengeFixture, wantOK: false, }, { name: "demonic markup handed to the asura rule", site: "asura", seriesURL: asuraURL, body: demonicSeriesFixture, wantOK: false, }, { name: "unknown site", site: "mangadex", seriesURL: "https://example.com/x", body: asuraSeriesFixture, wantOK: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, ok := latestChapterFrom(tt.site, tt.seriesURL, tt.body) if ok != tt.wantOK { t.Fatalf("ok = %v, want %v (got %+v)", ok, tt.wantOK, got) } if !tt.wantOK { return } if got.Num != tt.wantNum { t.Errorf("Num = %v, want %v", got.Num, tt.wantNum) } if got.Label != tt.wantLabel { t.Errorf("Label = %q, want %q", got.Label, tt.wantLabel) } }) } }