You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

396 lines
11 KiB

import { describe, it, expect, beforeEach, vi } from "vitest";
import {
STORAGE_KEY,
COST_DATA_STORAGE_KEY,
GENERATE_IMAGE_DEFAULTS_KEY,
PROVIDER_SETTINGS_KEY,
NODE_DEFAULTS_KEY,
loadSaveConfigs,
saveSaveConfig,
loadWorkflowCostData,
saveWorkflowCostData,
loadGenerateImageDefaults,
saveGenerateImageDefaults,
getProviderSettings,
saveProviderSettings,
defaultProviderSettings,
generateWorkflowId,
loadNodeDefaults,
saveNodeDefaults,
getGenerateImageDefaults,
getGenerateVideoDefaults,
getLLMDefaults,
} from "../localStorage";
// Mock localStorage
const localStorageMock = (() => {
let store: Record<string, string> = {};
return {
getItem: vi.fn((key: string) => store[key] ?? null),
setItem: vi.fn((key: string, value: string) => {
store[key] = value;
}),
removeItem: vi.fn((key: string) => {
delete store[key];
}),
clear: vi.fn(() => {
store = {};
}),
};
})();
Object.defineProperty(globalThis, "localStorage", {
value: localStorageMock,
writable: true,
});
describe("localStorage utilities", () => {
beforeEach(() => {
localStorageMock.clear();
vi.clearAllMocks();
});
describe("loadSaveConfigs", () => {
it("returns empty object when localStorage is empty", () => {
const result = loadSaveConfigs();
expect(result).toEqual({});
});
it("returns stored configs when data exists", () => {
const mockConfigs = {
"wf_123": {
workflowId: "wf_123",
name: "Test Workflow",
path: "/path/to/workflow",
lastSaved: Date.now(),
},
};
localStorageMock.setItem(STORAGE_KEY, JSON.stringify(mockConfigs));
const result = loadSaveConfigs();
expect(result).toEqual(mockConfigs);
});
});
describe("saveSaveConfig", () => {
it("stores and retrieves config", () => {
const config = {
workflowId: "wf_456",
name: "New Workflow",
path: "/path/to/new",
lastSaved: Date.now(),
};
saveSaveConfig(config);
const stored = JSON.parse(localStorageMock.getItem(STORAGE_KEY)!);
expect(stored["wf_456"]).toEqual(config);
});
it("merges with existing configs", () => {
const existingConfig = {
workflowId: "wf_existing",
name: "Existing",
path: "/existing",
lastSaved: Date.now(),
};
localStorageMock.setItem(
STORAGE_KEY,
JSON.stringify({ "wf_existing": existingConfig })
);
const newConfig = {
workflowId: "wf_new",
name: "New",
path: "/new",
lastSaved: Date.now(),
};
saveSaveConfig(newConfig);
const stored = JSON.parse(localStorageMock.getItem(STORAGE_KEY)!);
expect(stored["wf_existing"]).toEqual(existingConfig);
expect(stored["wf_new"]).toEqual(newConfig);
});
});
describe("loadWorkflowCostData", () => {
it("returns null when localStorage is empty", () => {
const result = loadWorkflowCostData("wf_123");
expect(result).toBeNull();
});
it("returns null when workflow not found", () => {
localStorageMock.setItem(
COST_DATA_STORAGE_KEY,
JSON.stringify({ "wf_other": { workflowId: "wf_other", totalCost: 10 } })
);
const result = loadWorkflowCostData("wf_missing");
expect(result).toBeNull();
});
it("returns cost data when found", () => {
const costData = { workflowId: "wf_123", totalCost: 5.5 };
localStorageMock.setItem(
COST_DATA_STORAGE_KEY,
JSON.stringify({ "wf_123": costData })
);
const result = loadWorkflowCostData("wf_123");
expect(result).toEqual(costData);
});
it("returns null on invalid JSON", () => {
localStorageMock.setItem(COST_DATA_STORAGE_KEY, "invalid json");
const result = loadWorkflowCostData("wf_123");
expect(result).toBeNull();
});
});
describe("saveWorkflowCostData", () => {
it("stores cost data", () => {
const costData = { workflowId: "wf_789", totalCost: 2.5 };
saveWorkflowCostData(costData);
const stored = JSON.parse(localStorageMock.getItem(COST_DATA_STORAGE_KEY)!);
expect(stored["wf_789"]).toEqual(costData);
});
});
describe("loadGenerateImageDefaults", () => {
it("returns default settings when localStorage is empty", () => {
const result = loadGenerateImageDefaults();
expect(result).toEqual({
aspectRatio: "1:1",
resolution: "1K",
model: "nano-banana-pro",
useGoogleSearch: false,
});
});
it("returns stored settings when data exists", () => {
const customSettings = {
aspectRatio: "16:9",
resolution: "2K",
model: "nano-banana",
useGoogleSearch: true,
};
localStorageMock.setItem(
GENERATE_IMAGE_DEFAULTS_KEY,
JSON.stringify(customSettings)
);
const result = loadGenerateImageDefaults();
expect(result).toEqual(customSettings);
});
it("returns default on invalid JSON", () => {
localStorageMock.setItem(GENERATE_IMAGE_DEFAULTS_KEY, "not valid json");
const result = loadGenerateImageDefaults();
expect(result).toEqual({
aspectRatio: "1:1",
resolution: "1K",
model: "nano-banana-pro",
useGoogleSearch: false,
});
});
});
describe("saveGenerateImageDefaults", () => {
it("merges partial settings with existing", () => {
const existing = {
aspectRatio: "1:1",
resolution: "1K",
model: "nano-banana-pro",
useGoogleSearch: false,
};
localStorageMock.setItem(
GENERATE_IMAGE_DEFAULTS_KEY,
JSON.stringify(existing)
);
saveGenerateImageDefaults({ aspectRatio: "4:3" });
const stored = JSON.parse(localStorageMock.getItem(GENERATE_IMAGE_DEFAULTS_KEY)!);
expect(stored).toEqual({
...existing,
aspectRatio: "4:3",
});
});
});
describe("getProviderSettings", () => {
it("returns default settings when localStorage is empty", () => {
const result = getProviderSettings();
expect(result).toEqual(defaultProviderSettings);
});
it("merges with defaults for new providers", () => {
// Simulate old settings missing a new provider
const oldSettings = {
providers: {
gemini: { id: "gemini", name: "Google Gemini", enabled: true, apiKey: "test-key" },
},
};
localStorageMock.setItem(
PROVIDER_SETTINGS_KEY,
JSON.stringify(oldSettings)
);
const result = getProviderSettings();
// Should have the stored gemini settings
expect(result.providers.gemini.apiKey).toBe("test-key");
// Should also have the default providers that were missing
expect(result.providers.replicate).toBeDefined();
expect(result.providers.fal).toBeDefined();
});
it("returns default on invalid JSON", () => {
localStorageMock.setItem(PROVIDER_SETTINGS_KEY, "invalid");
const result = getProviderSettings();
expect(result).toEqual(defaultProviderSettings);
});
});
describe("saveProviderSettings", () => {
it("stores provider settings", () => {
const settings = {
providers: {
gemini: { id: "gemini", name: "Gemini", enabled: true, apiKey: "key123" },
},
};
saveProviderSettings(settings as any);
const stored = JSON.parse(localStorageMock.getItem(PROVIDER_SETTINGS_KEY)!);
expect(stored).toEqual(settings);
});
});
describe("generateWorkflowId", () => {
it("generates unique IDs", () => {
const id1 = generateWorkflowId();
const id2 = generateWorkflowId();
expect(id1).not.toBe(id2);
});
it("has correct format", () => {
const id = generateWorkflowId();
expect(id).toMatch(/^wf_\d+_[a-z0-9]+$/);
});
});
describe("loadNodeDefaults", () => {
it("returns empty object when localStorage is empty", () => {
const result = loadNodeDefaults();
expect(result).toEqual({});
});
it("returns stored config when data exists", () => {
const config = {
generateImage: {
selectedModel: { provider: "fal", modelId: "test-model", displayName: "Test Model" },
aspectRatio: "16:9",
},
llm: {
provider: "openai",
model: "gpt-4.1-mini",
},
};
localStorageMock.setItem(NODE_DEFAULTS_KEY, JSON.stringify(config));
const result = loadNodeDefaults();
expect(result).toEqual(config);
});
it("returns empty object on invalid JSON", () => {
localStorageMock.setItem(NODE_DEFAULTS_KEY, "not valid json");
const result = loadNodeDefaults();
expect(result).toEqual({});
});
});
describe("saveNodeDefaults", () => {
it("stores config to localStorage", () => {
const config = {
generateVideo: {
selectedModel: { provider: "replicate", modelId: "video-model", displayName: "Video Model" },
},
};
saveNodeDefaults(config);
const stored = JSON.parse(localStorageMock.getItem(NODE_DEFAULTS_KEY)!);
expect(stored).toEqual(config);
});
});
describe("getGenerateImageDefaults", () => {
it("returns undefined when not configured", () => {
const result = getGenerateImageDefaults();
expect(result).toBeUndefined();
});
it("returns stored generateImage defaults when configured", () => {
const config = {
generateImage: {
selectedModel: { provider: "gemini", modelId: "nano-banana-pro", displayName: "Nano Banana Pro" },
aspectRatio: "4:3",
useGoogleSearch: true,
},
};
localStorageMock.setItem(NODE_DEFAULTS_KEY, JSON.stringify(config));
const result = getGenerateImageDefaults();
expect(result).toEqual(config.generateImage);
});
});
describe("getGenerateVideoDefaults", () => {
it("returns undefined when not configured", () => {
const result = getGenerateVideoDefaults();
expect(result).toBeUndefined();
});
it("returns stored generateVideo defaults when configured", () => {
const config = {
generateVideo: {
selectedModel: { provider: "fal", modelId: "kling-video", displayName: "Kling Video" },
},
};
localStorageMock.setItem(NODE_DEFAULTS_KEY, JSON.stringify(config));
const result = getGenerateVideoDefaults();
expect(result).toEqual(config.generateVideo);
});
});
describe("getLLMDefaults", () => {
it("returns undefined when not configured", () => {
const result = getLLMDefaults();
expect(result).toBeUndefined();
});
it("returns stored llm defaults when configured", () => {
const config = {
llm: {
provider: "openai",
model: "gpt-4.1-nano",
temperature: 0.5,
maxTokens: 4096,
},
};
localStorageMock.setItem(NODE_DEFAULTS_KEY, JSON.stringify(config));
const result = getLLMDefaults();
expect(result).toEqual(config.llm);
});
});
});