mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
- 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>
243 lines
7.1 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|