Back to Documentation
Testing Framework
Purpose-built testing tools for AI applications. Semantic matching, statistical assertions, cost tracking, and regression testing.
npm install @rana/testing
AI Test Runner
Purpose-built test runner for AI applications with special matchers
import { aiTest, expect } from '@rana/testing';
aiTest('summarizes articles correctly', async () => {
const result = await summarize(article);
// Semantic matching - not exact string comparison
await expect(result).toSemanticMatch('A brief overview of AI trends');
// Check it mentions key topics
await expect(result).toContainConcepts(['machine learning', 'neural networks']);
});Semantic Matching
Compare outputs by meaning, not exact strings
import { semanticMatch, semanticSimilarity } from '@rana/testing';
// Check if two texts have the same meaning
const match = await semanticMatch(
"The weather is nice today",
"It's a beautiful day outside"
);
// match.isMatch: true, match.similarity: 0.87
// Get similarity score
const score = await semanticSimilarity(text1, text2);
// Returns 0-1 similarity scoreStatistical Assertions
Handle non-deterministic AI outputs with statistical testing
import { aiTest, expect } from '@rana/testing';
aiTest('classifier is mostly accurate', async () => {
const results = await runMultiple(100, () =>
classify(email, ['spam', 'ham'])
);
// Pass if 90%+ are correct
await expect(results).toMostlyBe('ham', { threshold: 0.9 });
// Check distribution
await expect(results).toHaveDistribution({
'ham': { min: 0.85, max: 0.95 },
'spam': { min: 0.05, max: 0.15 }
});
});Latency Assertions
Ensure responses meet performance requirements
import { aiTest, expect } from '@rana/testing';
aiTest('responds within SLA', async () => {
const result = await timed(() => chat('Hello'));
// Assert latency
await expect(result).toRespondWithin(2000); // 2 seconds
// P95 latency over multiple runs
const results = await runMultiple(50, () => chat('Hello'));
await expect(results).toHaveP95LatencyUnder(3000);
});Cost Assertions
Control costs with per-test budget limits
import { aiTest, expect } from '@rana/testing';
aiTest('stays within budget', async () => {
const result = await tracked(() =>
summarize(longDocument)
);
// Assert cost
await expect(result).toCostLessThan(0.05); // $0.05
// Assert token usage
await expect(result).toUseTokensLessThan({
input: 1000,
output: 500
});
});Snapshot Testing
Catch regressions with semantic snapshots
import { aiTest, expect } from '@rana/testing';
aiTest('prompt output is stable', async () => {
const result = await generate(prompt);
// Semantic snapshot - allows minor wording changes
await expect(result).toMatchSemanticSnapshot();
// Regression testing against baseline
await expect(result).toPassRegression({
baseline: 'baseline-v1',
tolerance: 0.1 // Allow 10% variation
});
});Configuration
// rana.test.config.ts
import { defineConfig } from '@rana/testing';
export default defineConfig({
// Run tests in parallel
parallel: true,
// Global timeout
timeout: 30000,
// Cost limits
maxCostPerTest: 0.10,
maxCostPerSuite: 1.00,
// Semantic matching model
semanticModel: 'text-embedding-3-small',
// Snapshot directory
snapshotDir: '__snapshots__',
// Reporter
reporter: ['default', 'html'],
});Jest Integration
Use RANA's AI matchers with your existing Jest setup:
// jest.setup.ts
import '@rana/testing/jest';
// Now use in any Jest test
test('AI output is correct', async () => {
const result = await myAIFunction();
await expect(result).toSemanticMatch('expected meaning');
});