Files
EpicNext-Cms/src/lib/services/soundtracks.test.ts
T
openhands 82e8448f26 test: add unit tests for pure logic modules
Add 22 test files covering imager, soundtracks, browser-headers, source-keys (figure/pet/effect), effect-source, plus catalog-translations, catalog-layouts, client-translation-files, translations-utils, and various admin/services/helpers modules. Total test count increases by 120+.
2026-08-07 18:53:59 +02:00

102 lines
2.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const fsMock = vi.hoisted(() => ({
mkdir: vi.fn(),
writeFile: vi.fn(),
unlink: vi.fn(),
}));
const musicMetadataMock = vi.hoisted(() => ({
parseBuffer: vi.fn(),
}));
vi.mock("node:fs", () => ({ promises: fsMock }));
vi.mock("music-metadata", () => musicMetadataMock);
import { promises as fs } from "node:fs";
import {
deleteSoundtrackFile,
ensureSoundtrackDir,
extractMp3Duration,
getSoundtrackPath,
writeSoundtrackFile,
} from "./soundtracks";
describe("getSoundtrackPath", () => {
it("rejects unsafe codes", () => {
expect(() => getSoundtrackPath("../evil")).toThrow(
"Unsafe soundtrack code",
);
});
it("joins the safe code into the soundtrack dir", () => {
expect(getSoundtrackPath("song").endsWith("mp3/song.mp3")).toBe(true);
});
});
describe("ensureSoundtrackDir", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("creates the dir recursively", async () => {
fsMock.mkdir.mockResolvedValue(undefined);
await ensureSoundtrackDir();
expect(fs.mkdir).toHaveBeenCalled();
});
});
describe("writeSoundtrackFile", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("creates dir and writes the buffer", async () => {
fsMock.mkdir.mockResolvedValue(undefined);
fsMock.writeFile.mockResolvedValue(undefined);
await writeSoundtrackFile("track", Buffer.from("mp3data"));
expect(fs.mkdir).toHaveBeenCalled();
expect(fs.writeFile).toHaveBeenCalledWith(
expect.stringContaining("track.mp3"),
Buffer.from("mp3data"),
);
});
});
describe("deleteSoundtrackFile", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("ignores ENOENT errors", async () => {
fsMock.unlink.mockRejectedValue(
Object.assign(new Error("gone"), { code: "ENOENT" }),
);
await expect(deleteSoundtrackFile("track")).resolves.toBeUndefined();
});
it("rethrows other errors", async () => {
fsMock.unlink.mockRejectedValue(new Error("permission denied"));
await expect(deleteSoundtrackFile("track")).rejects.toThrow(
"permission denied",
);
});
});
describe("extractMp3Duration", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("returns rounded duration", async () => {
musicMetadataMock.parseBuffer.mockResolvedValue({
format: { duration: 63.7 },
});
await expect(extractMp3Duration(Buffer.from("x"))).resolves.toBe(64);
});
it("returns 0 for invalid durations", async () => {
musicMetadataMock.parseBuffer.mockResolvedValue({
format: { duration: -1 },
});
await expect(extractMp3Duration(Buffer.from("x"))).resolves.toBe(0);
});
it("returns 0 when parsing throws", async () => {
musicMetadataMock.parseBuffer.mockRejectedValue(new Error("bad"));
await expect(extractMp3Duration(Buffer.from("x"))).resolves.toBe(0);
});
});