2025-08-18 17:49:57 -07:00
/ * *
* Regression Test Suite for Brainy
*
* This test suite verifies that core functionality works across :
* - All storage adapters
* - All environments ( Node . js , Browser simulation )
* - Performance benchmarks
* - Package size limits
* - CLI and API consistency
*
* These tests should ALWAYS pass before any release .
* /
import { describe , it , expect , beforeEach , afterEach } from 'vitest'
import { BrainyData , NounType , VerbType , MemoryStorage , OPFSStorage , createEmbeddingFunction } from '../src/index.js'
import { performance } from 'perf_hooks'
describe ( 'Brainy Regression Tests' , ( ) = > {
describe ( 'Core Functionality Across Storage Adapters' , ( ) = > {
const storageAdapters = [
{ name : 'Memory' , create : ( ) = > new MemoryStorage ( ) } ,
// Note: FileSystem and OPFS require different test environments
// { name: 'OPFS', create: () => new OPFSStorage() }, // Browser only
// { name: 'FileSystem', create: () => new FileSystemStorage('./test-fs') }, // Node only
]
storageAdapters . forEach ( ( { name , create } ) = > {
describe ( ` ${ name } Storage ` , ( ) = > {
let brainy : BrainyData
beforeEach ( async ( ) = > {
brainy = new BrainyData ( {
storage : create ( )
} )
await brainy . init ( )
} )
afterEach ( async ( ) = > {
if ( brainy ) {
await brainy . cleanup ( )
}
} )
it ( 'should handle basic add and search operations' , async ( ) = > {
const id = await brainy . add ( "Test data for regression testing" )
expect ( id ) . toBeDefined ( )
const results = await brainy . search ( "regression testing" , 5 )
expect ( results . length ) . toBeGreaterThan ( 0 )
expect ( results [ 0 ] . id ) . toBe ( id )
} )
it ( 'should handle typed noun and verb operations' , async ( ) = > {
const personId = await brainy . addNoun ( "John Doe" , NounType . Person )
const companyId = await brainy . addNoun ( "Tech Corp" , NounType . Organization )
const verbId = await brainy . addVerb ( personId , companyId , VerbType . WorksWith )
expect ( personId ) . toBeDefined ( )
expect ( companyId ) . toBeDefined ( )
expect ( verbId ) . toBeDefined ( )
} )
it ( 'should handle metadata filtering' , async ( ) = > {
await brainy . add ( "Item 1" , { category : "A" , priority : 1 } )
await brainy . add ( "Item 2" , { category : "B" , priority : 2 } )
const results = await brainy . search ( "" , 10 , {
metadata : { category : "A" }
} )
expect ( results . length ) . toBe ( 1 )
expect ( results [ 0 ] . metadata . category ) . toBe ( "A" )
} )
it ( 'should handle update operations' , async ( ) = > {
const id = await brainy . add ( "Original content" , { version : 1 } )
const success = await brainy . update ( id , "Updated content" , { version : 2 } )
expect ( success ) . toBe ( true )
const results = await brainy . search ( "Updated content" , 5 )
expect ( results [ 0 ] . metadata . version ) . toBe ( 2 )
} )
it ( 'should handle soft delete (default behavior)' , async ( ) = > {
const id = await brainy . add ( "Content to delete" )
const success = await brainy . delete ( id ) // Soft delete by default
expect ( success ) . toBe ( true )
// Should not appear in search results
const results = await brainy . search ( "Content to delete" , 10 )
expect ( results . length ) . toBe ( 0 )
} )
} )
} )
} )
describe ( 'Performance Benchmarks' , ( ) = > {
let brainy : BrainyData
beforeEach ( async ( ) = > {
brainy = new BrainyData ( )
await brainy . init ( )
} )
afterEach ( async ( ) = > {
if ( brainy ) {
await brainy . cleanup ( )
}
} )
it ( 'should add 100 items within performance threshold' , async ( ) = > {
const startTime = performance . now ( )
const promises = [ ]
for ( let i = 0 ; i < 100 ; i ++ ) {
promises . push ( brainy . add ( ` Test item ${ i } ` ) )
}
await Promise . all ( promises )
const endTime = performance . now ( )
const duration = endTime - startTime
// Should complete within 10 seconds (generous threshold for CI)
expect ( duration ) . toBeLessThan ( 10000 )
} )
it ( 'should search through 1000+ items efficiently' , async ( ) = > {
// Add test data
const promises = [ ]
for ( let i = 0 ; i < 200 ; i ++ ) {
promises . push ( brainy . add ( ` Document ${ i } about various topics and information ` ) )
}
await Promise . all ( promises )
// Benchmark search
const startTime = performance . now ( )
const results = await brainy . search ( "document topics" , 10 )
const endTime = performance . now ( )
const duration = endTime - startTime
expect ( results . length ) . toBeGreaterThan ( 0 )
// Search should complete within 1 second
expect ( duration ) . toBeLessThan ( 1000 )
} )
it ( 'should handle batch import efficiently' , async ( ) = > {
const data = Array . from ( { length : 50 } , ( _ , i ) = > ` Batch item ${ i } ` )
const startTime = performance . now ( )
const ids = await brainy . import ( data )
const endTime = performance . now ( )
const duration = endTime - startTime
expect ( ids . length ) . toBe ( 50 )
// Batch import should be faster than individual adds
expect ( duration ) . toBeLessThan ( 5000 )
} )
} )
describe ( 'Environment Compatibility' , ( ) = > {
it ( 'should detect Node.js environment correctly' , async ( ) = > {
const { isNode , isBrowser , isWebWorker } = await import ( '../src/index.js' )
expect ( isNode ( ) ) . toBe ( true )
expect ( isBrowser ( ) ) . toBe ( false )
expect ( isWebWorker ( ) ) . toBe ( false )
} )
it ( 'should create embedding functions in Node.js' , async ( ) = > {
const embeddingFn = await createEmbeddingFunction ( )
expect ( typeof embeddingFn ) . toBe ( 'function' )
const embedding = await embeddingFn ( "test text" )
expect ( Array . isArray ( embedding ) ) . toBe ( true )
expect ( embedding . length ) . toBeGreaterThan ( 0 )
} )
} )
describe ( 'Data Integrity' , ( ) = > {
let brainy : BrainyData
beforeEach ( async ( ) = > {
brainy = new BrainyData ( )
await brainy . init ( )
} )
afterEach ( async ( ) = > {
if ( brainy ) {
await brainy . cleanup ( )
}
} )
it ( 'should maintain data consistency across operations' , async ( ) = > {
// Add initial data
const id1 = await brainy . add ( "Document about machine learning" )
const id2 = await brainy . add ( "Article about artificial intelligence" )
// Verify both exist
let results = await brainy . search ( "machine learning" , 10 )
expect ( results . some ( r = > r . id === id1 ) ) . toBe ( true )
results = await brainy . search ( "artificial intelligence" , 10 )
expect ( results . some ( r = > r . id === id2 ) ) . toBe ( true )
// Update one item
await brainy . update ( id1 , "Updated document about deep learning" )
// Verify update
results = await brainy . search ( "deep learning" , 10 )
expect ( results . some ( r = > r . id === id1 ) ) . toBe ( true )
// Original content should not be found
results = await brainy . search ( "machine learning" , 10 )
expect ( results . some ( r = > r . id === id1 ) ) . toBe ( false )
// Other document should remain unchanged
results = await brainy . search ( "artificial intelligence" , 10 )
expect ( results . some ( r = > r . id === id2 ) ) . toBe ( true )
} )
it ( 'should handle concurrent operations without corruption' , async ( ) = > {
const concurrentOperations = [ ]
// Start multiple operations concurrently
for ( let i = 0 ; i < 20 ; i ++ ) {
concurrentOperations . push ( brainy . add ( ` Concurrent item ${ i } ` ) )
}
const ids = await Promise . all ( concurrentOperations )
expect ( ids . length ) . toBe ( 20 )
// Verify all items can be found
const results = await brainy . search ( "Concurrent item" , 25 )
expect ( results . length ) . toBe ( 20 )
} )
} )
describe ( 'Error Handling & Edge Cases' , ( ) = > {
let brainy : BrainyData
beforeEach ( async ( ) = > {
brainy = new BrainyData ( )
await brainy . init ( )
} )
afterEach ( async ( ) = > {
if ( brainy ) {
await brainy . cleanup ( )
}
} )
it ( 'should handle empty search queries gracefully' , async ( ) = > {
await brainy . add ( "Some content" )
const results = await brainy . search ( "" , 10 )
expect ( Array . isArray ( results ) ) . toBe ( true )
// Empty query might return all results or none, but should not throw
} )
it ( 'should handle invalid IDs gracefully' , async ( ) = > {
const result = await brainy . update ( "invalid-id" , "new data" )
expect ( result ) . toBe ( false )
const deleteResult = await brainy . delete ( "invalid-id" )
expect ( deleteResult ) . toBe ( false )
} )
it ( 'should handle very large text content' , async ( ) = > {
const largeText = "Lorem ipsum " . repeat ( 1000 ) // ~11KB text
const id = await brainy . add ( largeText )
expect ( id ) . toBeDefined ( )
const results = await brainy . search ( "Lorem ipsum" , 5 )
expect ( results . some ( r = > r . id === id ) ) . toBe ( true )
} )
it ( 'should handle special characters and unicode' , async ( ) = > {
const specialText = "Hello 世界! 🌍 Special chars: @#$%^&*()_+-=[]{}|;':\",./<>?"
const id = await brainy . add ( specialText )
expect ( id ) . toBeDefined ( )
const results = await brainy . search ( "世界" , 5 )
expect ( results . some ( r = > r . id === id ) ) . toBe ( true )
} )
} )
describe ( 'Package Size Regression' , ( ) = > {
it ( 'should not exceed package size threshold' , async ( ) = > {
// This is a placeholder test - actual implementation would check built package size
// For now, we'll just verify core imports don't significantly bloat
const coreModules = await import ( '../src/index.js' )
// Verify main exports exist (prevents tree-shaking regression)
expect ( coreModules . BrainyData ) . toBeDefined ( )
expect ( coreModules . NounType ) . toBeDefined ( )
expect ( coreModules . VerbType ) . toBeDefined ( )
expect ( coreModules . createEmbeddingFunction ) . toBeDefined ( )
} )
} )
describe ( 'Configuration & Initialization' , ( ) = > {
it ( 'should initialize with default configuration' , async ( ) = > {
const brainy = new BrainyData ( )
await brainy . init ( )
// Should not throw and should be usable
const id = await brainy . add ( "Test initialization" )
expect ( id ) . toBeDefined ( )
await brainy . cleanup ( )
} )
it ( 'should initialize with custom configuration' , async ( ) = > {
const brainy = new BrainyData ( {
maxNeighbors : 32 ,
efConstruction : 400 ,
storage : new MemoryStorage ( )
} )
await brainy . init ( )
const id = await brainy . add ( "Test custom config" )
expect ( id ) . toBeDefined ( )
await brainy . cleanup ( )
} )
it ( 'should handle multiple instances' , async ( ) = > {
const brainy1 = new BrainyData ( )
const brainy2 = new BrainyData ( )
await brainy1 . init ( )
await brainy2 . init ( )
// Both should work independently
const id1 = await brainy1 . add ( "Instance 1 data" )
const id2 = await brainy2 . add ( "Instance 2 data" )
expect ( id1 ) . toBeDefined ( )
expect ( id2 ) . toBeDefined ( )
expect ( id1 ) . not . toBe ( id2 )
2025-08-18 18:28:10 -07:00
// No destroy method needed - instances will be garbage collected
2025-08-18 17:49:57 -07:00
} )
} )
} )