Files
automaker/apps/server/tests/unit/providers/base-provider.test.ts
Kacper 23ff99d2e2 feat: add comprehensive integration tests for auto-mode-service
- Created git-test-repo helper for managing test git repositories
- Added 13 integration tests covering:
  - Worktree operations (create, error handling, non-worktree mode)
  - Feature execution (status updates, model selection, duplicate prevention)
  - Auto loop (start/stop, pending features, max concurrency, events)
  - Error handling (provider errors, continue after failures)
- Integration tests use real git operations with temporary repos
- All 416 tests passing with 72.65% overall coverage
- Service coverage improved: agent-service 58%, auto-mode-service 44%, feature-loader 66%

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 13:34:27 +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 "@/providers/types.js";
// 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);
});
});
});