Merge pull request 'fix(sources): Manger Bouger sans filtre déroule tout le catalogue (#78)' (#126) from fix/manger-bouger-empty-filter into main
All checks were successful
All checks were successful
This commit is contained in:
commit
b20bcca07e
2 changed files with 73 additions and 8 deletions
|
|
@ -18,11 +18,13 @@ const SOURCE_KEY = "mangerBouger";
|
|||
// all (unlike marmiton.ts's search page) — but it's server-rendered, and a
|
||||
// plain GET carries the exact same Redux state the client hydrates from as
|
||||
// a `__NEXT_DATA__` script tag (see `extractNextData` below), which already
|
||||
// has everything `list()` needs. Verified live: `?query=<free text>` really
|
||||
// filters server-side (not just a client-side URL update over an
|
||||
// already-fetched page), and `page`/`hasMorePages` behave as real,
|
||||
// consistent pagination — the best-behaved of this adapter family's three
|
||||
// sources on that front.
|
||||
// has everything `list()` needs. Verified live for the *search* path
|
||||
// (`?diet=ALL&page=N&query=<free text>`): `query` really filters
|
||||
// server-side (not just a client-side URL update over an already-fetched
|
||||
// page), and `page`/`hasMorePages` behave as real, consistent pagination.
|
||||
// The *catalogue browse* path (no `query` term) must be the bare
|
||||
// `?diet=ALL&page=N` — a trailing empty `&query=` made the deployed server
|
||||
// repeat page 1 for every page (issue #78); `list()` below now omits it.
|
||||
const LIST_URL = "https://www.mangerbouger.fr/manger-mieux/la-fabrique-a-menus/recettes";
|
||||
const DETAIL_BASE_URL = "https://www.mangerbouger.fr/manger-mieux/la-fabrique-a-menus/recettes/";
|
||||
|
||||
|
|
@ -42,7 +44,7 @@ interface MangerBougerListPageData {
|
|||
initialState?: {
|
||||
recipes?: {
|
||||
list?: MangerBougerListEntry[];
|
||||
/** Whether a further page exists for the current `page`/`query`/`diet` combination — verified live: an out-of-range page comes back `false` with an empty `list` rather than repeating the last page or erroring, a cleaner end-of-results signal than either `marmiton.ts` (infers it from a 404) or `750g.ts` (this search has no real pagination at all). */
|
||||
/** Whether a further page exists for the current `page`/`query`/`diet` combination — verified live on the `query`-term path: an out-of-range page comes back `false` with an empty `list` rather than repeating the last page or erroring, a cleaner end-of-results signal than either `marmiton.ts` (infers it from a 404) or `750g.ts` (this search has no real pagination at all). The catalogue-browse path (no `query`) only paginates when the request URL omits `&query=` entirely — see `LIST_URL` and issue #78. */
|
||||
hasMorePages?: boolean;
|
||||
};
|
||||
};
|
||||
|
|
@ -284,8 +286,18 @@ export const mangerBougerAdapter: RecipeSourceAdapter<{ html: string; url: strin
|
|||
async list(params: RecipeSourceListParams): Promise<RecipeSourceListResult> {
|
||||
try {
|
||||
const page = params.cursor ? Number(params.cursor) : 1;
|
||||
const query = params.query ?? "";
|
||||
const listUrl = `${LIST_URL}?diet=ALL&page=${page}&query=${encodeURIComponent(query)}`;
|
||||
// Only append `&query=` when there's an actual search term. A trailing
|
||||
// empty `&query=` on the "browse everything" path (filter absent) made
|
||||
// the *deployed* server serve page 1 for every `page=N` — the
|
||||
// infinite scroll then stopped after 9 recipes (issue #38's
|
||||
// "0 new externalIds ⇒ end of list" guard cutting in). The bare
|
||||
// `?diet=ALL&page=N` catalogue request paginates correctly. The
|
||||
// sibling adapters (marmiton/quitoque/ohmonbento) already make their
|
||||
// search param conditional; this one didn't.
|
||||
const query = (params.query ?? "").trim();
|
||||
const listUrl = `${LIST_URL}?diet=ALL&page=${page}${
|
||||
query ? `&query=${encodeURIComponent(query)}` : ""
|
||||
}`;
|
||||
|
||||
let response: Response;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -132,6 +132,59 @@ describe("mangerBougerAdapter", () => {
|
|||
expect(requestedUrl).to.include("query=cr%C3%A8me%20br%C3%BBl%C3%A9e");
|
||||
});
|
||||
|
||||
it("omits the query param entirely on the catalogue-browse path (no filter) — issue #78", async () => {
|
||||
let requestedUrl: string | undefined;
|
||||
globalThis.fetch = (async (url: string) => {
|
||||
requestedUrl = url;
|
||||
return new Response(htmlWithListNextData({ list: [], hasMorePages: true }), {
|
||||
status: 200,
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
await mangerBougerAdapter.list({});
|
||||
|
||||
expect(requestedUrl).to.equal(
|
||||
"https://www.mangerbouger.fr/manger-mieux/la-fabrique-a-menus/recettes?diet=ALL&page=1",
|
||||
);
|
||||
expect(requestedUrl).not.to.include("query=");
|
||||
});
|
||||
|
||||
it("treats a blank/whitespace query the same as no filter (no query param)", async () => {
|
||||
let requestedUrl: string | undefined;
|
||||
globalThis.fetch = (async (url: string) => {
|
||||
requestedUrl = url;
|
||||
return new Response(htmlWithListNextData({ list: [], hasMorePages: false }), {
|
||||
status: 200,
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
await mangerBougerAdapter.list({ query: " " });
|
||||
|
||||
expect(requestedUrl).not.to.include("query=");
|
||||
});
|
||||
|
||||
it("still paginates the catalogue-browse path (nextCursor set when hasMorePages)", async () => {
|
||||
stubFetchHtml(htmlWithListNextData({ list: [], hasMorePages: true }));
|
||||
|
||||
const result = await mangerBougerAdapter.list({});
|
||||
|
||||
expect(result.nextCursor).to.equal("2");
|
||||
});
|
||||
|
||||
it("still appends the query param when a real search term is given", async () => {
|
||||
let requestedUrl: string | undefined;
|
||||
globalThis.fetch = (async (url: string) => {
|
||||
requestedUrl = url;
|
||||
return new Response(htmlWithListNextData({ list: [], hasMorePages: false }), {
|
||||
status: 200,
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
await mangerBougerAdapter.list({ query: "salade" });
|
||||
|
||||
expect(requestedUrl).to.include("&query=salade");
|
||||
});
|
||||
|
||||
it("skips a list entry missing a slug or a name", async () => {
|
||||
stubFetchHtml(
|
||||
htmlWithListNextData({
|
||||
|
|
|
|||
Loading…
Reference in a new issue