import { describe, it, expect } from "vitest";
import { manualExportProvider } from "../../src/providers/manual-export.js";
// --- Basic structure ---
describe("basic structure", () => {
it("exports a provider with send method", () => {
expect(manualExportProvider).toBeDefined();
expect(typeof manualExportProvider.send).toBe("function");
});
it("returns { content: string } shape on success", async () => {
const result = await manualExportProvider.send(
{ prompt: "test prompt" },
{},
);
expect(result).toHaveProperty("content");
expect(typeof result.content).toBe("string");
});
it("returns non-empty content for valid prompt", async () => {
const result = await manualExportProvider.send(
{ prompt: "test prompt" },
{},
);
expect(result.content.length).toBeGreaterThan(0);
});
it("is deterministic — same input produces same output", async () => {
const input = { prompt: "deterministic test", input: { question: "hi" } };
const r1 = await manualExportProvider.send(input, {});
const r2 = await manualExportProvider.send(input, {});
expect(r1.content).toBe(r2.content);
});
it("does not modify the request object", async () => {
const req = { prompt: "test", input: { question: "hi" } };
const original = JSON.stringify(req);
await manualExportProvider.send(req, {});
expect(JSON.stringify(req)).toBe(original);
});
it("does not modify the config object", async () => {
const config = { openaiApiKey: "sk-test" };
await manualExportProvider.send({ prompt: "test" }, config);
expect(config.openaiApiKey).toBe("sk-test");
});
});
// --- Copy-ready structure ---
describe("copy-ready structure", () => {
it("includes MANUAL EXPORT header with tool name", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("MANUAL EXPORT");
});
it("includes COPY box with top-left corner delimiters (┌)", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("┌");
});
it("includes COPY box with bottom-right corner delimiters (┐ and ┘)", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("┐");
expect(result.content).toContain("└");
expect(result.content).toContain("┘");
});
it("includes instructions section with numbered steps", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("📝 INSTRUCTIONS:");
expect(result.content).toContain("1.");
expect(result.content).toContain("2.");
expect(result.content).toContain("3.");
});
it("includes metadata section", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("📊 METADATA:");
});
it("includes provider info in metadata", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("Manual Export");
});
it("includes tool name in metadata", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toMatch(/Tool: \w+/);
});
it("includes prompt length in metadata with formatted thousands separator", async () => {
const longPrompt = "x".repeat(12345);
const result = await manualExportProvider.send(
{ prompt: longPrompt, input: { question: "hi" } },
{},
);
expect(result.content).toContain("Prompt Length:");
expect(result.content).toContain("12,345 characters");
});
it("includes advisory footer", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("advisory output only");
});
it("wraps each line of prompt in box with │ delimiter", async () => {
const multiLine = "line one\nline two\nline three";
const result = await manualExportProvider.send(
{ prompt: multiLine, input: { question: "hi" } },
{},
);
expect(result.content).toContain("│ line one");
expect(result.content).toContain("│ line two");
expect(result.content).toContain("│ line three");
});
});
// --- Per-tool detection ---
describe("tool name detection", () => {
it("detects debug_issue when input has logs", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { logs: "Error: boom" } },
{},
);
expect(result.content).toContain("Tool: debug_issue");
});
it("detects review_code when input has relevantFiles with paths", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { relevantFiles: [{ path: "src/foo.js" }] } },
{},
);
expect(result.content).toContain("Tool: review_code");
});
it("detects architecture_review when context includes 'architecture'", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { context: "Architecture decision here" } },
{},
);
expect(result.content).toContain("Tool: architecture_review");
});
it("detects review_plan when input has projectSummary", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { projectSummary: "Project scope" } },
{},
);
expect(result.content).toContain("Tool: review_plan");
});
it("defaults to ask_chatgpt when no hints available", async () => {
const result = await manualExportProvider.send(
{ prompt: "test", input: { question: "hi" } },
{},
);
expect(result.content).toContain("Tool: ask_chatgpt");
});
it("uses 'unknown' when input is absent in request", async () => {
const result = await manualExportProvider.send(
{ prompt: "test" },
{},
);
expect(result.content).toContain("Tool: unknown");
});
});
// --- Long prompt handling ---
describe("long prompt handling", () => {
it("adds warning banner for prompts over 30k characters", async () => {
const longPrompt = "x".repeat(31_000);
const result = await manualExportProvider.send({ prompt: longPrompt, input: {} }, {});
expect(result.content).toContain("⚠️ NOTE");
});
it("does NOT add warning for prompts under 30k characters", async () => {
const validPrompt = "x".repeat(29_999);
const result = await manualExportProvider.send({ prompt: validPrompt, input: {} }, {});
expect(result.content).not.toContain("⚠️ NOTE");
});
it("still returns valid output for very long prompts (>50k chars)", async () => {
const veryLongPrompt = "x".repeat(50_000);
const result = await manualExportProvider.send({ prompt: veryLongPrompt, input: {} }, {});
expect(result.content).toContain("MANUAL EXPORT");
expect(result.content.length).toBeGreaterThan(0);
});
it("shows correct character count in metadata for long prompts", async () => {
const length = 50_000;
const result = await manualExportProvider.send({ prompt: "x".repeat(length), input: {} }, {});
expect(result.content).toContain(`${length.toLocaleString()} characters`);
});
it("handles prompts at exactly the 30k boundary", async () => {
const exactPrompt = "x".repeat(30_000);
const result = await manualExportProvider.send({ prompt: exactPrompt, input: {} }, {});
expect(result.content).not.toContain("⚠️ NOTE"); // not over 30k, exactly at it
});
});
// --- Unicode and special characters ---
describe("unicode and special characters", () => {
it("preserves Japanese characters in prompt", async () => {
const result = await manualExportProvider.send(
{ prompt: "こんにちは世界", input: {} },
{},
);
expect(result.content).toContain("こんにちは世界");
});
it("preserves emoji in prompt", async () => {
const result = await manualExportProvider.send(
{ prompt: "🚀 Launch plan 🎯", input: {} },
{},
);
expect(result.content).toContain("🚀");
expect(result.content).toContain("🎯");
});
it("preserves markdown code blocks in prompt", async () => {
const codePrompt = "```js\nconst x = 1;\n```";
const result = await manualExportProvider.send(
{ prompt: codePrompt, input: {} },
{},
);
expect(result.content).toContain("```js");
expect(result.content).toContain("const x = 1;");
});
it("preserves JSON in prompt", async () => {
const jsonPrompt = '{"key": "value", "nested": {"a": 1}}';
const result = await manualExportProvider.send(
{ prompt: jsonPrompt, input: {} },
{},
);
expect(result.content).toContain('"key"');
expect(result.content).toContain('"value"');
});
it("preserves special HTML-like characters", async () => {
const htmlPrompt = '';
const result = await manualExportProvider.send(
{ prompt: htmlPrompt, input: {} },
{},
);
expect(result.content).toContain('