Files
Multi-Debrid-Downloader/tests/renderer-settings-form.test.tsx
Sucukdeluxe 2e94484274 Validate daily schedule start times
Disable schedule activation until the local time input matches a strict HH:MM value.

Keep a defensive activation guard that surfaces a localized validation error and skips persistence when invoked with invalid state.

Add red-green coverage for empty, malformed, out-of-range hour, and out-of-range minute values.
2026-08-22 10:12:25 +02:00

100 lines
3.6 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import type { RendererSettings, UiSnapshot } from "../src/shared/types";
import {
activateDailyScheduleSettings,
buildDailyScheduleSettingsUpdate,
persistDailyScheduleSettingsUpdate
} from "../src/renderer/App";
describe("daily schedule settings form", () => {
it("maps local time and the chosen start day to the recurring schedule settings", () => {
const now = new Date(2026, 7, 22, 18, 30, 0, 0);
expect(buildDailyScheduleSettingsUpdate("08:15", "today", now)).toEqual({
dailyStartEnabled: true,
dailyStartMinuteOfDay: 8 * 60 + 15,
dailyStartFirstLocalDate: "2026-08-22"
});
expect(buildDailyScheduleSettingsUpdate("23:45", "tomorrow", now)).toEqual({
dailyStartEnabled: true,
dailyStartMinuteOfDay: 23 * 60 + 45,
dailyStartFirstLocalDate: "2026-08-23"
});
});
it.each(["", "8:15", "24:00", "12:60"])("reports the invalid time %j when activation is invoked directly", async (time) => {
const persist = vi.fn();
const showError = vi.fn();
await expect(activateDailyScheduleSettings(
time,
"today",
persist,
showError,
new Date(2026, 7, 22, 18, 30, 0, 0)
)).resolves.toBe(false);
expect(showError).toHaveBeenCalledWith("Bitte eine gültige Startzeit auswählen.");
expect(persist).not.toHaveBeenCalled();
});
it("applies persisted settings after a successful activation", async () => {
const persisted = { dailyStartEnabled: true } as RendererSettings;
const updateSettings = vi.fn().mockResolvedValue(persisted);
const applySettings = vi.fn();
const getSnapshot = vi.fn();
const applySnapshot = vi.fn();
const showError = vi.fn();
const update = {
dailyStartEnabled: true,
dailyStartMinuteOfDay: 495,
dailyStartFirstLocalDate: "2026-08-23"
};
await expect(persistDailyScheduleSettingsUpdate(update, "activate", {
updateSettings,
getSnapshot,
applySettings,
applySnapshot,
showError
})).resolves.toBe(true);
expect(updateSettings).toHaveBeenCalledWith(update);
expect(applySettings).toHaveBeenCalledWith(persisted);
expect(getSnapshot).not.toHaveBeenCalled();
expect(showError).not.toHaveBeenCalled();
});
it.each([
["activate" as const, "Zeitplan konnte nicht aktiviert werden: Error: Speichern fehlgeschlagen"],
["cancel" as const, "Zeitplan konnte nicht abgebrochen werden: Error: Speichern fehlgeschlagen"]
])("shows %s failures before reconciling the authoritative snapshot", async (operation, expectedMessage) => {
const authoritative = { settings: { dailyStartEnabled: false } } as UiSnapshot;
const sequence: string[] = [];
const updateSettings = vi.fn().mockRejectedValue(new Error("Speichern fehlgeschlagen"));
const getSnapshot = vi.fn(async () => {
sequence.push("snapshot");
return authoritative;
});
const applySnapshot = vi.fn((snapshot: UiSnapshot) => {
sequence.push(`apply:${String(snapshot.settings.dailyStartEnabled)}`);
});
const showError = vi.fn((message: string) => {
sequence.push(`error:${message}`);
});
await expect(persistDailyScheduleSettingsUpdate({ dailyStartEnabled: false }, operation, {
updateSettings,
getSnapshot,
applySettings: vi.fn(),
applySnapshot,
showError
})).resolves.toBe(false);
expect(showError).toHaveBeenCalledWith(expectedMessage);
expect(getSnapshot).toHaveBeenCalledTimes(1);
expect(applySnapshot).toHaveBeenCalledWith(authoritative);
expect(sequence).toEqual([`error:${expectedMessage}`, "snapshot", "apply:false"]);
});
});