5e adaptateur, calqué sur `marmiton.ts` (le plus fin des wrappers scrapés) : `fetchDetail`/`parse` délèguent tels quels à `jsonLdRecipeAdapter` — une page recette quitoque.fr porte un `Recipe` schema.org, seul élément d'un tableau JSON-LD de premier niveau, déjà géré nativement par `findRecipeNode`. Seul `list()` est spécifique : `GET /recettes?page=N` (page 1 implicite si curseur absent), scrape des cartes `<a class="card__content_header" href="/recettes/…">` (image réelle dans `data-src`, `src` n'étant qu'un placeholder lazy-load ; `href` relatif résolu contre l'origine). Extraction agnostique à l'ordre des attributs. Pas de vraie recherche serveur sur le site → `query` est un filtre sous-chaîne « best effort » sur les titres de la page courante (même lacune assumée que `750g.ts`). Fin de liste = page sans aucune carte (comme `marmiton.ts`). `rekeySourceError` dupliqué localement (750g / manger-bouger en ont chacun une copie). Enregistré dans `registerAllRecipeSources()`. Tests : `quitoque.test.ts` (`stubFetchHtml`, pas de base) — scrape des cartes, pagination `?page=N`, filtre par query, fin de liste, erreurs re-labellisées `quitoque`, `parse` sur un JSON-LD tableau-de-premier- niveau. Vérifié localement, 9/9. + `sources-index.test.ts` couvre l'enregistrement. Docs : section `quitoque.ts` dans `backend-architecture.md` (+ correction de la ligne « n'enregistre que TheMealDB », devenue fausse). Closes #37 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
70 lines
2.6 KiB
TypeScript
70 lines
2.6 KiB
TypeScript
import { expect } from "chai";
|
|
import {
|
|
clearRecipeSources,
|
|
getRecipeSource,
|
|
listRecipeSources,
|
|
} from "../../src/lib/recipe-sources/recipe-source-registry.js";
|
|
import { registerAllRecipeSources } from "../../src/sources/index.js";
|
|
|
|
// Not exercised by any other test file — `registerAllRecipeSources` is
|
|
// deliberately never imported by `app.ts` (see its own doc comment), so
|
|
// nothing else in the suite triggers it. Registers/clears explicitly here
|
|
// rather than relying on module-load order, so this test's outcome doesn't
|
|
// depend on which other test file Mocha happens to load first.
|
|
describe("registerAllRecipeSources", () => {
|
|
afterEach(() => {
|
|
clearRecipeSources();
|
|
});
|
|
|
|
it("registers TheMealDB into the shared registry", () => {
|
|
registerAllRecipeSources();
|
|
|
|
const theMealDb = getRecipeSource("theMealDb");
|
|
expect(theMealDb).to.not.be.undefined;
|
|
expect(theMealDb?.name).to.equal("TheMealDB");
|
|
expect(listRecipeSources().map((adapter) => adapter.key)).to.include("theMealDb");
|
|
});
|
|
|
|
it("registers Marmiton into the shared registry", () => {
|
|
registerAllRecipeSources();
|
|
|
|
const marmiton = getRecipeSource("marmiton");
|
|
expect(marmiton).to.not.be.undefined;
|
|
expect(marmiton?.name).to.equal("Marmiton");
|
|
expect(listRecipeSources().map((adapter) => adapter.key)).to.include("marmiton");
|
|
});
|
|
|
|
it("registers 750g into the shared registry", () => {
|
|
registerAllRecipeSources();
|
|
|
|
const sevenFiftyG = getRecipeSource("750g");
|
|
expect(sevenFiftyG).to.not.be.undefined;
|
|
expect(sevenFiftyG?.name).to.equal("750g");
|
|
expect(listRecipeSources().map((adapter) => adapter.key)).to.include("750g");
|
|
});
|
|
|
|
it("registers Manger Bouger into the shared registry", () => {
|
|
registerAllRecipeSources();
|
|
|
|
const mangerBouger = getRecipeSource("mangerBouger");
|
|
expect(mangerBouger).to.not.be.undefined;
|
|
expect(mangerBouger?.name).to.equal("Manger Bouger");
|
|
expect(listRecipeSources().map((adapter) => adapter.key)).to.include("mangerBouger");
|
|
});
|
|
|
|
it("registers Quitoque into the shared registry", () => {
|
|
registerAllRecipeSources();
|
|
|
|
const quitoque = getRecipeSource("quitoque");
|
|
expect(quitoque).to.not.be.undefined;
|
|
expect(quitoque?.name).to.equal("Quitoque");
|
|
expect(listRecipeSources().map((adapter) => adapter.key)).to.include("quitoque");
|
|
});
|
|
|
|
it("does not register the generic JSON-LD adapter — it's not a household-toggleable source in its own right", () => {
|
|
registerAllRecipeSources();
|
|
|
|
expect(getRecipeSource("jsonLdRecipe")).to.be.undefined;
|
|
expect(listRecipeSources().map((adapter) => adapter.key)).to.not.include("jsonLdRecipe");
|
|
});
|
|
});
|