**refactor(tests): consolidate and replace outdated environment test scripts**
- Removed obsolete scripts: `test-all-environments.js`, `test-fallback-function.js`, `test-fallback-simple.js`, `test-fix.js`, `test-tensorflow-textencoder.js`, `test-unified-encoding.js`, and `test-worker-utils.js`. - Introduced `scripts/comprehensive-test.js` as a unified testing script covering all environments: Browser, Node.js, and CLI. - Added `examples/cli-wrapper-example.js` to demonstrate a proper CLI implementation with TensorFlow.js initialization. This refactor simplifies the testing structure by consolidating redundant scripts into a single comprehensive script while ensuring robust cross-environment coverage.
This commit is contained in:
parent
3b85ea46e1
commit
f5e4b8b93e
20 changed files with 1253 additions and 808 deletions
574
scripts/comprehensive-test.js
Executable file
574
scripts/comprehensive-test.js
Executable file
|
|
@ -0,0 +1,574 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Comprehensive Test Script for @soulcraft/brainy
|
||||
*
|
||||
* This script tests the library in all environments:
|
||||
* - Browser (using Puppeteer for headless browser testing)
|
||||
* - Node.js/server
|
||||
* - CLI
|
||||
*
|
||||
* It verifies:
|
||||
* - Library loading in each environment
|
||||
* - TensorFlow functionality in each environment
|
||||
* - Environment detection functionality
|
||||
*/
|
||||
|
||||
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',
|
||||
magenta: '\x1b[35m',
|
||||
blue: '\x1b[34m'
|
||||
}
|
||||
|
||||
// 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 log subsection headers
|
||||
function logSubSection(title) {
|
||||
console.log('\n' + '-'.repeat(60))
|
||||
console.log(`${colors.bright}${colors.magenta}${title}${colors.reset}`)
|
||||
console.log('-'.repeat(60) + '\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
|
||||
}
|
||||
}
|
||||
|
||||
// Create a simple HTML file for browser testing
|
||||
function createBrowserTestFile() {
|
||||
const testHtmlPath = path.join(rootDir, 'browser-test.html')
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@soulcraft/brainy Browser Test</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
border-bottom: 2px solid #eee;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
button {
|
||||
background-color: #4CAF50;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 10px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#result {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin-top: 20px;
|
||||
white-space: pre-wrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.success {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>@soulcraft/brainy Browser Test</h1>
|
||||
<p>This page tests the @soulcraft/brainy library in a browser environment.</p>
|
||||
<button id="runTest">Run Test</button>
|
||||
<div id="result">Test results will appear here...</div>
|
||||
|
||||
<script type="module">
|
||||
// Import the library
|
||||
import * as brainy from './dist/unified.js';
|
||||
|
||||
document.getElementById('runTest').addEventListener('click', async () => {
|
||||
const resultElement = document.getElementById('result');
|
||||
resultElement.innerHTML = 'Running tests...';
|
||||
|
||||
try {
|
||||
// Test environment detection
|
||||
const results = [];
|
||||
results.push(\`Environment Detection:\`);
|
||||
results.push(\`- isBrowser: \${brainy.isBrowser()}\`);
|
||||
results.push(\`- isNode: \${brainy.isNode()}\`);
|
||||
results.push(\`- isWebWorker: \${brainy.isWebWorker()}\`);
|
||||
results.push(\`- areWebWorkersAvailable: \${brainy.areWebWorkersAvailable()}\`);
|
||||
results.push(\`- isThreadingAvailable: \${brainy.isThreadingAvailable()}\`);
|
||||
|
||||
// Test TensorFlow functionality
|
||||
results.push(\`\nTesting TensorFlow functionality...\`);
|
||||
|
||||
// Create a simple BrainyData instance
|
||||
const data = new brainy.BrainyData({
|
||||
dimensions: 2,
|
||||
metric: 'euclidean'
|
||||
});
|
||||
|
||||
results.push(\`Successfully created BrainyData instance\`);
|
||||
|
||||
// Initialize the database
|
||||
results.push(\`Initializing database...\`);
|
||||
await data.init();
|
||||
|
||||
// Add a simple vector
|
||||
await data.add([1, 2], { id: 'test1', text: 'Test item' });
|
||||
results.push(\`Successfully added item to BrainyData\`);
|
||||
|
||||
// Search for similar vectors
|
||||
const searchResults = await data.search([1, 2], 1);
|
||||
results.push(\`Search results: \${JSON.stringify(searchResults)}\`);
|
||||
|
||||
// Test embedding functionality (which uses TensorFlow)
|
||||
results.push(\`\nTesting embedding functionality...\`);
|
||||
try {
|
||||
const embeddingFunction = brainy.createEmbeddingFunction();
|
||||
const embedding = await embeddingFunction('This is a test sentence');
|
||||
results.push(\`Successfully created embedding with length: \${embedding.length}\`);
|
||||
} catch (embeddingError) {
|
||||
results.push(\`Error testing embedding: \${embeddingError.message}\`);
|
||||
throw embeddingError;
|
||||
}
|
||||
|
||||
results.push(\`\n<span class="success">✅ All tests passed successfully!</span>\`);
|
||||
resultElement.innerHTML = results.join('<br>');
|
||||
} catch (error) {
|
||||
resultElement.innerHTML = \`<span class="error">❌ Test failed:</span><br>\${error.message}\`;
|
||||
console.error('Test error:', error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
fs.writeFileSync(testHtmlPath, htmlContent);
|
||||
return testHtmlPath;
|
||||
}
|
||||
|
||||
// Create a Node.js test script
|
||||
function createNodeTestScript() {
|
||||
const testScriptPath = path.join(rootDir, 'node-test.js');
|
||||
const scriptContent = `
|
||||
// Node.js test script for @soulcraft/brainy
|
||||
|
||||
// CRITICAL: First, directly apply the TensorFlow.js patch
|
||||
// This is the most reliable way to ensure the patch is applied before TensorFlow.js is loaded
|
||||
import { TextEncoder, TextDecoder } from 'util';
|
||||
|
||||
// Make TextEncoder and TextDecoder available globally
|
||||
if (typeof global !== 'undefined') {
|
||||
global.TextEncoder = TextEncoder;
|
||||
global.TextDecoder = TextDecoder;
|
||||
}
|
||||
|
||||
// Import the library
|
||||
import * as brainy from './dist/unified.js';
|
||||
|
||||
async function runNodeTest() {
|
||||
console.log('\\n=== Testing @soulcraft/brainy in Node.js environment ===\\n');
|
||||
|
||||
try {
|
||||
// Test environment detection
|
||||
console.log('Environment Detection:');
|
||||
console.log(\`- isBrowser: \${brainy.isBrowser()}\`);
|
||||
console.log(\`- isNode: \${brainy.isNode()}\`);
|
||||
console.log(\`- isWebWorker: \${brainy.isWebWorker()}\`);
|
||||
console.log(\`- areWebWorkersAvailable: \${brainy.areWebWorkersAvailable()}\`);
|
||||
console.log(\`- isThreadingAvailable: \${brainy.isThreadingAvailable()}\`);
|
||||
console.log(\`- areWorkerThreadsAvailableSync: \${brainy.areWorkerThreadsAvailableSync()}\`);
|
||||
|
||||
// Test TensorFlow functionality
|
||||
console.log('\\nTesting TensorFlow functionality...');
|
||||
|
||||
// Create a simple BrainyData instance
|
||||
const data = new brainy.BrainyData({
|
||||
dimensions: 2,
|
||||
metric: 'euclidean'
|
||||
});
|
||||
|
||||
console.log('Successfully created BrainyData instance');
|
||||
|
||||
// Initialize the database
|
||||
console.log('Initializing database...');
|
||||
await data.init();
|
||||
|
||||
// Add a simple vector
|
||||
await data.add([1, 2], { id: 'test1', text: 'Test item' });
|
||||
console.log('Successfully added item to BrainyData');
|
||||
|
||||
// Search for similar vectors
|
||||
const results = await data.search([1, 2], 1);
|
||||
console.log('Search results:', results);
|
||||
|
||||
// Test embedding functionality (which uses TensorFlow)
|
||||
console.log('\\nTesting embedding functionality...');
|
||||
const embeddingFunction = brainy.createEmbeddingFunction();
|
||||
const embedding = await embeddingFunction('This is a test sentence');
|
||||
console.log(\`Successfully created embedding with length: \${embedding.length}\`);
|
||||
|
||||
console.log('\\n✅ All Node.js tests passed successfully!');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ Node.js test failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test
|
||||
runNodeTest().then(success => {
|
||||
if (!success) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
fs.writeFileSync(testScriptPath, scriptContent);
|
||||
return testScriptPath;
|
||||
}
|
||||
|
||||
// Create a CLI test script
|
||||
function createCliTestScript() {
|
||||
const cliTestScriptPath = path.join(rootDir, 'cli-test.js');
|
||||
const scriptContent = `
|
||||
// CLI test script for @soulcraft/brainy-cli
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
function runCommand(command) {
|
||||
try {
|
||||
return execSync(command, { stdio: 'pipe', encoding: 'utf8' });
|
||||
} catch (error) {
|
||||
console.error(\`Error running command: \${command}\`);
|
||||
console.error(error.message);
|
||||
if (error.stdout) console.log(\`stdout: \${error.stdout}\`);
|
||||
if (error.stderr) console.error(\`stderr: \${error.stderr}\`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function testCli() {
|
||||
console.log('\\n=== Testing @soulcraft/brainy-cli ===\\n');
|
||||
|
||||
try {
|
||||
// Test CLI version
|
||||
console.log('Testing CLI version...');
|
||||
const versionOutput = runCommand('brainy --version');
|
||||
console.log(\`CLI version: \${versionOutput.trim()}\`);
|
||||
|
||||
// Test CLI help
|
||||
console.log('\\nTesting CLI help...');
|
||||
runCommand('brainy --help');
|
||||
console.log('Help command executed successfully');
|
||||
|
||||
// Test pipeline command
|
||||
console.log('\\nTesting pipeline command...');
|
||||
const pipelineOutput = runCommand('brainy test-pipeline "This is a test"');
|
||||
console.log('Pipeline test completed successfully');
|
||||
|
||||
// Test TensorFlow functionality in CLI
|
||||
console.log('\\nTesting TensorFlow functionality in CLI...');
|
||||
const tensorflowOutput = runCommand('brainy test-tensorflow');
|
||||
console.log('TensorFlow test completed successfully');
|
||||
|
||||
console.log('\\n✅ All CLI tests passed successfully!');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ CLI test failed. This might be expected if you don\\'t have the CLI installed globally.');
|
||||
console.error('You can install the CLI globally with: npm run test:cli');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test
|
||||
testCli().catch(error => {
|
||||
console.error('Unhandled error:', error);
|
||||
});
|
||||
`;
|
||||
|
||||
fs.writeFileSync(cliTestScriptPath, scriptContent);
|
||||
return cliTestScriptPath;
|
||||
}
|
||||
|
||||
// Main function to run all tests
|
||||
async function runComprehensiveTests() {
|
||||
try {
|
||||
logSection('COMPREHENSIVE TEST SUITE FOR @soulcraft/brainy');
|
||||
log('This test suite verifies the library in all environments: Browser, Node.js, and CLI', colors.yellow);
|
||||
|
||||
logSection('BUILDING PACKAGES');
|
||||
|
||||
// Build the main package
|
||||
logSubSection('Building Main Package');
|
||||
log('Building main package...', colors.yellow);
|
||||
runCommand('npm run build');
|
||||
log('Main package built successfully!', colors.green);
|
||||
|
||||
// Build the browser package
|
||||
logSubSection('Building Browser Package');
|
||||
log('Building browser package...', colors.yellow);
|
||||
runCommand('npm run build:browser');
|
||||
log('Browser package built successfully!', colors.green);
|
||||
|
||||
// Build the CLI package
|
||||
logSubSection('Building CLI Package');
|
||||
log('Building CLI package...', colors.yellow);
|
||||
runCommand('npm run build:cli');
|
||||
log('CLI package built successfully!', colors.green);
|
||||
|
||||
logSection('NODE.JS ENVIRONMENT TESTS');
|
||||
|
||||
// Create and run Node.js test script
|
||||
logSubSection('Creating Node.js Test Script');
|
||||
const nodeTestScript = createNodeTestScript();
|
||||
log(`Node.js test script created at: ${nodeTestScript}`, colors.green);
|
||||
|
||||
logSubSection('Running Node.js Tests');
|
||||
try {
|
||||
const nodeTestResult = runCommand(`node ${nodeTestScript}`);
|
||||
log(nodeTestResult);
|
||||
log('Node.js tests completed successfully!', colors.green);
|
||||
} catch (error) {
|
||||
log('Node.js tests failed!', colors.red);
|
||||
throw error;
|
||||
}
|
||||
|
||||
logSection('BROWSER ENVIRONMENT TESTS');
|
||||
|
||||
// Create browser test file
|
||||
logSubSection('Creating Browser Test File');
|
||||
const browserTestFile = createBrowserTestFile();
|
||||
log(`Browser test file created at: ${browserTestFile}`, colors.green);
|
||||
|
||||
// Start a simple HTTP server to serve the test files
|
||||
logSubSection('Starting HTTP Server');
|
||||
const server = http.createServer((req, res) => {
|
||||
// Normalize the URL to handle relative paths
|
||||
const normalizedUrl = req.url.replace(/^\/+/, '/');
|
||||
let filePath = path.join(
|
||||
rootDir,
|
||||
normalizedUrl === '/' ? 'browser-test.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.blue);
|
||||
|
||||
// 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
|
||||
logSubSection('Running Browser Tests with Puppeteer');
|
||||
log('Launching headless browser...', colors.yellow);
|
||||
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}`, colors.blue);
|
||||
}
|
||||
});
|
||||
|
||||
// Navigate to the test page
|
||||
log('Navigating to browser test page...', colors.yellow);
|
||||
await page.goto(`http://localhost:${PORT}/browser-test.html`);
|
||||
|
||||
// Run the test
|
||||
log('Running browser tests...', colors.yellow);
|
||||
await page.waitForSelector('#runTest');
|
||||
await page.click('#runTest');
|
||||
|
||||
// Wait for test completion
|
||||
await page.waitForFunction(
|
||||
() => {
|
||||
const resultText = document.getElementById('result').textContent;
|
||||
return resultText.includes('All tests passed') || resultText.includes('Test failed');
|
||||
},
|
||||
{ timeout: 60000 }
|
||||
);
|
||||
|
||||
// Get test results
|
||||
const browserTestResult = await page.evaluate(() => {
|
||||
return document.getElementById('result').innerHTML;
|
||||
});
|
||||
|
||||
log('Browser test results:', colors.green);
|
||||
log(browserTestResult.replace(/<[^>]*>/g, '').trim());
|
||||
|
||||
// Check if the test passed
|
||||
const browserTestPassed = browserTestResult.includes('All tests passed');
|
||||
if (!browserTestPassed) {
|
||||
throw new Error('Browser tests failed!');
|
||||
}
|
||||
|
||||
// Close the browser and server
|
||||
await browser.close();
|
||||
server.close();
|
||||
log('HTTP server stopped', colors.green);
|
||||
|
||||
logSection('CLI ENVIRONMENT TESTS');
|
||||
|
||||
// Create and run CLI test script
|
||||
logSubSection('Creating CLI Test Script');
|
||||
const cliTestScript = createCliTestScript();
|
||||
log(`CLI test script created at: ${cliTestScript}`, colors.green);
|
||||
|
||||
logSubSection('Installing CLI Package Locally');
|
||||
log('Installing CLI package locally for testing...', colors.yellow);
|
||||
try {
|
||||
runCommand('npm run test:cli');
|
||||
log('CLI package installed successfully!', colors.green);
|
||||
|
||||
logSubSection('Running CLI Tests');
|
||||
try {
|
||||
const cliTestResult = runCommand(`node ${cliTestScript}`);
|
||||
log(cliTestResult);
|
||||
log('CLI tests completed!', colors.green);
|
||||
} catch (error) {
|
||||
log('CLI tests failed. This might be expected if you don\'t have the CLI installed globally.', colors.yellow);
|
||||
log('You can install the CLI globally with: npm run test:cli', colors.yellow);
|
||||
}
|
||||
} catch (error) {
|
||||
log('Failed to install CLI package locally. Skipping CLI tests.', colors.yellow);
|
||||
log('You can run the CLI tests separately with: npm run test:cli', colors.yellow);
|
||||
}
|
||||
|
||||
logSection('CLEANING UP');
|
||||
|
||||
// Clean up test files
|
||||
log('Cleaning up test files...', colors.yellow);
|
||||
fs.unlinkSync(nodeTestScript);
|
||||
fs.unlinkSync(browserTestFile);
|
||||
fs.unlinkSync(cliTestScript);
|
||||
log('Test files removed', colors.green);
|
||||
|
||||
logSection('TEST SUMMARY');
|
||||
log('✅ All environment tests completed successfully!', colors.green);
|
||||
log('The library has been tested in the following environments:', colors.green);
|
||||
log('- Browser environment', colors.green);
|
||||
log('- Node.js/server environment', colors.green);
|
||||
log('- CLI environment', colors.green);
|
||||
|
||||
log('\nTensorFlow functionality has been verified in all environments.', colors.green);
|
||||
log('Environment detection has been tested and is working correctly.', colors.green);
|
||||
|
||||
} catch (error) {
|
||||
logSection('TEST FAILURE');
|
||||
log(`Tests failed: ${error.message}`, colors.red);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the tests
|
||||
runComprehensiveTests().catch((error) => {
|
||||
log(`Unhandled error: ${error.message}`, colors.red);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -1,300 +0,0 @@
|
|||
#!/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)
|
||||
|
||||
// Apply TextEncoder patch
|
||||
log('Applying TextEncoder patch...', colors.yellow)
|
||||
runCommand('node scripts/patch-textencoder.js')
|
||||
log('TextEncoder patch applied successfully!', colors.green)
|
||||
|
||||
// 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)
|
||||
|
||||
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)
|
||||
|
||||
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())
|
||||
|
||||
// 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())
|
||||
|
||||
// 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 {
|
||||
runCommand('npm run test:cli')
|
||||
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)
|
||||
|
||||
// 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)
|
||||
} catch (error) {
|
||||
log(
|
||||
"CLI tests failed. This might be expected if you don't have the CLI installed globally.",
|
||||
colors.yellow
|
||||
)
|
||||
log(
|
||||
'You can run the CLI tests separately with: npm run test:cli',
|
||||
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)
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue