💄 format

This commit is contained in:
Tw93
2025-08-21 20:34:10 +08:00
parent e2bc7859e2
commit a539067e57
10 changed files with 478 additions and 389 deletions

View File

@@ -171,7 +171,7 @@ export default abstract class BaseBuilder {
// Add features // Add features
const features = ['cli-build']; const features = ['cli-build'];
// Add macos-proxy feature for modern macOS (Darwin 23+ = macOS 14+) // Add macos-proxy feature for modern macOS (Darwin 23+ = macOS 14+)
if (IS_MAC) { if (IS_MAC) {
const macOSVersion = this.getMacOSMajorVersion(); const macOSVersion = this.getMacOSMajorVersion();
@@ -179,7 +179,7 @@ export default abstract class BaseBuilder {
features.push('macos-proxy'); features.push('macos-proxy');
} }
} }
if (features.length > 0) { if (features.length > 0) {
fullCommand += ` --features ${features.join(',')}`; fullCommand += ` --features ${features.join(',')}`;
} }

View File

@@ -38,24 +38,20 @@ export default class MacBuilder extends BaseBuilder {
const baseCommand = this.options.debug const baseCommand = this.options.debug
? 'npm run tauri build -- --debug' ? 'npm run tauri build -- --debug'
: 'npm run tauri build --'; : 'npm run tauri build --';
// Use temporary config directory to avoid modifying source files // Use temporary config directory to avoid modifying source files
const configPath = path.join( const configPath = path.join('src-tauri', '.pake', 'tauri.conf.json');
'src-tauri',
'.pake',
'tauri.conf.json',
);
let fullCommand = `${baseCommand} --target universal-apple-darwin -c "${configPath}"`; let fullCommand = `${baseCommand} --target universal-apple-darwin -c "${configPath}"`;
// Add features // Add features
const features = ['cli-build']; const features = ['cli-build'];
// Add macos-proxy feature for modern macOS (Darwin 23+ = macOS 14+) // Add macos-proxy feature for modern macOS (Darwin 23+ = macOS 14+)
const macOSVersion = this.getMacOSMajorVersion(); const macOSVersion = this.getMacOSMajorVersion();
if (macOSVersion >= 23) { if (macOSVersion >= 23) {
features.push('macos-proxy'); features.push('macos-proxy');
} }
if (features.length > 0) { if (features.length > 0) {
fullCommand += ` --features ${features.join(',')}`; fullCommand += ` --features ${features.join(',')}`;
} }

View File

@@ -5,10 +5,18 @@ import { npmDirectory } from '@/utils/dir';
// Load configs from npm package directory, not from project source // Load configs from npm package directory, not from project source
const tauriSrcDir = path.join(npmDirectory, 'src-tauri'); const tauriSrcDir = path.join(npmDirectory, 'src-tauri');
const pakeConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'pake.json')); const pakeConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'pake.json'));
const CommonConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.conf.json')); const CommonConf = fsExtra.readJSONSync(
const WinConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.windows.conf.json')); path.join(tauriSrcDir, 'tauri.conf.json'),
const MacConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.macos.conf.json')); );
const LinuxConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.linux.conf.json')); const WinConf = fsExtra.readJSONSync(
path.join(tauriSrcDir, 'tauri.windows.conf.json'),
);
const MacConf = fsExtra.readJSONSync(
path.join(tauriSrcDir, 'tauri.macos.conf.json'),
);
const LinuxConf = fsExtra.readJSONSync(
path.join(tauriSrcDir, 'tauri.linux.conf.json'),
);
const platformConfigs = { const platformConfigs = {
win32: WinConf, win32: WinConf,

3
rollup.config.js vendored
View File

@@ -11,7 +11,8 @@ import { spawn, exec } from "child_process";
// Set macOS SDK environment variables for compatibility // Set macOS SDK environment variables for compatibility
if (process.platform === "darwin") { if (process.platform === "darwin") {
process.env.MACOSX_DEPLOYMENT_TARGET = process.env.MACOSX_DEPLOYMENT_TARGET || "14.0"; process.env.MACOSX_DEPLOYMENT_TARGET =
process.env.MACOSX_DEPLOYMENT_TARGET || "14.0";
process.env.CFLAGS = process.env.CFLAGS || "-fno-modules"; process.env.CFLAGS = process.env.CFLAGS || "-fno-modules";
process.env.CXXFLAGS = process.env.CXXFLAGS || "-fno-modules"; process.env.CXXFLAGS = process.env.CXXFLAGS || "-fno-modules";
} }

View File

@@ -51,11 +51,11 @@ const main = async () => {
const targetDirs = [ const targetDirs = [
"src-tauri/target", "src-tauri/target",
"src-tauri/target/debug", "src-tauri/target/debug",
"src-tauri/target/release", "src-tauri/target/release",
"src-tauri/target/universal-apple-darwin" "src-tauri/target/universal-apple-darwin",
]; ];
targetDirs.forEach(dir => { targetDirs.forEach((dir) => {
if (fs.existsSync(dir)) { if (fs.existsSync(dir)) {
// Only remove .pake subdirectories, not the entire target directory // Only remove .pake subdirectories, not the entire target directory
const targetPakeDir = path.join(dir, ".pake"); const targetPakeDir = path.join(dir, ".pake");

View File

@@ -85,14 +85,14 @@ GitHub.com 专用快速构建验证:
## 测试命令 ## 测试命令
| 命令 | 描述 | 覆盖范围 | 持续时间 | | 命令 | 描述 | 覆盖范围 | 持续时间 |
| --------------------------- | -------------------- | ------------------------------- | ----------- | | ---------------------------------- | -------------------- | ----------------------------- | ----------- |
| `npm test` | **真实完整构建测试** | 完整 GitHub.com 应用打包 | **~8 分钟** | | `npm test` | **真实完整构建测试** | 完整 GitHub.com 应用打包 | **~8 分钟** |
| `node tests/index.js` | 基础测试套件 | Unit + Integration + Builder | ~30 秒 | | `node tests/index.js` | 基础测试套件 | Unit + Integration + Builder | ~30 秒 |
| `node tests/index.js --real-build` | 真实构建测试 | 完整 GitHub.com 应用打包 | ~8 分钟 | | `node tests/index.js --real-build` | 真实构建测试 | 完整 GitHub.com 应用打包 | ~8 分钟 |
| `node tests/github.js` | GitHub Actions 测试 | 12 个 GitHub Actions 专项测试 | ~2 分钟 | | `node tests/github.js` | GitHub Actions 测试 | 12 个 GitHub Actions 专项测试 | ~2 分钟 |
| `node tests/build.js` | 快速构建测试 | GitHub.com 构建验证 | ~3 分钟 | | `node tests/build.js` | 快速构建测试 | GitHub.com 构建验证 | ~3 分钟 |
| `node tests/complete.js` | 完整构建测试 | 端到端完整构建流程 | ~10 分钟 | | `node tests/complete.js` | 完整构建测试 | 端到端完整构建流程 | ~10 分钟 |
## 高级用法 ## 高级用法

View File

@@ -2,7 +2,7 @@
/** /**
* GitHub.com Real Build Test * GitHub.com Real Build Test
* *
* This is a standalone test for actual GitHub.com app packaging * This is a standalone test for actual GitHub.com app packaging
* to validate that both CLI and GitHub Actions scenarios work correctly. * to validate that both CLI and GitHub Actions scenarios work correctly.
*/ */
@@ -34,7 +34,7 @@ const cleanup = () => {
fs.unlinkSync(dmgFile); fs.unlinkSync(dmgFile);
console.log("✅ Cleaned up .dmg file"); console.log("✅ Cleaned up .dmg file");
} }
// Clean .pake directory // Clean .pake directory
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake"); const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
if (fs.existsSync(pakeDir)) { if (fs.existsSync(pakeDir)) {
@@ -47,16 +47,18 @@ const cleanup = () => {
}; };
// Handle cleanup on exit // Handle cleanup on exit
process.on('exit', cleanup); process.on("exit", cleanup);
process.on('SIGINT', () => { process.on("SIGINT", () => {
console.log("\n🛑 Build interrupted by user"); console.log("\n🛑 Build interrupted by user");
cleanup(); cleanup();
process.exit(1); process.exit(1);
}); });
process.on('SIGTERM', cleanup); process.on("SIGTERM", cleanup);
console.log("🔧 Testing GitHub.com packaging with CLI..."); console.log("🔧 Testing GitHub.com packaging with CLI...");
console.log(`Command: node ${config.CLI_PATH} https://github.com --name ${testName} --debug --width 1200 --height 780\n`); console.log(
`Command: node ${config.CLI_PATH} https://github.com --name ${testName} --debug --width 1200 --height 780\n`,
);
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --debug --width 1200 --height 780`; const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --debug --width 1200 --height 780`;
@@ -79,7 +81,7 @@ console.log("------------------");
child.stdout.on("data", (data) => { child.stdout.on("data", (data) => {
const output = data.toString(); const output = data.toString();
// Track build progress // Track build progress
if (output.includes("Installing package")) { if (output.includes("Installing package")) {
console.log("📦 Installing pake dependencies..."); console.log("📦 Installing pake dependencies...");
@@ -105,7 +107,7 @@ child.stdout.on("data", (data) => {
child.stderr.on("data", (data) => { child.stderr.on("data", (data) => {
const output = data.toString(); const output = data.toString();
// Track stderr progress (Tauri outputs build info to stderr) // Track stderr progress (Tauri outputs build info to stderr)
if (output.includes("Installing package")) { if (output.includes("Installing package")) {
console.log("📦 Installing pake dependencies..."); console.log("📦 Installing pake dependencies...");
@@ -127,20 +129,22 @@ child.stderr.on("data", (data) => {
if (output.includes("Built application at:")) { if (output.includes("Built application at:")) {
console.log("✅ Application built successfully!"); console.log("✅ Application built successfully!");
} }
// Only show actual errors, filter out build progress // Only show actual errors, filter out build progress
if (!output.includes("warning:") && if (
!output.includes("verbose") && !output.includes("warning:") &&
!output.includes("npm info") && !output.includes("verbose") &&
!output.includes("Installing package") && !output.includes("npm info") &&
!output.includes("Package installed") && !output.includes("Installing package") &&
!output.includes("Building app") && !output.includes("Package installed") &&
!output.includes("Compiling") && !output.includes("Building app") &&
!output.includes("Finished") && !output.includes("Compiling") &&
!output.includes("Built application at:") && !output.includes("Finished") &&
!output.includes("Bundling") && !output.includes("Built application at:") &&
!output.includes("npm http") && !output.includes("Bundling") &&
output.trim().length > 0) { !output.includes("npm http") &&
output.trim().length > 0
) {
console.log("❌ Build error:", output.trim()); console.log("❌ Build error:", output.trim());
} }
}); });
@@ -149,7 +153,7 @@ child.stderr.on("data", (data) => {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
console.log("\n⏱ Build timeout reached (3 minutes)"); console.log("\n⏱ Build timeout reached (3 minutes)");
child.kill("SIGTERM"); child.kill("SIGTERM");
if (buildStarted && compilationStarted) { if (buildStarted && compilationStarted) {
console.log("✅ SUCCESS: GitHub.com CLI build started successfully!"); console.log("✅ SUCCESS: GitHub.com CLI build started successfully!");
console.log(" - Build process initiated ✓"); console.log(" - Build process initiated ✓");
@@ -157,7 +161,9 @@ const timeout = setTimeout(() => {
console.log(" - Configuration generated for GitHub.com ✓"); console.log(" - Configuration generated for GitHub.com ✓");
console.log("\n🎯 Test Result: PASS"); console.log("\n🎯 Test Result: PASS");
console.log(" The GitHub.com app build is working correctly."); console.log(" The GitHub.com app build is working correctly.");
console.log(" Build was terminated early to save time, but core functionality verified."); console.log(
" Build was terminated early to save time, but core functionality verified.",
);
process.exit(0); process.exit(0);
} else if (buildStarted) { } else if (buildStarted) {
console.log("⚠️ PARTIAL: Build started but compilation not detected"); console.log("⚠️ PARTIAL: Build started but compilation not detected");
@@ -172,25 +178,27 @@ const timeout = setTimeout(() => {
child.on("close", (code) => { child.on("close", (code) => {
clearTimeout(timeout); clearTimeout(timeout);
console.log(`\n📊 Build Process Summary:`); console.log(`\n📊 Build Process Summary:`);
console.log("========================"); console.log("========================");
console.log(`Exit Code: ${code}`); console.log(`Exit Code: ${code}`);
console.log(`Build Started: ${buildStarted ? "✅" : "❌"}`); console.log(`Build Started: ${buildStarted ? "✅" : "❌"}`);
console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`); console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`);
// Check for output files // Check for output files
const appExists = fs.existsSync(appFile); const appExists = fs.existsSync(appFile);
const dmgExists = fs.existsSync(dmgFile); const dmgExists = fs.existsSync(dmgFile);
console.log(`App File (.app): ${appExists ? "✅" : "❌"}`); console.log(`App File (.app): ${appExists ? "✅" : "❌"}`);
console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`); console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`);
if (buildStarted && compilationStarted) { if (buildStarted && compilationStarted) {
console.log("\n🎉 SUCCESS: GitHub.com CLI build verification completed!"); console.log("\n🎉 SUCCESS: GitHub.com CLI build verification completed!");
console.log(" All critical build stages detected."); console.log(" All critical build stages detected.");
process.exit(0); process.exit(0);
} else if (buildStarted) { } else if (buildStarted) {
console.log("\n⚠ PARTIAL SUCCESS: Build started but may not have completed"); console.log(
"\n⚠ PARTIAL SUCCESS: Build started but may not have completed",
);
process.exit(0); process.exit(0);
} else { } else {
console.log("\n❌ FAILED: Build did not start properly"); console.log("\n❌ FAILED: Build did not start properly");
@@ -206,4 +214,4 @@ child.on("error", (error) => {
}); });
// Send empty input to handle any prompts // Send empty input to handle any prompts
child.stdin.end(); child.stdin.end();

View File

@@ -2,7 +2,7 @@
/** /**
* GitHub.com Complete Build Test * GitHub.com Complete Build Test
* *
* This test performs a complete build of github.com to verify * This test performs a complete build of github.com to verify
* that the entire packaging pipeline works correctly end-to-end. * that the entire packaging pipeline works correctly end-to-end.
*/ */
@@ -34,7 +34,7 @@ const cleanup = () => {
fs.unlinkSync(dmgFile); fs.unlinkSync(dmgFile);
console.log("✅ Cleaned up .dmg file"); console.log("✅ Cleaned up .dmg file");
} }
// Clean .pake directory // Clean .pake directory
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake"); const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
if (fs.existsSync(pakeDir)) { if (fs.existsSync(pakeDir)) {
@@ -47,16 +47,18 @@ const cleanup = () => {
}; };
// Handle cleanup on exit // Handle cleanup on exit
process.on('exit', cleanup); process.on("exit", cleanup);
process.on('SIGINT', () => { process.on("SIGINT", () => {
console.log("\n🛑 Build interrupted by user"); console.log("\n🛑 Build interrupted by user");
cleanup(); cleanup();
process.exit(1); process.exit(1);
}); });
process.on('SIGTERM', cleanup); process.on("SIGTERM", cleanup);
console.log("🔧 Testing GitHub app packaging with optimal settings..."); console.log("🔧 Testing GitHub app packaging with optimal settings...");
console.log(`Command: pake https://github.com --name ${testName} --width 1200 --height 800 --hide-title-bar\n`); console.log(
`Command: pake https://github.com --name ${testName} --width 1200 --height 800 --hide-title-bar\n`,
);
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar`; const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar`;
@@ -80,7 +82,7 @@ console.log("------------------");
child.stdout.on("data", (data) => { child.stdout.on("data", (data) => {
const output = data.toString(); const output = data.toString();
// Track build progress // Track build progress
if (output.includes("Installing package")) { if (output.includes("Installing package")) {
console.log("📦 Installing pake dependencies..."); console.log("📦 Installing pake dependencies...");
@@ -111,7 +113,7 @@ child.stdout.on("data", (data) => {
child.stderr.on("data", (data) => { child.stderr.on("data", (data) => {
const output = data.toString(); const output = data.toString();
// Track stderr progress (Tauri outputs build info to stderr) // Track stderr progress (Tauri outputs build info to stderr)
if (output.includes("Installing package")) { if (output.includes("Installing package")) {
console.log("📦 Installing pake dependencies..."); console.log("📦 Installing pake dependencies...");
@@ -135,34 +137,36 @@ child.stderr.on("data", (data) => {
buildCompleted = true; buildCompleted = true;
console.log("✅ Application built successfully!"); console.log("✅ Application built successfully!");
} }
// Only show actual errors, filter out build progress // Only show actual errors, filter out build progress
if (!output.includes("warning:") && if (
!output.includes("verbose") && !output.includes("warning:") &&
!output.includes("npm info") && !output.includes("verbose") &&
!output.includes("Installing package") && !output.includes("npm info") &&
!output.includes("Package installed") && !output.includes("Installing package") &&
!output.includes("Building app") && !output.includes("Package installed") &&
!output.includes("Compiling") && !output.includes("Building app") &&
!output.includes("Finished") && !output.includes("Compiling") &&
!output.includes("Built application at:") && !output.includes("Finished") &&
!output.includes("Bundling") && !output.includes("Built application at:") &&
!output.includes("npm http") && !output.includes("Bundling") &&
!output.includes("Info Looking up installed") && !output.includes("npm http") &&
output.trim().length > 0) { !output.includes("Info Looking up installed") &&
output.trim().length > 0
) {
console.log("❌ Build error:", output.trim()); console.log("❌ Build error:", output.trim());
} }
}); });
// Set a 10-minute timeout for the complete build (real packaging takes time) // Set a 10-minute timeout for the complete build (real packaging takes time)
// DON'T kill the process early - let it complete naturally // DON'T kill the process early - let it complete naturally
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
console.log("\n⏱ Build timeout reached (10 minutes)"); console.log("\n⏱ Build timeout reached (10 minutes)");
// Check if we actually have output files even if process is still running // Check if we actually have output files even if process is still running
const appExists = fs.existsSync(appFile); const appExists = fs.existsSync(appFile);
const dmgExists = fs.existsSync(dmgFile); const dmgExists = fs.existsSync(dmgFile);
if (appExists || buildCompleted) { if (appExists || buildCompleted) {
console.log("🎉 SUCCESS: GitHub app was built successfully!"); console.log("🎉 SUCCESS: GitHub app was built successfully!");
console.log(" App file exists, build completed despite long duration"); console.log(" App file exists, build completed despite long duration");
@@ -177,7 +181,7 @@ const timeout = setTimeout(() => {
child.on("close", (code) => { child.on("close", (code) => {
clearTimeout(timeout); clearTimeout(timeout);
console.log(`\n📊 GitHub App Build Summary:`); console.log(`\n📊 GitHub App Build Summary:`);
console.log("============================="); console.log("=============================");
console.log(`Exit Code: ${code}`); console.log(`Exit Code: ${code}`);
@@ -185,29 +189,33 @@ child.on("close", (code) => {
console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`); console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`);
console.log(`Bundling Started: ${bundlingStarted ? "✅" : "❌"}`); console.log(`Bundling Started: ${bundlingStarted ? "✅" : "❌"}`);
console.log(`Build Completed: ${buildCompleted ? "✅" : "❌"}`); console.log(`Build Completed: ${buildCompleted ? "✅" : "❌"}`);
// Check for output files // Check for output files
const appExists = fs.existsSync(appFile); const appExists = fs.existsSync(appFile);
const dmgExists = fs.existsSync(dmgFile); const dmgExists = fs.existsSync(dmgFile);
console.log(`App File (.app): ${appExists ? "✅" : "❌"}`); console.log(`App File (.app): ${appExists ? "✅" : "❌"}`);
console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`); console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`);
// Check .app bundle structure if it exists // Check .app bundle structure if it exists
if (appExists) { if (appExists) {
try { try {
const contentsPath = path.join(appFile, "Contents"); const contentsPath = path.join(appFile, "Contents");
const macOSPath = path.join(contentsPath, "MacOS"); const macOSPath = path.join(contentsPath, "MacOS");
const resourcesPath = path.join(contentsPath, "Resources"); const resourcesPath = path.join(contentsPath, "Resources");
console.log(`App Bundle Structure:`); console.log(`App Bundle Structure:`);
console.log(` Contents/: ${fs.existsSync(contentsPath) ? "✅" : "❌"}`); console.log(` Contents/: ${fs.existsSync(contentsPath) ? "✅" : "❌"}`);
console.log(` Contents/MacOS/: ${fs.existsSync(macOSPath) ? "✅" : "❌"}`); console.log(
console.log(` Contents/Resources/: ${fs.existsSync(resourcesPath) ? "✅" : "❌"}`); ` Contents/MacOS/: ${fs.existsSync(macOSPath) ? "✅" : "❌"}`,
);
console.log(
` Contents/Resources/: ${fs.existsSync(resourcesPath) ? "✅" : "❌"}`,
);
} catch (error) { } catch (error) {
console.log(`App Bundle Check: ❌ (${error.message})`); console.log(`App Bundle Check: ❌ (${error.message})`);
} }
} }
// Real success check: app file must exist and build must have completed // Real success check: app file must exist and build must have completed
if (appExists && (buildCompleted || code === 0)) { if (appExists && (buildCompleted || code === 0)) {
console.log("\n🎉 COMPLETE SUCCESS: GitHub app build fully completed!"); console.log("\n🎉 COMPLETE SUCCESS: GitHub app build fully completed!");
@@ -221,7 +229,9 @@ child.on("close", (code) => {
console.log(" 🎯 Build process successful"); console.log(" 🎯 Build process successful");
process.exit(0); process.exit(0);
} else if (code === 0 && buildStarted && compilationStarted) { } else if (code === 0 && buildStarted && compilationStarted) {
console.log("\n⚠ PARTIAL SUCCESS: Build process completed but no app file found"); console.log(
"\n⚠ PARTIAL SUCCESS: Build process completed but no app file found",
);
console.log(" 🐙 GitHub.com build process executed successfully"); console.log(" 🐙 GitHub.com build process executed successfully");
console.log(" ⚠️ App file may be in a different location"); console.log(" ⚠️ App file may be in a different location");
process.exit(0); process.exit(0);
@@ -240,4 +250,4 @@ child.on("error", (error) => {
}); });
// Send empty input to handle any prompts // Send empty input to handle any prompts
child.stdin.end(); child.stdin.end();

View File

@@ -161,8 +161,12 @@ class PakeCliTestRunner {
console.log("🚀 GitHub Actions Usage Guide:"); console.log("🚀 GitHub Actions Usage Guide:");
console.log("==============================\n"); console.log("==============================\n");
console.log("This test suite validates that pake-cli works correctly in GitHub Actions."); console.log(
console.log("The following workflow file (.github/workflows/pake-cli.yaml) is ready to use:\n"); "This test suite validates that pake-cli works correctly in GitHub Actions.",
);
console.log(
"The following workflow file (.github/workflows/pake-cli.yaml) is ready to use:\n",
);
console.log("Key features tested:"); console.log("Key features tested:");
console.log(" ✅ npm package installation and caching"); console.log(" ✅ npm package installation and caching");
@@ -284,14 +288,14 @@ runner.addTest(
// Create a temporary .pake directory to test cleanup // Create a temporary .pake directory to test cleanup
const tempDir = "/tmp/test_pake_cleanup"; const tempDir = "/tmp/test_pake_cleanup";
const pakeDir = path.join(tempDir, ".pake"); const pakeDir = path.join(tempDir, ".pake");
fs.mkdirSync(tempDir, { recursive: true }); fs.mkdirSync(tempDir, { recursive: true });
fs.mkdirSync(pakeDir, { recursive: true }); fs.mkdirSync(pakeDir, { recursive: true });
// Create some test config files // Create some test config files
fs.writeFileSync(path.join(pakeDir, "pake.json"), '{"test": true}'); fs.writeFileSync(path.join(pakeDir, "pake.json"), '{"test": true}');
fs.writeFileSync(path.join(pakeDir, "tauri.conf.json"), '{"test": true}'); fs.writeFileSync(path.join(pakeDir, "tauri.conf.json"), '{"test": true}');
runner.trackTempDir(tempDir); runner.trackTempDir(tempDir);
// Test cleanup script logic (from build_with_pake_cli.js) // Test cleanup script logic (from build_with_pake_cli.js)
@@ -327,7 +331,9 @@ process.exit(cleanedDirs > 0 ? 0 : 1);
}); });
// Verify .pake directory was cleaned // Verify .pake directory was cleaned
return !fs.existsSync(pakeDir) && result.includes("Cleaned directories: 1"); return (
!fs.existsSync(pakeDir) && result.includes("Cleaned directories: 1")
);
} catch (error) { } catch (error) {
console.error("Cleanup test failed:", error.message); console.error("Cleanup test failed:", error.message);
return false; return false;
@@ -384,8 +390,10 @@ process.exit(validResults && invalidResults ? 0 : 1);
timeout: 5000, timeout: 5000,
}); });
return result.includes("Valid URLs passed: true") && return (
result.includes("Invalid URLs rejected: true"); result.includes("Valid URLs passed: true") &&
result.includes("Invalid URLs rejected: true")
);
} catch { } catch {
return false; return false;
} }
@@ -432,7 +440,9 @@ process.exit(isSupported ? 0 : 1);
timeout: 5000, timeout: 5000,
}); });
return result.includes("Platform:") && result.includes("Expected extension:"); return (
result.includes("Platform:") && result.includes("Expected extension:")
);
} catch { } catch {
return false; return false;
} }
@@ -513,33 +523,36 @@ runner.addTest(
async () => { async () => {
try { try {
// Check if the workflow file exists and has correct structure // Check if the workflow file exists and has correct structure
const workflowPath = path.join(config.PROJECT_ROOT, ".github/workflows/pake-cli.yaml"); const workflowPath = path.join(
config.PROJECT_ROOT,
".github/workflows/pake-cli.yaml",
);
if (!fs.existsSync(workflowPath)) { if (!fs.existsSync(workflowPath)) {
console.error("Workflow file not found:", workflowPath); console.error("Workflow file not found:", workflowPath);
return false; return false;
} }
const workflowContent = fs.readFileSync(workflowPath, "utf8"); const workflowContent = fs.readFileSync(workflowPath, "utf8");
// Check for essential workflow components // Check for essential workflow components
const requiredElements = [ const requiredElements = [
"npm install pake-cli@latest --no-package-lock", // Latest version installation "npm install pake-cli@latest --no-package-lock", // Latest version installation
"timeout-minutes: 15", // Sufficient timeout "timeout-minutes: 15", // Sufficient timeout
"node ./script/build_with_pake_cli.js", // Build script execution "node ./script/build_with_pake_cli.js", // Build script execution
"ubuntu-24.04", // Linux support "ubuntu-24.04", // Linux support
"macos-latest", // macOS support "macos-latest", // macOS support
"windows-latest" // Windows support "windows-latest", // Windows support
]; ];
const hasAllElements = requiredElements.every(element => const hasAllElements = requiredElements.every((element) =>
workflowContent.includes(element) workflowContent.includes(element),
); );
if (!hasAllElements) { if (!hasAllElements) {
console.error("Workflow missing required elements"); console.error("Workflow missing required elements");
const missing = requiredElements.filter(element => const missing = requiredElements.filter(
!workflowContent.includes(element) (element) => !workflowContent.includes(element),
); );
console.error("Missing elements:", missing); console.error("Missing elements:", missing);
} }
@@ -556,7 +569,7 @@ runner.addTest(
// Test 9: Rust feature flags validation // Test 9: Rust feature flags validation
runner.addTest( runner.addTest(
"Rust Feature Flags Validation", "Rust Feature Flags Validation",
async () => { async () => {
try { try {
const testScript = ` const testScript = `
@@ -761,10 +774,12 @@ process.exit(validBuild ? 0 : 1);
timeout: 10000, timeout: 10000,
}); });
return result.includes("GitHub Actions GitHub.com build simulation started") && return (
result.includes("URL: https://github.com") && result.includes("GitHub Actions GitHub.com build simulation started") &&
result.includes("NAME: github") && result.includes("URL: https://github.com") &&
result.includes("Build configuration valid: true"); result.includes("NAME: github") &&
result.includes("Build configuration valid: true")
);
} catch (error) { } catch (error) {
console.error("GitHub Actions simulation failed:", error.message); console.error("GitHub Actions simulation failed:", error.message);
return false; return false;
@@ -833,9 +848,11 @@ process.exit(validParams ? 0 : 1);
timeout: 8000, timeout: 8000,
}); });
return result.includes("GitHub.com build parameters validated: true") && return (
result.includes("URL: https://github.com") && result.includes("GitHub.com build parameters validated: true") &&
result.includes("App name: github"); result.includes("URL: https://github.com") &&
result.includes("App name: github")
);
} catch (error) { } catch (error) {
console.error("Build script test failed:", error.message); console.error("Build script test failed:", error.message);
return false; return false;
@@ -847,7 +864,8 @@ process.exit(validParams ? 0 : 1);
// Run the test suite // Run the test suite
if (import.meta.url === `file://${process.argv[1]}`) { if (import.meta.url === `file://${process.argv[1]}`) {
runner.runAll() runner
.runAll()
.then((success) => { .then((success) => {
process.exit(success ? 0 : 1); process.exit(success ? 0 : 1);
}) })
@@ -857,4 +875,4 @@ if (import.meta.url === `file://${process.argv[1]}`) {
}); });
} }
export default runner; export default runner;

View File

@@ -2,7 +2,7 @@
/** /**
* Unified Test Runner for Pake CLI * Unified Test Runner for Pake CLI
* *
* This is a simplified, unified test runner that replaces the scattered * This is a simplified, unified test runner that replaces the scattered
* test files with a single, easy-to-use interface. * test files with a single, easy-to-use interface.
*/ */
@@ -23,12 +23,12 @@ class PakeTestRunner {
async runAll(options = {}) { async runAll(options = {}) {
const { const {
unit = true, unit = true,
integration = true, integration = true,
builder = true, builder = true,
pakeCliTests = false, pakeCliTests = false,
e2e = false, e2e = false,
quick = false, quick = false,
realBuild = false // Add option for real build test realBuild = false, // Add option for real build test
} = options; } = options;
console.log("🚀 Pake CLI Test Suite"); console.log("🚀 Pake CLI Test Suite");
@@ -72,9 +72,9 @@ class PakeTestRunner {
console.log("\n🏗 Running Real Build Test..."); console.log("\n🏗 Running Real Build Test...");
await this.runRealBuildTest(); await this.runRealBuildTest();
testCount++; testCount++;
// Add multi-arch test on macOS // Add multi-arch test on macOS
if (process.platform === 'darwin') { if (process.platform === "darwin") {
console.log("\n🔧 Running Multi-Arch Build Test..."); console.log("\n🔧 Running Multi-Arch Build Test...");
await this.runMultiArchBuildTest(); await this.runMultiArchBuildTest();
testCount++; testCount++;
@@ -89,9 +89,9 @@ class PakeTestRunner {
this.cleanup(); this.cleanup();
this.displayFinalResults(); this.displayFinalResults();
const passed = this.results.filter(r => r.passed).length; const passed = this.results.filter((r) => r.passed).length;
const total = this.results.length; const total = this.results.length;
return passed === total; return passed === total;
} }
@@ -121,10 +121,10 @@ class PakeTestRunner {
// Platform info // Platform info
console.log(`✅ Platform: ${process.platform} (${process.arch})`); console.log(`✅ Platform: ${process.platform} (${process.arch})`);
console.log(`✅ Node.js: ${process.version}`); console.log(`✅ Node.js: ${process.version}`);
const isCI = process.env.CI || process.env.GITHUB_ACTIONS; const isCI = process.env.CI || process.env.GITHUB_ACTIONS;
console.log(`${isCI ? "✅" : ""} CI Environment: ${isCI ? "Yes" : "No"}`); console.log(`${isCI ? "✅" : ""} CI Environment: ${isCI ? "Yes" : "No"}`);
console.log(); console.log();
} }
@@ -135,7 +135,7 @@ class PakeTestRunner {
const result = await Promise.race([ const result = await Promise.race([
testFn(), testFn(),
new Promise((_, reject) => new Promise((_, reject) =>
setTimeout(() => reject(new Error("Test timeout")), timeout) setTimeout(() => reject(new Error("Test timeout")), timeout),
), ),
]); ]);
@@ -148,10 +148,10 @@ class PakeTestRunner {
} }
} catch (error) { } catch (error) {
spinner.fail(`${name}: ERROR - ${error.message.slice(0, 100)}...`); spinner.fail(`${name}: ERROR - ${error.message.slice(0, 100)}...`);
this.results.push({ this.results.push({
name, name,
passed: false, passed: false,
error: error.message error: error.message,
}); });
} }
} }
@@ -167,7 +167,7 @@ class PakeTestRunner {
}); });
return /^\d+\.\d+\.\d+/.test(output.trim()); return /^\d+\.\d+\.\d+/.test(output.trim());
}, },
TIMEOUTS.QUICK TIMEOUTS.QUICK,
); );
// Help command test // Help command test
@@ -180,174 +180,151 @@ class PakeTestRunner {
}); });
return output.includes("Usage: cli [url] [options]"); return output.includes("Usage: cli [url] [options]");
}, },
TIMEOUTS.QUICK TIMEOUTS.QUICK,
); );
// URL validation test // URL validation test
await this.runTest( await this.runTest("URL Validation", () => {
"URL Validation", try {
() => { execSync(`node "${config.CLI_PATH}" "invalid-url" --name TestApp`, {
try {
execSync(`node "${config.CLI_PATH}" "invalid-url" --name TestApp`, {
encoding: "utf8",
timeout: 3000,
});
return false; // Should have failed
} catch (error) {
return error.status !== 0;
}
}
);
// Number validation test
await this.runTest(
"Number Validation",
() => {
try {
execSync(`node "${config.CLI_PATH}" https://example.com --width abc`, {
encoding: "utf8",
timeout: 3000,
});
return false; // Should throw error
} catch (error) {
return error.message.includes("Not a number");
}
}
);
// CLI response time test
await this.runTest(
"CLI Response Time",
() => {
const start = Date.now();
execSync(`node "${config.CLI_PATH}" --version`, {
encoding: "utf8", encoding: "utf8",
timeout: 3000, timeout: 3000,
}); });
const elapsed = Date.now() - start; return false; // Should have failed
return elapsed < 2000; } catch (error) {
return error.status !== 0;
} }
); });
// Number validation test
await this.runTest("Number Validation", () => {
try {
execSync(`node "${config.CLI_PATH}" https://example.com --width abc`, {
encoding: "utf8",
timeout: 3000,
});
return false; // Should throw error
} catch (error) {
return error.message.includes("Not a number");
}
});
// CLI response time test
await this.runTest("CLI Response Time", () => {
const start = Date.now();
execSync(`node "${config.CLI_PATH}" --version`, {
encoding: "utf8",
timeout: 3000,
});
const elapsed = Date.now() - start;
return elapsed < 2000;
});
// Weekly URL accessibility test // Weekly URL accessibility test
await this.runTest( await this.runTest("Weekly URL Accessibility", () => {
"Weekly URL Accessibility", try {
() => { const testCommand = `node "${config.CLI_PATH}" ${TEST_URLS.WEEKLY} --name "URLTest" --debug`;
try { execSync(`echo "n" | timeout 5s ${testCommand} || true`, {
const testCommand = `node "${config.CLI_PATH}" ${TEST_URLS.WEEKLY} --name "URLTest" --debug`; encoding: "utf8",
execSync(`echo "n" | timeout 5s ${testCommand} || true`, { timeout: 8000,
encoding: "utf8", });
timeout: 8000, return true; // If we get here, URL was parsed successfully
}); } catch (error) {
return true; // If we get here, URL was parsed successfully return (
} catch (error) { !error.message.includes("Invalid URL") &&
return !error.message.includes("Invalid URL") && !error.message.includes("invalid"); !error.message.includes("invalid")
} );
} }
); });
} }
async runIntegrationTests() { async runIntegrationTests() {
// Process spawning test // Process spawning test
await this.runTest( await this.runTest("CLI Process Spawning", () => {
"CLI Process Spawning", return new Promise((resolve) => {
() => { const child = spawn("node", [config.CLI_PATH, "--version"], {
return new Promise((resolve) => { stdio: ["pipe", "pipe", "pipe"],
const child = spawn("node", [config.CLI_PATH, "--version"], {
stdio: ["pipe", "pipe", "pipe"],
});
let output = "";
child.stdout.on("data", (data) => {
output += data.toString();
});
child.on("close", (code) => {
resolve(code === 0 && /\d+\.\d+\.\d+/.test(output));
});
setTimeout(() => {
child.kill();
resolve(false);
}, 3000);
}); });
}
); let output = "";
child.stdout.on("data", (data) => {
output += data.toString();
});
child.on("close", (code) => {
resolve(code === 0 && /\d+\.\d+\.\d+/.test(output));
});
setTimeout(() => {
child.kill();
resolve(false);
}, 3000);
});
});
// File system permissions test // File system permissions test
await this.runTest( await this.runTest("File System Permissions", () => {
"File System Permissions", try {
() => { const testFile = "test-write-permission.tmp";
try { fs.writeFileSync(testFile, "test");
const testFile = "test-write-permission.tmp"; this.trackTempFile(testFile);
fs.writeFileSync(testFile, "test");
this.trackTempFile(testFile);
const cliStats = fs.statSync(config.CLI_PATH); const cliStats = fs.statSync(config.CLI_PATH);
return cliStats.isFile(); return cliStats.isFile();
} catch { } catch {
return false; return false;
}
} }
); });
// Dependency resolution test // Dependency resolution test
await this.runTest( await this.runTest("Dependency Resolution", () => {
"Dependency Resolution", try {
() => { const packageJsonPath = path.join(config.PROJECT_ROOT, "package.json");
try { const packageJson = JSON.parse(
const packageJsonPath = path.join(config.PROJECT_ROOT, "package.json"); fs.readFileSync(packageJsonPath, "utf8"),
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); );
const essentialDeps = ["commander", "chalk", "fs-extra", "execa"]; const essentialDeps = ["commander", "chalk", "fs-extra", "execa"];
return essentialDeps.every(dep => packageJson.dependencies && packageJson.dependencies[dep]); return essentialDeps.every(
} catch { (dep) => packageJson.dependencies && packageJson.dependencies[dep],
return false; );
} } catch {
return false;
} }
); });
} }
async runBuilderTests() { async runBuilderTests() {
// Platform detection test // Platform detection test
await this.runTest( await this.runTest("Platform Detection", () => {
"Platform Detection", const platform = process.platform;
() => { const platformConfigs = {
const platform = process.platform; darwin: { ext: ".dmg", multiArch: true },
const platformConfigs = { win32: { ext: ".msi", multiArch: false },
darwin: { ext: '.dmg', multiArch: true }, linux: { ext: ".deb", multiArch: false },
win32: { ext: '.msi', multiArch: false }, };
linux: { ext: '.deb', multiArch: false }
};
const config = platformConfigs[platform]; const config = platformConfigs[platform];
return config && typeof config.ext === 'string'; return config && typeof config.ext === "string";
} });
);
// Architecture detection test // Architecture detection test
await this.runTest( await this.runTest("Architecture Detection", () => {
"Architecture Detection", const currentArch = process.arch;
() => { const macArch = currentArch === "arm64" ? "aarch64" : currentArch;
const currentArch = process.arch; const linuxArch = currentArch === "x64" ? "amd64" : currentArch;
const macArch = currentArch === "arm64" ? "aarch64" : currentArch;
const linuxArch = currentArch === "x64" ? "amd64" : currentArch;
return typeof macArch === "string" && typeof linuxArch === "string"; return typeof macArch === "string" && typeof linuxArch === "string";
} });
);
// File naming pattern test // File naming pattern test
await this.runTest( await this.runTest("File Naming Patterns", () => {
"File Naming Patterns", const testNames = ["Simple App", "App-With_Symbols", "CamelCaseApp"];
() => { return testNames.every((name) => {
const testNames = ["Simple App", "App-With_Symbols", "CamelCaseApp"]; const processed = name.toLowerCase().replace(/\s+/g, "");
return testNames.every(name => { return processed.length > 0;
const processed = name.toLowerCase().replace(/\s+/g, ""); });
return processed.length > 0; });
});
}
);
} }
async runPakeCliTests() { async runPakeCliTests() {
@@ -369,63 +346,59 @@ class PakeTestRunner {
return false; return false;
} }
}, },
TIMEOUTS.LONG TIMEOUTS.LONG,
); );
// Version command test // Version command test
await this.runTest( await this.runTest("pake-cli Version Command", async () => {
"pake-cli Version Command", try {
async () => { const version = execSync("npx pake --version", {
try { encoding: "utf8",
const version = execSync("npx pake --version", { timeout: 10000,
encoding: "utf8", });
timeout: 10000, return /^\d+\.\d+\.\d+/.test(version.trim());
}); } catch {
return /^\d+\.\d+\.\d+/.test(version.trim()); return false;
} catch {
return false;
}
} }
); });
// Configuration validation test // Configuration validation test
await this.runTest( await this.runTest("Configuration Validation", async () => {
"Configuration Validation", try {
async () => { const validateConfig = (config) => {
try { const required = ["url", "name", "width", "height"];
const validateConfig = (config) => { const hasRequired = required.every((field) =>
const required = ['url', 'name', 'width', 'height']; config.hasOwnProperty(field),
const hasRequired = required.every(field => config.hasOwnProperty(field)); );
const validTypes =
typeof config.url === 'string' &&
typeof config.name === 'string' &&
typeof config.width === 'number' &&
typeof config.height === 'number';
let validUrl = false;
try {
new URL(config.url);
validUrl = true;
} catch {}
const validName = config.name.length > 0;
return hasRequired && validTypes && validUrl && validName;
};
const testConfig = { const validTypes =
url: 'https://github.com', typeof config.url === "string" &&
name: 'github', typeof config.name === "string" &&
width: 1200, typeof config.width === "number" &&
height: 780 typeof config.height === "number";
};
return validateConfig(testConfig); let validUrl = false;
} catch { try {
return false; new URL(config.url);
} validUrl = true;
} catch {}
const validName = config.name.length > 0;
return hasRequired && validTypes && validUrl && validName;
};
const testConfig = {
url: "https://github.com",
name: "github",
width: 1200,
height: 780,
};
return validateConfig(testConfig);
} catch {
return false;
} }
); });
} }
async runE2ETests() { async runE2ETests() {
@@ -453,20 +426,32 @@ class PakeTestRunner {
child.stdout.on("data", (data) => { child.stdout.on("data", (data) => {
const output = data.toString(); const output = data.toString();
if (output.includes("Building app") || output.includes("Compiling") || if (
output.includes("Installing package") || output.includes("Bundling")) { output.includes("Building app") ||
output.includes("Compiling") ||
output.includes("Installing package") ||
output.includes("Bundling")
) {
buildStarted = true; buildStarted = true;
} }
if (output.includes("GitHub") && (output.includes("config") || output.includes("name"))) { if (
output.includes("GitHub") &&
(output.includes("config") || output.includes("name"))
) {
configGenerated = true; configGenerated = true;
} }
}); });
child.stderr.on("data", (data) => { child.stderr.on("data", (data) => {
const output = data.toString(); const output = data.toString();
if (output.includes("Building app") || output.includes("Compiling") || if (
output.includes("Installing package") || output.includes("Bundling") || output.includes("Building app") ||
output.includes("Finished") || output.includes("Built application at:")) { output.includes("Compiling") ||
output.includes("Installing package") ||
output.includes("Bundling") ||
output.includes("Finished") ||
output.includes("Built application at:")
) {
buildStarted = true; buildStarted = true;
} }
}); });
@@ -474,17 +459,21 @@ class PakeTestRunner {
// Kill process after 60 seconds if build started // Kill process after 60 seconds if build started
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
child.kill("SIGTERM"); child.kill("SIGTERM");
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`); const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`); const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
this.trackTempFile(appFile); this.trackTempFile(appFile);
this.trackTempFile(dmgFile); this.trackTempFile(dmgFile);
if (buildStarted) { if (buildStarted) {
console.log(`✓ GitHub.com CLI build started successfully (${testName})`); console.log(
`✓ GitHub.com CLI build started successfully (${testName})`,
);
resolve(true); resolve(true);
} else { } else {
reject(new Error("GitHub.com CLI build did not start within timeout")); reject(
new Error("GitHub.com CLI build did not start within timeout"),
);
} }
}, 60000); }, 60000);
@@ -498,18 +487,22 @@ class PakeTestRunner {
if (buildStarted) { if (buildStarted) {
resolve(true); resolve(true);
} else { } else {
reject(new Error("GitHub.com CLI build process ended before starting")); reject(
new Error("GitHub.com CLI build process ended before starting"),
);
} }
}); });
child.on("error", (error) => { child.on("error", (error) => {
reject(new Error(`GitHub.com CLI build process error: ${error.message}`)); reject(
new Error(`GitHub.com CLI build process error: ${error.message}`),
);
}); });
child.stdin.end(); child.stdin.end();
}); });
}, },
70000 // 70 seconds timeout 70000, // 70 seconds timeout
); );
// Configuration verification test // Configuration verification test
@@ -517,7 +510,7 @@ class PakeTestRunner {
"Configuration File Verification", "Configuration File Verification",
async () => { async () => {
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake"); const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const testName = "GitHubConfigTest"; const testName = "GitHubConfigTest";
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --debug --width 1200 --height 780`; const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --debug --width 1200 --height 780`;
@@ -528,7 +521,7 @@ class PakeTestRunner {
stdio: ["pipe", "pipe", "pipe"], stdio: ["pipe", "pipe", "pipe"],
env: { env: {
...process.env, ...process.env,
PAKE_E2E_TEST: "1", PAKE_E2E_TEST: "1",
PAKE_CREATE_APP: "1", PAKE_CREATE_APP: "1",
}, },
}); });
@@ -540,14 +533,22 @@ class PakeTestRunner {
if (fs.existsSync(configFile) && fs.existsSync(pakeConfigFile)) { if (fs.existsSync(configFile) && fs.existsSync(pakeConfigFile)) {
try { try {
const config = JSON.parse(fs.readFileSync(configFile, "utf8")); const config = JSON.parse(
const pakeConfig = JSON.parse(fs.readFileSync(pakeConfigFile, "utf8")); fs.readFileSync(configFile, "utf8"),
);
if (config.productName === testName && const pakeConfig = JSON.parse(
pakeConfig.windows[0].url === "https://github.com/") { fs.readFileSync(pakeConfigFile, "utf8"),
);
if (
config.productName === testName &&
pakeConfig.windows[0].url === "https://github.com/"
) {
child.kill("SIGTERM"); child.kill("SIGTERM");
this.trackTempDir(pakeDir); this.trackTempDir(pakeDir);
console.log("✓ GitHub.com configuration files verified correctly"); console.log(
"✓ GitHub.com configuration files verified correctly",
);
resolve(true); resolve(true);
return true; return true;
} }
@@ -561,15 +562,21 @@ class PakeTestRunner {
child.stdout.on("data", (data) => { child.stdout.on("data", (data) => {
const output = data.toString(); const output = data.toString();
if (output.includes("Installing package") || output.includes("Building app")) { if (
output.includes("Installing package") ||
output.includes("Building app")
) {
setTimeout(checkConfigFiles, 1000); setTimeout(checkConfigFiles, 1000);
} }
}); });
child.stderr.on("data", (data) => { child.stderr.on("data", (data) => {
const output = data.toString(); const output = data.toString();
if (output.includes("Installing package") || output.includes("Building app") || if (
output.includes("Package installed")) { output.includes("Installing package") ||
output.includes("Building app") ||
output.includes("Package installed")
) {
setTimeout(checkConfigFiles, 1000); setTimeout(checkConfigFiles, 1000);
} }
}); });
@@ -582,13 +589,17 @@ class PakeTestRunner {
}, 20000); }, 20000);
child.on("error", (error) => { child.on("error", (error) => {
reject(new Error(`GitHub.com config verification error: ${error.message}`)); reject(
new Error(
`GitHub.com config verification error: ${error.message}`,
),
);
}); });
child.stdin.end(); child.stdin.end();
}); });
}, },
25000 25000,
); );
} }
@@ -601,10 +612,10 @@ class PakeTestRunner {
const testName = "GitHubRealBuild"; const testName = "GitHubRealBuild";
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`); const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`); const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
console.log(`🔧 Starting real build test for GitHub.com...`); console.log(`🔧 Starting real build test for GitHub.com...`);
console.log(`📝 Expected output: ${appFile}`); console.log(`📝 Expected output: ${appFile}`);
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar`; const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar`;
const child = spawn(command, { const child = spawn(command, {
@@ -651,7 +662,8 @@ class PakeTestRunner {
if (output.includes("Building app")) buildStarted = true; if (output.includes("Building app")) buildStarted = true;
if (output.includes("Compiling")) compilationStarted = true; if (output.includes("Compiling")) compilationStarted = true;
if (output.includes("Bundling")) bundlingStarted = true; if (output.includes("Bundling")) bundlingStarted = true;
if (output.includes("Finished")) console.log(" ✅ Compilation finished!"); if (output.includes("Finished"))
console.log(" ✅ Compilation finished!");
if (output.includes("Built application at:")) buildCompleted = true; if (output.includes("Built application at:")) buildCompleted = true;
}); });
@@ -659,9 +671,11 @@ class PakeTestRunner {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
const appExists = fs.existsSync(appFile); const appExists = fs.existsSync(appFile);
const dmgExists = fs.existsSync(dmgFile); const dmgExists = fs.existsSync(dmgFile);
if (appExists) { if (appExists) {
console.log(" 🎉 Build completed successfully (app file exists)!"); console.log(
" 🎉 Build completed successfully (app file exists)!",
);
console.log(` 📱 App location: ${appFile}`); console.log(` 📱 App location: ${appFile}`);
if (dmgExists) { if (dmgExists) {
console.log(` 💿 DMG location: ${dmgFile}`); console.log(` 💿 DMG location: ${dmgFile}`);
@@ -679,10 +693,10 @@ class PakeTestRunner {
child.on("close", (code) => { child.on("close", (code) => {
clearTimeout(timeout); clearTimeout(timeout);
const appExists = fs.existsSync(appFile); const appExists = fs.existsSync(appFile);
const dmgExists = fs.existsSync(dmgFile); const dmgExists = fs.existsSync(dmgFile);
// DON'T track files for cleanup - let user see the results // DON'T track files for cleanup - let user see the results
// this.trackTempFile(appFile); // this.trackTempFile(appFile);
// this.trackTempFile(dmgFile); // this.trackTempFile(dmgFile);
@@ -696,7 +710,9 @@ class PakeTestRunner {
console.log(" ✨ Build artifacts preserved for inspection"); console.log(" ✨ Build artifacts preserved for inspection");
resolve(true); resolve(true);
} else if (code === 0 && buildStarted && compilationStarted) { } else if (code === 0 && buildStarted && compilationStarted) {
console.log(" ⚠️ Build process completed but no app file found"); console.log(
" ⚠️ Build process completed but no app file found",
);
console.log(` 📍 Expected location: ${appFile}`); console.log(` 📍 Expected location: ${appFile}`);
resolve(false); resolve(false);
} else { } else {
@@ -706,13 +722,15 @@ class PakeTestRunner {
child.on("error", (error) => { child.on("error", (error) => {
clearTimeout(timeout); clearTimeout(timeout);
reject(new Error(`Real build test process error: ${error.message}`)); reject(
new Error(`Real build test process error: ${error.message}`),
);
}); });
child.stdin.end(); child.stdin.end();
}); });
}, },
500000 // 8+ minutes timeout 500000, // 8+ minutes timeout
); );
} }
@@ -725,11 +743,11 @@ class PakeTestRunner {
const testName = "GitHubMultiArch"; const testName = "GitHubMultiArch";
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`); const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`); const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
console.log(`🔧 Starting multi-arch build test for GitHub.com...`); console.log(`🔧 Starting multi-arch build test for GitHub.com...`);
console.log(`📝 Expected output: ${appFile}`); console.log(`📝 Expected output: ${appFile}`);
console.log(`🏗️ Building Universal Binary (Intel + Apple Silicon)`); console.log(`🏗️ Building Universal Binary (Intel + Apple Silicon)`);
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar --multi-arch`; const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar --multi-arch`;
const child = spawn(command, { const child = spawn(command, {
@@ -762,7 +780,10 @@ class PakeTestRunner {
compilationStarted = true; compilationStarted = true;
console.log(" ⚙️ Compiling for multiple architectures..."); console.log(" ⚙️ Compiling for multiple architectures...");
} }
if (output.includes("universal-apple-darwin") || output.includes("Universal")) { if (
output.includes("universal-apple-darwin") ||
output.includes("Universal")
) {
multiArchDetected = true; multiArchDetected = true;
console.log(" 🔀 Universal binary target detected"); console.log(" 🔀 Universal binary target detected");
} }
@@ -780,9 +801,11 @@ class PakeTestRunner {
const output = data.toString(); const output = data.toString();
if (output.includes("Building app")) buildStarted = true; if (output.includes("Building app")) buildStarted = true;
if (output.includes("Compiling")) compilationStarted = true; if (output.includes("Compiling")) compilationStarted = true;
if (output.includes("universal-apple-darwin")) multiArchDetected = true; if (output.includes("universal-apple-darwin"))
multiArchDetected = true;
if (output.includes("Bundling")) bundlingStarted = true; if (output.includes("Bundling")) bundlingStarted = true;
if (output.includes("Finished")) console.log(" ✅ Multi-arch compilation finished!"); if (output.includes("Finished"))
console.log(" ✅ Multi-arch compilation finished!");
if (output.includes("Built application at:")) buildCompleted = true; if (output.includes("Built application at:")) buildCompleted = true;
}); });
@@ -790,7 +813,7 @@ class PakeTestRunner {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
const appExists = fs.existsSync(appFile); const appExists = fs.existsSync(appFile);
const dmgExists = fs.existsSync(dmgFile); const dmgExists = fs.existsSync(dmgFile);
if (appExists) { if (appExists) {
console.log(" 🎉 Multi-arch build completed successfully!"); console.log(" 🎉 Multi-arch build completed successfully!");
console.log(` 📱 App location: ${appFile}`); console.log(` 📱 App location: ${appFile}`);
@@ -801,7 +824,9 @@ class PakeTestRunner {
child.kill("SIGTERM"); child.kill("SIGTERM");
resolve(true); resolve(true);
} else { } else {
console.log(" ❌ Multi-arch build timeout - no app file generated"); console.log(
" ❌ Multi-arch build timeout - no app file generated",
);
console.log(` 📍 Expected location: ${appFile}`); console.log(` 📍 Expected location: ${appFile}`);
child.kill("SIGTERM"); child.kill("SIGTERM");
reject(new Error("Multi-arch build test timeout")); reject(new Error("Multi-arch build test timeout"));
@@ -810,49 +835,67 @@ class PakeTestRunner {
child.on("close", (code) => { child.on("close", (code) => {
clearTimeout(timeout); clearTimeout(timeout);
const appExists = fs.existsSync(appFile); const appExists = fs.existsSync(appFile);
const dmgExists = fs.existsSync(dmgFile); const dmgExists = fs.existsSync(dmgFile);
if (appExists) { if (appExists) {
console.log(" 🎉 Multi-arch build test SUCCESS: Universal binary generated!"); console.log(
" 🎉 Multi-arch build test SUCCESS: Universal binary generated!",
);
console.log(` 📱 App location: ${appFile}`); console.log(` 📱 App location: ${appFile}`);
if (dmgExists) { if (dmgExists) {
console.log(` 💿 DMG location: ${dmgFile}`); console.log(` 💿 DMG location: ${dmgFile}`);
} }
console.log(" 🔀 Universal binary preserved for inspection"); console.log(" 🔀 Universal binary preserved for inspection");
// Verify it's actually a universal binary // Verify it's actually a universal binary
try { try {
const fileOutput = execSync(`file "${appFile}/Contents/MacOS/pake"`, { encoding: 'utf8' }); const fileOutput = execSync(
if (fileOutput.includes('universal binary')) { `file "${appFile}/Contents/MacOS/pake"`,
console.log(" ✅ Verified: Universal binary created successfully"); { encoding: "utf8" },
);
if (fileOutput.includes("universal binary")) {
console.log(
" ✅ Verified: Universal binary created successfully",
);
} else { } else {
console.log(" ⚠️ Note: Binary architecture:", fileOutput.trim()); console.log(
" ⚠️ Note: Binary architecture:",
fileOutput.trim(),
);
} }
} catch (error) { } catch (error) {
console.log(" ⚠️ Could not verify binary architecture"); console.log(" ⚠️ Could not verify binary architecture");
} }
resolve(true); resolve(true);
} else if (code === 0 && buildStarted && compilationStarted) { } else if (code === 0 && buildStarted && compilationStarted) {
console.log(" ⚠️ Multi-arch build process completed but no app file found"); console.log(
" ⚠️ Multi-arch build process completed but no app file found",
);
console.log(` 📍 Expected location: ${appFile}`); console.log(` 📍 Expected location: ${appFile}`);
resolve(false); resolve(false);
} else { } else {
reject(new Error(`Multi-arch build test failed with code ${code}`)); reject(
new Error(`Multi-arch build test failed with code ${code}`),
);
} }
}); });
child.on("error", (error) => { child.on("error", (error) => {
clearTimeout(timeout); clearTimeout(timeout);
reject(new Error(`Multi-arch build test process error: ${error.message}`)); reject(
new Error(
`Multi-arch build test process error: ${error.message}`,
),
);
}); });
child.stdin.end(); child.stdin.end();
}); });
}, },
750000 // 12+ minutes timeout 750000, // 12+ minutes timeout
); );
} }
@@ -867,11 +910,11 @@ class PakeTestRunner {
}); });
return /^\d+\.\d+\.\d+/.test(output.trim()); return /^\d+\.\d+\.\d+/.test(output.trim());
}, },
TIMEOUTS.QUICK TIMEOUTS.QUICK,
); );
await this.runTest( await this.runTest(
"Quick Help Check", "Quick Help Check",
() => { () => {
const output = execSync(`node "${config.CLI_PATH}" --help`, { const output = execSync(`node "${config.CLI_PATH}" --help`, {
encoding: "utf8", encoding: "utf8",
@@ -879,7 +922,7 @@ class PakeTestRunner {
}); });
return output.includes("Usage: cli [url] [options]"); return output.includes("Usage: cli [url] [options]");
}, },
TIMEOUTS.QUICK TIMEOUTS.QUICK,
); );
await this.runTest( await this.runTest(
@@ -888,12 +931,14 @@ class PakeTestRunner {
const platform = process.platform; const platform = process.platform;
const arch = process.arch; const arch = process.arch;
const nodeVersion = process.version; const nodeVersion = process.version;
return typeof platform === 'string' && return (
typeof arch === 'string' && typeof platform === "string" &&
nodeVersion.startsWith('v'); typeof arch === "string" &&
nodeVersion.startsWith("v")
);
}, },
TIMEOUTS.QUICK TIMEOUTS.QUICK,
); );
} }
@@ -943,8 +988,10 @@ class PakeTestRunner {
if (passed === total) { if (passed === total) {
console.log("🎉 All tests passed! CLI is ready for use.\n"); console.log("🎉 All tests passed! CLI is ready for use.\n");
} else { } else {
console.log(`${total - passed} test(s) failed. Please check the issues above.\n`); console.log(
`${total - passed} test(s) failed. Please check the issues above.\n`,
);
// Show failed tests // Show failed tests
const failed = this.results.filter((r) => !r.passed); const failed = this.results.filter((r) => !r.passed);
if (failed.length > 0) { if (failed.length > 0) {
@@ -964,17 +1011,17 @@ const args = process.argv.slice(2);
// Parse command line arguments // Parse command line arguments
const options = { const options = {
unit: args.includes('--unit') || args.length === 0, unit: args.includes("--unit") || args.length === 0,
integration: args.includes('--integration') || args.length === 0, integration: args.includes("--integration") || args.length === 0,
builder: args.includes('--builder') || args.length === 0, builder: args.includes("--builder") || args.length === 0,
pakeCliTests: args.includes('--pake-cli'), pakeCliTests: args.includes("--pake-cli"),
e2e: args.includes('--e2e') || args.includes('--full'), e2e: args.includes("--e2e") || args.includes("--full"),
realBuild: args.includes('--real-build') || args.length === 0, // Include real build in default tests realBuild: args.includes("--real-build") || args.length === 0, // Include real build in default tests
quick: args.includes('--quick') quick: args.includes("--quick"),
}; };
// Help message // Help message
if (args.includes('--help') || args.includes('-h')) { if (args.includes("--help") || args.includes("-h")) {
console.log(` console.log(`
🚀 Pake CLI Test Suite 🚀 Pake CLI Test Suite
@@ -1009,7 +1056,8 @@ Environment:
// Run tests // Run tests
const runner = new PakeTestRunner(); const runner = new PakeTestRunner();
runner.runAll(options) runner
.runAll(options)
.then((success) => { .then((success) => {
process.exit(success ? 0 : 1); process.exit(success ? 0 : 1);
}) })
@@ -1018,4 +1066,4 @@ runner.runAll(options)
process.exit(1); process.exit(1);
}); });
export default runner; export default runner;