test(extensions): cover xai and firecrawl helpers

This commit is contained in:
Vincent Koc
2026-03-22 16:04:03 -07:00
parent bd1c6efca5
commit 19c85cf44f
3 changed files with 172 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import {
DEFAULT_FIRECRAWL_BASE_URL,
DEFAULT_FIRECRAWL_MAX_AGE_MS,
DEFAULT_FIRECRAWL_SCRAPE_TIMEOUT_SECONDS,
DEFAULT_FIRECRAWL_SEARCH_TIMEOUT_SECONDS,
resolveFirecrawlApiKey,
resolveFirecrawlBaseUrl,
resolveFirecrawlMaxAgeMs,
resolveFirecrawlOnlyMainContent,
resolveFirecrawlScrapeTimeoutSeconds,
resolveFirecrawlSearchConfig,
resolveFirecrawlSearchTimeoutSeconds,
} from "./config.js";
describe("firecrawl config helpers", () => {
afterEach(() => {
vi.unstubAllEnvs();
});
it("prefers plugin webSearch config over legacy tool search config", () => {
const cfg = {
plugins: {
entries: {
firecrawl: {
config: {
webSearch: {
apiKey: "plugin-key",
baseUrl: "https://plugin.firecrawl.test",
},
},
},
},
},
tools: {
web: {
search: {
firecrawl: {
apiKey: "legacy-key",
baseUrl: "https://legacy.firecrawl.test",
},
},
},
},
} as OpenClawConfig;
expect(resolveFirecrawlSearchConfig(cfg)).toEqual({
apiKey: "plugin-key",
baseUrl: "https://plugin.firecrawl.test",
});
expect(resolveFirecrawlApiKey(cfg)).toBe("plugin-key");
expect(resolveFirecrawlBaseUrl(cfg)).toBe("https://plugin.firecrawl.test");
});
it("falls back to environment and defaults for fetch config values", () => {
vi.stubEnv("FIRECRAWL_API_KEY", "env-key");
vi.stubEnv("FIRECRAWL_BASE_URL", "https://env.firecrawl.test");
expect(resolveFirecrawlApiKey()).toBe("env-key");
expect(resolveFirecrawlBaseUrl()).toBe("https://env.firecrawl.test");
expect(resolveFirecrawlOnlyMainContent()).toBe(true);
expect(resolveFirecrawlMaxAgeMs()).toBe(DEFAULT_FIRECRAWL_MAX_AGE_MS);
expect(resolveFirecrawlScrapeTimeoutSeconds()).toBe(DEFAULT_FIRECRAWL_SCRAPE_TIMEOUT_SECONDS);
expect(resolveFirecrawlSearchTimeoutSeconds()).toBe(DEFAULT_FIRECRAWL_SEARCH_TIMEOUT_SECONDS);
expect(resolveFirecrawlBaseUrl({} as OpenClawConfig)).not.toBe(DEFAULT_FIRECRAWL_BASE_URL);
});
it("respects positive numeric overrides for scrape and cache behavior", () => {
const cfg = {
tools: {
web: {
fetch: {
firecrawl: {
onlyMainContent: false,
maxAgeMs: 1234,
timeoutSeconds: 42,
},
},
},
},
} as OpenClawConfig;
expect(resolveFirecrawlOnlyMainContent(cfg)).toBe(false);
expect(resolveFirecrawlMaxAgeMs(cfg)).toBe(1234);
expect(resolveFirecrawlMaxAgeMs(cfg, 77.9)).toBe(77);
expect(resolveFirecrawlScrapeTimeoutSeconds(cfg)).toBe(42);
expect(resolveFirecrawlScrapeTimeoutSeconds(cfg, 19.8)).toBe(19);
expect(resolveFirecrawlSearchTimeoutSeconds(9.7)).toBe(9);
});
});

View File

@@ -0,0 +1,15 @@
import { describe, expect, it } from "vitest";
import { __testing } from "./grok-web-search-provider.js";
describe("grok web search provider helpers", () => {
it("prefers configured api keys and resolves grok scoped defaults", () => {
expect(__testing.resolveGrokApiKey({ apiKey: "xai-secret" })).toBe("xai-secret");
expect(__testing.resolveGrokModel()).toBe("grok-4-1-fast");
expect(__testing.resolveGrokInlineCitations()).toBe(false);
});
it("reads grok-specific overrides from scoped config", () => {
expect(__testing.resolveGrokModel({ model: "xai/grok-4-fast" })).toBe("xai/grok-4-fast");
expect(__testing.resolveGrokInlineCitations({ inlineCitations: true })).toBe(true);
});
});

View File

@@ -0,0 +1,66 @@
import { describe, expect, it } from "vitest";
import { __testing } from "./web-search-shared.js";
describe("xai web search shared helpers", () => {
it("uses sane defaults for model and inline citations", () => {
expect(__testing.resolveXaiWebSearchModel()).toBe(__testing.XAI_DEFAULT_WEB_SEARCH_MODEL);
expect(__testing.resolveXaiInlineCitations()).toBe(false);
});
it("reads grok-scoped overrides for model and inline citations", () => {
const searchConfig = {
grok: {
model: "xai/grok-4-fast",
inlineCitations: true,
},
};
expect(__testing.resolveXaiWebSearchModel(searchConfig)).toBe("xai/grok-4-fast");
expect(__testing.resolveXaiInlineCitations(searchConfig)).toBe(true);
});
it("extracts text and deduplicated citations from response output", () => {
expect(
__testing.extractXaiWebSearchContent({
output: [
{
type: "message",
content: [
{
type: "output_text",
text: "hello",
annotations: [
{ type: "url_citation", url: "https://a.test" },
{ type: "url_citation", url: "https://a.test" },
],
},
],
},
],
}),
).toEqual({
text: "hello",
annotationCitations: ["https://a.test"],
});
});
it("builds wrapped payloads with optional inline citations", () => {
expect(
__testing.buildXaiWebSearchPayload({
query: "q",
provider: "grok",
model: "grok-4-fast",
tookMs: 12,
content: "body",
citations: ["https://a.test"],
}),
).toMatchObject({
query: "q",
provider: "grok",
model: "grok-4-fast",
tookMs: 12,
citations: ["https://a.test"],
externalContent: expect.objectContaining({ wrapped: true }),
});
});
});