mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-16 06:25:42 -04:00
feat: migrate test runner from Bun to Vitest
- Replace bun:test with Vitest across all 22 test files - Create @sofa/test package with shared setup and DB test helpers - setup.ts: vi.mock for @sofa/db/client, Bun.randomUUIDv7 polyfill - db.ts: in-memory SQLite via better-sqlite3, seed helpers - Add per-project vitest configs (packages/core, apps/web) - Add root vitest.config.ts with projects and v8 coverage - Set up @vitest/browser + Playwright for web component tests - Move validateBackupDatabase from core/backup.ts to @sofa/db/client - Derive required backup tables from schema instead of hard-coded list - Update CI workflow with Playwright install and Codecov upload - Update CLAUDE.md documentation for Vitest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
45 files changed
+589
-364
No files matched your search
@@ -1,19 +1,13 @@
|
||||
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { availabilityOffers } from "@sofa/db/schema";
|
||||
import {
|
||||
clearAllTables,
|
||||
eq,
|
||||
insertAvailabilityOffer,
|
||||
insertTitle,
|
||||
testDb,
|
||||
} from "@sofa/db/test-utils";
|
||||
import { clearAllTables, eq, insertAvailabilityOffer, insertTitle, testDb } from "@sofa/test/db";
|
||||
|
||||
let watchProvidersResponse: { results: Record<string, unknown> } = { results: {} };
|
||||
const { getWatchProviders } = vi.hoisted(() => ({
|
||||
getWatchProviders: vi.fn(async () => ({ results: {} as Record<string, unknown> })),
|
||||
}));
|
||||
|
||||
const getWatchProviders = mock(async () => watchProvidersResponse);
|
||||
|
||||
mock.module("@sofa/tmdb/client", () => ({
|
||||
vi.mock("@sofa/tmdb/client", () => ({
|
||||
getWatchProviders,
|
||||
}));
|
||||
|
||||
@@ -21,7 +15,7 @@ import { refreshAvailability } from "../src/availability";
|
||||
|
||||
beforeEach(() => {
|
||||
clearAllTables();
|
||||
watchProvidersResponse = { results: {} };
|
||||
getWatchProviders.mockImplementation(async () => ({ results: {} }));
|
||||
});
|
||||
|
||||
describe("refreshAvailability", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { getBackupSource, isKnownBackup, isValidBackupFilename } from "../src/backup";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { parseColorPalette } from "../src/colors";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { persons, titleCast } from "@sofa/db/schema";
|
||||
import { clearAllTables, insertTitle, testDb } from "@sofa/db/test-utils";
|
||||
import { clearAllTables, insertTitle, testDb } from "@sofa/test/db";
|
||||
|
||||
import { getCastForTitle } from "../src/credits";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
clearAllTables,
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
insertTitle,
|
||||
insertTvShow,
|
||||
insertUser,
|
||||
} from "@sofa/db/test-utils";
|
||||
} from "@sofa/test/db";
|
||||
|
||||
import {
|
||||
getContinueWatchingFeed,
|
||||
@@ -82,7 +82,7 @@ describe("getWatchHistory", () => {
|
||||
insertMovieWatch("user-1", "m2");
|
||||
|
||||
const history = getWatchHistory("user-1", "movies", "this_week");
|
||||
expect(history).toBeArrayOfSize(7);
|
||||
expect(history).toHaveLength(7);
|
||||
const totalCount = history.reduce((sum, b) => sum + b.count, 0);
|
||||
expect(totalCount).toBe(2);
|
||||
});
|
||||
@@ -90,20 +90,20 @@ describe("getWatchHistory", () => {
|
||||
test("returns all-zero buckets when no watches", () => {
|
||||
insertUser();
|
||||
const history = getWatchHistory("user-1", "movies", "this_month");
|
||||
expect(history).toBeArrayOfSize(30);
|
||||
expect(history).toHaveLength(30);
|
||||
expect(history.every((b) => b.count === 0)).toBe(true);
|
||||
});
|
||||
|
||||
test("returns correct bucket count for today period", () => {
|
||||
insertUser();
|
||||
const history = getWatchHistory("user-1", "episodes", "today");
|
||||
expect(history).toBeArrayOfSize(24);
|
||||
expect(history).toHaveLength(24);
|
||||
});
|
||||
|
||||
test("returns correct bucket count for this_year period", () => {
|
||||
insertUser();
|
||||
const history = getWatchHistory("user-1", "movies", "this_year");
|
||||
expect(history).toBeArrayOfSize(12);
|
||||
expect(history).toHaveLength(12);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
clearAllTables,
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
insertTitle,
|
||||
insertTvShow,
|
||||
insertUser,
|
||||
} from "@sofa/db/test-utils";
|
||||
} from "@sofa/test/db";
|
||||
|
||||
import { generateUserExport } from "../src/export";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { loadImageBuffer } from "../src/image-cache";
|
||||
|
||||
@@ -13,7 +13,7 @@ afterEach(() => {
|
||||
describe("loadImageBuffer", () => {
|
||||
test("uses category-specific TMDB sizes when cache is disabled", async () => {
|
||||
const urls: string[] = [];
|
||||
const fetchSpy = spyOn(globalThis, "fetch").mockImplementation((async (
|
||||
const fetchSpy = vi.spyOn(globalThis, "fetch").mockImplementation((async (
|
||||
input: string | URL | Request,
|
||||
) => {
|
||||
urls.push(String(input));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import AdmZip from "adm-zip";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
type ParseResult,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, spyOn, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import {
|
||||
importJobs,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
insertTvShow,
|
||||
insertUser,
|
||||
testDb,
|
||||
} from "@sofa/db/test-utils";
|
||||
} from "@sofa/test/db";
|
||||
import * as tmdbClient from "@sofa/tmdb/client";
|
||||
|
||||
import type { NormalizedImport } from "../src/imports/parsers";
|
||||
@@ -435,7 +435,7 @@ describe("processImportJob — failed resolution", () => {
|
||||
};
|
||||
|
||||
// Mock TMDB search to return empty results (no network call)
|
||||
const searchSpy = spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
const searchSpy = vi.spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
results: [],
|
||||
} as never);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, describe, expect, spyOn, test } from "bun:test";
|
||||
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import * as tmdbClient from "@sofa/tmdb/client";
|
||||
|
||||
@@ -9,9 +9,9 @@ import { resolveMovieTmdbId, resolveShowTmdbId } from "../src/imports/resolve";
|
||||
// globalThis.fetch because openapi-fetch captures the fetch reference at
|
||||
// module-init time, making globalThis.fetch mocking ineffective.
|
||||
|
||||
let findSpy: ReturnType<typeof spyOn>;
|
||||
let searchMoviesSpy: ReturnType<typeof spyOn>;
|
||||
let searchTvSpy: ReturnType<typeof spyOn>;
|
||||
let findSpy: ReturnType<typeof vi.spyOn>;
|
||||
let searchMoviesSpy: ReturnType<typeof vi.spyOn>;
|
||||
let searchTvSpy: ReturnType<typeof vi.spyOn>;
|
||||
|
||||
afterEach(() => {
|
||||
findSpy?.mockRestore();
|
||||
@@ -23,8 +23,8 @@ afterEach(() => {
|
||||
|
||||
describe("resolveMovieTmdbId", () => {
|
||||
test("returns tmdbId directly when provided", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId");
|
||||
searchMoviesSpy = spyOn(tmdbClient, "searchMovies");
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId");
|
||||
searchMoviesSpy = vi.spyOn(tmdbClient, "searchMovies");
|
||||
|
||||
const result = await resolveMovieTmdbId({ tmdbId: 123 });
|
||||
expect(result).toBe(123);
|
||||
@@ -33,7 +33,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("resolves via IMDB ID lookup", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [{ id: 456 }],
|
||||
tv_results: [],
|
||||
tv_episode_results: [],
|
||||
@@ -45,7 +45,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("falls back to TVDB lookup when no IMDB ID", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [{ id: 789 }],
|
||||
tv_results: [],
|
||||
tv_episode_results: [],
|
||||
@@ -58,7 +58,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
|
||||
test("IMDB returns no movie, falls back to TVDB", async () => {
|
||||
let callIndex = 0;
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockImplementation(async () => {
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockImplementation(async () => {
|
||||
callIndex++;
|
||||
if (callIndex === 1) {
|
||||
// IMDB lookup — no results
|
||||
@@ -85,7 +85,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("falls back to title search when no IDs available", async () => {
|
||||
searchMoviesSpy = spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
searchMoviesSpy = vi.spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
results: [{ id: 321, title: "Inception", release_date: "2010-07-16" }],
|
||||
} as never);
|
||||
|
||||
@@ -95,7 +95,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("title search with year prefers matching year", async () => {
|
||||
searchMoviesSpy = spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
searchMoviesSpy = vi.spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
results: [
|
||||
{ id: 100, title: "Dune", release_date: "1984-12-14" },
|
||||
{ id: 200, title: "Dune", release_date: "2021-10-22" },
|
||||
@@ -107,7 +107,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("title search without year match returns null", async () => {
|
||||
searchMoviesSpy = spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
searchMoviesSpy = vi.spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
results: [
|
||||
{ id: 100, title: "Dune", release_date: "1984-12-14" },
|
||||
{ id: 200, title: "Dune", release_date: "2021-10-22" },
|
||||
@@ -120,12 +120,12 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("returns null when all methods fail", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [],
|
||||
tv_results: [],
|
||||
tv_episode_results: [],
|
||||
} as never);
|
||||
searchMoviesSpy = spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
searchMoviesSpy = vi.spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
results: [],
|
||||
} as never);
|
||||
|
||||
@@ -137,8 +137,8 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("returns null when no identifiers at all", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId");
|
||||
searchMoviesSpy = spyOn(tmdbClient, "searchMovies");
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId");
|
||||
searchMoviesSpy = vi.spyOn(tmdbClient, "searchMovies");
|
||||
|
||||
const result = await resolveMovieTmdbId({});
|
||||
expect(result).toBeNull();
|
||||
@@ -147,7 +147,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("cache prevents duplicate lookups", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [{ id: 555 }],
|
||||
tv_results: [],
|
||||
tv_episode_results: [],
|
||||
@@ -166,7 +166,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
});
|
||||
|
||||
test("cache stores null for unresolvable items", async () => {
|
||||
searchMoviesSpy = spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
searchMoviesSpy = vi.spyOn(tmdbClient, "searchMovies").mockResolvedValue({
|
||||
results: [],
|
||||
} as never);
|
||||
|
||||
@@ -186,7 +186,7 @@ describe("resolveMovieTmdbId", () => {
|
||||
|
||||
describe("resolveShowTmdbId", () => {
|
||||
test("returns tmdbId directly when provided", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId");
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId");
|
||||
|
||||
const result = await resolveShowTmdbId({ tmdbId: 42 });
|
||||
expect(result).toBe(42);
|
||||
@@ -194,7 +194,7 @@ describe("resolveShowTmdbId", () => {
|
||||
});
|
||||
|
||||
test("resolves via IMDB ID — show-level result", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [],
|
||||
tv_results: [{ id: 600, name: "Breaking Bad" }],
|
||||
tv_episode_results: [],
|
||||
@@ -205,7 +205,7 @@ describe("resolveShowTmdbId", () => {
|
||||
});
|
||||
|
||||
test("resolves via IMDB ID — episode-level result extracts show_id", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [],
|
||||
tv_results: [],
|
||||
tv_episode_results: [
|
||||
@@ -224,7 +224,7 @@ describe("resolveShowTmdbId", () => {
|
||||
});
|
||||
|
||||
test("falls back to TVDB lookup", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [],
|
||||
tv_results: [{ id: 800 }],
|
||||
tv_episode_results: [],
|
||||
@@ -236,7 +236,7 @@ describe("resolveShowTmdbId", () => {
|
||||
});
|
||||
|
||||
test("TVDB lookup extracts show_id from episode result", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [],
|
||||
tv_results: [],
|
||||
tv_episode_results: [
|
||||
@@ -255,7 +255,7 @@ describe("resolveShowTmdbId", () => {
|
||||
});
|
||||
|
||||
test("falls back to title search", async () => {
|
||||
searchTvSpy = spyOn(tmdbClient, "searchTv").mockResolvedValue({
|
||||
searchTvSpy = vi.spyOn(tmdbClient, "searchTv").mockResolvedValue({
|
||||
results: [{ id: 900, name: "The Office" }],
|
||||
} as never);
|
||||
|
||||
@@ -265,12 +265,12 @@ describe("resolveShowTmdbId", () => {
|
||||
});
|
||||
|
||||
test("returns null when all methods fail", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [],
|
||||
tv_results: [],
|
||||
tv_episode_results: [],
|
||||
} as never);
|
||||
searchTvSpy = spyOn(tmdbClient, "searchTv").mockResolvedValue({
|
||||
searchTvSpy = vi.spyOn(tmdbClient, "searchTv").mockResolvedValue({
|
||||
results: [],
|
||||
} as never);
|
||||
|
||||
@@ -282,7 +282,7 @@ describe("resolveShowTmdbId", () => {
|
||||
});
|
||||
|
||||
test("cache prevents duplicate show lookups", async () => {
|
||||
findSpy = spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
findSpy = vi.spyOn(tmdbClient, "findByExternalId").mockResolvedValue({
|
||||
movie_results: [],
|
||||
tv_results: [{ id: 950 }],
|
||||
tv_episode_results: [],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import {
|
||||
clearAllTables,
|
||||
@@ -6,19 +6,21 @@ import {
|
||||
insertStatus,
|
||||
insertTitle,
|
||||
insertUser,
|
||||
} from "@sofa/db/test-utils";
|
||||
} from "@sofa/test/db";
|
||||
|
||||
import { getRadarrList, getSonarrList, parseStatusParam, resolveListToken } from "../src/lists";
|
||||
const { mockGetTvExternalIds } = vi.hoisted(() => ({
|
||||
mockGetTvExternalIds: vi.fn(
|
||||
(): Promise<{ tvdb_id: number | null; imdb_id: string | null }> =>
|
||||
Promise.resolve({ tvdb_id: 55555, imdb_id: "tt9999999" }),
|
||||
),
|
||||
}));
|
||||
|
||||
// Mock getTvExternalIds for lazy resolution tests
|
||||
const mockGetTvExternalIds = mock(
|
||||
(): Promise<{ tvdb_id: number | null; imdb_id: string | null }> =>
|
||||
Promise.resolve({ tvdb_id: 55555, imdb_id: "tt9999999" }),
|
||||
);
|
||||
mock.module("@sofa/tmdb/client", () => ({
|
||||
vi.mock("@sofa/tmdb/client", () => ({
|
||||
getTvExternalIds: mockGetTvExternalIds,
|
||||
}));
|
||||
|
||||
import { getRadarrList, getSonarrList, parseStatusParam, resolveListToken } from "../src/lists";
|
||||
|
||||
beforeEach(() => {
|
||||
clearAllTables();
|
||||
mockGetTvExternalIds.mockClear();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { episodes, seasons, titles } from "@sofa/db/schema";
|
||||
import { clearAllTables, eq, insertTitle, testDb } from "@sofa/db/test-utils";
|
||||
import { clearAllTables, eq, insertTitle, testDb } from "@sofa/test/db";
|
||||
|
||||
interface MockSeasonEpisode {
|
||||
episode_number: number;
|
||||
@@ -21,7 +21,7 @@ interface MockSeasonDetails {
|
||||
episodes: MockSeasonEpisode[];
|
||||
}
|
||||
|
||||
let seasonDetails: MockSeasonDetails = {
|
||||
const defaultSeasonDetails: MockSeasonDetails = {
|
||||
season_number: 1,
|
||||
name: "Season 1",
|
||||
overview: null,
|
||||
@@ -39,7 +39,11 @@ let seasonDetails: MockSeasonDetails = {
|
||||
],
|
||||
};
|
||||
|
||||
mock.module("@sofa/tmdb/client", () => ({
|
||||
const { mockGetTvSeasonDetails } = vi.hoisted(() => ({
|
||||
mockGetTvSeasonDetails: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@sofa/tmdb/client", () => ({
|
||||
getMovieDetails: async () => {
|
||||
throw new Error("not used");
|
||||
},
|
||||
@@ -48,7 +52,7 @@ mock.module("@sofa/tmdb/client", () => ({
|
||||
getTvDetails: async () => {
|
||||
throw new Error("not used");
|
||||
},
|
||||
getTvSeasonDetails: async () => seasonDetails,
|
||||
getTvSeasonDetails: mockGetTvSeasonDetails,
|
||||
getVideos: async () => ({ results: [] }),
|
||||
}));
|
||||
|
||||
@@ -56,23 +60,10 @@ import { refreshTvChildren, updateTitleWithArtInvalidation } from "../src/metada
|
||||
|
||||
beforeEach(() => {
|
||||
clearAllTables();
|
||||
seasonDetails = {
|
||||
season_number: 1,
|
||||
name: "Season 1",
|
||||
overview: null,
|
||||
poster_path: "/new-season.png",
|
||||
air_date: null,
|
||||
episodes: [
|
||||
{
|
||||
episode_number: 1,
|
||||
name: "Episode 1",
|
||||
overview: null,
|
||||
still_path: "/new-still.png",
|
||||
air_date: null,
|
||||
runtime: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
mockGetTvSeasonDetails.mockImplementation(async () => ({
|
||||
...defaultSeasonDetails,
|
||||
episodes: [...defaultSeasonDetails.episodes],
|
||||
}));
|
||||
});
|
||||
|
||||
describe("refreshTvChildren", () => {
|
||||
@@ -132,8 +123,8 @@ describe("refreshTvChildren", () => {
|
||||
})
|
||||
.run();
|
||||
|
||||
seasonDetails = {
|
||||
...seasonDetails,
|
||||
mockGetTvSeasonDetails.mockImplementation(async () => ({
|
||||
...defaultSeasonDetails,
|
||||
poster_path: "/season.png",
|
||||
episodes: [
|
||||
{
|
||||
@@ -145,7 +136,7 @@ describe("refreshTvChildren", () => {
|
||||
runtime: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
}));
|
||||
|
||||
await refreshTvChildren("tv-1", 10, 1);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import type { TmdbMovieDetails, TmdbTvDetails, TmdbVideo } from "@sofa/tmdb/client";
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { personFilmography, persons } from "@sofa/db/schema";
|
||||
import { clearAllTables, eq, testDb } from "@sofa/db/test-utils";
|
||||
import { clearAllTables, eq, testDb } from "@sofa/test/db";
|
||||
|
||||
const TINY_PNG = Buffer.from(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4//8/AwAI/AL+X2NDNwAAAABJRU5ErkJggg==",
|
||||
"base64",
|
||||
);
|
||||
|
||||
let nextBuffer: Buffer | null = TINY_PNG;
|
||||
let nextPersonDetails = {
|
||||
const defaultPersonDetails = {
|
||||
id: 100,
|
||||
name: "Updated Person",
|
||||
biography: "Bio",
|
||||
@@ -21,8 +20,8 @@ let nextPersonDetails = {
|
||||
popularity: 10,
|
||||
imdb_id: null,
|
||||
};
|
||||
let combinedCreditsCalls = 0;
|
||||
let nextCombinedCredits = {
|
||||
|
||||
const defaultCombinedCredits = {
|
||||
cast: [
|
||||
{
|
||||
id: 501,
|
||||
@@ -43,62 +42,34 @@ let nextCombinedCredits = {
|
||||
crew: [],
|
||||
};
|
||||
|
||||
mock.module("@sofa/tmdb/client", () => ({
|
||||
getPersonDetails: async () => nextPersonDetails,
|
||||
getPersonCombinedCredits: async () => {
|
||||
combinedCreditsCalls++;
|
||||
return nextCombinedCredits;
|
||||
},
|
||||
const { mockGetPersonDetails, mockGetPersonCombinedCredits } = vi.hoisted(() => ({
|
||||
mockGetPersonDetails: vi.fn(),
|
||||
mockGetPersonCombinedCredits: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@sofa/tmdb/client", () => ({
|
||||
getPersonDetails: mockGetPersonDetails,
|
||||
getPersonCombinedCredits: mockGetPersonCombinedCredits,
|
||||
}));
|
||||
|
||||
import { fetchFullFilmography, getOrFetchPerson } from "../src/person";
|
||||
|
||||
let combinedCreditsCalls = 0;
|
||||
|
||||
beforeEach(() => {
|
||||
clearAllTables();
|
||||
process.env.IMAGE_CACHE_ENABLED = "false";
|
||||
nextBuffer = TINY_PNG;
|
||||
nextPersonDetails = {
|
||||
id: 100,
|
||||
name: "Updated Person",
|
||||
biography: "Bio",
|
||||
birthday: null,
|
||||
deathday: null,
|
||||
place_of_birth: null,
|
||||
profile_path: "/new-profile.png",
|
||||
known_for_department: "Acting",
|
||||
popularity: 10,
|
||||
imdb_id: null,
|
||||
};
|
||||
combinedCreditsCalls = 0;
|
||||
nextCombinedCredits = {
|
||||
cast: [
|
||||
{
|
||||
id: 501,
|
||||
media_type: "movie",
|
||||
title: "Cached Movie",
|
||||
name: undefined,
|
||||
overview: "Overview",
|
||||
release_date: "2024-01-01",
|
||||
first_air_date: undefined,
|
||||
poster_path: "/poster.png",
|
||||
backdrop_path: "/backdrop.png",
|
||||
popularity: 5,
|
||||
vote_average: 7.5,
|
||||
vote_count: 42,
|
||||
character: "Lead",
|
||||
},
|
||||
],
|
||||
crew: [],
|
||||
};
|
||||
spyOn(globalThis, "fetch").mockImplementation((async (
|
||||
mockGetPersonDetails.mockImplementation(async () => ({ ...defaultPersonDetails }));
|
||||
mockGetPersonCombinedCredits.mockImplementation(async () => {
|
||||
combinedCreditsCalls++;
|
||||
return { cast: [...defaultCombinedCredits.cast], crew: [] };
|
||||
});
|
||||
vi.spyOn(globalThis, "fetch").mockImplementation((async (
|
||||
_input: string | URL | Request,
|
||||
_init?: RequestInit,
|
||||
) => {
|
||||
if (!nextBuffer) {
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
|
||||
return new Response(nextBuffer, {
|
||||
return new Response(TINY_PNG, {
|
||||
status: 200,
|
||||
headers: { "content-type": "image/png" },
|
||||
});
|
||||
@@ -107,7 +78,6 @@ beforeEach(() => {
|
||||
|
||||
afterEach(() => {
|
||||
delete process.env.IMAGE_CACHE_ENABLED;
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
describe("getOrFetchPerson", () => {
|
||||
@@ -127,7 +97,7 @@ describe("getOrFetchPerson", () => {
|
||||
const person = await getOrFetchPerson("p1");
|
||||
const stored = testDb.select().from(persons).where(eq(persons.id, "p1")).get();
|
||||
|
||||
expect(person?.profileThumbHash).toBeString();
|
||||
expect(person?.profileThumbHash).toBeTypeOf("string");
|
||||
expect(stored?.profileThumbHash).toBe(person?.profileThumbHash);
|
||||
});
|
||||
|
||||
@@ -148,7 +118,7 @@ describe("getOrFetchPerson", () => {
|
||||
const stored = testDb.select().from(persons).where(eq(persons.id, "p1")).get();
|
||||
|
||||
expect(stored?.profilePath).toBe("/new-profile.png");
|
||||
expect(person?.profileThumbHash).toBeString();
|
||||
expect(person?.profileThumbHash).toBeTypeOf("string");
|
||||
expect(person?.profileThumbHash).not.toBe("stale-hash");
|
||||
expect(stored?.profileThumbHash).toBe(person?.profileThumbHash);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { personFilmography, persons } from "@sofa/db/schema";
|
||||
import { clearAllTables, insertTitle, testDb } from "@sofa/db/test-utils";
|
||||
import { clearAllTables, insertTitle, testDb } from "@sofa/test/db";
|
||||
|
||||
import { getLocalFilmography } from "../src/person";
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { afterEach, mock } from "bun:test";
|
||||
|
||||
import { applyMigrations, testDb } from "@sofa/db/test-utils";
|
||||
|
||||
process.env.LOG_LEVEL ??= "error";
|
||||
|
||||
mock.module("@sofa/db/client", () => ({
|
||||
db: testDb,
|
||||
optimizeDatabase: () => {},
|
||||
vacuumDatabase: () => {},
|
||||
closeDatabase: () => {},
|
||||
isDatabaseAccessBlocked: () => false,
|
||||
withDatabaseAccessBlocked: async (fn: () => Promise<unknown> | unknown) => await fn(),
|
||||
}));
|
||||
|
||||
applyMigrations();
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { user } from "@sofa/db/schema";
|
||||
import { clearAllTables, eq, insertUser, testDb } from "@sofa/db/test-utils";
|
||||
import { clearAllTables, eq, insertUser, testDb } from "@sofa/test/db";
|
||||
|
||||
import {
|
||||
claimInitialAdmin,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { parseSofaExport } from "../src/imports/sofa-parser";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { episodes, seasons, titles } from "@sofa/db/schema";
|
||||
import { clearAllTables, eq, testDb } from "@sofa/db/test-utils";
|
||||
import { clearAllTables, eq, testDb } from "@sofa/test/db";
|
||||
|
||||
const TINY_PNG = Buffer.from(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4//8/AwAI/AL+X2NDNwAAAABJRU5ErkJggg==",
|
||||
@@ -16,7 +16,7 @@ beforeEach(() => {
|
||||
clearAllTables();
|
||||
process.env.IMAGE_CACHE_ENABLED = "false";
|
||||
nextBuffer = TINY_PNG;
|
||||
spyOn(globalThis, "fetch").mockImplementation((async (
|
||||
vi.spyOn(globalThis, "fetch").mockImplementation((async (
|
||||
_input: string | URL | Request,
|
||||
_init?: RequestInit,
|
||||
) => {
|
||||
@@ -33,13 +33,12 @@ beforeEach(() => {
|
||||
|
||||
afterEach(() => {
|
||||
delete process.env.IMAGE_CACHE_ENABLED;
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
describe("thumbhash generation", () => {
|
||||
test("generates a thumbhash from a loaded image buffer", async () => {
|
||||
const hash = await generateThumbHash("/poster.png", "posters");
|
||||
expect(hash).toBeString();
|
||||
expect(hash).toBeTypeOf("string");
|
||||
expect(hash).not.toBe("");
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
userEpisodeWatches,
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
insertTvShow,
|
||||
insertUser,
|
||||
testDb,
|
||||
} from "@sofa/db/test-utils";
|
||||
} from "@sofa/test/db";
|
||||
|
||||
import {
|
||||
getUserTitleInfo,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, test } from "bun:test";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
clearAllTables,
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
insertTitle,
|
||||
insertTvShow,
|
||||
insertUser,
|
||||
} from "@sofa/db/test-utils";
|
||||
} from "@sofa/test/db";
|
||||
|
||||
import { getUpcomingFeed } from "../src/discovery";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { isNewerVersion } from "../src/update-check";
|
||||
|
||||
|
||||
Reference in new issue
Block a user