253 lines
8.3 KiB
TypeScript
253 lines
8.3 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { ZodError } from "zod";
|
|
|
|
const { SearchProviderCatalogItemSchema, SearchProviderCatalogResponseSchema, ScrapeResultSchema } =
|
|
await import("../../src/shared/schemas/searchTools.ts");
|
|
const searchToolsModule = await import("../../src/shared/schemas/searchTools.ts");
|
|
|
|
// ── SearchProviderCatalogItemSchema ───────────────────────────────────────────
|
|
|
|
test("SearchProviderCatalogItemSchema: valid search provider parses", () => {
|
|
const item = {
|
|
id: "tavily",
|
|
name: "Tavily",
|
|
kind: "search",
|
|
costPerQuery: 0.001,
|
|
freeMonthlyQuota: 1000,
|
|
searchTypes: ["web", "news"],
|
|
status: "configured",
|
|
configureHref: "/dashboard/providers",
|
|
};
|
|
const result = SearchProviderCatalogItemSchema.safeParse(item);
|
|
assert.ok(result.success, "valid search item should parse");
|
|
if (result.success) {
|
|
assert.equal(result.data.kind, "search");
|
|
assert.equal(result.data.id, "tavily");
|
|
assert.equal(result.data.status, "configured");
|
|
}
|
|
});
|
|
|
|
test("SearchProviderCatalogItemSchema: valid fetch provider parses", () => {
|
|
const item = {
|
|
id: "firecrawl",
|
|
name: "Firecrawl",
|
|
kind: "fetch",
|
|
costPerQuery: 0.002,
|
|
freeMonthlyQuota: 500,
|
|
fetchFormats: ["markdown", "html", "links"],
|
|
status: "configured",
|
|
configureHref: "/dashboard/providers",
|
|
};
|
|
const result = SearchProviderCatalogItemSchema.safeParse(item);
|
|
assert.ok(result.success, "valid fetch item should parse");
|
|
if (result.success) {
|
|
assert.equal(result.data.kind, "fetch");
|
|
assert.deepEqual(result.data.fetchFormats, ["markdown", "html", "links"]);
|
|
}
|
|
});
|
|
|
|
test("SearchProviderCatalogItemSchema: status 'missing' is valid", () => {
|
|
const item = {
|
|
id: "bing",
|
|
name: "Bing",
|
|
kind: "search",
|
|
costPerQuery: 0.005,
|
|
freeMonthlyQuota: 0,
|
|
status: "missing",
|
|
};
|
|
const result = SearchProviderCatalogItemSchema.safeParse(item);
|
|
assert.ok(result.success, "status=missing should parse");
|
|
if (result.success) {
|
|
// configureHref has a default value
|
|
assert.equal(result.data.configureHref, "/dashboard/providers");
|
|
}
|
|
});
|
|
|
|
test("SearchProviderCatalogItemSchema: status 'rate_limited' is valid", () => {
|
|
const item = {
|
|
id: "serper",
|
|
name: "Serper",
|
|
kind: "search",
|
|
costPerQuery: 0.001,
|
|
freeMonthlyQuota: 100,
|
|
status: "rate_limited",
|
|
};
|
|
const result = SearchProviderCatalogItemSchema.safeParse(item);
|
|
assert.ok(result.success, "status=rate_limited should parse");
|
|
});
|
|
|
|
test("SearchProviderCatalogItemSchema: invalid — kind not in enum", () => {
|
|
const item = {
|
|
id: "custom",
|
|
name: "Custom",
|
|
kind: "unknown",
|
|
costPerQuery: 0.001,
|
|
freeMonthlyQuota: 0,
|
|
status: "configured",
|
|
};
|
|
const result = SearchProviderCatalogItemSchema.safeParse(item);
|
|
assert.ok(!result.success, "invalid kind should fail");
|
|
if (!result.success) {
|
|
assert.ok(result.error instanceof ZodError);
|
|
}
|
|
});
|
|
|
|
test("SearchProviderCatalogItemSchema: invalid — negative costPerQuery", () => {
|
|
const item = {
|
|
id: "test",
|
|
name: "Test",
|
|
kind: "search",
|
|
costPerQuery: -0.001,
|
|
freeMonthlyQuota: 0,
|
|
status: "configured",
|
|
};
|
|
const result = SearchProviderCatalogItemSchema.safeParse(item);
|
|
assert.ok(!result.success, "negative costPerQuery should fail");
|
|
});
|
|
|
|
test("SearchProviderCatalogItemSchema: invalid — status not in enum", () => {
|
|
const item = {
|
|
id: "test",
|
|
name: "Test",
|
|
kind: "search",
|
|
costPerQuery: 0,
|
|
freeMonthlyQuota: 0,
|
|
status: "active",
|
|
};
|
|
const result = SearchProviderCatalogItemSchema.safeParse(item);
|
|
assert.ok(!result.success, "invalid status should fail");
|
|
});
|
|
|
|
// ── SearchProviderCatalogResponseSchema ───────────────────────────────────────
|
|
|
|
test("SearchProviderCatalogResponseSchema: valid response with multiple providers", () => {
|
|
const response = {
|
|
providers: [
|
|
{
|
|
id: "tavily",
|
|
name: "Tavily",
|
|
kind: "search",
|
|
costPerQuery: 0.001,
|
|
freeMonthlyQuota: 1000,
|
|
status: "configured",
|
|
},
|
|
{
|
|
id: "firecrawl",
|
|
name: "Firecrawl",
|
|
kind: "fetch",
|
|
costPerQuery: 0.002,
|
|
freeMonthlyQuota: 500,
|
|
status: "configured",
|
|
},
|
|
],
|
|
};
|
|
const result = SearchProviderCatalogResponseSchema.safeParse(response);
|
|
assert.ok(result.success, "valid response should parse");
|
|
if (result.success) {
|
|
assert.equal(result.data.providers.length, 2);
|
|
assert.equal(result.data.providers[0].kind, "search");
|
|
assert.equal(result.data.providers[1].kind, "fetch");
|
|
}
|
|
});
|
|
|
|
test("SearchProviderCatalogResponseSchema: empty providers array is valid", () => {
|
|
const result = SearchProviderCatalogResponseSchema.safeParse({ providers: [] });
|
|
assert.ok(result.success, "empty providers array should parse");
|
|
});
|
|
|
|
test("SearchProviderCatalogResponseSchema: invalid — providers not array", () => {
|
|
const result = SearchProviderCatalogResponseSchema.safeParse({ providers: "not-array" });
|
|
assert.ok(!result.success, "non-array providers should fail");
|
|
});
|
|
|
|
test("SearchProviderCatalogResponseSchemaFull alias is not exported", () => {
|
|
assert.equal("SearchProviderCatalogResponseSchemaFull" in searchToolsModule, false);
|
|
assert.equal(typeof searchToolsModule.SearchProviderCatalogResponseSchema.safeParse, "function");
|
|
});
|
|
|
|
// ── ScrapeResultSchema ────────────────────────────────────────────────────────
|
|
|
|
test("ScrapeResultSchema: valid scrape result parses", () => {
|
|
const result_data = {
|
|
provider: "firecrawl",
|
|
url: "https://example.com",
|
|
content: "# Hello\n\nThis is the content.",
|
|
links: ["https://example.com/page1", "https://example.com/page2"],
|
|
metadata: {
|
|
title: "Example Domain",
|
|
description: "An example page.",
|
|
},
|
|
screenshot_url: null,
|
|
};
|
|
const result = ScrapeResultSchema.safeParse(result_data);
|
|
assert.ok(result.success, "valid scrape result should parse");
|
|
if (result.success) {
|
|
assert.equal(result.data.provider, "firecrawl");
|
|
assert.equal(result.data.links.length, 2);
|
|
assert.equal(result.data.metadata?.title, "Example Domain");
|
|
}
|
|
});
|
|
|
|
test("ScrapeResultSchema: null metadata is valid", () => {
|
|
const result_data = {
|
|
provider: "jina-reader",
|
|
url: "https://example.com",
|
|
content: "Content here.",
|
|
links: [],
|
|
metadata: null,
|
|
screenshot_url: null,
|
|
};
|
|
const result = ScrapeResultSchema.safeParse(result_data);
|
|
assert.ok(result.success, "null metadata should parse");
|
|
});
|
|
|
|
test("ScrapeResultSchema: with screenshot_url as string", () => {
|
|
const result_data = {
|
|
provider: "firecrawl",
|
|
url: "https://example.com",
|
|
content: "Content.",
|
|
links: [],
|
|
metadata: { title: null, description: null },
|
|
screenshot_url: "https://screenshots.example.com/abc123.png",
|
|
};
|
|
const result = ScrapeResultSchema.safeParse(result_data);
|
|
assert.ok(result.success, "screenshot_url as string should parse");
|
|
if (result.success) {
|
|
assert.equal(result.data.screenshot_url, "https://screenshots.example.com/abc123.png");
|
|
}
|
|
});
|
|
|
|
test("ScrapeResultSchema: null metadata title/description is valid", () => {
|
|
const result_data = {
|
|
provider: "tavily-search",
|
|
url: "https://example.com",
|
|
content: "Content.",
|
|
links: [],
|
|
metadata: { title: null, description: null },
|
|
screenshot_url: null,
|
|
};
|
|
const result = ScrapeResultSchema.safeParse(result_data);
|
|
assert.ok(result.success, "null title/description in metadata should parse");
|
|
});
|
|
|
|
test("ScrapeResultSchema: invalid — missing required fields", () => {
|
|
const result = ScrapeResultSchema.safeParse({ provider: "firecrawl" });
|
|
assert.ok(!result.success, "missing required fields should fail");
|
|
if (!result.success) {
|
|
assert.ok(result.error instanceof ZodError);
|
|
}
|
|
});
|
|
|
|
test("ScrapeResultSchema: invalid — links must be array of strings", () => {
|
|
const result = ScrapeResultSchema.safeParse({
|
|
provider: "firecrawl",
|
|
url: "https://example.com",
|
|
content: "Content.",
|
|
links: [42, 43], // non-strings
|
|
metadata: null,
|
|
screenshot_url: null,
|
|
});
|
|
assert.ok(!result.success, "non-string links should fail");
|
|
});
|