/** * Test Case Generator * * Generates test cases for workflow evaluation using LLM with structured output. * For default test cases, see fixtures/default-prompts.csv. */ import type { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { HumanMessage, SystemMessage } from '@langchain/core/messages'; import { z } from 'zod'; /** * Options for test case generation. */ export interface TestCaseGeneratorOptions { /** Number of test cases to generate (default: 10) */ count?: number; /** Focus areas for generation */ focus?: string; /** Complexity distribution */ complexity?: 'balanced' | 'simple' | 'complex'; } /** * A test case generated by the LLM. */ export interface GeneratedTestCase { id: string; name: string; summary: string; prompt: string; } /** * Test case generator interface. */ export interface TestCaseGenerator { /** Generate test cases */ generate(): Promise; } /** * Zod schema for structured output. */ const generatedTestCasesSchema = z.object({ testCases: z.array( z.object({ id: z.string().describe('Unique identifier (e.g., "test_001")'), name: z.string().describe('Short descriptive title'), summary: z.string().describe('Brief description of what the workflow does'), prompt: z.string().describe('User-facing prompt for workflow generation'), }), ), }); /** Inferred type from the Zod schema */ type GeneratedTestCasesOutput = z.infer; /** Parse and validate LLM output using the Zod schema */ function parseTestCasesOutput(value: unknown): GeneratedTestCasesOutput { const parsed = generatedTestCasesSchema.safeParse(value); if (!parsed.success) { throw new Error(`Invalid LLM output: ${parsed.error.message}`); } return parsed.data; } /** * System prompt for test case generation. */ const systemPrompt = `You are an expert at generating diverse test cases for an n8n workflow builder AI. Create test cases that cover various real-world scenarios and complexity levels. ## Test Case Requirements: 1. **Simple Test Cases**: Single operation workflows - API calls - Data transformations - File operations - Basic integrations 2. **Medium Test Cases**: Multi-step workflows with logic - Conditional logic (IF nodes) - Data filtering and transformation - Multiple API integrations - Error handling 3. **Complex Test Cases**: Advanced workflows - Parallel execution branches - Complex error handling and retry logic - Multiple integrations with data synchronization - Webhooks and event-driven flows ## Guidelines: - Create realistic business scenarios - Include specific requirements that can be evaluated - Vary the domains (e-commerce, HR, marketing, DevOps, etc.) - Include both common and edge-case scenarios - Make prompts clear and unambiguous - Specify expected node types when possible ## Output Format: Each test case should have: - Unique ID (e.g., "test_001") - Descriptive name - Brief description - Clear prompt that a user would give`; /** * Get default focus based on complexity option. */ function getFocus(options?: TestCaseGeneratorOptions): string { const complexity = options?.complexity ?? 'balanced'; if (options?.focus) { return options.focus; } switch (complexity) { case 'simple': return 'simple, single-operation workflows like basic API calls, data transformations, and file operations'; case 'complex': return 'complex, multi-step workflows with parallel execution, error handling, and multiple integrations'; case 'balanced': default: return 'balanced mix of API integrations, data processing, and automation scenarios'; } } /** * Build the human message content. */ function buildHumanMessage(count: number, focus: string): string { return `Generate ${count} diverse test cases for workflow generation evaluation. Focus on: ${focus} Ensure a good mix of complexity levels and use cases.`; } /** * Create a test case generator that uses LLM to generate test cases. * * @param llm - Language model to use for generation * @param options - Generation options * @returns A test case generator * * @example * ```typescript * const generator = createTestCaseGenerator(llm, { count: 20 }); * const testCases = await generator.generate(); * ``` */ export function createTestCaseGenerator( llm: BaseChatModel, options?: TestCaseGeneratorOptions, ): TestCaseGenerator { const count = options?.count ?? 10; const focus = getFocus(options); // Create LLM with structured output const llmWithStructuredOutput = llm.withStructuredOutput(generatedTestCasesSchema); return { async generate(): Promise { const humanMessage = buildHumanMessage(count, focus); const rawResult = await llmWithStructuredOutput.invoke([ new SystemMessage(systemPrompt), new HumanMessage(humanMessage), ]); // Validate and parse the LLM output using Zod const result = parseTestCasesOutput(rawResult); return result.testCases; }, }; }