Series by slug, id or episode link; portrait original and banner; age-checked mature series resolve with a warning and no current covers; Wayback history keeps only this series' captures. Co-Authored-By: Claude Opus 5.5 <[email protected]>
80 lines
4.3 KiB
TypeScript
80 lines
4.3 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { allowedFetchHosts, findSource } from "../src/core/sources/registry";
|
|
import { SourceError } from "../src/core/sources/source";
|
|
import { webtoons } from "../src/core/sources/webtoons";
|
|
import { FakeTransport, text } from "./helpers/fake-transport";
|
|
import { fixtureText } from "./helpers/fixtures";
|
|
|
|
const TOG = "https://www.webtoons.com/-/-/-/list?title_no=95";
|
|
|
|
test("resolve fetches the /-/-/-/ form and reads the canonical page", async () => {
|
|
const fake = new FakeTransport().on(TOG, async () => text(await fixtureText("webtoons/tower-of-god.html")));
|
|
const series = await webtoons.resolve(new URL("https://m.webtoons.com/en/made-up-slug/list?title_no=95"), { transport: fake });
|
|
expect(fake.urls()).toEqual([TOG]);
|
|
expect(series).toEqual({
|
|
source: "webtoons",
|
|
externalId: "95",
|
|
title: "Tower of God",
|
|
language: "en",
|
|
canonicalUrl: "https://www.webtoons.com/en/fantasy/tower-of-god/list?title_no=95",
|
|
archiveUrls: [
|
|
"www.webtoons.com/en/fantasy/tower-of-god/list?title_no=95",
|
|
"m.webtoons.com/en/fantasy/tower-of-god/list?title_no=95",
|
|
],
|
|
mature: false,
|
|
flags: { canvas: false },
|
|
});
|
|
});
|
|
|
|
test("currentCovers reuses the page fetched by resolve and marks covers current", async () => {
|
|
const fake = new FakeTransport().on(TOG, async () => text(await fixtureText("webtoons/tower-of-god.html")));
|
|
const series = await webtoons.resolve(new URL(TOG), { transport: fake });
|
|
const covers = await webtoons.currentCovers(series, { transport: fake });
|
|
expect(fake.calls.length).toBe(1);
|
|
expect(covers.map((c) => c.role)).toEqual(["poster", "square", "banner", "foreground"]);
|
|
expect(covers.every((c) => c.current)).toBe(true);
|
|
});
|
|
|
|
test("canvas and mature flags come through", async () => {
|
|
const fake = new FakeTransport()
|
|
.on("https://www.webtoons.com/-/canvas/-/list?title_no=693372", async () => text(await fixtureText("webtoons/crow-time-canvas.html")))
|
|
.on("https://www.webtoons.com/-/-/-/list?title_no=6065", async () => text(await fixtureText("webtoons/zombie-revelation-mature.html")));
|
|
const canvas = await webtoons.resolve(new URL("https://www.webtoons.com/en/canvas/crow-time/list?title_no=693372"), { transport: fake });
|
|
expect(canvas.flags.canvas).toBe(true);
|
|
const mature = await webtoons.resolve(new URL("https://www.webtoons.com/-/-/-/list?title_no=6065"), { transport: fake });
|
|
expect(mature.mature).toBe(true);
|
|
});
|
|
|
|
test("a canvas series linked in the /-/-/-/ form: the official form 404s, the canvas form is tried", async () => {
|
|
const fake = new FakeTransport()
|
|
.on("https://www.webtoons.com/-/-/-/list?title_no=693372", () => text("not found", 404))
|
|
.on("https://www.webtoons.com/-/canvas/-/list?title_no=693372", async () => text(await fixtureText("webtoons/crow-time-canvas.html")));
|
|
const series = await webtoons.resolve(new URL("https://www.webtoons.com/-/-/-/list?title_no=693372"), { transport: fake });
|
|
expect(fake.urls()).toEqual([
|
|
"https://www.webtoons.com/-/-/-/list?title_no=693372",
|
|
"https://www.webtoons.com/-/canvas/-/list?title_no=693372",
|
|
]);
|
|
expect(series.flags.canvas).toBe(true);
|
|
expect(series.canonicalUrl).toContain("/en/canvas/crow-time/");
|
|
});
|
|
|
|
test("a Webtoons error is a SourceError with the status", async () => {
|
|
const fake = new FakeTransport().on(() => true, () => text("gone", 404));
|
|
await expect(webtoons.resolve(new URL(TOG), { transport: fake })).rejects.toThrow(SourceError);
|
|
await expect(webtoons.resolve(new URL(TOG), { transport: fake })).rejects.toThrow(/404/);
|
|
});
|
|
|
|
test("registry finds the source and builds the proxy allowlist", () => {
|
|
expect(findSource(new URL("https://www.webtoons.com/en/x/list?title_no=1"))).toBe(webtoons);
|
|
expect(findSource(new URL("https://www.lezhin.com/en/comic/x"))).toBeUndefined();
|
|
expect([...allowedFetchHosts()].sort()).toEqual(
|
|
["d30womf5coomej.cloudfront.net", "m.tapas.io", "m.webtoons.com", "swebtoon-phinf.pstatic.net", "tapas.io", "us-a.tapas.io",
|
|
"web.archive.org", "www.tapas.io", "www.webtoons.com"]);
|
|
});
|
|
|
|
test("isSameSeries checks title_no", () => {
|
|
const series = { externalId: "95" } as Parameters<typeof webtoons.isSameSeries>[1];
|
|
expect(webtoons.isSameSeries("https://www.webtoons.com/-/-/-/list?title_no=95", series)).toBe(true);
|
|
expect(webtoons.isSameSeries("https://www.webtoons.com/-/-/-/list?title_no=318", series)).toBe(false);
|
|
});
|