import { act, render } from "../../../test/render"; import { RegistryProvider } from "@effect/atom-react"; import { DEFAULT_SERVER_SETTINGS, type StorageCleanupReport } from "@t3tools/contracts"; import { type ReactNode } from "react"; import { expect, it, vi } from "vite-plus/test"; const state = vi.hoisted(() => ({ settings: {} as typeof DEFAULT_SERVER_SETTINGS, targets: [] as { environmentId: string; settings: typeof DEFAULT_SERVER_SETTINGS; }[], run: vi.fn(), update: vi.fn(), report: null as StorageCleanupReport | null, })); vi.mock(import("../../state/server"), async (original) => { const actual = await original(); const { Atom } = await import("effect/reactivity"); const report = Atom.make(() => ({ _tag: "Success", value: state.report, waiting: false })); const allowed = Atom.make(true); return { ...actual, serverEnvironment: { ...actual.serverEnvironment, storageCleanupReport: (() => report) as never, runStorageCleanup: { ...actual.serverEnvironment.runStorageCleanup, permissionAtom: () => allowed, }, }, }; }); vi.mock(import("../../state/use-atom-command"), async (original) => ({ ...(await original()), useAtomCommand: (() => state.run) as never, })); vi.mock(import("./SettingsScopeContext"), async (original) => ({ ...(await original()), useSettingsScope: (() => { const environments = state.targets.map(({ environmentId, settings }) => ({ environmentId, label: environmentId, serverConfig: { settings, environment: { capabilities: { storageCleanup: true, storageCleanupRun: true, settledWorktreeCleanup: true, }, }, }, })); return { scope: { kind: "all" }, environments, connectedEnvironments: environments, targets: state.targets.map(({ environmentId, settings }) => ({ environmentId, settings, })), target: state.targets[0] ? { settings: state.targets[0].settings } : null, }; }) as never, })); vi.mock(import("./useScopedSettings"), async (original) => ({ ...(await original()), useScopedSettings: (() => state.settings) as never, useScopedSettingsMixed: () => false, useUpdateScopedSettings: () => state.update, useClearScopedSettings: () => vi.fn(), })); vi.mock(import("./settingsLayout"), async (original) => ({ ...(await original()), SettingsPageContainer: (({ children }: { children: ReactNode }) => children) as never, SettingsRow: ({ title, description, status, control, children }) => (

{title}

{description} {status} {control} {children}
), SettingResetButton: (() => null) as never, })); vi.mock(import("../ui/toast"), async (original) => { const actual = await original(); return { ...actual, toastManager: { ...actual.toastManager, add: vi.fn() } }; }); import { StorageCleanupSections } from "./StorageSettings"; function setup() { state.settings = { ...DEFAULT_SERVER_SETTINGS, storageCleanup: { worktreeKeepWhen: "uncommitted-changes", worktreeAfterDays: null, worktreeSettledAfterDays: null, worktreeOnMerge: false, worktreeOnDelete: false, worktreeUnchanged: false, browserArtifactsAfterDays: null, logsAfterDays: null, }, projectSettingsOverrides: {}, }; state.report = null; state.run.mockReset(); state.targets = [ { environmentId: "machine-a", settings: state.settings }, { environmentId: "machine-b", settings: { ...state.settings, storageCleanup: { ...state.settings.storageCleanup }, }, }, ]; state.update.mockReset(); } const panel = () => ( ); const deleteButton = (container: HTMLElement) => Array.from(container.querySelectorAll("button")).find( (button) => button.textContent === "Delete now", )!; it("keeps cleanup disabled when settled retention and all other rules are off", async () => { setup(); await using screen = await render(panel()); const button = deleteButton(screen.container); expect(button.disabled).toBe(true); await act(async () => button.click()); expect(state.run).not.toHaveBeenCalled(); }); function setArtifactRetention(machineIndex: number, value: number | null) { const target = state.targets[machineIndex]!; target.settings = { ...target.settings, storageCleanup: { ...target.settings.storageCleanup, browserArtifactsAfterDays: value }, }; if (machineIndex === 0) state.settings = target.settings; } function retentionSwitch(container: HTMLElement) { return Array.from(container.querySelectorAll('[role="switch"]')).find( (control) => control.getAttribute("aria-label") === "Delete old browser artifacts", )!; } function artifactStatus(container: HTMLElement) { const title = Array.from(container.querySelectorAll("h3")).find( (heading) => heading.textContent === "Delete old browser artifacts", ); return title?.parentElement?.querySelector("span[aria-hidden]") as HTMLSpanElement; } function logsStatus(container: HTMLElement) { const title = Array.from(container.querySelectorAll("h3")).find( (heading) => heading.textContent === "Delete old rotated logs", ); return title?.parentElement?.querySelector("span[aria-hidden]") as HTMLSpanElement; } it("keeps a uniform retention rule free of a transient mixed warning while machines save", async () => { setup(); setArtifactRetention(0, 9); setArtifactRetention(1, 9); let onSettled: (() => void) | undefined; state.update.mockImplementation((_patch, options) => { onSettled = options?.onSettled; }); await using screen = await render(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("true"); await act(async () => screen.container .querySelector('[aria-label="Increase Delete old browser artifacts"]')! .click(), ); setArtifactRetention(0, 10); const machineB = state.targets[1]!; machineB.settings = { ...machineB.settings, storageCleanup: { ...machineB.settings.storageCleanup, logsAfterDays: 30 }, }; await screen.rerender(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("true"); expect(logsStatus(screen.container).getAttribute("aria-hidden")).toBe("false"); setArtifactRetention(1, 10); await act(async () => onSettled?.()); await screen.rerender(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("true"); expect(logsStatus(screen.container).getAttribute("aria-hidden")).toBe("false"); }); it.each([14, 30])( "shows genuine differences after a partial save with a second value of %i", async (secondValue) => { setup(); setArtifactRetention(0, 14); setArtifactRetention(1, secondValue); let onSettled: (() => void) | undefined; state.update.mockImplementation((_patch, options) => { onSettled = options?.onSettled; }); await using screen = await render(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe( String(secondValue === 14), ); await act(async () => retentionSwitch(screen.container).click()); setArtifactRetention(0, null); await screen.rerender(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe( String(secondValue === 14), ); await act(async () => onSettled?.()); await screen.rerender(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("false"); }, ); it("keeps the starting status until overlapping saves for the selected machines settle", async () => { setup(); const onSettled: (() => void)[] = []; state.update.mockImplementation((_patch, options) => { if (options?.onSettled) onSettled.push(options.onSettled); }); await using screen = await render(panel()); await act(async () => retentionSwitch(screen.container).click()); setArtifactRetention(0, 8); await screen.rerender(panel()); await act(async () => retentionSwitch(screen.container).click()); setArtifactRetention(0, null); setArtifactRetention(1, 8); await screen.rerender(panel()); expect(onSettled).toHaveLength(2); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("true"); await act(async () => onSettled[0]!()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("true"); setArtifactRetention(1, null); await act(async () => onSettled[1]!()); await screen.rerender(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("true"); }); it("derives mixed status from a newly selected machine set during an older save", async () => { setup(); let onSettled: (() => void) | undefined; state.update.mockImplementation((_patch, options) => { onSettled = options?.onSettled; }); await using screen = await render(panel()); await act(async () => retentionSwitch(screen.container).click()); setArtifactRetention(0, 8); state.targets[1] = { ...state.targets[1]!, environmentId: "machine-c", settings: { ...state.targets[1]!.settings, storageCleanup: { ...state.targets[1]!.settings.storageCleanup }, }, }; setArtifactRetention(1, 30); await screen.rerender(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("false"); await act(async () => onSettled?.()); await screen.rerender(panel()); expect(artifactStatus(screen.container).getAttribute("aria-hidden")).toBe("false"); });