mirror of https://github.com/openclaw/openclaw.git
test(firecrawl): cover client and tool helpers
This commit is contained in:
parent
a8f7c274bc
commit
2ce79428c5
|
|
@ -0,0 +1,77 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { __testing } from "./firecrawl-client.js";
|
||||
|
||||
describe("firecrawl client helpers", () => {
|
||||
it("normalizes mixed search payload shapes into search items", () => {
|
||||
expect(
|
||||
__testing.resolveSearchItems({
|
||||
data: {
|
||||
results: [
|
||||
{
|
||||
sourceURL: "https://www.example.com/post",
|
||||
snippet: "Snippet text",
|
||||
markdown: "# Title\nBody",
|
||||
metadata: {
|
||||
title: "Example title",
|
||||
publishedDate: "2026-03-22",
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
).toEqual([
|
||||
{
|
||||
title: "Example title",
|
||||
url: "https://www.example.com/post",
|
||||
description: "Snippet text",
|
||||
content: "# Title\nBody",
|
||||
published: "2026-03-22",
|
||||
siteName: "example.com",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("parses scrape payloads, extracts text, and marks truncation", () => {
|
||||
const result = __testing.parseFirecrawlScrapePayload({
|
||||
payload: {
|
||||
data: {
|
||||
markdown: "# Hello\n\nThis is a long body for scraping.",
|
||||
metadata: {
|
||||
title: "Example page",
|
||||
sourceURL: "https://docs.example.com/page",
|
||||
statusCode: 200,
|
||||
},
|
||||
},
|
||||
warning: "cached result",
|
||||
},
|
||||
url: "https://docs.example.com/page",
|
||||
extractMode: "text",
|
||||
maxChars: 12,
|
||||
});
|
||||
|
||||
expect(result.finalUrl).toBe("https://docs.example.com/page");
|
||||
expect(result.status).toBe(200);
|
||||
expect(result.extractMode).toBe("text");
|
||||
expect(result.truncated).toBe(true);
|
||||
expect(result.rawLength).toBeGreaterThan(12);
|
||||
expect(String(result.text)).toContain("Hello");
|
||||
expect(String(result.title)).toContain("Example page");
|
||||
expect(String(result.warning)).toContain("cached result");
|
||||
});
|
||||
|
||||
it("throws when scrape payload has no usable content", () => {
|
||||
expect(() =>
|
||||
__testing.parseFirecrawlScrapePayload({
|
||||
payload: {
|
||||
data: {},
|
||||
},
|
||||
url: "https://docs.example.com/page",
|
||||
extractMode: "markdown",
|
||||
maxChars: 100,
|
||||
}),
|
||||
).toThrow("Firecrawl scrape returned no content.");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const runFirecrawlScrape = vi.fn(async (params: Record<string, unknown>) => ({
|
||||
ok: true,
|
||||
params,
|
||||
}));
|
||||
|
||||
vi.mock("./firecrawl-client.js", () => ({
|
||||
runFirecrawlScrape,
|
||||
}));
|
||||
|
||||
describe("firecrawl scrape tool", () => {
|
||||
it("maps scrape params and defaults extract mode to markdown", async () => {
|
||||
const { createFirecrawlScrapeTool } = await import("./firecrawl-scrape-tool.js");
|
||||
const tool = createFirecrawlScrapeTool({
|
||||
config: { env: "test" },
|
||||
} as never);
|
||||
|
||||
const result = await tool.execute("call-1", {
|
||||
url: "https://docs.openclaw.ai",
|
||||
maxChars: 1500,
|
||||
onlyMainContent: false,
|
||||
maxAgeMs: 5000,
|
||||
proxy: "stealth",
|
||||
storeInCache: false,
|
||||
timeoutSeconds: 22,
|
||||
});
|
||||
|
||||
expect(runFirecrawlScrape).toHaveBeenCalledWith({
|
||||
cfg: { env: "test" },
|
||||
url: "https://docs.openclaw.ai",
|
||||
extractMode: "markdown",
|
||||
maxChars: 1500,
|
||||
onlyMainContent: false,
|
||||
maxAgeMs: 5000,
|
||||
proxy: "stealth",
|
||||
storeInCache: false,
|
||||
timeoutSeconds: 22,
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
details: {
|
||||
ok: true,
|
||||
params: {
|
||||
cfg: { env: "test" },
|
||||
url: "https://docs.openclaw.ai",
|
||||
extractMode: "markdown",
|
||||
maxChars: 1500,
|
||||
onlyMainContent: false,
|
||||
maxAgeMs: 5000,
|
||||
proxy: "stealth",
|
||||
storeInCache: false,
|
||||
timeoutSeconds: 22,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("passes text mode through and ignores invalid proxy values", async () => {
|
||||
const { createFirecrawlScrapeTool } = await import("./firecrawl-scrape-tool.js");
|
||||
const tool = createFirecrawlScrapeTool({
|
||||
config: { env: "test" },
|
||||
} as never);
|
||||
|
||||
await tool.execute("call-2", {
|
||||
url: "https://docs.openclaw.ai",
|
||||
extractMode: "text",
|
||||
proxy: "invalid",
|
||||
});
|
||||
|
||||
expect(runFirecrawlScrape).toHaveBeenCalledWith({
|
||||
cfg: { env: "test" },
|
||||
url: "https://docs.openclaw.ai",
|
||||
extractMode: "text",
|
||||
maxChars: undefined,
|
||||
onlyMainContent: undefined,
|
||||
maxAgeMs: undefined,
|
||||
proxy: undefined,
|
||||
storeInCache: undefined,
|
||||
timeoutSeconds: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const runFirecrawlSearch = vi.fn(async (params: Record<string, unknown>) => params);
|
||||
|
||||
vi.mock("./firecrawl-client.js", () => ({
|
||||
runFirecrawlSearch,
|
||||
}));
|
||||
|
||||
describe("firecrawl web search provider", () => {
|
||||
it("exposes selection metadata and enables the plugin in config", async () => {
|
||||
const { createFirecrawlWebSearchProvider } = await import("./firecrawl-search-provider.js");
|
||||
|
||||
const provider = createFirecrawlWebSearchProvider();
|
||||
const applied = provider.applySelectionConfig({});
|
||||
|
||||
expect(provider.id).toBe("firecrawl");
|
||||
expect(provider.credentialPath).toBe("plugins.entries.firecrawl.config.webSearch.apiKey");
|
||||
expect(applied.plugins?.entries?.firecrawl?.enabled).toBe(true);
|
||||
});
|
||||
|
||||
it("maps generic arguments into firecrawl search params", async () => {
|
||||
const { createFirecrawlWebSearchProvider } = await import("./firecrawl-search-provider.js");
|
||||
const provider = createFirecrawlWebSearchProvider();
|
||||
const tool = provider.createTool({
|
||||
config: { test: true },
|
||||
} as never);
|
||||
|
||||
const result = await tool.execute({
|
||||
query: "openclaw docs",
|
||||
count: 4,
|
||||
});
|
||||
|
||||
expect(runFirecrawlSearch).toHaveBeenCalledWith({
|
||||
cfg: { test: true },
|
||||
query: "openclaw docs",
|
||||
count: 4,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
cfg: { test: true },
|
||||
query: "openclaw docs",
|
||||
count: 4,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const runFirecrawlSearch = vi.fn(async (params: Record<string, unknown>) => ({
|
||||
ok: true,
|
||||
params,
|
||||
}));
|
||||
|
||||
vi.mock("./firecrawl-client.js", () => ({
|
||||
runFirecrawlSearch,
|
||||
}));
|
||||
|
||||
describe("firecrawl search tool", () => {
|
||||
it("normalizes optional search parameters before invoking Firecrawl", async () => {
|
||||
const { createFirecrawlSearchTool } = await import("./firecrawl-search-tool.js");
|
||||
const tool = createFirecrawlSearchTool({
|
||||
config: { env: "test" },
|
||||
} as never);
|
||||
|
||||
const result = await tool.execute("call-1", {
|
||||
query: "web search",
|
||||
count: 6,
|
||||
timeoutSeconds: 12,
|
||||
sources: ["web", "", "news"],
|
||||
categories: ["research", ""],
|
||||
scrapeResults: true,
|
||||
});
|
||||
|
||||
expect(runFirecrawlSearch).toHaveBeenCalledWith({
|
||||
cfg: { env: "test" },
|
||||
query: "web search",
|
||||
count: 6,
|
||||
timeoutSeconds: 12,
|
||||
sources: ["web", "news"],
|
||||
categories: ["research"],
|
||||
scrapeResults: true,
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
details: {
|
||||
ok: true,
|
||||
params: {
|
||||
cfg: { env: "test" },
|
||||
query: "web search",
|
||||
count: 6,
|
||||
timeoutSeconds: 12,
|
||||
sources: ["web", "news"],
|
||||
categories: ["research"],
|
||||
scrapeResults: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue