💄 format
This commit is contained in:
@@ -85,14 +85,14 @@ GitHub.com 专用快速构建验证:
|
||||
|
||||
## 测试命令
|
||||
|
||||
| 命令 | 描述 | 覆盖范围 | 持续时间 |
|
||||
| --------------------------- | -------------------- | ------------------------------- | ----------- |
|
||||
| `npm test` | **真实完整构建测试** | 完整 GitHub.com 应用打包 | **~8 分钟** |
|
||||
| `node tests/index.js` | 基础测试套件 | Unit + Integration + Builder | ~30 秒 |
|
||||
| `node tests/index.js --real-build` | 真实构建测试 | 完整 GitHub.com 应用打包 | ~8 分钟 |
|
||||
| `node tests/github.js` | GitHub Actions 测试 | 12 个 GitHub Actions 专项测试 | ~2 分钟 |
|
||||
| `node tests/build.js` | 快速构建测试 | GitHub.com 构建验证 | ~3 分钟 |
|
||||
| `node tests/complete.js` | 完整构建测试 | 端到端完整构建流程 | ~10 分钟 |
|
||||
| 命令 | 描述 | 覆盖范围 | 持续时间 |
|
||||
| ---------------------------------- | -------------------- | ----------------------------- | ----------- |
|
||||
| `npm test` | **真实完整构建测试** | 完整 GitHub.com 应用打包 | **~8 分钟** |
|
||||
| `node tests/index.js` | 基础测试套件 | Unit + Integration + Builder | ~30 秒 |
|
||||
| `node tests/index.js --real-build` | 真实构建测试 | 完整 GitHub.com 应用打包 | ~8 分钟 |
|
||||
| `node tests/github.js` | GitHub Actions 测试 | 12 个 GitHub Actions 专项测试 | ~2 分钟 |
|
||||
| `node tests/build.js` | 快速构建测试 | GitHub.com 构建验证 | ~3 分钟 |
|
||||
| `node tests/complete.js` | 完整构建测试 | 端到端完整构建流程 | ~10 分钟 |
|
||||
|
||||
## 高级用法
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* GitHub.com Real Build Test
|
||||
*
|
||||
*
|
||||
* This is a standalone test for actual GitHub.com app packaging
|
||||
* to validate that both CLI and GitHub Actions scenarios work correctly.
|
||||
*/
|
||||
@@ -34,7 +34,7 @@ const cleanup = () => {
|
||||
fs.unlinkSync(dmgFile);
|
||||
console.log("✅ Cleaned up .dmg file");
|
||||
}
|
||||
|
||||
|
||||
// Clean .pake directory
|
||||
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
|
||||
if (fs.existsSync(pakeDir)) {
|
||||
@@ -47,16 +47,18 @@ const cleanup = () => {
|
||||
};
|
||||
|
||||
// Handle cleanup on exit
|
||||
process.on('exit', cleanup);
|
||||
process.on('SIGINT', () => {
|
||||
process.on("exit", cleanup);
|
||||
process.on("SIGINT", () => {
|
||||
console.log("\n🛑 Build interrupted by user");
|
||||
cleanup();
|
||||
process.exit(1);
|
||||
});
|
||||
process.on('SIGTERM', cleanup);
|
||||
process.on("SIGTERM", cleanup);
|
||||
|
||||
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`;
|
||||
|
||||
@@ -79,7 +81,7 @@ console.log("------------------");
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
|
||||
// Track build progress
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
@@ -105,7 +107,7 @@ child.stdout.on("data", (data) => {
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
|
||||
// Track stderr progress (Tauri outputs build info to stderr)
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
@@ -127,20 +129,22 @@ child.stderr.on("data", (data) => {
|
||||
if (output.includes("Built application at:")) {
|
||||
console.log("✅ Application built successfully!");
|
||||
}
|
||||
|
||||
|
||||
// Only show actual errors, filter out build progress
|
||||
if (!output.includes("warning:") &&
|
||||
!output.includes("verbose") &&
|
||||
!output.includes("npm info") &&
|
||||
!output.includes("Installing package") &&
|
||||
!output.includes("Package installed") &&
|
||||
!output.includes("Building app") &&
|
||||
!output.includes("Compiling") &&
|
||||
!output.includes("Finished") &&
|
||||
!output.includes("Built application at:") &&
|
||||
!output.includes("Bundling") &&
|
||||
!output.includes("npm http") &&
|
||||
output.trim().length > 0) {
|
||||
if (
|
||||
!output.includes("warning:") &&
|
||||
!output.includes("verbose") &&
|
||||
!output.includes("npm info") &&
|
||||
!output.includes("Installing package") &&
|
||||
!output.includes("Package installed") &&
|
||||
!output.includes("Building app") &&
|
||||
!output.includes("Compiling") &&
|
||||
!output.includes("Finished") &&
|
||||
!output.includes("Built application at:") &&
|
||||
!output.includes("Bundling") &&
|
||||
!output.includes("npm http") &&
|
||||
output.trim().length > 0
|
||||
) {
|
||||
console.log("❌ Build error:", output.trim());
|
||||
}
|
||||
});
|
||||
@@ -149,7 +153,7 @@ child.stderr.on("data", (data) => {
|
||||
const timeout = setTimeout(() => {
|
||||
console.log("\n⏱️ Build timeout reached (3 minutes)");
|
||||
child.kill("SIGTERM");
|
||||
|
||||
|
||||
if (buildStarted && compilationStarted) {
|
||||
console.log("✅ SUCCESS: GitHub.com CLI build started successfully!");
|
||||
console.log(" - Build process initiated ✓");
|
||||
@@ -157,7 +161,9 @@ const timeout = setTimeout(() => {
|
||||
console.log(" - Configuration generated for GitHub.com ✓");
|
||||
console.log("\n🎯 Test Result: PASS");
|
||||
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);
|
||||
} else if (buildStarted) {
|
||||
console.log("⚠️ PARTIAL: Build started but compilation not detected");
|
||||
@@ -172,25 +178,27 @@ const timeout = setTimeout(() => {
|
||||
|
||||
child.on("close", (code) => {
|
||||
clearTimeout(timeout);
|
||||
|
||||
|
||||
console.log(`\n📊 Build Process Summary:`);
|
||||
console.log("========================");
|
||||
console.log(`Exit Code: ${code}`);
|
||||
console.log(`Build Started: ${buildStarted ? "✅" : "❌"}`);
|
||||
console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`);
|
||||
|
||||
|
||||
// Check for output files
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
console.log(`App File (.app): ${appExists ? "✅" : "❌"}`);
|
||||
console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`);
|
||||
|
||||
|
||||
if (buildStarted && compilationStarted) {
|
||||
console.log("\n🎉 SUCCESS: GitHub.com CLI build verification completed!");
|
||||
console.log(" All critical build stages detected.");
|
||||
process.exit(0);
|
||||
} 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);
|
||||
} else {
|
||||
console.log("\n❌ FAILED: Build did not start properly");
|
||||
@@ -206,4 +214,4 @@ child.on("error", (error) => {
|
||||
});
|
||||
|
||||
// Send empty input to handle any prompts
|
||||
child.stdin.end();
|
||||
child.stdin.end();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* GitHub.com Complete Build Test
|
||||
*
|
||||
*
|
||||
* This test performs a complete build of github.com to verify
|
||||
* that the entire packaging pipeline works correctly end-to-end.
|
||||
*/
|
||||
@@ -34,7 +34,7 @@ const cleanup = () => {
|
||||
fs.unlinkSync(dmgFile);
|
||||
console.log("✅ Cleaned up .dmg file");
|
||||
}
|
||||
|
||||
|
||||
// Clean .pake directory
|
||||
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
|
||||
if (fs.existsSync(pakeDir)) {
|
||||
@@ -47,16 +47,18 @@ const cleanup = () => {
|
||||
};
|
||||
|
||||
// Handle cleanup on exit
|
||||
process.on('exit', cleanup);
|
||||
process.on('SIGINT', () => {
|
||||
process.on("exit", cleanup);
|
||||
process.on("SIGINT", () => {
|
||||
console.log("\n🛑 Build interrupted by user");
|
||||
cleanup();
|
||||
process.exit(1);
|
||||
});
|
||||
process.on('SIGTERM', cleanup);
|
||||
process.on("SIGTERM", cleanup);
|
||||
|
||||
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`;
|
||||
|
||||
@@ -80,7 +82,7 @@ console.log("------------------");
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
|
||||
// Track build progress
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
@@ -111,7 +113,7 @@ child.stdout.on("data", (data) => {
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
|
||||
// Track stderr progress (Tauri outputs build info to stderr)
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
@@ -135,34 +137,36 @@ child.stderr.on("data", (data) => {
|
||||
buildCompleted = true;
|
||||
console.log("✅ Application built successfully!");
|
||||
}
|
||||
|
||||
|
||||
// Only show actual errors, filter out build progress
|
||||
if (!output.includes("warning:") &&
|
||||
!output.includes("verbose") &&
|
||||
!output.includes("npm info") &&
|
||||
!output.includes("Installing package") &&
|
||||
!output.includes("Package installed") &&
|
||||
!output.includes("Building app") &&
|
||||
!output.includes("Compiling") &&
|
||||
!output.includes("Finished") &&
|
||||
!output.includes("Built application at:") &&
|
||||
!output.includes("Bundling") &&
|
||||
!output.includes("npm http") &&
|
||||
!output.includes("Info Looking up installed") &&
|
||||
output.trim().length > 0) {
|
||||
if (
|
||||
!output.includes("warning:") &&
|
||||
!output.includes("verbose") &&
|
||||
!output.includes("npm info") &&
|
||||
!output.includes("Installing package") &&
|
||||
!output.includes("Package installed") &&
|
||||
!output.includes("Building app") &&
|
||||
!output.includes("Compiling") &&
|
||||
!output.includes("Finished") &&
|
||||
!output.includes("Built application at:") &&
|
||||
!output.includes("Bundling") &&
|
||||
!output.includes("npm http") &&
|
||||
!output.includes("Info Looking up installed") &&
|
||||
output.trim().length > 0
|
||||
) {
|
||||
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
|
||||
const timeout = setTimeout(() => {
|
||||
console.log("\n⏱️ Build timeout reached (10 minutes)");
|
||||
|
||||
|
||||
// Check if we actually have output files even if process is still running
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
|
||||
|
||||
if (appExists || buildCompleted) {
|
||||
console.log("🎉 SUCCESS: GitHub app was built successfully!");
|
||||
console.log(" App file exists, build completed despite long duration");
|
||||
@@ -177,7 +181,7 @@ const timeout = setTimeout(() => {
|
||||
|
||||
child.on("close", (code) => {
|
||||
clearTimeout(timeout);
|
||||
|
||||
|
||||
console.log(`\n📊 GitHub App Build Summary:`);
|
||||
console.log("=============================");
|
||||
console.log(`Exit Code: ${code}`);
|
||||
@@ -185,29 +189,33 @@ child.on("close", (code) => {
|
||||
console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`);
|
||||
console.log(`Bundling Started: ${bundlingStarted ? "✅" : "❌"}`);
|
||||
console.log(`Build Completed: ${buildCompleted ? "✅" : "❌"}`);
|
||||
|
||||
|
||||
// Check for output files
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
console.log(`App File (.app): ${appExists ? "✅" : "❌"}`);
|
||||
console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`);
|
||||
|
||||
|
||||
// Check .app bundle structure if it exists
|
||||
if (appExists) {
|
||||
try {
|
||||
const contentsPath = path.join(appFile, "Contents");
|
||||
const macOSPath = path.join(contentsPath, "MacOS");
|
||||
const resourcesPath = path.join(contentsPath, "Resources");
|
||||
|
||||
|
||||
console.log(`App Bundle Structure:`);
|
||||
console.log(` Contents/: ${fs.existsSync(contentsPath) ? "✅" : "❌"}`);
|
||||
console.log(` Contents/MacOS/: ${fs.existsSync(macOSPath) ? "✅" : "❌"}`);
|
||||
console.log(` Contents/Resources/: ${fs.existsSync(resourcesPath) ? "✅" : "❌"}`);
|
||||
console.log(
|
||||
` Contents/MacOS/: ${fs.existsSync(macOSPath) ? "✅" : "❌"}`,
|
||||
);
|
||||
console.log(
|
||||
` Contents/Resources/: ${fs.existsSync(resourcesPath) ? "✅" : "❌"}`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(`App Bundle Check: ❌ (${error.message})`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Real success check: app file must exist and build must have completed
|
||||
if (appExists && (buildCompleted || code === 0)) {
|
||||
console.log("\n🎉 COMPLETE SUCCESS: GitHub app build fully completed!");
|
||||
@@ -221,7 +229,9 @@ child.on("close", (code) => {
|
||||
console.log(" 🎯 Build process successful");
|
||||
process.exit(0);
|
||||
} 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(" ⚠️ App file may be in a different location");
|
||||
process.exit(0);
|
||||
@@ -240,4 +250,4 @@ child.on("error", (error) => {
|
||||
});
|
||||
|
||||
// Send empty input to handle any prompts
|
||||
child.stdin.end();
|
||||
child.stdin.end();
|
||||
|
||||
@@ -161,8 +161,12 @@ class PakeCliTestRunner {
|
||||
console.log("🚀 GitHub Actions Usage Guide:");
|
||||
console.log("==============================\n");
|
||||
|
||||
console.log("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(
|
||||
"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(" ✅ npm package installation and caching");
|
||||
@@ -284,14 +288,14 @@ runner.addTest(
|
||||
// Create a temporary .pake directory to test cleanup
|
||||
const tempDir = "/tmp/test_pake_cleanup";
|
||||
const pakeDir = path.join(tempDir, ".pake");
|
||||
|
||||
|
||||
fs.mkdirSync(tempDir, { recursive: true });
|
||||
fs.mkdirSync(pakeDir, { recursive: true });
|
||||
|
||||
|
||||
// Create some test config files
|
||||
fs.writeFileSync(path.join(pakeDir, "pake.json"), '{"test": true}');
|
||||
fs.writeFileSync(path.join(pakeDir, "tauri.conf.json"), '{"test": true}');
|
||||
|
||||
|
||||
runner.trackTempDir(tempDir);
|
||||
|
||||
// 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
|
||||
return !fs.existsSync(pakeDir) && result.includes("Cleaned directories: 1");
|
||||
return (
|
||||
!fs.existsSync(pakeDir) && result.includes("Cleaned directories: 1")
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Cleanup test failed:", error.message);
|
||||
return false;
|
||||
@@ -384,8 +390,10 @@ process.exit(validResults && invalidResults ? 0 : 1);
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
return result.includes("Valid URLs passed: true") &&
|
||||
result.includes("Invalid URLs rejected: true");
|
||||
return (
|
||||
result.includes("Valid URLs passed: true") &&
|
||||
result.includes("Invalid URLs rejected: true")
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
@@ -432,7 +440,9 @@ process.exit(isSupported ? 0 : 1);
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
return result.includes("Platform:") && result.includes("Expected extension:");
|
||||
return (
|
||||
result.includes("Platform:") && result.includes("Expected extension:")
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
@@ -513,33 +523,36 @@ runner.addTest(
|
||||
async () => {
|
||||
try {
|
||||
// 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)) {
|
||||
console.error("Workflow file not found:", workflowPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
const workflowContent = fs.readFileSync(workflowPath, "utf8");
|
||||
|
||||
|
||||
// Check for essential workflow components
|
||||
const requiredElements = [
|
||||
"npm install pake-cli@latest --no-package-lock", // Latest version installation
|
||||
"timeout-minutes: 15", // Sufficient timeout
|
||||
"node ./script/build_with_pake_cli.js", // Build script execution
|
||||
"ubuntu-24.04", // Linux support
|
||||
"macos-latest", // macOS support
|
||||
"windows-latest" // Windows support
|
||||
"macos-latest", // macOS support
|
||||
"windows-latest", // Windows support
|
||||
];
|
||||
|
||||
const hasAllElements = requiredElements.every(element =>
|
||||
workflowContent.includes(element)
|
||||
const hasAllElements = requiredElements.every((element) =>
|
||||
workflowContent.includes(element),
|
||||
);
|
||||
|
||||
if (!hasAllElements) {
|
||||
console.error("Workflow missing required elements");
|
||||
const missing = requiredElements.filter(element =>
|
||||
!workflowContent.includes(element)
|
||||
const missing = requiredElements.filter(
|
||||
(element) => !workflowContent.includes(element),
|
||||
);
|
||||
console.error("Missing elements:", missing);
|
||||
}
|
||||
@@ -556,7 +569,7 @@ runner.addTest(
|
||||
|
||||
// Test 9: Rust feature flags validation
|
||||
runner.addTest(
|
||||
"Rust Feature Flags Validation",
|
||||
"Rust Feature Flags Validation",
|
||||
async () => {
|
||||
try {
|
||||
const testScript = `
|
||||
@@ -761,10 +774,12 @@ process.exit(validBuild ? 0 : 1);
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
return result.includes("GitHub Actions GitHub.com build simulation started") &&
|
||||
result.includes("URL: https://github.com") &&
|
||||
result.includes("NAME: github") &&
|
||||
result.includes("Build configuration valid: true");
|
||||
return (
|
||||
result.includes("GitHub Actions GitHub.com build simulation started") &&
|
||||
result.includes("URL: https://github.com") &&
|
||||
result.includes("NAME: github") &&
|
||||
result.includes("Build configuration valid: true")
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("GitHub Actions simulation failed:", error.message);
|
||||
return false;
|
||||
@@ -833,9 +848,11 @@ process.exit(validParams ? 0 : 1);
|
||||
timeout: 8000,
|
||||
});
|
||||
|
||||
return result.includes("GitHub.com build parameters validated: true") &&
|
||||
result.includes("URL: https://github.com") &&
|
||||
result.includes("App name: github");
|
||||
return (
|
||||
result.includes("GitHub.com build parameters validated: true") &&
|
||||
result.includes("URL: https://github.com") &&
|
||||
result.includes("App name: github")
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Build script test failed:", error.message);
|
||||
return false;
|
||||
@@ -847,7 +864,8 @@ process.exit(validParams ? 0 : 1);
|
||||
|
||||
// Run the test suite
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
runner.runAll()
|
||||
runner
|
||||
.runAll()
|
||||
.then((success) => {
|
||||
process.exit(success ? 0 : 1);
|
||||
})
|
||||
@@ -857,4 +875,4 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
});
|
||||
}
|
||||
|
||||
export default runner;
|
||||
export default runner;
|
||||
|
||||
592
tests/index.js
592
tests/index.js
@@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* Unified Test Runner for Pake CLI
|
||||
*
|
||||
*
|
||||
* This is a simplified, unified test runner that replaces the scattered
|
||||
* test files with a single, easy-to-use interface.
|
||||
*/
|
||||
@@ -23,12 +23,12 @@ class PakeTestRunner {
|
||||
async runAll(options = {}) {
|
||||
const {
|
||||
unit = true,
|
||||
integration = true,
|
||||
integration = true,
|
||||
builder = true,
|
||||
pakeCliTests = false,
|
||||
e2e = false,
|
||||
quick = false,
|
||||
realBuild = false // Add option for real build test
|
||||
realBuild = false, // Add option for real build test
|
||||
} = options;
|
||||
|
||||
console.log("🚀 Pake CLI Test Suite");
|
||||
@@ -72,9 +72,9 @@ class PakeTestRunner {
|
||||
console.log("\n🏗️ Running Real Build Test...");
|
||||
await this.runRealBuildTest();
|
||||
testCount++;
|
||||
|
||||
|
||||
// Add multi-arch test on macOS
|
||||
if (process.platform === 'darwin') {
|
||||
if (process.platform === "darwin") {
|
||||
console.log("\n🔧 Running Multi-Arch Build Test...");
|
||||
await this.runMultiArchBuildTest();
|
||||
testCount++;
|
||||
@@ -89,9 +89,9 @@ class PakeTestRunner {
|
||||
this.cleanup();
|
||||
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;
|
||||
|
||||
|
||||
return passed === total;
|
||||
}
|
||||
|
||||
@@ -121,10 +121,10 @@ class PakeTestRunner {
|
||||
// Platform info
|
||||
console.log(`✅ Platform: ${process.platform} (${process.arch})`);
|
||||
console.log(`✅ Node.js: ${process.version}`);
|
||||
|
||||
|
||||
const isCI = process.env.CI || process.env.GITHUB_ACTIONS;
|
||||
console.log(`${isCI ? "✅" : "ℹ️"} CI Environment: ${isCI ? "Yes" : "No"}`);
|
||||
|
||||
|
||||
console.log();
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ class PakeTestRunner {
|
||||
const result = await Promise.race([
|
||||
testFn(),
|
||||
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) {
|
||||
spinner.fail(`${name}: ERROR - ${error.message.slice(0, 100)}...`);
|
||||
this.results.push({
|
||||
name,
|
||||
passed: false,
|
||||
error: error.message
|
||||
this.results.push({
|
||||
name,
|
||||
passed: false,
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ class PakeTestRunner {
|
||||
});
|
||||
return /^\d+\.\d+\.\d+/.test(output.trim());
|
||||
},
|
||||
TIMEOUTS.QUICK
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
|
||||
// Help command test
|
||||
@@ -180,174 +180,151 @@ class PakeTestRunner {
|
||||
});
|
||||
return output.includes("Usage: cli [url] [options]");
|
||||
},
|
||||
TIMEOUTS.QUICK
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
|
||||
// URL validation test
|
||||
await this.runTest(
|
||||
"URL Validation",
|
||||
() => {
|
||||
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`, {
|
||||
await this.runTest("URL Validation", () => {
|
||||
try {
|
||||
execSync(`node "${config.CLI_PATH}" "invalid-url" --name TestApp`, {
|
||||
encoding: "utf8",
|
||||
timeout: 3000,
|
||||
});
|
||||
const elapsed = Date.now() - start;
|
||||
return elapsed < 2000;
|
||||
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",
|
||||
timeout: 3000,
|
||||
});
|
||||
const elapsed = Date.now() - start;
|
||||
return elapsed < 2000;
|
||||
});
|
||||
|
||||
// Weekly URL accessibility test
|
||||
await this.runTest(
|
||||
"Weekly URL Accessibility",
|
||||
() => {
|
||||
try {
|
||||
const testCommand = `node "${config.CLI_PATH}" ${TEST_URLS.WEEKLY} --name "URLTest" --debug`;
|
||||
execSync(`echo "n" | timeout 5s ${testCommand} || true`, {
|
||||
encoding: "utf8",
|
||||
timeout: 8000,
|
||||
});
|
||||
return true; // If we get here, URL was parsed successfully
|
||||
} catch (error) {
|
||||
return !error.message.includes("Invalid URL") && !error.message.includes("invalid");
|
||||
}
|
||||
await this.runTest("Weekly URL Accessibility", () => {
|
||||
try {
|
||||
const testCommand = `node "${config.CLI_PATH}" ${TEST_URLS.WEEKLY} --name "URLTest" --debug`;
|
||||
execSync(`echo "n" | timeout 5s ${testCommand} || true`, {
|
||||
encoding: "utf8",
|
||||
timeout: 8000,
|
||||
});
|
||||
return true; // If we get here, URL was parsed successfully
|
||||
} catch (error) {
|
||||
return (
|
||||
!error.message.includes("Invalid URL") &&
|
||||
!error.message.includes("invalid")
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async runIntegrationTests() {
|
||||
// Process spawning test
|
||||
await this.runTest(
|
||||
"CLI Process Spawning",
|
||||
() => {
|
||||
return new Promise((resolve) => {
|
||||
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);
|
||||
await this.runTest("CLI Process Spawning", () => {
|
||||
return new Promise((resolve) => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
// File system permissions test
|
||||
await this.runTest(
|
||||
"File System Permissions",
|
||||
() => {
|
||||
try {
|
||||
const testFile = "test-write-permission.tmp";
|
||||
fs.writeFileSync(testFile, "test");
|
||||
this.trackTempFile(testFile);
|
||||
await this.runTest("File System Permissions", () => {
|
||||
try {
|
||||
const testFile = "test-write-permission.tmp";
|
||||
fs.writeFileSync(testFile, "test");
|
||||
this.trackTempFile(testFile);
|
||||
|
||||
const cliStats = fs.statSync(config.CLI_PATH);
|
||||
return cliStats.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
const cliStats = fs.statSync(config.CLI_PATH);
|
||||
return cliStats.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Dependency resolution test
|
||||
await this.runTest(
|
||||
"Dependency Resolution",
|
||||
() => {
|
||||
try {
|
||||
const packageJsonPath = path.join(config.PROJECT_ROOT, "package.json");
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
||||
await this.runTest("Dependency Resolution", () => {
|
||||
try {
|
||||
const packageJsonPath = path.join(config.PROJECT_ROOT, "package.json");
|
||||
const packageJson = JSON.parse(
|
||||
fs.readFileSync(packageJsonPath, "utf8"),
|
||||
);
|
||||
|
||||
const essentialDeps = ["commander", "chalk", "fs-extra", "execa"];
|
||||
return essentialDeps.every(dep => packageJson.dependencies && packageJson.dependencies[dep]);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
const essentialDeps = ["commander", "chalk", "fs-extra", "execa"];
|
||||
return essentialDeps.every(
|
||||
(dep) => packageJson.dependencies && packageJson.dependencies[dep],
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async runBuilderTests() {
|
||||
// Platform detection test
|
||||
await this.runTest(
|
||||
"Platform Detection",
|
||||
() => {
|
||||
const platform = process.platform;
|
||||
const platformConfigs = {
|
||||
darwin: { ext: '.dmg', multiArch: true },
|
||||
win32: { ext: '.msi', multiArch: false },
|
||||
linux: { ext: '.deb', multiArch: false }
|
||||
};
|
||||
await this.runTest("Platform Detection", () => {
|
||||
const platform = process.platform;
|
||||
const platformConfigs = {
|
||||
darwin: { ext: ".dmg", multiArch: true },
|
||||
win32: { ext: ".msi", multiArch: false },
|
||||
linux: { ext: ".deb", multiArch: false },
|
||||
};
|
||||
|
||||
const config = platformConfigs[platform];
|
||||
return config && typeof config.ext === 'string';
|
||||
}
|
||||
);
|
||||
const config = platformConfigs[platform];
|
||||
return config && typeof config.ext === "string";
|
||||
});
|
||||
|
||||
// Architecture detection test
|
||||
await this.runTest(
|
||||
"Architecture Detection",
|
||||
() => {
|
||||
const currentArch = process.arch;
|
||||
const macArch = currentArch === "arm64" ? "aarch64" : currentArch;
|
||||
const linuxArch = currentArch === "x64" ? "amd64" : currentArch;
|
||||
await this.runTest("Architecture Detection", () => {
|
||||
const currentArch = process.arch;
|
||||
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
|
||||
await this.runTest(
|
||||
"File Naming Patterns",
|
||||
() => {
|
||||
const testNames = ["Simple App", "App-With_Symbols", "CamelCaseApp"];
|
||||
return testNames.every(name => {
|
||||
const processed = name.toLowerCase().replace(/\s+/g, "");
|
||||
return processed.length > 0;
|
||||
});
|
||||
}
|
||||
);
|
||||
await this.runTest("File Naming Patterns", () => {
|
||||
const testNames = ["Simple App", "App-With_Symbols", "CamelCaseApp"];
|
||||
return testNames.every((name) => {
|
||||
const processed = name.toLowerCase().replace(/\s+/g, "");
|
||||
return processed.length > 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async runPakeCliTests() {
|
||||
@@ -369,63 +346,59 @@ class PakeTestRunner {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
TIMEOUTS.LONG
|
||||
TIMEOUTS.LONG,
|
||||
);
|
||||
|
||||
// Version command test
|
||||
await this.runTest(
|
||||
"pake-cli Version Command",
|
||||
async () => {
|
||||
try {
|
||||
const version = execSync("npx pake --version", {
|
||||
encoding: "utf8",
|
||||
timeout: 10000,
|
||||
});
|
||||
return /^\d+\.\d+\.\d+/.test(version.trim());
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
await this.runTest("pake-cli Version Command", async () => {
|
||||
try {
|
||||
const version = execSync("npx pake --version", {
|
||||
encoding: "utf8",
|
||||
timeout: 10000,
|
||||
});
|
||||
return /^\d+\.\d+\.\d+/.test(version.trim());
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Configuration validation test
|
||||
await this.runTest(
|
||||
"Configuration Validation",
|
||||
async () => {
|
||||
try {
|
||||
const validateConfig = (config) => {
|
||||
const required = ['url', 'name', 'width', 'height'];
|
||||
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;
|
||||
};
|
||||
await this.runTest("Configuration Validation", async () => {
|
||||
try {
|
||||
const validateConfig = (config) => {
|
||||
const required = ["url", "name", "width", "height"];
|
||||
const hasRequired = required.every((field) =>
|
||||
config.hasOwnProperty(field),
|
||||
);
|
||||
|
||||
const testConfig = {
|
||||
url: 'https://github.com',
|
||||
name: 'github',
|
||||
width: 1200,
|
||||
height: 780
|
||||
};
|
||||
const validTypes =
|
||||
typeof config.url === "string" &&
|
||||
typeof config.name === "string" &&
|
||||
typeof config.width === "number" &&
|
||||
typeof config.height === "number";
|
||||
|
||||
return validateConfig(testConfig);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
let validUrl = false;
|
||||
try {
|
||||
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() {
|
||||
@@ -453,20 +426,32 @@ class PakeTestRunner {
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
if (output.includes("Building app") || output.includes("Compiling") ||
|
||||
output.includes("Installing package") || output.includes("Bundling")) {
|
||||
if (
|
||||
output.includes("Building app") ||
|
||||
output.includes("Compiling") ||
|
||||
output.includes("Installing package") ||
|
||||
output.includes("Bundling")
|
||||
) {
|
||||
buildStarted = true;
|
||||
}
|
||||
if (output.includes("GitHub") && (output.includes("config") || output.includes("name"))) {
|
||||
if (
|
||||
output.includes("GitHub") &&
|
||||
(output.includes("config") || output.includes("name"))
|
||||
) {
|
||||
configGenerated = true;
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
if (output.includes("Building app") || output.includes("Compiling") ||
|
||||
output.includes("Installing package") || output.includes("Bundling") ||
|
||||
output.includes("Finished") || output.includes("Built application at:")) {
|
||||
if (
|
||||
output.includes("Building app") ||
|
||||
output.includes("Compiling") ||
|
||||
output.includes("Installing package") ||
|
||||
output.includes("Bundling") ||
|
||||
output.includes("Finished") ||
|
||||
output.includes("Built application at:")
|
||||
) {
|
||||
buildStarted = true;
|
||||
}
|
||||
});
|
||||
@@ -474,17 +459,21 @@ class PakeTestRunner {
|
||||
// Kill process after 60 seconds if build started
|
||||
const timeout = setTimeout(() => {
|
||||
child.kill("SIGTERM");
|
||||
|
||||
|
||||
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
|
||||
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
|
||||
this.trackTempFile(appFile);
|
||||
this.trackTempFile(dmgFile);
|
||||
|
||||
if (buildStarted) {
|
||||
console.log(`✓ GitHub.com CLI build started successfully (${testName})`);
|
||||
console.log(
|
||||
`✓ GitHub.com CLI build started successfully (${testName})`,
|
||||
);
|
||||
resolve(true);
|
||||
} 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);
|
||||
|
||||
@@ -498,18 +487,22 @@ class PakeTestRunner {
|
||||
if (buildStarted) {
|
||||
resolve(true);
|
||||
} 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) => {
|
||||
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();
|
||||
});
|
||||
},
|
||||
70000 // 70 seconds timeout
|
||||
70000, // 70 seconds timeout
|
||||
);
|
||||
|
||||
// Configuration verification test
|
||||
@@ -517,7 +510,7 @@ class PakeTestRunner {
|
||||
"Configuration File Verification",
|
||||
async () => {
|
||||
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const testName = "GitHubConfigTest";
|
||||
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"],
|
||||
env: {
|
||||
...process.env,
|
||||
PAKE_E2E_TEST: "1",
|
||||
PAKE_E2E_TEST: "1",
|
||||
PAKE_CREATE_APP: "1",
|
||||
},
|
||||
});
|
||||
@@ -540,14 +533,22 @@ class PakeTestRunner {
|
||||
|
||||
if (fs.existsSync(configFile) && fs.existsSync(pakeConfigFile)) {
|
||||
try {
|
||||
const config = JSON.parse(fs.readFileSync(configFile, "utf8"));
|
||||
const pakeConfig = JSON.parse(fs.readFileSync(pakeConfigFile, "utf8"));
|
||||
|
||||
if (config.productName === testName &&
|
||||
pakeConfig.windows[0].url === "https://github.com/") {
|
||||
const config = JSON.parse(
|
||||
fs.readFileSync(configFile, "utf8"),
|
||||
);
|
||||
const pakeConfig = JSON.parse(
|
||||
fs.readFileSync(pakeConfigFile, "utf8"),
|
||||
);
|
||||
|
||||
if (
|
||||
config.productName === testName &&
|
||||
pakeConfig.windows[0].url === "https://github.com/"
|
||||
) {
|
||||
child.kill("SIGTERM");
|
||||
this.trackTempDir(pakeDir);
|
||||
console.log("✓ GitHub.com configuration files verified correctly");
|
||||
console.log(
|
||||
"✓ GitHub.com configuration files verified correctly",
|
||||
);
|
||||
resolve(true);
|
||||
return true;
|
||||
}
|
||||
@@ -561,15 +562,21 @@ class PakeTestRunner {
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
if (output.includes("Installing package") || output.includes("Building app") ||
|
||||
output.includes("Package installed")) {
|
||||
if (
|
||||
output.includes("Installing package") ||
|
||||
output.includes("Building app") ||
|
||||
output.includes("Package installed")
|
||||
) {
|
||||
setTimeout(checkConfigFiles, 1000);
|
||||
}
|
||||
});
|
||||
@@ -582,13 +589,17 @@ class PakeTestRunner {
|
||||
}, 20000);
|
||||
|
||||
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();
|
||||
});
|
||||
},
|
||||
25000
|
||||
25000,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -601,10 +612,10 @@ class PakeTestRunner {
|
||||
const testName = "GitHubRealBuild";
|
||||
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
|
||||
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
|
||||
|
||||
|
||||
console.log(`🔧 Starting real build test for GitHub.com...`);
|
||||
console.log(`📝 Expected output: ${appFile}`);
|
||||
|
||||
|
||||
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar`;
|
||||
|
||||
const child = spawn(command, {
|
||||
@@ -651,7 +662,8 @@ class PakeTestRunner {
|
||||
if (output.includes("Building app")) buildStarted = true;
|
||||
if (output.includes("Compiling")) compilationStarted = 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;
|
||||
});
|
||||
|
||||
@@ -659,9 +671,11 @@ class PakeTestRunner {
|
||||
const timeout = setTimeout(() => {
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
|
||||
|
||||
if (appExists) {
|
||||
console.log(" 🎉 Build completed successfully (app file exists)!");
|
||||
console.log(
|
||||
" 🎉 Build completed successfully (app file exists)!",
|
||||
);
|
||||
console.log(` 📱 App location: ${appFile}`);
|
||||
if (dmgExists) {
|
||||
console.log(` 💿 DMG location: ${dmgFile}`);
|
||||
@@ -679,10 +693,10 @@ class PakeTestRunner {
|
||||
|
||||
child.on("close", (code) => {
|
||||
clearTimeout(timeout);
|
||||
|
||||
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
|
||||
|
||||
// DON'T track files for cleanup - let user see the results
|
||||
// this.trackTempFile(appFile);
|
||||
// this.trackTempFile(dmgFile);
|
||||
@@ -696,7 +710,9 @@ class PakeTestRunner {
|
||||
console.log(" ✨ Build artifacts preserved for inspection");
|
||||
resolve(true);
|
||||
} 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}`);
|
||||
resolve(false);
|
||||
} else {
|
||||
@@ -706,13 +722,15 @@ class PakeTestRunner {
|
||||
|
||||
child.on("error", (error) => {
|
||||
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();
|
||||
});
|
||||
},
|
||||
500000 // 8+ minutes timeout
|
||||
500000, // 8+ minutes timeout
|
||||
);
|
||||
}
|
||||
|
||||
@@ -725,11 +743,11 @@ class PakeTestRunner {
|
||||
const testName = "GitHubMultiArch";
|
||||
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
|
||||
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
|
||||
|
||||
|
||||
console.log(`🔧 Starting multi-arch build test for GitHub.com...`);
|
||||
console.log(`📝 Expected output: ${appFile}`);
|
||||
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 child = spawn(command, {
|
||||
@@ -762,7 +780,10 @@ class PakeTestRunner {
|
||||
compilationStarted = true;
|
||||
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;
|
||||
console.log(" 🔀 Universal binary target detected");
|
||||
}
|
||||
@@ -780,9 +801,11 @@ class PakeTestRunner {
|
||||
const output = data.toString();
|
||||
if (output.includes("Building app")) buildStarted = 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("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;
|
||||
});
|
||||
|
||||
@@ -790,7 +813,7 @@ class PakeTestRunner {
|
||||
const timeout = setTimeout(() => {
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
|
||||
|
||||
if (appExists) {
|
||||
console.log(" 🎉 Multi-arch build completed successfully!");
|
||||
console.log(` 📱 App location: ${appFile}`);
|
||||
@@ -801,7 +824,9 @@ class PakeTestRunner {
|
||||
child.kill("SIGTERM");
|
||||
resolve(true);
|
||||
} 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}`);
|
||||
child.kill("SIGTERM");
|
||||
reject(new Error("Multi-arch build test timeout"));
|
||||
@@ -810,49 +835,67 @@ class PakeTestRunner {
|
||||
|
||||
child.on("close", (code) => {
|
||||
clearTimeout(timeout);
|
||||
|
||||
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
|
||||
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}`);
|
||||
if (dmgExists) {
|
||||
console.log(` 💿 DMG location: ${dmgFile}`);
|
||||
}
|
||||
console.log(" 🔀 Universal binary preserved for inspection");
|
||||
|
||||
|
||||
// Verify it's actually a universal binary
|
||||
try {
|
||||
const fileOutput = execSync(`file "${appFile}/Contents/MacOS/pake"`, { encoding: 'utf8' });
|
||||
if (fileOutput.includes('universal binary')) {
|
||||
console.log(" ✅ Verified: Universal binary created successfully");
|
||||
const fileOutput = execSync(
|
||||
`file "${appFile}/Contents/MacOS/pake"`,
|
||||
{ encoding: "utf8" },
|
||||
);
|
||||
if (fileOutput.includes("universal binary")) {
|
||||
console.log(
|
||||
" ✅ Verified: Universal binary created successfully",
|
||||
);
|
||||
} else {
|
||||
console.log(" ⚠️ Note: Binary architecture:", fileOutput.trim());
|
||||
console.log(
|
||||
" ⚠️ Note: Binary architecture:",
|
||||
fileOutput.trim(),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(" ⚠️ Could not verify binary architecture");
|
||||
}
|
||||
|
||||
|
||||
resolve(true);
|
||||
} 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}`);
|
||||
resolve(false);
|
||||
} 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) => {
|
||||
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();
|
||||
});
|
||||
},
|
||||
750000 // 12+ minutes timeout
|
||||
750000, // 12+ minutes timeout
|
||||
);
|
||||
}
|
||||
|
||||
@@ -867,11 +910,11 @@ class PakeTestRunner {
|
||||
});
|
||||
return /^\d+\.\d+\.\d+/.test(output.trim());
|
||||
},
|
||||
TIMEOUTS.QUICK
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
|
||||
await this.runTest(
|
||||
"Quick Help Check",
|
||||
"Quick Help Check",
|
||||
() => {
|
||||
const output = execSync(`node "${config.CLI_PATH}" --help`, {
|
||||
encoding: "utf8",
|
||||
@@ -879,7 +922,7 @@ class PakeTestRunner {
|
||||
});
|
||||
return output.includes("Usage: cli [url] [options]");
|
||||
},
|
||||
TIMEOUTS.QUICK
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
|
||||
await this.runTest(
|
||||
@@ -888,12 +931,14 @@ class PakeTestRunner {
|
||||
const platform = process.platform;
|
||||
const arch = process.arch;
|
||||
const nodeVersion = process.version;
|
||||
|
||||
return typeof platform === 'string' &&
|
||||
typeof arch === 'string' &&
|
||||
nodeVersion.startsWith('v');
|
||||
|
||||
return (
|
||||
typeof platform === "string" &&
|
||||
typeof arch === "string" &&
|
||||
nodeVersion.startsWith("v")
|
||||
);
|
||||
},
|
||||
TIMEOUTS.QUICK
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -943,8 +988,10 @@ class PakeTestRunner {
|
||||
if (passed === total) {
|
||||
console.log("🎉 All tests passed! CLI is ready for use.\n");
|
||||
} 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
|
||||
const failed = this.results.filter((r) => !r.passed);
|
||||
if (failed.length > 0) {
|
||||
@@ -964,17 +1011,17 @@ const args = process.argv.slice(2);
|
||||
|
||||
// Parse command line arguments
|
||||
const options = {
|
||||
unit: args.includes('--unit') || args.length === 0,
|
||||
integration: args.includes('--integration') || args.length === 0,
|
||||
builder: args.includes('--builder') || args.length === 0,
|
||||
pakeCliTests: args.includes('--pake-cli'),
|
||||
e2e: args.includes('--e2e') || args.includes('--full'),
|
||||
realBuild: args.includes('--real-build') || args.length === 0, // Include real build in default tests
|
||||
quick: args.includes('--quick')
|
||||
unit: args.includes("--unit") || args.length === 0,
|
||||
integration: args.includes("--integration") || args.length === 0,
|
||||
builder: args.includes("--builder") || args.length === 0,
|
||||
pakeCliTests: args.includes("--pake-cli"),
|
||||
e2e: args.includes("--e2e") || args.includes("--full"),
|
||||
realBuild: args.includes("--real-build") || args.length === 0, // Include real build in default tests
|
||||
quick: args.includes("--quick"),
|
||||
};
|
||||
|
||||
// Help message
|
||||
if (args.includes('--help') || args.includes('-h')) {
|
||||
if (args.includes("--help") || args.includes("-h")) {
|
||||
console.log(`
|
||||
🚀 Pake CLI Test Suite
|
||||
|
||||
@@ -1009,7 +1056,8 @@ Environment:
|
||||
|
||||
// Run tests
|
||||
const runner = new PakeTestRunner();
|
||||
runner.runAll(options)
|
||||
runner
|
||||
.runAll(options)
|
||||
.then((success) => {
|
||||
process.exit(success ? 0 : 1);
|
||||
})
|
||||
@@ -1018,4 +1066,4 @@ runner.runAll(options)
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
export default runner;
|
||||
export default runner;
|
||||
|
||||
Reference in New Issue
Block a user