diff --git a/api/src/controllers/movies.ts b/api/src/controllers/movies.ts index 9a9cc57b..7e96fe3e 100644 --- a/api/src/controllers/movies.ts +++ b/api/src/controllers/movies.ts @@ -109,12 +109,16 @@ export const movies = new Elysia({ prefix: "/movies", tags: ["movies"] }) }); } set.headers["content-language"] = translation.language; + const ot = ret.originalTranslation; return { ...ret, ...translation, - ...(ret.originalTranslation?.preferOriginal - ? ret.originalTranslation - : {}), + ...(ot?.preferOriginal && { + ...(ot.poster && { poster: ot.poster }), + ...(ot.thumbnail && { thumbnail: ot.thumbnail }), + ...(ot.banner && { banner: ot.banner }), + ...(ot.logo && { logo: ot.logo }), + }), }; }, { diff --git a/api/src/models/examples/bubble.ts b/api/src/models/examples/bubble.ts index d1583d0e..3b816d9c 100644 --- a/api/src/models/examples/bubble.ts +++ b/api/src/models/examples/bubble.ts @@ -26,10 +26,10 @@ export const bubble: SeedMovie = { thumbnail: "https://image.tmdb.org/t/p/original/a8Q2g0g7XzAF6gcB8qgn37ccb9Y.jpg", banner: null, - logo: null, + logo: "https://image.tmdb.org/t/p/original/ihIs7fayAmZieMlMQbs6TWM77uf.png", trailerUrl: "https://www.youtube.com/watch?v=vs7zsyIZkMM", }, - jp: { + ja: { name: "バブル:2022", tagline: null, description: null, @@ -37,10 +37,9 @@ export const bubble: SeedMovie = { tags: ["アニメ"], poster: "https://image.tmdb.org/t/p/original/65dad96VE8FJPEdrAkhdsuWMWH9.jpg", - thumbnail: - "https://image.tmdb.org/t/p/original/a8Q2g0g7XzAF6gcB8qgn37ccb9Y.jpg", + thumbnail: "https://image.tmdb.org/t/p/original/jp.jpg", banner: null, - logo: "https://image.tmdb.org/t/p/original/ihIs7fayAmZieMlMQbs6TWM77uf.png", + logo: null, trailerUrl: "https://www.youtube.com/watch?v=vs7zsyIZkMM", }, }, diff --git a/api/tests/movies/get-movie.test.ts b/api/tests/movies/get-movie.test.ts index 2fa27abd..0a1ad311 100644 --- a/api/tests/movies/get-movie.test.ts +++ b/api/tests/movies/get-movie.test.ts @@ -12,8 +12,17 @@ beforeAll(async () => { }); describe("Get movie", () => { + it("Invalid slug", async () => { + const [resp, body] = await getMovie("sotneuhn", { langs: "en" }); + + expectStatus(resp, body).toBe(404); + expect(body).toMatchObject({ + status: 404, + message: "Movie not found", + }); + }); it("Retrive by slug", async () => { - const [resp, body] = await getMovie(bubble.slug, "en"); + const [resp, body] = await getMovie(bubble.slug, { langs: "en" }); expectStatus(resp, body).toBe(200); expect(body).toMatchObject({ @@ -22,7 +31,7 @@ describe("Get movie", () => { }); }); it("Retrive by id", async () => { - const [resp, body] = await getMovie(bubbleId, "en"); + const [resp, body] = await getMovie(bubbleId, { langs: "en" }); expectStatus(resp, body).toBe(200); expect(body).toMatchObject({ @@ -32,7 +41,7 @@ describe("Get movie", () => { }); }); it("Get non available translation", async () => { - const [resp, body] = await getMovie(bubble.slug, "fr"); + const [resp, body] = await getMovie(bubble.slug, { langs: "fr" }); expectStatus(resp, body).toBe(422); expect(body).toMatchObject({ @@ -40,7 +49,7 @@ describe("Get movie", () => { }); }); it("Get first available language", async () => { - const [resp, body] = await getMovie(bubble.slug, "fr,en"); + const [resp, body] = await getMovie(bubble.slug, { langs: "fr,en" }); expectStatus(resp, body).toBe(200); expect(body).toMatchObject({ @@ -50,7 +59,7 @@ describe("Get movie", () => { expect(resp.headers.get("Content-Language")).toBe("en"); }); it("Use language fallback", async () => { - const [resp, body] = await getMovie(bubble.slug, "fr,ja,*"); + const [resp, body] = await getMovie(bubble.slug, { langs: "fr,pr,*" }); expectStatus(resp, body).toBe(200); expect(body).toMatchObject({ @@ -60,7 +69,7 @@ describe("Get movie", () => { expect(resp.headers.get("Content-Language")).toBe("en"); }); it("Works without accept-language header", async () => { - const [resp, body] = await getMovie(bubble.slug, undefined); + const [resp, body] = await getMovie(bubble.slug, { langs: undefined }); expectStatus(resp, body).toBe(200); expect(body).toMatchObject({ @@ -70,7 +79,7 @@ describe("Get movie", () => { expect(resp.headers.get("Content-Language")).toBe("en"); }); it("Fallback if translations does not exist", async () => { - const [resp, body] = await getMovie(bubble.slug, "en-au"); + const [resp, body] = await getMovie(bubble.slug, { langs: "en-au" }); expectStatus(resp, body).toBe(200); expect(body).toMatchObject({ @@ -79,4 +88,29 @@ describe("Get movie", () => { }); expect(resp.headers.get("Content-Language")).toBe("en"); }); + it("Prefer original", async () => { + expect(bubble.translations.ja.logo).toBe(null); + expect(bubble.translations.en.logo).not.toBe(null); + + const [resp, body] = await getMovie(bubble.slug, { + langs: "en-au", + preferOriginal: true, + }); + + expectStatus(resp, body).toBe(200); + expect(body).toMatchObject({ + slug: bubble.slug, + name: bubble.translations.en.name, + poster: ({ + source: bubble.translations.ja.poster, + }), + thumbnail: ({ + source: bubble.translations.ja.thumbnail, + }), + banner: null, + // we fallback to the translated value when the original is null. + logo: ({ source: bubble.translations.en.logo }), + }); + expect(resp.headers.get("Content-Language")).toBe("en"); + }); }); diff --git a/api/tests/movies/movies-helper.ts b/api/tests/movies/movies-helper.ts index 9d160b15..4398f2e1 100644 --- a/api/tests/movies/movies-helper.ts +++ b/api/tests/movies/movies-helper.ts @@ -7,9 +7,12 @@ import type { SeedMovie } from "~/models/movie"; export const movieApp = new Elysia().use(base).use(movies).use(seed); -export const getMovie = async (id: string, langs?: string) => { +export const getMovie = async ( + id: string, + { langs, ...query }: { langs?: string; preferOriginal?: boolean }, +) => { const resp = await movieApp.handle( - new Request(`http://localhost/movies/${id}`, { + new Request(buildUrl(`movies/${id}`, query), { method: "GET", headers: langs ? { @@ -48,7 +51,7 @@ export const getMovies = async ({ export const createMovie = async (movie: SeedMovie) => { const resp = await movieApp.handle( - new Request("http://localhost/movies", { + new Request(buildUrl("movies"), { method: "POST", body: JSON.stringify(movie), headers: { diff --git a/api/tests/utils.ts b/api/tests/utils.ts index be2480d8..a3101a87 100644 --- a/api/tests/utils.ts +++ b/api/tests/utils.ts @@ -1,5 +1,4 @@ import { expect } from "bun:test"; -import Elysia from "elysia"; export function expectStatus(resp: Response, body: object) { const matcher = expect({ ...body, status: resp.status }); @@ -10,14 +9,18 @@ export function expectStatus(resp: Response, body: object) { }; } -export const buildUrl = (route: string, query: Record) => { +export const buildUrl = (route: string, query?: Record) => { const params = new URLSearchParams(); - for (const [key, value] of Object.entries(query)) { - if (!Array.isArray(value)) { - params.append(key, value.toString()); - continue; + if (query) { + for (const [key, value] of Object.entries(query)) { + if (!Array.isArray(value)) { + params.append(key, value.toString()); + continue; + } + for (const v of value) params.append(key, v.toString()); } - for (const v of value) params.append(key, v.toString()); } - return `http://localhost/${route}?${params}`; + return params.size + ? `http://localhost/${route}?${params}` + : `http://localhost/${route}`; };