#!/usr/bin/env node /** * Builder-specific Tests for Pake CLI * * These tests verify platform-specific builder logic and file naming patterns * Based on analysis of bin/builders/ implementation */ import { execSync } from 'child_process'; import path from 'path'; import config, { TEST_URLS, TEST_NAMES } from './test.config.js'; import ora from 'ora'; class BuilderTestRunner { constructor() { this.tests = []; this.results = []; } addTest(name, testFn, description = '') { this.tests.push({ name, testFn, description }); } async runAll() { console.log('šŸ—ļø Builder-specific Tests'); console.log('==========================\n'); for (const [index, test] of this.tests.entries()) { const spinner = ora(`Running ${test.name}...`).start(); try { const result = await test.testFn(); if (result) { spinner.succeed(`${index + 1}. ${test.name}: PASS`); this.results.push({ name: test.name, passed: true }); } else { spinner.fail(`${index + 1}. ${test.name}: FAIL`); this.results.push({ name: test.name, passed: false }); } } catch (error) { spinner.fail(`${index + 1}. ${test.name}: ERROR - ${error.message.slice(0, 50)}...`); this.results.push({ name: test.name, passed: false, error: error.message }); } } this.displayResults(); } displayResults() { const passed = this.results.filter(r => r.passed).length; const total = this.results.length; console.log(`\nšŸ“Š Builder Test Results: ${passed}/${total} passed\n`); if (passed === total) { console.log('šŸŽ‰ All builder tests passed!'); } else { console.log('āŒ Some builder tests failed'); this.results.filter(r => !r.passed).forEach(result => { console.log(` - ${result.name}${result.error ? `: ${result.error}` : ''}`); }); } } } const runner = new BuilderTestRunner(); // Platform-specific file naming tests runner.addTest( 'Mac Builder File Naming Pattern', () => { try { // Test macOS file naming: name_version_arch.dmg const mockName = 'TestApp'; const mockVersion = '1.0.0'; const arch = process.arch === 'arm64' ? 'aarch64' : process.arch; // Expected pattern: TestApp_1.0.0_aarch64.dmg (for M1) or TestApp_1.0.0_x64.dmg (for Intel) const expectedPattern = `${mockName}_${mockVersion}_${arch}`; const universalPattern = `${mockName}_${mockVersion}_universal`; // Test that naming pattern is consistent return expectedPattern.includes(mockName) && expectedPattern.includes(mockVersion) && (expectedPattern.includes(arch) || universalPattern.includes('universal')); } catch (error) { return false; } }, 'Should generate correct macOS file naming pattern' ); runner.addTest( 'Windows Builder File Naming Pattern', () => { try { // Test Windows file naming: name_version_arch_language.msi const mockName = 'TestApp'; const mockVersion = '1.0.0'; const arch = process.arch; const language = 'en-US'; // default language // Expected pattern: TestApp_1.0.0_x64_en-US.msi const expectedPattern = `${mockName}_${mockVersion}_${arch}_${language}`; return expectedPattern.includes(mockName) && expectedPattern.includes(mockVersion) && expectedPattern.includes(arch) && expectedPattern.includes(language); } catch (error) { return false; } }, 'Should generate correct Windows file naming pattern' ); runner.addTest( 'Linux Builder File Naming Pattern', () => { try { // Test Linux file naming variations const mockName = 'testapp'; const mockVersion = '1.0.0'; let arch = process.arch === 'x64' ? 'amd64' : process.arch; // Test different target formats const debPattern = `${mockName}_${mockVersion}_${arch}`; // .deb const rpmPattern = `${mockName}-${mockVersion}-1.${arch === 'arm64' ? 'aarch64' : arch}`; // .rpm const appImagePattern = `${mockName}_${mockVersion}_${arch === 'arm64' ? 'aarch64' : arch}`; // .AppImage return debPattern.includes(mockName) && rpmPattern.includes(mockName) && appImagePattern.includes(mockName); } catch (error) { return false; } }, 'Should generate correct Linux file naming patterns for different targets' ); runner.addTest( 'Architecture Detection Logic', () => { try { // Test architecture mapping logic const currentArch = process.arch; // Mac: arm64 -> aarch64, others keep same const macArch = currentArch === 'arm64' ? 'aarch64' : currentArch; // Linux: x64 -> amd64 for deb, arm64 -> aarch64 for rpm/appimage const linuxArch = currentArch === 'x64' ? 'amd64' : currentArch; // Windows: keeps process.arch as-is const winArch = currentArch; return typeof macArch === 'string' && typeof linuxArch === 'string' && typeof winArch === 'string'; } catch (error) { return false; } }, 'Should correctly detect and map system architecture' ); runner.addTest( 'Multi-arch Build Detection', () => { try { // Test universal binary logic for macOS const platform = process.platform; if (platform === 'darwin') { // macOS should support multi-arch with --multi-arch flag const supportsMultiArch = true; const universalSuffix = 'universal'; return supportsMultiArch && universalSuffix === 'universal'; } else { // Other platforms don't support multi-arch return true; } } catch (error) { return false; } }, 'Should handle multi-architecture builds correctly' ); runner.addTest( 'Target Format Validation', () => { try { // Test valid target formats per platform const platform = process.platform; const validTargets = { 'darwin': ['dmg'], 'win32': ['msi'], 'linux': ['deb', 'appimage', 'rpm'] }; const platformTargets = validTargets[platform]; return Array.isArray(platformTargets) && platformTargets.length > 0; } catch (error) { return false; } }, 'Should validate target formats per platform' ); runner.addTest( 'Build Path Generation', () => { try { // Test build path logic: debug vs release const debugPath = 'src-tauri/target/debug/bundle/'; const releasePath = 'src-tauri/target/release/bundle/'; const universalPath = 'src-tauri/target/universal-apple-darwin/release/bundle'; // Paths should be consistent return debugPath.includes('debug') && releasePath.includes('release') && universalPath.includes('universal'); } catch (error) { return false; } }, 'Should generate correct build paths for different modes' ); runner.addTest( 'File Extension Mapping', () => { try { // Test file extension mapping logic const platform = process.platform; const extensionMap = { 'darwin': 'dmg', 'win32': 'msi', 'linux': 'deb' // default, can be appimage or rpm }; const expectedExt = extensionMap[platform]; // Special case for Linux AppImage (capital A) const appImageExt = 'AppImage'; return typeof expectedExt === 'string' && (expectedExt.length > 0 || appImageExt === 'AppImage'); } catch (error) { return false; } }, 'Should map file extensions correctly per platform' ); runner.addTest( 'Name Sanitization Logic', () => { try { // Test name sanitization for file systems const testNames = [ 'Simple App', // Should handle spaces 'App-With_Symbols', // Should handle hyphens and underscores 'CamelCaseApp', // Should handle case variations 'App123', // Should handle numbers ]; // Test that names can be processed (basic validation) return testNames.every(name => { const processed = name.toLowerCase().replace(/\s+/g, ''); return processed.length > 0; }); } catch (error) { return false; } }, 'Should sanitize app names for filesystem compatibility' ); // Run builder tests if this file is executed directly if (import.meta.url === `file://${process.argv[1]}`) { runner.runAll().catch(console.error); } export default runner;