test: Importpfad gegen nachgebildete TMDB-Antworten prüfen
npm test läuft ohne TMDB-Schlüssel gegen die Entwicklungsdatenbank und deckt Kopfdaten, Staffeln, Episoden, Streamingdienste je Region, wiederholten Import und die Auffrischlogik ab. Dabei aufgefallen: importSeries gab den Titel zurück, bevor die Staffel- und Episodenzähler geschrieben waren — die Zähler standen auf 0.
This commit is contained in:
Vendored
+289
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* Nachgebildete TMDB-Antworten.
|
||||
*
|
||||
* Damit lässt sich der komplette Importpfad (Kopfdaten, Staffeln, Episoden,
|
||||
* Streamingdienste, Collections) prüfen, ohne einen echten Schlüssel zu
|
||||
* brauchen — und ohne bei jedem Lauf die TMDB-API zu belasten. Der Aufbau
|
||||
* entspricht dem, was TMDB tatsächlich liefert; gekürzt auf die Felder, die
|
||||
* Flimmer verwendet.
|
||||
*/
|
||||
|
||||
export const SERIES_ID = 999001;
|
||||
export const MOVIE_ID = 999002;
|
||||
export const MOVIE_2_ID = 999003;
|
||||
export const COLLECTION_ID = 999100;
|
||||
|
||||
export const seriesDetails = {
|
||||
id: SERIES_ID,
|
||||
name: "Nordlicht",
|
||||
original_name: "Nordlys",
|
||||
overview:
|
||||
"Eine Meteorologin kehrt in ihr Heimatdorf am Polarkreis zurück und stößt auf ein Wetterphänomen, das es nicht geben dürfte.",
|
||||
tagline: "Manche Lichter wollen nicht gesehen werden.",
|
||||
poster_path: "/abcdef1234567890.jpg",
|
||||
backdrop_path: "/bcdefa1234567890.jpg",
|
||||
first_air_date: "2023-03-14",
|
||||
last_air_date: "2025-05-02",
|
||||
episode_run_time: [48],
|
||||
status: "Returning Series",
|
||||
in_production: true,
|
||||
genres: [
|
||||
{ id: 18, name: "Drama" },
|
||||
{ id: 9648, name: "Mystery" },
|
||||
],
|
||||
original_language: "no",
|
||||
homepage: "https://example.org/nordlicht",
|
||||
vote_average: 8.1,
|
||||
number_of_seasons: 2,
|
||||
number_of_episodes: 5,
|
||||
external_ids: { imdb_id: "tt9990010" },
|
||||
seasons: [
|
||||
{
|
||||
id: 500000,
|
||||
season_number: 0,
|
||||
name: "Specials",
|
||||
overview: "Zusätzliche Folgen außerhalb der Handlung.",
|
||||
poster_path: null,
|
||||
air_date: "2023-12-24",
|
||||
episode_count: 1,
|
||||
},
|
||||
{
|
||||
id: 500001,
|
||||
season_number: 1,
|
||||
name: "Staffel 1",
|
||||
overview: "Die Rückkehr.",
|
||||
poster_path: "/cdefab1234567890.jpg",
|
||||
air_date: "2023-03-14",
|
||||
episode_count: 3,
|
||||
},
|
||||
{
|
||||
id: 500002,
|
||||
season_number: 2,
|
||||
name: "Staffel 2",
|
||||
overview: "Der lange Winter.",
|
||||
poster_path: "/defabc1234567890.jpg",
|
||||
air_date: "2025-04-11",
|
||||
episode_count: 2,
|
||||
},
|
||||
],
|
||||
"watch/providers": {
|
||||
results: {
|
||||
DE: {
|
||||
link: "https://www.themoviedb.org/tv/999001/watch?locale=DE",
|
||||
flatrate: [
|
||||
{ provider_id: 8, provider_name: "Netflix", logo_path: "/netflix12345678.jpg" },
|
||||
{ provider_id: 30, provider_name: "WOW", logo_path: "/wowlogo123456789.jpg" },
|
||||
],
|
||||
buy: [
|
||||
{
|
||||
provider_id: 3,
|
||||
provider_name: "Google Play Movies",
|
||||
logo_path: "/googleplay123456.jpg",
|
||||
},
|
||||
],
|
||||
},
|
||||
AT: {
|
||||
flatrate: [{ provider_id: 8, provider_name: "Netflix", logo_path: "/netflix12345678.jpg" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const seasons: Record<number, unknown> = {
|
||||
0: {
|
||||
id: 500000,
|
||||
season_number: 0,
|
||||
name: "Specials",
|
||||
air_date: "2023-12-24",
|
||||
episodes: [
|
||||
{
|
||||
id: 600000,
|
||||
season_number: 0,
|
||||
episode_number: 1,
|
||||
name: "Weihnachten am Fjord",
|
||||
overview: "Eine Folge außer der Reihe.",
|
||||
still_path: "/still000000000001.jpg",
|
||||
air_date: "2023-12-24",
|
||||
runtime: 30,
|
||||
},
|
||||
],
|
||||
},
|
||||
1: {
|
||||
id: 500001,
|
||||
season_number: 1,
|
||||
name: "Staffel 1",
|
||||
air_date: "2023-03-14",
|
||||
episodes: [
|
||||
{
|
||||
id: 600001,
|
||||
season_number: 1,
|
||||
episode_number: 1,
|
||||
name: "Ankunft",
|
||||
overview: "Ida steigt in Bodø aus dem Zug.",
|
||||
still_path: "/still000000000002.jpg",
|
||||
air_date: "2023-03-14",
|
||||
runtime: 52,
|
||||
},
|
||||
{
|
||||
id: 600002,
|
||||
season_number: 1,
|
||||
episode_number: 2,
|
||||
name: "Der Messwert",
|
||||
overview: "Ein Gerät zeigt etwas Unmögliches an.",
|
||||
still_path: null,
|
||||
air_date: "2023-03-21",
|
||||
runtime: 47,
|
||||
},
|
||||
{
|
||||
id: 600003,
|
||||
season_number: 1,
|
||||
episode_number: 3,
|
||||
name: "Polarnacht",
|
||||
overview: "Die Sonne bleibt weg — länger als sie darf.",
|
||||
still_path: null,
|
||||
air_date: "2023-03-28",
|
||||
// Ohne Laufzeit: muss auf episode_run_time zurückfallen.
|
||||
runtime: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
2: {
|
||||
id: 500002,
|
||||
season_number: 2,
|
||||
name: "Staffel 2",
|
||||
air_date: "2025-04-11",
|
||||
episodes: [
|
||||
{
|
||||
id: 600004,
|
||||
season_number: 2,
|
||||
episode_number: 1,
|
||||
name: "Rückkehr des Lichts",
|
||||
overview: null,
|
||||
still_path: null,
|
||||
air_date: "2025-04-11",
|
||||
runtime: 50,
|
||||
},
|
||||
{
|
||||
id: 600005,
|
||||
season_number: 2,
|
||||
episode_number: 2,
|
||||
name: "Der zweite Winter",
|
||||
overview: null,
|
||||
still_path: null,
|
||||
// Noch nicht ausgestrahlt — kommt in Etappe 5 im Kalender vor.
|
||||
air_date: "2099-01-08",
|
||||
runtime: 50,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const movieDetails = {
|
||||
id: MOVIE_ID,
|
||||
imdb_id: "tt9990020",
|
||||
title: "Die Stille zwischen den Bildern",
|
||||
original_title: "The Silence Between Frames",
|
||||
overview: "Ein Filmvorführer entdeckt in einer alten Rolle Bilder, die dort nicht sein können.",
|
||||
tagline: "24 Bilder pro Sekunde. Eins davon lügt.",
|
||||
poster_path: "/movie0001234567890.jpg",
|
||||
backdrop_path: "/movieback01234567.jpg",
|
||||
release_date: "2024-10-17",
|
||||
runtime: 118,
|
||||
status: "Released",
|
||||
genres: [
|
||||
{ id: 27, name: "Horror" },
|
||||
{ id: 53, name: "Thriller" },
|
||||
],
|
||||
original_language: "en",
|
||||
homepage: null,
|
||||
vote_average: 7.4,
|
||||
belongs_to_collection: {
|
||||
id: COLLECTION_ID,
|
||||
name: "Vorführer-Reihe",
|
||||
poster_path: "/collection00123456.jpg",
|
||||
},
|
||||
"watch/providers": {
|
||||
results: {
|
||||
DE: {
|
||||
flatrate: [
|
||||
{ provider_id: 337, provider_name: "Disney Plus", logo_path: "/disney1234567890.jpg" },
|
||||
],
|
||||
rent: [
|
||||
{ provider_id: 3, provider_name: "Google Play Movies", logo_path: "/googleplay123456.jpg" },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const movie2Details = {
|
||||
...movieDetails,
|
||||
id: MOVIE_2_ID,
|
||||
imdb_id: "tt9990030",
|
||||
title: "Die Stille zwischen den Bildern II",
|
||||
original_title: "The Silence Between Frames II",
|
||||
release_date: "2026-02-06",
|
||||
runtime: 126,
|
||||
poster_path: "/movie0002234567890.jpg",
|
||||
"watch/providers": { results: {} },
|
||||
};
|
||||
|
||||
export const collectionDetails = {
|
||||
id: COLLECTION_ID,
|
||||
name: "Vorführer-Reihe",
|
||||
overview: "Zwei Filme über alte Projektoren und das, was sie zeigen.",
|
||||
poster_path: "/collection00123456.jpg",
|
||||
backdrop_path: null,
|
||||
parts: [
|
||||
// Absichtlich in falscher Reihenfolge — der Import muss nach Datum sortieren.
|
||||
{ id: MOVIE_2_ID, title: movie2Details.title, release_date: "2026-02-06" },
|
||||
{ id: MOVIE_ID, title: movieDetails.title, release_date: "2024-10-17" },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Ersetzt `fetch` durch eine Fassung, die aus den Fixtures antwortet.
|
||||
* Liefert eine Funktion zum Zurücksetzen sowie die Liste der Aufrufe.
|
||||
*/
|
||||
export function installTmdbStub() {
|
||||
const original = globalThis.fetch;
|
||||
const calls: string[] = [];
|
||||
|
||||
globalThis.fetch = (async (input: string | URL | Request) => {
|
||||
const url = new URL(typeof input === "string" ? input : input.toString());
|
||||
calls.push(url.pathname);
|
||||
|
||||
const json = (body: unknown) =>
|
||||
new Response(JSON.stringify(body), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
|
||||
const path = url.pathname;
|
||||
|
||||
if (path === `/3/tv/${SERIES_ID}`) return json(seriesDetails);
|
||||
const seasonMatch = path.match(new RegExp(`^/3/tv/${SERIES_ID}/season/(\\d+)$`));
|
||||
if (seasonMatch?.[1] !== undefined) {
|
||||
const number = Number(seasonMatch[1]);
|
||||
const season = seasons[number];
|
||||
return season
|
||||
? json(season)
|
||||
: new Response(JSON.stringify({ status_message: "Not found" }), { status: 404 });
|
||||
}
|
||||
if (path === `/3/movie/${MOVIE_ID}`) return json(movieDetails);
|
||||
if (path === `/3/movie/${MOVIE_2_ID}`) return json(movie2Details);
|
||||
if (path === `/3/collection/${COLLECTION_ID}`) return json(collectionDetails);
|
||||
|
||||
return new Response(JSON.stringify({ status_message: `Kein Fixture für ${path}` }), {
|
||||
status: 404,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
return {
|
||||
calls,
|
||||
restore() {
|
||||
globalThis.fetch = original;
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user