add tests
This commit is contained in:
37
tests/api/client.spec.ts
Normal file
37
tests/api/client.spec.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { describe, it, expect, vi, Mock } from "vitest";
|
||||
import { makeClient } from "../../src/api/client";
|
||||
import { type paths } from "../../generated/schema";
|
||||
import createClient from "openapi-fetch";
|
||||
|
||||
describe("api/client", () => {
|
||||
it("whenClientCreated_thenHeadersInjectedOnEachRequest()", async () => {
|
||||
// Arrange
|
||||
const spy: Mock = vi
|
||||
.spyOn(globalThis as unknown as { fetch: typeof fetch }, "fetch")
|
||||
.mockResolvedValue(
|
||||
new Response(JSON.stringify({ ok: true }), { status: 200 }),
|
||||
);
|
||||
|
||||
try {
|
||||
// Act
|
||||
const jf: ReturnType<typeof createClient<paths>> = makeClient(
|
||||
"http://example:8096",
|
||||
"XYZ",
|
||||
);
|
||||
|
||||
await jf.GET("/System/Info/Public");
|
||||
|
||||
// Assert
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
|
||||
const req: Request = spy.mock.calls[0]?.[0] as Request;
|
||||
expect(req).toBeInstanceOf(Request);
|
||||
|
||||
const h: Headers = req.headers;
|
||||
expect(h.get("X-Emby-Token")).toBe("XYZ");
|
||||
expect(h.get("X-Emby-Authorization")).toContain("jellarr");
|
||||
} finally {
|
||||
spy.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
43
tests/lib/logger.spec.ts
Normal file
43
tests/lib/logger.spec.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { describe, it, expect, vi, Mock } from "vitest";
|
||||
import { logger } from "../../src/lib/logger";
|
||||
|
||||
describe("lib/logger", () => {
|
||||
it("whenInfoCalled_thenWritesToConsoleLog()", () => {
|
||||
// Arrange
|
||||
const spy: Mock = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
|
||||
// Act
|
||||
logger.info("hello");
|
||||
|
||||
// Assert
|
||||
expect(spy).toHaveBeenCalledWith("hello");
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it("whenWarnCalled_thenWritesToConsoleWarn()", () => {
|
||||
// Arrange
|
||||
const spy: Mock = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
|
||||
// Act
|
||||
logger.warn("w");
|
||||
|
||||
// Assert
|
||||
expect(spy).toHaveBeenCalledWith("w");
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it("whenErrorCalled_thenWritesToConsoleError()", () => {
|
||||
// Arrange
|
||||
const spy: Mock = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
|
||||
// Act
|
||||
logger.error("e");
|
||||
|
||||
// Assert
|
||||
expect(spy).toHaveBeenCalledWith("e");
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
74
tests/mappers/system.spec.ts
Normal file
74
tests/mappers/system.spec.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
fromJFRepos,
|
||||
toJFRepos,
|
||||
equalReposUnordered,
|
||||
} from "../../src/mappers/system";
|
||||
import type {
|
||||
JFPluginRepo,
|
||||
PluginRepositoryCfg,
|
||||
} from "../../src/domain/system/types";
|
||||
|
||||
describe("mappers/system", () => {
|
||||
it("whenJellyfinReposGiven_thenFromJFReposMapsToCfgShape()", () => {
|
||||
// Arrange
|
||||
const jf: JFPluginRepo[] = [
|
||||
{ Name: "A", Url: "https://a", Enabled: true },
|
||||
{ Name: "B", Url: "https://b", Enabled: false },
|
||||
];
|
||||
|
||||
// Act
|
||||
const out: PluginRepositoryCfg[] = fromJFRepos(jf);
|
||||
|
||||
// Assert
|
||||
expect(out).toEqual<PluginRepositoryCfg[]>([
|
||||
{ name: "A", url: "https://a", enabled: true },
|
||||
{ name: "B", url: "https://b", enabled: false },
|
||||
]);
|
||||
});
|
||||
|
||||
it("whenCfgReposGiven_thenToJFReposMapsToJellyfinShape()", () => {
|
||||
// Arrange
|
||||
const cfg: PluginRepositoryCfg[] = [
|
||||
{ name: "A", url: "https://a", enabled: true },
|
||||
{ name: "B", url: "https://b", enabled: false },
|
||||
];
|
||||
|
||||
// Act
|
||||
const out: JFPluginRepo[] = toJFRepos(cfg);
|
||||
|
||||
// Assert
|
||||
expect(out).toEqual<JFPluginRepo[]>([
|
||||
{ Name: "A", Url: "https://a", Enabled: true },
|
||||
{ Name: "B", Url: "https://b", Enabled: false },
|
||||
]);
|
||||
});
|
||||
|
||||
it("whenReposReordered_thenEqualReposUnorderedReturnsTrue()", () => {
|
||||
// Arrange
|
||||
const a: PluginRepositoryCfg[] = [
|
||||
{ name: "A", url: "https://a", enabled: true },
|
||||
{ name: "B", url: "https://b", enabled: false },
|
||||
];
|
||||
const b: PluginRepositoryCfg[] = [
|
||||
{ name: "B", url: "https://b", enabled: false },
|
||||
{ name: "A", url: "https://a", enabled: true },
|
||||
];
|
||||
|
||||
// Act & Assert
|
||||
expect(equalReposUnordered(a, b)).toBe(true);
|
||||
});
|
||||
|
||||
it("whenRepoEnabledFlagDiffers_thenEqualReposUnorderedReturnsFalse()", () => {
|
||||
// Arrange
|
||||
const a: PluginRepositoryCfg[] = [
|
||||
{ name: "A", url: "https://a", enabled: true },
|
||||
];
|
||||
const b: PluginRepositoryCfg[] = [
|
||||
{ name: "A", url: "https://a", enabled: false },
|
||||
];
|
||||
|
||||
// Act & Assert
|
||||
expect(equalReposUnordered(a, b)).toBe(false);
|
||||
});
|
||||
});
|
||||
130
tests/services/system/apply.spec.ts
Normal file
130
tests/services/system/apply.spec.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { apply } from "../../../src/services/system/apply";
|
||||
import type {
|
||||
SystemCfg,
|
||||
ServerConfiguration,
|
||||
JFTrickplay,
|
||||
PluginRepositoryCfg,
|
||||
} from "../../../src/domain/system/types";
|
||||
|
||||
function makeConfig(
|
||||
partial?: Partial<ServerConfiguration>,
|
||||
): ServerConfiguration {
|
||||
const base: ServerConfiguration = {
|
||||
EnableMetrics: false,
|
||||
PluginRepositories: [],
|
||||
TrickplayOptions: undefined,
|
||||
} as ServerConfiguration;
|
||||
return { ...base, ...(partial ?? {}) } as ServerConfiguration;
|
||||
}
|
||||
|
||||
describe("services/system/apply", () => {
|
||||
it("whenDesiredEmpty_thenApplyReturnsCurrentUnchanged()", () => {
|
||||
// Arrange
|
||||
const current: ServerConfiguration = makeConfig({ EnableMetrics: true });
|
||||
const desired: SystemCfg = {};
|
||||
|
||||
// Act
|
||||
const updated: ServerConfiguration = apply(current, desired);
|
||||
|
||||
// Assert
|
||||
expect(updated).toEqual(current);
|
||||
});
|
||||
|
||||
it("whenEnableMetricsDiffers_thenApplyUpdatesOnlyEnableMetrics()", () => {
|
||||
// Arrange
|
||||
const current: ServerConfiguration = makeConfig({ EnableMetrics: false });
|
||||
const desired: SystemCfg = { enableMetrics: true };
|
||||
|
||||
// Act
|
||||
const updated: ServerConfiguration = apply(current, desired);
|
||||
|
||||
// Assert
|
||||
expect(updated.EnableMetrics).toBe(true);
|
||||
expect(updated.PluginRepositories).toEqual(current.PluginRepositories);
|
||||
expect(updated.TrickplayOptions).toEqual(current.TrickplayOptions);
|
||||
});
|
||||
|
||||
it("whenPluginRepositoriesProvided_thenApplyReplacesRepos()", () => {
|
||||
// Arrange
|
||||
const current: ServerConfiguration = makeConfig({
|
||||
PluginRepositories: [{ Name: "A", Url: "https://a", Enabled: true }],
|
||||
});
|
||||
const repos: PluginRepositoryCfg[] = [
|
||||
{ name: "B", url: "https://b", enabled: true },
|
||||
{ name: "A", url: "https://a", enabled: true },
|
||||
];
|
||||
const desired: SystemCfg = { pluginRepositories: repos };
|
||||
|
||||
// Act
|
||||
const updated: ServerConfiguration = apply(current, desired);
|
||||
|
||||
// Assert
|
||||
expect(updated.PluginRepositories).toEqual([
|
||||
{ Name: "B", Url: "https://b", Enabled: true },
|
||||
{ Name: "A", Url: "https://a", Enabled: true },
|
||||
]);
|
||||
});
|
||||
|
||||
describe("trickplay tri-state (true/false/null)", () => {
|
||||
it("whenBothBooleansProvided_thenApplySetsBothFields()", () => {
|
||||
// Arrange
|
||||
const current: ServerConfiguration = makeConfig({
|
||||
TrickplayOptions: {} as JFTrickplay,
|
||||
});
|
||||
const desired: SystemCfg = {
|
||||
trickplayOptions: {
|
||||
enableHwAcceleration: true,
|
||||
enableHwEncoding: false,
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
const updated: ServerConfiguration = apply(current, desired);
|
||||
|
||||
// Assert
|
||||
expect(updated.TrickplayOptions?.EnableHwAcceleration).toBe(true);
|
||||
expect(updated.TrickplayOptions?.EnableHwEncoding).toBe(false);
|
||||
});
|
||||
|
||||
it("whenAccelerationIsNull_thenApplyOmitsAccelerationKey()", () => {
|
||||
// Arrange
|
||||
const current: ServerConfiguration = makeConfig({
|
||||
TrickplayOptions: {
|
||||
EnableHwAcceleration: true,
|
||||
EnableHwEncoding: true,
|
||||
},
|
||||
});
|
||||
const desired: SystemCfg = {
|
||||
trickplayOptions: { enableHwAcceleration: null },
|
||||
};
|
||||
|
||||
// Act
|
||||
const updated: ServerConfiguration = apply(current, desired);
|
||||
|
||||
// Assert
|
||||
expect(updated.TrickplayOptions?.EnableHwAcceleration).toBeUndefined();
|
||||
expect(updated.TrickplayOptions?.EnableHwEncoding).toBe(true);
|
||||
});
|
||||
|
||||
it("whenOnlyAccelerationProvided_thenApplyLeavesEncodingUntouched()", () => {
|
||||
// Arrange
|
||||
const current: ServerConfiguration = makeConfig({
|
||||
TrickplayOptions: {
|
||||
EnableHwAcceleration: false,
|
||||
EnableHwEncoding: true,
|
||||
},
|
||||
});
|
||||
const desired: SystemCfg = {
|
||||
trickplayOptions: { enableHwAcceleration: true },
|
||||
};
|
||||
|
||||
// Act
|
||||
const updated: ServerConfiguration = apply(current, desired);
|
||||
|
||||
// Assert
|
||||
expect(updated.TrickplayOptions?.EnableHwAcceleration).toBe(true);
|
||||
expect(updated.TrickplayOptions?.EnableHwEncoding).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -11,5 +11,5 @@
|
||||
"outDir": "dist",
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["src", "generated"]
|
||||
"include": ["src", "tests", "generated"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user