Files
automaker/apps/server/tests/unit/providers/base-provider.test.ts
Kacper dd58b70730 fix: resolve critical package issues and update imports
CRITICAL FIXES:
- Fix dependency-resolver ES module failure by reverting to CommonJS
  - Removed "type": "module" from package.json
  - Changed tsconfig.json module from "ESNext" to "commonjs"
  - Added exports field for better module resolution
  - Package now works correctly at runtime

- Fix Feature type incompatibility between server and UI
  - Added FeatureImagePath interface to @automaker/types
  - Made imagePaths property accept multiple formats
  - Added index signature for backward compatibility

HIGH PRIORITY FIXES:
- Remove duplicate model-resolver.ts from apps/server/src/lib/
  - Update sdk-options.ts to import from @automaker/model-resolver
  - Use @automaker/types for CLAUDE_MODEL_MAP and DEFAULT_MODELS

- Remove duplicate session types from apps/ui/src/types/
  - Deleted identical session.ts file
  - Use @automaker/types for session type definitions

- Update source file Feature imports
  - Fix create.ts and update.ts to import Feature from @automaker/types
  - Separate Feature type import from FeatureLoader class import

MEDIUM PRIORITY FIXES:
- Remove unused imports
  - Remove unused AbortError from agent-service.ts
  - Remove unused MessageSquare icon from kanban-card.tsx
  - Consolidate duplicate React imports in hotkey-button.tsx

