2025-07-04 14:42:33 -07:00
#!/usr/bin/env node
/ * *
* Test All Environments
*
* This script runs tests for the Brainy library in all environments :
* - Browser ( using Puppeteer for headless browser testing )
* - Node . js
* - CLI
* /
import { execSync } from 'child_process'
import { fileURLToPath } from 'url'
import path from 'path'
import fs from 'fs'
import http from 'http'
import puppeteer from 'puppeteer'
// Get the directory of the current module
const _ _filename = fileURLToPath ( import . meta . url )
const _ _dirname = path . dirname ( _ _filename )
const rootDir = path . join ( _ _dirname , '..' )
// Define colors for console output
const colors = {
reset : '\x1b[0m' ,
bright : '\x1b[1m' ,
green : '\x1b[32m' ,
yellow : '\x1b[33m' ,
red : '\x1b[31m' ,
cyan : '\x1b[36m'
}
// Helper function to log with colors
function log ( message , color = colors . reset ) {
console . log ( ` ${ color } ${ message } ${ colors . reset } ` )
}
// Helper function to log section headers
function logSection ( title ) {
console . log ( '\n' + '=' . repeat ( 80 ) )
console . log ( ` ${ colors . bright } ${ colors . cyan } ${ title } ${ colors . reset } ` )
console . log ( '=' . repeat ( 80 ) + '\n' )
}
// Helper function to run a command and return its output
function runCommand ( command , cwd = rootDir ) {
try {
return execSync ( command , { stdio : 'pipe' , cwd , encoding : 'utf8' } )
} catch ( error ) {
log ( ` Error running command: ${ command } ` , colors . red )
log ( error . message , colors . red )
if ( error . stdout ) log ( ` stdout: ${ error . stdout } ` )
if ( error . stderr ) log ( ` stderr: ${ error . stderr } ` , colors . red )
throw error
}
}
// Main function to run all tests
async function runAllTests ( ) {
try {
logSection ( 'BUILDING PACKAGES' )
// Build the main package
log ( 'Building main package...' , colors . yellow )
runCommand ( 'npm run build' )
log ( 'Main package built successfully!' , colors . green )
2025-07-11 11:11:56 -07:00
// Apply TextEncoder patch
log ( 'Applying TextEncoder patch...' , colors . yellow )
runCommand ( 'node scripts/patch-textencoder.js' )
log ( 'TextEncoder patch applied successfully!' , colors . green )
2025-07-04 14:42:33 -07:00
// Build the browser package
log ( 'Building browser package...' , colors . yellow )
runCommand ( 'npm run build:browser' )
log ( 'Browser package built successfully!' , colors . green )
// Build the CLI package
log ( 'Building CLI package...' , colors . yellow )
runCommand ( 'npm run build:cli' )
log ( 'CLI package built successfully!' , colors . green )
logSection ( 'RUNNING NODE.JS TESTS' )
// Run Node.js tests
log ( 'Running Node.js worker test...' , colors . yellow )
const nodeWorkerResult = runCommand ( 'node test-worker.js' )
log ( nodeWorkerResult )
log ( 'Node.js worker test completed!' , colors . green )
log ( 'Running unified text encoding test...' , colors . yellow )
const textEncodingResult = runCommand ( 'node test-unified-encoding.js' )
log ( textEncodingResult )
log ( 'Unified text encoding test completed!' , colors . green )
2025-07-11 11:11:56 -07:00
log ( 'Running TensorFlow and TextEncoder test...' , colors . yellow )
const tensorflowTextEncoderResult = runCommand ( 'node test-tensorflow-textencoder.js' )
log ( tensorflowTextEncoderResult )
log ( 'TensorFlow and TextEncoder test completed!' , colors . green )
2025-07-04 14:42:33 -07:00
logSection ( 'RUNNING BROWSER TESTS' )
// Start a simple HTTP server to serve the test files
log ( 'Starting HTTP server...' , colors . yellow )
const server = http . createServer ( ( req , res ) => {
// Normalize the URL to handle relative paths
const normalizedUrl = req . url . replace ( /^\/+/ , '/' )
let filePath = path . join (
rootDir ,
normalizedUrl === '/' ? 'index.html' : normalizedUrl
)
// Handle relative paths (e.g., ../dist/unified.js)
if ( normalizedUrl . includes ( '../' ) ) {
// Convert the URL to an absolute path relative to the root directory
const parts = normalizedUrl . split ( '/' )
const resolvedParts = [ ]
for ( const part of parts ) {
if ( part === '..' ) {
resolvedParts . pop ( )
} else if ( part && part !== '.' ) {
resolvedParts . push ( part )
}
}
filePath = path . join ( rootDir , resolvedParts . join ( '/' ) )
}
log ( ` Request for: ${ req . url } , resolved to: ${ filePath } ` , colors . yellow )
// Check if the file exists
if ( fs . existsSync ( filePath ) ) {
const extname = path . extname ( filePath )
let contentType = 'text/html'
switch ( extname ) {
case '.js' :
contentType = 'text/javascript'
break
case '.css' :
contentType = 'text/css'
break
case '.json' :
contentType = 'application/json'
break
case '.png' :
contentType = 'image/png'
break
case '.jpg' :
contentType = 'image/jpg'
break
}
res . writeHead ( 200 , { 'Content-Type' : contentType } )
const fileStream = fs . createReadStream ( filePath )
fileStream . pipe ( res )
} else {
log ( ` File not found: ${ filePath } ` , colors . red )
res . writeHead ( 404 )
res . end ( 'File not found' )
}
} )
// Start the server on a random port
const PORT = 3000 + Math . floor ( Math . random ( ) * 1000 )
server . listen ( PORT )
log ( ` HTTP server started on port ${ PORT } ` , colors . green )
// Run browser tests using Puppeteer
log ( 'Launching headless browser...' , colors . yellow )
// Using --no-sandbox flag to avoid issues with the Chrome sandbox in certain environments
// See: https://chromium.googlesource.com/chromium/src/+/main/docs/linux/suid_sandbox_development.md
const browser = await puppeteer . launch ( { args : [ '--no-sandbox' ] } )
const page = await browser . newPage ( )
// Capture console logs from the page
page . on ( 'console' , ( message ) => {
const type = message . type ( )
const text = message . text ( )
if ( type === 'error' ) {
log ( ` Browser console error: ${ text } ` , colors . red )
} else {
log ( ` Browser console: ${ text } ` )
}
} )
// Test browser worker
log ( 'Running browser worker test...' , colors . yellow )
await page . goto ( ` http://localhost: ${ PORT } /demo/test-browser-worker.html ` )
await page . waitForSelector ( '#runTest' )
await page . click ( '#runTest' )
await page . waitForFunction (
( ) => {
const resultText = document . getElementById ( 'result' ) . textContent
return resultText . includes ( 'Worker thread execution completed' )
} ,
{ timeout : 30000 }
)
const browserWorkerResult = await page . evaluate ( ( ) => {
return document . getElementById ( 'result' ) . innerHTML
} )
log ( 'Browser worker test result:' , colors . green )
log ( browserWorkerResult . replace ( /<[^>]*>/g , '' ) . trim ( ) )
// Test fallback mechanism
log ( 'Running fallback test...' , colors . yellow )
await page . goto ( ` http://localhost: ${ PORT } /demo/test-fallback.html ` )
await page . waitForSelector ( '#runTest' )
await page . click ( '#runTest' )
await page . waitForFunction (
( ) => {
const resultText = document . getElementById ( 'result' ) . textContent
return resultText . includes ( 'Test completed' )
} ,
{ timeout : 30000 }
)
const fallbackResult = await page . evaluate ( ( ) => {
return document . getElementById ( 'result' ) . innerHTML
} )
log ( 'Fallback test result:' , colors . green )
log ( fallbackResult . replace ( /<[^>]*>/g , '' ) . trim ( ) )
2025-07-11 11:11:56 -07:00
// Test TensorFlow and TextEncoder in browser
log ( 'Running TensorFlow and TextEncoder browser test...' , colors . yellow )
await page . goto ( ` http://localhost: ${ PORT } /demo/test-tensorflow-textencoder.html ` )
await page . waitForSelector ( '#runTest' )
await page . click ( '#runTest' )
await page . waitForFunction (
( ) => {
const resultText = document . getElementById ( 'result' ) . textContent
return resultText . includes ( 'Test completed' )
} ,
{ timeout : 30000 }
)
const browserTensorflowTextEncoderResult = await page . evaluate ( ( ) => {
return document . getElementById ( 'result' ) . innerHTML
} )
log ( 'TensorFlow and TextEncoder browser test result:' , colors . green )
log ( browserTensorflowTextEncoderResult . replace ( /<[^>]*>/g , '' ) . trim ( ) )
2025-07-04 14:42:33 -07:00
// Close the browser and server
await browser . close ( )
server . close ( )
log ( 'HTTP server stopped' , colors . green )
logSection ( 'RUNNING CLI TESTS' )
// Run CLI tests
log ( 'Testing CLI package locally...' , colors . yellow )
try {
2025-07-07 10:19:04 -07:00
runCommand ( 'npm run test:cli' )
2025-07-04 14:42:33 -07:00
log ( 'CLI test completed!' , colors . green )
// Run some basic CLI commands to verify functionality
log ( 'Testing basic CLI commands...' , colors . yellow )
const cliVersionResult = runCommand ( 'brainy --version' )
log ( ` CLI version: ${ cliVersionResult . trim ( ) } ` , colors . green )
const cliHelpResult = runCommand ( 'brainy --help' )
log ( 'CLI help command executed successfully' , colors . green )
// Test the pipeline command
log ( 'Testing pipeline command...' , colors . yellow )
const pipelineResult = runCommand ( 'brainy test-pipeline "This is a test"' )
log ( 'Pipeline test completed!' , colors . green )
2025-07-11 11:11:56 -07:00
// Test TensorFlow and TextEncoder in CLI
log ( 'Testing TensorFlow and TextEncoder in CLI...' , colors . yellow )
const cliTensorflowResult = runCommand ( 'brainy test-tensorflow-textencoder' )
log ( 'TensorFlow and TextEncoder CLI test completed!' , colors . green )
2025-07-04 14:42:33 -07:00
} catch ( error ) {
log (
"CLI tests failed. This might be expected if you don't have the CLI installed globally." ,
colors . yellow
)
log (
2025-07-07 10:19:04 -07:00
'You can run the CLI tests separately with: npm run test:cli' ,
2025-07-04 14:42:33 -07:00
colors . yellow
)
}
logSection ( 'ALL TESTS COMPLETED' )
log ( 'All environment tests completed successfully!' , colors . green )
} catch ( error ) {
logSection ( 'TEST FAILURE' )
log ( ` Tests failed: ${ error . message } ` , colors . red )
process . exit ( 1 )
}
}
// Run the tests
runAllTests ( ) . catch ( ( error ) => {
log ( ` Unhandled error: ${ error . message } ` , colors . red )
process . exit ( 1 )
} )