Files
alighasami 3d5eaf9445
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
first commit
2026-03-17 16:22:57 +03:30

180 lines
4.9 KiB
TypeScript

/**
* 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<GeneratedTestCase[]>;
}
/**
* 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<typeof generatedTestCasesSchema>;
/** 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<GeneratedTestCase[]> {
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;
},
};
}