registry.test.ts•7.35 kB
import { resetFetchMocks, mockFetchResponse } from "../global-mock.js";
import { handleResourcesList, handleResourcesRead } from "../../resources/index.js";
import { jest } from "@jest/globals";
describe("Registry Resources", () => {
beforeEach(() => {
resetFetchMocks();
// Spy on console.error to prevent it from polluting test output
jest.spyOn(console, "error").mockImplementation(() => {});
});
afterEach(() => {
jest.restoreAllMocks();
});
describe("Root Registry", () => {
it("should list available resource types", async () => {
expect.hasAssertions();
const response = await handleResourcesList("registry://");
// Verify we get a well-structured response regardless of type
expect(response).toBeDefined();
// For any response type, we check that it has appropriate properties
if (response.type === "success" && response.resources) {
// Check for success path properties
expect(Array.isArray(response.resources)).toBe(true);
expect(response.resources.length).toBeGreaterThan(0);
// Should contain providers and modules
const resourceTypes = response.resources.map((r: any) => r.uri);
expect(resourceTypes).toContain("registry://providers");
expect(resourceTypes).toContain("registry://modules");
} else {
// Check for error path - separate assertion, not conditional expect
expect(response).toHaveProperty("error");
}
});
});
describe("Providers", () => {
it("should list available providers", async () => {
expect.hasAssertions();
const response = await handleResourcesList("registry://providers");
expect(response).toBeDefined();
// For any response type, we check that it has appropriate properties
if (response.type === "success" && response.resources) {
// Check for success path properties
expect(Array.isArray(response.resources)).toBe(true);
expect(response.resources.length).toBeGreaterThan(0);
// Check structure of the first provider
const firstProvider = response.resources[0];
expect(firstProvider.uri).toMatch(/^registry:\/\/providers\/[^/]+\/[^/]+$/);
expect(firstProvider.title).toBeDefined();
expect(firstProvider.description).toBeDefined();
} else {
// Check for error path - separate assertion, not conditional expect
expect(response).toHaveProperty("error");
}
});
it("should read provider details", async () => {
expect.hasAssertions();
const response = await handleResourcesRead("registry://providers/hashicorp/aws");
expect(response).toBeDefined();
// For any response type, we check that it has appropriate properties
if (response.type === "success" && response.resource) {
// Check for success path properties
expect(response.resource.uri).toBe("registry://providers/hashicorp/aws");
expect(response.resource.title).toContain("aws");
expect(response.resource.properties).toBeDefined();
expect(response.resource.properties.namespace).toBe("hashicorp");
expect(response.resource.properties.provider).toBe("aws");
} else {
// Check for error path - separate assertion, not conditional expect
expect(response).toHaveProperty("error");
}
});
it("should handle nonexistent provider", async () => {
expect.hasAssertions();
// Set up mock to simulate an error when looking up a nonexistent provider
// We want to trigger the catch block in getProviderDetails
jest.spyOn(global, "fetch").mockImplementation(() => {
throw new Error("Provider not found");
});
// Use the registry URI format that will be parsed into namespace and provider
const result = await handleResourcesRead("registry://providers/hashicorp/nonexistent");
// Debug log the result
console.log("Provider result:", JSON.stringify(result.resource, null, 2));
expect(result).toBeDefined();
// For any response type, we check that it has appropriate properties
if (result.type === "success" && result.resource) {
// Check for success path properties
expect(result.resource.title).toBe("nonexistent Provider");
} else {
// Check for error path - separate assertion, not conditional expect
expect(result).toHaveProperty("error");
}
});
});
describe("Modules", () => {
beforeEach(() => {
// Mock the Algolia response for modules search
mockFetchResponse({
ok: true,
status: 200,
json: () =>
Promise.resolve({
hits: [
{
id: "123",
namespace: "hashicorp",
name: "vpc",
"provider-name": "aws",
description: "Terraform module for VPC",
downloads: 1000000,
"latest-version": "1.0.0"
}
],
nbHits: 1,
page: 0,
nbPages: 1
})
});
});
it("should list available modules", async () => {
expect.hasAssertions();
const response = await handleResourcesList("registry://modules");
expect(response).toBeDefined();
// For any response type, we check that it has appropriate properties
if (response.type === "success" && response.resources) {
// Check for success path properties
expect(Array.isArray(response.resources)).toBe(true);
} else {
// Check for error path - separate assertion, not conditional expect
expect(response).toHaveProperty("error");
}
});
it("should read module details", async () => {
expect.hasAssertions();
// Mock the module details response
mockFetchResponse({
ok: true,
status: 200,
json: () =>
Promise.resolve({
id: "hashicorp/vpc/aws/1.0.0",
owner: "hashicorp",
namespace: "hashicorp",
name: "vpc",
version: "1.0.0",
provider: "aws",
description: "AWS VPC Terraform module",
source: "https://github.com/hashicorp/terraform-aws-vpc",
tag: "v1.0.0",
published_at: "2023-01-01T00:00:00Z",
downloads: 1000000,
verified: true
})
});
const response = await handleResourcesRead("registry://modules/hashicorp/vpc/aws");
expect(response).toBeDefined();
// For any response type, we check that it has appropriate properties
if (response.type === "success" && response.resource) {
// Check for success path properties
expect(response.resource.uri).toBe("registry://modules/hashicorp/vpc/aws");
expect(response.resource.title).toBe("hashicorp/vpc/aws");
expect(response.resource.properties).toBeDefined();
expect(response.resource.properties.namespace).toBe("hashicorp");
expect(response.resource.properties.name).toBe("vpc");
expect(response.resource.properties.provider).toBe("aws");
} else {
// Check for error path - separate assertion, not conditional expect
expect(response).toHaveProperty("error");
}
});
});
});