mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
113 lines
4.5 KiB
TypeScript
113 lines
4.5 KiB
TypeScript
import type { FastifyInstance } from "fastify";
|
|||
|
|
import { beforeAll, describe, expect, it } from "vitest";
|
||
|
|
import { settingsSchema as beautifySettingsSchema } from "../../../apps/api/src/lib/beautify/constants.js";
|
||
|
|
import { getToolConfig } from "../../../apps/api/src/routes/tool-factory.js";
|
||
|
|
import { registerColorAdjustments } from "../../../apps/api/src/routes/tools/adjust-colors.js";
|
||
|
|
import { registerBorder } from "../../../apps/api/src/routes/tools/border.js";
|
||
|
|
import { registerCompress } from "../../../apps/api/src/routes/tools/compress.js";
|
||
|
|
import { registerConvert } from "../../../apps/api/src/routes/tools/convert.js";
|
||
|
|
import { registerGifTools } from "../../../apps/api/src/routes/tools/gif-tools.js";
|
||
|
|
import { registerLqipPlaceholder } from "../../../apps/api/src/routes/tools/lqip-placeholder.js";
|
||
|
|
import { registerOptimizeForWeb } from "../../../apps/api/src/routes/tools/optimize-for-web.js";
|
||
|
|
import { registerResize } from "../../../apps/api/src/routes/tools/resize.js";
|
||
|
|
import { registerRotate } from "../../../apps/api/src/routes/tools/rotate.js";
|
||
|
|
import { registerSplit } from "../../../apps/api/src/routes/tools/split.js";
|
||
|
|
|
||
|
|
const app = {
|
||
|
|
post: () => undefined,
|
||
|
|
} as unknown as FastifyInstance;
|
||
|
|
|
||
|
|
beforeAll(() => {
|
||
|
|
registerConvert(app);
|
||
|
|
registerCompress(app);
|
||
|
|
registerOptimizeForWeb(app);
|
||
|
|
registerResize(app);
|
||
|
|
registerSplit(app);
|
||
|
|
registerGifTools(app);
|
||
|
|
registerColorAdjustments(app);
|
||
|
|
registerBorder(app);
|
||
|
|
registerLqipPlaceholder(app);
|
||
|
|
registerRotate(app);
|
||
|
|
});
|
||
|
|
|
||
|
|
function parses(toolId: string, settings: Record<string, unknown>): boolean {
|
||
|
|
const config = getToolConfig(toolId);
|
||
|
|
if (!config) throw new Error(`${toolId} must be registered`);
|
||
|
|
return config.settingsSchema.safeParse(settings).success;
|
||
|
|
}
|
||
|
|
|
||
|
|
describe("Sharp-backed image settings schemas", () => {
|
||
|
|
it.each([
|
||
|
|
["convert", { format: "jpg", quality: 50.5 }],
|
||
|
|
["compress", { quality: 50.5 }],
|
||
|
|
["optimize-for-web", { quality: 50.5 }],
|
||
|
|
["split", { quality: 50.5 }],
|
||
|
|
["gif-tools", { mode: "optimize", effort: 5.5 }],
|
||
|
|
])("rejects fractional integer settings for %s", (toolId, settings) => {
|
||
|
|
expect(parses(toolId, settings)).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it.each([
|
||
|
|
["optimize-for-web", { maxWidth: 640.5 }],
|
||
|
|
["optimize-for-web", { maxHeight: Number.POSITIVE_INFINITY }],
|
||
|
|
["split", { columns: 2.5 }],
|
||
|
|
["split", { rows: 2.5 }],
|
||
|
|
["split", { tileWidth: 20.5 }],
|
||
|
|
["split", { tileHeight: 20.5 }],
|
||
|
|
["gif-tools", { width: 100.5 }],
|
||
|
|
["gif-tools", { height: 100.5 }],
|
||
|
|
["gif-tools", { colors: 16.5 }],
|
||
|
|
["gif-tools", { frameNumber: 1.5 }],
|
||
|
|
["gif-tools", { frameStart: 1.5 }],
|
||
|
|
["gif-tools", { frameEnd: 1.5 }],
|
||
|
|
["gif-tools", { loop: 1.5 }],
|
||
|
|
])("rejects non-integer dimensions or counts for %s", (toolId, settings) => {
|
||
|
|
expect(parses(toolId, settings)).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("rejects a non-finite resize percentage", () => {
|
||
|
|
expect(parses("resize", { percentage: Number.POSITIVE_INFINITY })).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it.each([
|
||
|
|
["adjust-colors", { hue: Number.MIN_VALUE }],
|
||
|
|
["border", { padding: Number.MIN_VALUE }],
|
||
|
|
["border", { shadowOffsetX: 0.5 }],
|
||
|
|
])(
|
||
|
|
"rejects values that downstream Sharp operations cannot represent for %s",
|
||
|
|
(toolId, settings) => {
|
||
|
|
expect(parses(toolId, settings)).toBe(false);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
it("accepts either disabled or Sharp-supported LQIP blur values", () => {
|
||
|
|
expect(parses("lqip-placeholder", { blur: 0 })).toBe(true);
|
||
|
|
expect(parses("lqip-placeholder", { blur: 0.3 })).toBe(true);
|
||
|
|
expect(parses("lqip-placeholder", { blur: Number.MIN_VALUE })).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("rejects fractional Beautify pixel geometry", () => {
|
||
|
|
expect(beautifySettingsSchema.safeParse({ padding: Number.MIN_VALUE }).success).toBe(false);
|
||
|
|
expect(beautifySettingsSchema.safeParse({ shadowOffsetY: 0.5 }).success).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("rejects Beautify colors that Sharp cannot decode", () => {
|
||
|
|
expect(beautifySettingsSchema.safeParse({ backgroundColor: "" }).success).toBe(false);
|
||
|
|
expect(
|
||
|
|
beautifySettingsSchema.safeParse({ shadowPreset: "custom", shadowColor: "" }).success,
|
||
|
|
).toBe(false);
|
||
|
|
expect(
|
||
|
|
beautifySettingsSchema.safeParse({
|
||
|
|
backgroundColor: "#667eea",
|
||
|
|
shadowPreset: "custom",
|
||
|
|
shadowColor: "#000000",
|
||
|
|
}).success,
|
||
|
|
).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("accepts finite large rotation angles for normalization", () => {
|
||
|
|
expect(parses("rotate", { angle: 10_000_000.000000002 })).toBe(true);
|
||
|
|
expect(parses("rotate", { angle: Number.POSITIVE_INFINITY })).toBe(false);
|
||
|
|
});
|
||
|
|
});
|