- Update test file imports to use @automaker/* packages
  - Update 12 test files to import from @automaker/utils
  - Update 2 test files to import from @automaker/platform
  - Update 1 test file to import from @automaker/model-resolver
  - Update dependency-resolver.test.ts imports
  - Update providers/types imports to @automaker/types

VERIFICATION:
- Server builds successfully ✓
- All 6 shared packages build correctly ✓
- Test imports updated and verified ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 00:16:00 +01:00

243 lines
7.1 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { BaseProvider } from "@/providers/base-provider.js";
import type {
ProviderConfig,
ExecuteOptions,
ProviderMessage,
InstallationStatus,
ModelDefinition,
} from "@automaker/types";
// Concrete implementation for testing the abstract class
class TestProvider extends BaseProvider {
getName(): string {
return "test-provider";
}
async *executeQuery(
_options: ExecuteOptions
): AsyncGenerator<ProviderMessage> {
yield { type: "text", text: "test response" };
}
async detectInstallation(): Promise<InstallationStatus> {
return { installed: true };
}
getAvailableModels(): ModelDefinition[] {
return [
{ id: "test-model-1", name: "Test Model 1", description: "A test model" },
];
}
}
describe("base-provider.ts", () => {
describe("constructor", () => {
it("should initialize with empty config when none provided", () => {
const provider = new TestProvider();
expect(provider.getConfig()).toEqual({});
});
it("should initialize with provided config", () => {
const config: ProviderConfig = {
apiKey: "test-key",
baseUrl: "https://test.com",
};
const provider = new TestProvider(config);
expect(provider.getConfig()).toEqual(config);
});
it("should call getName() during initialization", () => {
const provider = new TestProvider();
expect(provider.getName()).toBe("test-provider");
});
});
describe("validateConfig", () => {
it("should return valid when config exists", () => {
const provider = new TestProvider({ apiKey: "test" });
const result = provider.validateConfig();
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
expect(result.warnings).toHaveLength(0);
});
it("should return invalid when config is undefined", () => {
// Create provider without config
const provider = new TestProvider();
// Manually set config to undefined to test edge case
(provider as any).config = undefined;
const result = provider.validateConfig();
expect(result.valid).toBe(false);
expect(result.errors).toContain("Provider config is missing");
});
it("should return valid for empty config object", () => {
const provider = new TestProvider({});
const result = provider.validateConfig();
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it("should include warnings array in result", () => {
const provider = new TestProvider();
const result = provider.validateConfig();
expect(result).toHaveProperty("warnings");
expect(Array.isArray(result.warnings)).toBe(true);
});
});
describe("supportsFeature", () => {
it("should support 'tools' feature", () => {
const provider = new TestProvider();
expect(provider.supportsFeature("tools")).toBe(true);
});
it("should support 'text' feature", () => {
const provider = new TestProvider();
expect(provider.supportsFeature("text")).toBe(true);
});
it("should not support unknown features", () => {
const provider = new TestProvider();
expect(provider.supportsFeature("vision")).toBe(false);
expect(provider.supportsFeature("mcp")).toBe(false);
expect(provider.supportsFeature("unknown")).toBe(false);
});
it("should be case-sensitive", () => {
const provider = new TestProvider();
expect(provider.supportsFeature("TOOLS")).toBe(false);
expect(provider.supportsFeature("Text")).toBe(false);
});
});
describe("getConfig", () => {
it("should return current config", () => {
const config: ProviderConfig = {
apiKey: "test-key",
model: "test-model",
};
const provider = new TestProvider(config);
expect(provider.getConfig()).toEqual(config);
});
it("should return same reference", () => {
const config: ProviderConfig = { apiKey: "test" };
const provider = new TestProvider(config);
const retrieved1 = provider.getConfig();
const retrieved2 = provider.getConfig();
expect(retrieved1).toBe(retrieved2);
});
});
describe("setConfig", () => {
it("should merge partial config with existing config", () => {
const provider = new TestProvider({ apiKey: "original-key" });
provider.setConfig({ model: "new-model" });
expect(provider.getConfig()).toEqual({
apiKey: "original-key",
model: "new-model",
});
});
it("should override existing fields", () => {
const provider = new TestProvider({ apiKey: "old-key", model: "old-model" });
provider.setConfig({ apiKey: "new-key" });
expect(provider.getConfig()).toEqual({
apiKey: "new-key",
model: "old-model",
});
});
it("should accept empty object", () => {
const provider = new TestProvider({ apiKey: "test" });
const originalConfig = provider.getConfig();
provider.setConfig({});
expect(provider.getConfig()).toEqual(originalConfig);
});
it("should handle multiple updates", () => {
const provider = new TestProvider();
provider.setConfig({ apiKey: "key1" });
provider.setConfig({ model: "model1" });
provider.setConfig({ baseUrl: "https://test.com" });
expect(provider.getConfig()).toEqual({
apiKey: "key1",
model: "model1",
baseUrl: "https://test.com",
});
});
it("should preserve other fields when updating one field", () => {
const provider = new TestProvider({
apiKey: "key",
model: "model",
baseUrl: "https://test.com",
});
provider.setConfig({ model: "new-model" });
expect(provider.getConfig()).toEqual({
apiKey: "key",
model: "new-model",
baseUrl: "https://test.com",
});
});
});
describe("abstract methods", () => {
it("should require getName implementation", () => {
const provider = new TestProvider();
expect(typeof provider.getName).toBe("function");
expect(provider.getName()).toBe("test-provider");
});
it("should require executeQuery implementation", async () => {
const provider = new TestProvider();
expect(typeof provider.executeQuery).toBe("function");
const generator = provider.executeQuery({
prompt: "test",
projectDirectory: "/test",
});
const result = await generator.next();
expect(result.value).toEqual({ type: "text", text: "test response" });
});
it("should require detectInstallation implementation", async () => {
const provider = new TestProvider();
expect(typeof provider.detectInstallation).toBe("function");
const status = await provider.detectInstallation();
expect(status).toHaveProperty("installed");
});
it("should require getAvailableModels implementation", () => {
const provider = new TestProvider();
expect(typeof provider.getAvailableModels).toBe("function");
const models = provider.getAvailableModels();
expect(Array.isArray(models)).toBe(true);
expect(models.length).toBeGreaterThan(0);
});
});
});