2025-08-14 11:17:19 +08:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-21 15:29:19 +08:00
|
|
|
* Unified Test Runner for Pake CLI
|
2025-08-21 20:34:10 +08:00
|
|
|
*
|
2025-08-21 15:29:19 +08:00
|
|
|
* This is a simplified, unified test runner that replaces the scattered
|
|
|
|
|
* test files with a single, easy-to-use interface.
|
2025-08-14 11:17:19 +08:00
|
|
|
*/
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
import { execSync, spawn } from "child_process";
|
|
|
|
|
import fs from "fs";
|
2025-08-14 11:20:15 +08:00
|
|
|
import path from "path";
|
|
|
|
|
import ora from "ora";
|
2025-08-21 15:29:19 +08:00
|
|
|
import config, { TIMEOUTS, TEST_URLS } from "./config.js";
|
2025-08-14 11:17:19 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
class PakeTestRunner {
|
|
|
|
|
constructor() {
|
|
|
|
|
this.results = [];
|
|
|
|
|
this.tempFiles = [];
|
|
|
|
|
this.tempDirs = [];
|
|
|
|
|
}
|
2025-08-14 11:17:19 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
async runAll(options = {}) {
|
|
|
|
|
const {
|
|
|
|
|
unit = true,
|
2025-08-21 20:34:10 +08:00
|
|
|
integration = true,
|
2025-08-21 15:29:19 +08:00
|
|
|
builder = true,
|
|
|
|
|
pakeCliTests = false,
|
|
|
|
|
e2e = false,
|
|
|
|
|
quick = false,
|
2025-08-21 20:34:10 +08:00
|
|
|
realBuild = false, // Add option for real build test
|
2025-08-21 15:29:19 +08:00
|
|
|
} = options;
|
|
|
|
|
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("Pake CLI Test Suite");
|
2025-08-21 15:29:19 +08:00
|
|
|
console.log("======================\n");
|
|
|
|
|
|
|
|
|
|
this.validateEnvironment();
|
|
|
|
|
|
2025-12-25 14:52:06 +08:00
|
|
|
// Clean up any leftover files from previous test runs
|
|
|
|
|
console.log("[Clean] Removing any leftover test artifacts...");
|
|
|
|
|
this.cleanupTempIcons();
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
let testCount = 0;
|
|
|
|
|
|
|
|
|
|
if (unit && !quick) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("Running CLI Health Checks...");
|
2025-12-12 17:39:52 +08:00
|
|
|
await this.runCliHealthChecks();
|
2025-08-21 15:29:19 +08:00
|
|
|
testCount++;
|
2025-10-16 12:10:08 +08:00
|
|
|
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\nRunning Project Unit Tests (Vitest)...");
|
2025-12-12 17:39:52 +08:00
|
|
|
try {
|
2025-12-12 20:18:41 +08:00
|
|
|
execSync("npx vitest run", {
|
2025-12-12 12:24:11 +00:00
|
|
|
stdio: "inherit",
|
|
|
|
|
cwd: config.PROJECT_ROOT,
|
2025-12-12 17:39:52 +08:00
|
|
|
});
|
|
|
|
|
this.results.push({ name: "Vitest Unit Tests", passed: true });
|
|
|
|
|
testCount++;
|
|
|
|
|
} catch (e) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("[FAIL] Vitest unit tests failed");
|
2025-12-12 09:40:37 +00:00
|
|
|
this.results.push({
|
|
|
|
|
name: "Vitest Unit Tests",
|
|
|
|
|
passed: false,
|
|
|
|
|
error: e.message,
|
|
|
|
|
});
|
2025-10-16 12:10:08 +08:00
|
|
|
}
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (integration && !quick) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\n[Integration] Running Integration Tests...");
|
2025-08-21 15:29:19 +08:00
|
|
|
await this.runIntegrationTests();
|
|
|
|
|
testCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (builder && !quick) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\n[Build] Running Builder Tests...");
|
2025-08-21 15:29:19 +08:00
|
|
|
await this.runBuilderTests();
|
|
|
|
|
testCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pakeCliTests) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\n[Package] Running Pake-CLI GitHub Actions Tests...");
|
2025-08-21 15:29:19 +08:00
|
|
|
await this.runPakeCliTests();
|
|
|
|
|
testCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e2e && !quick) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\n[Run] Running End-to-End Tests...");
|
2025-08-21 15:29:19 +08:00
|
|
|
await this.runE2ETests();
|
|
|
|
|
testCount++;
|
2025-12-25 14:52:06 +08:00
|
|
|
|
|
|
|
|
console.log("\n[Network] Running Proxy Configuration Test...");
|
|
|
|
|
await this.runProxyTest();
|
|
|
|
|
testCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (builder && !quick) {
|
|
|
|
|
console.log("\n[Build] Running Local File Build Test...");
|
|
|
|
|
await this.runLocalFileTest();
|
|
|
|
|
testCount++;
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (realBuild && !quick) {
|
2025-08-22 07:21:22 +08:00
|
|
|
// On macOS, prefer multi-arch test as it's more likely to catch issues
|
2025-08-21 20:34:10 +08:00
|
|
|
if (process.platform === "darwin") {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\n[Build] Running Real Build Test (Multi-Arch)...");
|
2025-08-21 15:29:19 +08:00
|
|
|
await this.runMultiArchBuildTest();
|
|
|
|
|
testCount++;
|
2025-08-22 07:21:22 +08:00
|
|
|
} else {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\n[Build] Running Real Build Test...");
|
2025-08-22 07:21:22 +08:00
|
|
|
await this.runRealBuildTest();
|
|
|
|
|
testCount++;
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.cleanup();
|
|
|
|
|
this.displayFinalResults();
|
|
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
const passed = this.results.filter((r) => r.passed).length;
|
2025-08-21 15:29:19 +08:00
|
|
|
const total = this.results.length;
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
return passed === total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
validateEnvironment() {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("Environment Validation:");
|
|
|
|
|
console.log("-----------------------");
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// Check if CLI file exists
|
|
|
|
|
if (!fs.existsSync(config.CLI_PATH)) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("[FAIL] CLI file not found. Run: pnpm run cli:build");
|
2025-08-21 15:29:19 +08:00
|
|
|
process.exit(1);
|
|
|
|
|
}
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("[PASS] CLI file exists");
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// Check if CLI is executable
|
|
|
|
|
try {
|
|
|
|
|
execSync(`node "${config.CLI_PATH}" --version`, {
|
|
|
|
|
encoding: "utf8",
|
|
|
|
|
timeout: 3000,
|
|
|
|
|
});
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("[PASS] CLI is executable");
|
2025-08-21 15:29:19 +08:00
|
|
|
} catch (error) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("[FAIL] CLI is not executable");
|
2025-08-21 15:29:19 +08:00
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Platform info
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`[PASS] Platform: ${process.platform} (${process.arch})`);
|
|
|
|
|
console.log(`[PASS] Node.js: ${process.version}`);
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
const isCI = process.env.CI || process.env.GITHUB_ACTIONS;
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`[INFO] CI Environment: ${isCI ? "Yes" : "No"}`);
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
console.log();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async runTest(name, testFn, timeout = TIMEOUTS.MEDIUM) {
|
|
|
|
|
const spinner = ora(`Running ${name}...`).start();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await Promise.race([
|
|
|
|
|
testFn(),
|
|
|
|
|
new Promise((_, reject) =>
|
2025-08-21 20:34:10 +08:00
|
|
|
setTimeout(() => reject(new Error("Test timeout")), timeout),
|
2025-08-21 15:29:19 +08:00
|
|
|
),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
|
spinner.succeed(`${name}: PASS`);
|
|
|
|
|
this.results.push({ name, passed: true });
|
|
|
|
|
} else {
|
|
|
|
|
spinner.fail(`${name}: FAIL`);
|
|
|
|
|
this.results.push({ name, passed: false });
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
spinner.fail(`${name}: ERROR - ${error.message.slice(0, 100)}...`);
|
2025-08-21 20:34:10 +08:00
|
|
|
this.results.push({
|
|
|
|
|
name,
|
|
|
|
|
passed: false,
|
|
|
|
|
error: error.message,
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-12 17:39:52 +08:00
|
|
|
async runCliHealthChecks() {
|
2025-08-21 15:29:19 +08:00
|
|
|
// Version command test
|
|
|
|
|
await this.runTest(
|
|
|
|
|
"Version Command",
|
|
|
|
|
() => {
|
|
|
|
|
const output = execSync(`node "${config.CLI_PATH}" --version`, {
|
|
|
|
|
encoding: "utf8",
|
2025-12-25 15:35:35 +08:00
|
|
|
timeout: TIMEOUTS.QUICK,
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
return /^\d+\.\d+\.\d+/.test(output.trim());
|
|
|
|
|
},
|
2025-08-21 20:34:10 +08:00
|
|
|
TIMEOUTS.QUICK,
|
2025-08-21 15:29:19 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Help command test
|
|
|
|
|
await this.runTest(
|
|
|
|
|
"Help Command",
|
|
|
|
|
() => {
|
2025-09-07 07:39:02 +08:00
|
|
|
const output = execSync(`node "${config.CLI_PATH}"`, {
|
2025-08-21 15:29:19 +08:00
|
|
|
encoding: "utf8",
|
2025-12-25 15:35:35 +08:00
|
|
|
timeout: TIMEOUTS.QUICK,
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
return output.includes("Usage: cli [url] [options]");
|
|
|
|
|
},
|
2025-08-21 20:34:10 +08:00
|
|
|
TIMEOUTS.QUICK,
|
2025-08-21 15:29:19 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// URL validation test
|
2025-08-21 20:34:10 +08:00
|
|
|
await this.runTest("URL Validation", () => {
|
|
|
|
|
try {
|
|
|
|
|
execSync(`node "${config.CLI_PATH}" "invalid-url" --name TestApp`, {
|
|
|
|
|
encoding: "utf8",
|
2025-12-25 15:35:35 +08:00
|
|
|
timeout: TIMEOUTS.QUICK,
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
|
|
|
|
return false; // Should have failed
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return error.status !== 0;
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// Number validation test
|
2025-08-21 20:34:10 +08:00
|
|
|
await this.runTest("Number Validation", () => {
|
|
|
|
|
try {
|
|
|
|
|
execSync(`node "${config.CLI_PATH}" https://example.com --width abc`, {
|
2025-08-21 15:29:19 +08:00
|
|
|
encoding: "utf8",
|
2025-12-25 15:35:35 +08:00
|
|
|
timeout: TIMEOUTS.QUICK,
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
2025-08-21 20:34:10 +08:00
|
|
|
return false; // Should throw error
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return error.message.includes("Not a number");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// CLI response time test
|
|
|
|
|
await this.runTest("CLI Response Time", () => {
|
|
|
|
|
const start = Date.now();
|
|
|
|
|
execSync(`node "${config.CLI_PATH}" --version`, {
|
|
|
|
|
encoding: "utf8",
|
2025-12-25 15:35:35 +08:00
|
|
|
timeout: TIMEOUTS.QUICK,
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
|
|
|
|
const elapsed = Date.now() - start;
|
2025-12-25 15:35:35 +08:00
|
|
|
return elapsed < 5000;
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// Weekly URL accessibility test
|
2025-08-21 20:34:10 +08:00
|
|
|
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")
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async runIntegrationTests() {
|
|
|
|
|
// Process spawning test
|
2025-08-21 20:34:10 +08:00
|
|
|
await this.runTest("CLI Process Spawning", () => {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
const child = spawn("node", [config.CLI_PATH, "--version"], {
|
|
|
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
let output = "";
|
|
|
|
|
child.stdout.on("data", (data) => {
|
|
|
|
|
output += data.toString();
|
|
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
child.on("close", (code) => {
|
|
|
|
|
resolve(code === 0 && /\d+\.\d+\.\d+/.test(output));
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
|
child.kill();
|
|
|
|
|
resolve(false);
|
2025-12-25 15:35:35 +08:00
|
|
|
}, TIMEOUTS.QUICK);
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
|
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
// File system permissions test
|
|
|
|
|
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;
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// Dependency resolution test
|
2025-08-21 20:34:10 +08:00
|
|
|
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;
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-14 11:17:19 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
async runBuilderTests() {
|
|
|
|
|
// Platform detection test
|
2025-08-21 20:34:10 +08:00
|
|
|
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";
|
|
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// Architecture detection test
|
2025-08-21 20:34:10 +08:00
|
|
|
await this.runTest("Architecture Detection", () => {
|
|
|
|
|
const currentArch = process.arch;
|
|
|
|
|
const macArch = currentArch === "arm64" ? "aarch64" : currentArch;
|
|
|
|
|
const linuxArch = currentArch === "x64" ? "amd64" : currentArch;
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
return typeof macArch === "string" && typeof linuxArch === "string";
|
|
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// File naming pattern test
|
2025-08-21 20:34:10 +08:00
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async runPakeCliTests() {
|
|
|
|
|
// Package installation test
|
|
|
|
|
await this.runTest(
|
|
|
|
|
"pake-cli Package Installation",
|
|
|
|
|
async () => {
|
|
|
|
|
try {
|
2025-08-26 15:10:06 +08:00
|
|
|
execSync("pnpm install pake-cli@latest", {
|
2025-08-21 15:29:19 +08:00
|
|
|
encoding: "utf8",
|
|
|
|
|
timeout: 60000,
|
|
|
|
|
cwd: "/tmp",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const pakeCliPath = "/tmp/node_modules/.bin/pake";
|
|
|
|
|
return fs.existsSync(pakeCliPath);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Package installation failed:", error.message);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-21 20:34:10 +08:00
|
|
|
TIMEOUTS.LONG,
|
2025-08-21 15:29:19 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Version command test
|
2025-08-21 20:34:10 +08:00
|
|
|
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;
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
// Configuration validation test
|
2025-08-21 20:34:10 +08:00
|
|
|
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;
|
|
|
|
|
};
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
const testConfig = {
|
|
|
|
|
url: "https://github.com",
|
|
|
|
|
name: "github",
|
|
|
|
|
width: 1200,
|
|
|
|
|
height: 780,
|
|
|
|
|
};
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
return validateConfig(testConfig);
|
|
|
|
|
} catch {
|
|
|
|
|
return false;
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
});
|
2025-08-14 11:17:19 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
async runE2ETests() {
|
|
|
|
|
// GitHub.com CLI build test
|
|
|
|
|
await this.runTest(
|
|
|
|
|
"GitHub.com CLI Build Test",
|
|
|
|
|
async () => {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const testName = "GitHubApp";
|
|
|
|
|
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --debug --width 1200 --height 780`;
|
|
|
|
|
|
|
|
|
|
const child = spawn(command, {
|
|
|
|
|
shell: true,
|
|
|
|
|
cwd: config.PROJECT_ROOT,
|
|
|
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
|
|
|
env: {
|
|
|
|
|
...process.env,
|
|
|
|
|
PAKE_E2E_TEST: "1",
|
|
|
|
|
PAKE_CREATE_APP: "1",
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let buildStarted = false;
|
|
|
|
|
let configGenerated = false;
|
|
|
|
|
|
|
|
|
|
child.stdout.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
2025-08-21 20:34:10 +08:00
|
|
|
if (
|
|
|
|
|
output.includes("Building app") ||
|
|
|
|
|
output.includes("Compiling") ||
|
|
|
|
|
output.includes("Installing package") ||
|
|
|
|
|
output.includes("Bundling")
|
|
|
|
|
) {
|
2025-08-21 15:29:19 +08:00
|
|
|
buildStarted = true;
|
|
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
if (
|
|
|
|
|
output.includes("GitHub") &&
|
|
|
|
|
(output.includes("config") || output.includes("name"))
|
|
|
|
|
) {
|
2025-08-21 15:29:19 +08:00
|
|
|
configGenerated = true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.stderr.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
2025-08-21 20:34:10 +08:00
|
|
|
if (
|
|
|
|
|
output.includes("Building app") ||
|
|
|
|
|
output.includes("Compiling") ||
|
|
|
|
|
output.includes("Installing package") ||
|
|
|
|
|
output.includes("Bundling") ||
|
|
|
|
|
output.includes("Finished") ||
|
|
|
|
|
output.includes("Built application at:")
|
|
|
|
|
) {
|
2025-08-21 15:29:19 +08:00
|
|
|
buildStarted = true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Kill process after 60 seconds if build started
|
|
|
|
|
const timeout = setTimeout(() => {
|
|
|
|
|
child.kill("SIGTERM");
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
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) {
|
2025-08-21 20:34:10 +08:00
|
|
|
console.log(
|
|
|
|
|
`✓ GitHub.com CLI build started successfully (${testName})`,
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
resolve(true);
|
|
|
|
|
} else {
|
2025-08-21 20:34:10 +08:00
|
|
|
reject(
|
|
|
|
|
new Error("GitHub.com CLI build did not start within timeout"),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
}, 60000);
|
|
|
|
|
|
|
|
|
|
child.on("close", () => {
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
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) {
|
|
|
|
|
resolve(true);
|
|
|
|
|
} else {
|
2025-08-21 20:34:10 +08:00
|
|
|
reject(
|
|
|
|
|
new Error("GitHub.com CLI build process ended before starting"),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.on("error", (error) => {
|
2025-08-21 20:34:10 +08:00
|
|
|
reject(
|
|
|
|
|
new Error(`GitHub.com CLI build process error: ${error.message}`),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.stdin.end();
|
|
|
|
|
});
|
|
|
|
|
},
|
2025-08-21 20:34:10 +08:00
|
|
|
70000, // 70 seconds timeout
|
2025-08-21 15:29:19 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Configuration verification test
|
|
|
|
|
await this.runTest(
|
|
|
|
|
"Configuration File Verification",
|
|
|
|
|
async () => {
|
|
|
|
|
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const testName = "GitHubConfigTest";
|
|
|
|
|
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --debug --width 1200 --height 780`;
|
|
|
|
|
|
|
|
|
|
const child = spawn(command, {
|
|
|
|
|
shell: true,
|
|
|
|
|
cwd: config.PROJECT_ROOT,
|
|
|
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
|
|
|
env: {
|
|
|
|
|
...process.env,
|
2025-08-21 20:34:10 +08:00
|
|
|
PAKE_E2E_TEST: "1",
|
2025-08-21 15:29:19 +08:00
|
|
|
PAKE_CREATE_APP: "1",
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const checkConfigFiles = () => {
|
|
|
|
|
if (fs.existsSync(pakeDir)) {
|
|
|
|
|
const configFile = path.join(pakeDir, "tauri.conf.json");
|
|
|
|
|
const pakeConfigFile = path.join(pakeDir, "pake.json");
|
|
|
|
|
|
|
|
|
|
if (fs.existsSync(configFile) && fs.existsSync(pakeConfigFile)) {
|
|
|
|
|
try {
|
2025-08-21 20:34:10 +08:00
|
|
|
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/"
|
|
|
|
|
) {
|
2025-08-21 15:29:19 +08:00
|
|
|
child.kill("SIGTERM");
|
|
|
|
|
this.trackTempDir(pakeDir);
|
2025-08-21 20:34:10 +08:00
|
|
|
console.log(
|
|
|
|
|
"✓ GitHub.com configuration files verified correctly",
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
resolve(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
// Continue if config parsing fails
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
child.stdout.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
2025-08-21 20:34:10 +08:00
|
|
|
if (
|
|
|
|
|
output.includes("Installing package") ||
|
|
|
|
|
output.includes("Building app")
|
|
|
|
|
) {
|
2025-08-21 15:29:19 +08:00
|
|
|
setTimeout(checkConfigFiles, 1000);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.stderr.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
2025-08-21 20:34:10 +08:00
|
|
|
if (
|
|
|
|
|
output.includes("Installing package") ||
|
|
|
|
|
output.includes("Building app") ||
|
|
|
|
|
output.includes("Package installed")
|
|
|
|
|
) {
|
2025-08-21 15:29:19 +08:00
|
|
|
setTimeout(checkConfigFiles, 1000);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Timeout after 20 seconds
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
child.kill("SIGTERM");
|
|
|
|
|
this.trackTempDir(pakeDir);
|
|
|
|
|
reject(new Error("GitHub.com configuration verification timeout"));
|
2025-12-25 14:52:06 +08:00
|
|
|
}, 40000);
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
child.on("error", (error) => {
|
2025-08-21 20:34:10 +08:00
|
|
|
reject(
|
|
|
|
|
new Error(
|
|
|
|
|
`GitHub.com config verification error: ${error.message}`,
|
|
|
|
|
),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.stdin.end();
|
|
|
|
|
});
|
|
|
|
|
},
|
2025-12-25 14:52:06 +08:00
|
|
|
45000,
|
2025-08-21 15:29:19 +08:00
|
|
|
);
|
2025-08-14 11:17:19 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-25 14:52:06 +08:00
|
|
|
async runProxyTest() {
|
|
|
|
|
await this.runTest("Proxy Configuration", async () => {
|
|
|
|
|
const command = `node "${config.CLI_PATH}" "https://google.com" --name "ProxyTest" --proxy-url "http://127.0.0.1:7890" --debug`;
|
|
|
|
|
// We just want to check if the command parses the proxy argument correctly
|
|
|
|
|
// It might fail to connect if no proxy is running, but that's expected
|
|
|
|
|
try {
|
|
|
|
|
execSync(`echo "n" | timeout 5s ${command} || true`, {
|
|
|
|
|
encoding: "utf8",
|
|
|
|
|
timeout: 8000,
|
|
|
|
|
});
|
|
|
|
|
return true;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
// If it fails with "connection refused" or similar, it means it TRIED to use the proxy
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async runLocalFileTest() {
|
|
|
|
|
await this.runTest("Local File Build Handling", async () => {
|
|
|
|
|
const testFile = path.join(config.PROJECT_ROOT, "test-local.html");
|
2025-12-25 06:54:04 +00:00
|
|
|
fs.writeFileSync(
|
|
|
|
|
testFile,
|
|
|
|
|
"<html><body><h1>Hello Pake</h1></body></html>",
|
|
|
|
|
);
|
2025-12-25 14:52:06 +08:00
|
|
|
this.trackTempFile(testFile);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const command = `node "${config.CLI_PATH}" "${testFile}" --name "LocalApp" --debug`;
|
|
|
|
|
// We just verify it accepts the local file path
|
|
|
|
|
execSync(`echo "n" | timeout 5s ${command} || true`, {
|
|
|
|
|
encoding: "utf8",
|
|
|
|
|
timeout: 8000,
|
|
|
|
|
});
|
|
|
|
|
return true;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
// Validation failure is what we want to catch (if it rejected local files)
|
|
|
|
|
return !error.message.includes("Invalid URL");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
async runRealBuildTest() {
|
|
|
|
|
// Real build test that actually creates a complete app
|
|
|
|
|
await this.runTest(
|
|
|
|
|
"Complete GitHub.com App Build",
|
|
|
|
|
async () => {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const testName = "GitHubRealBuild";
|
2025-08-21 21:14:42 +08:00
|
|
|
// Platform-specific output files
|
|
|
|
|
const outputFiles = {
|
|
|
|
|
darwin: {
|
|
|
|
|
app: path.join(config.PROJECT_ROOT, `${testName}.app`),
|
|
|
|
|
installer: path.join(config.PROJECT_ROOT, `${testName}.dmg`),
|
2025-08-27 09:39:53 +08:00
|
|
|
bundleDir: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle",
|
|
|
|
|
),
|
2025-08-21 21:14:42 +08:00
|
|
|
},
|
|
|
|
|
linux: {
|
|
|
|
|
app: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
2025-08-22 08:27:06 +08:00
|
|
|
`src-tauri/target/release/pake`,
|
2025-08-21 21:14:42 +08:00
|
|
|
),
|
|
|
|
|
installer: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
2025-08-27 09:39:36 +08:00
|
|
|
"src-tauri/target/release/bundle/deb",
|
2025-08-21 21:14:42 +08:00
|
|
|
),
|
2025-08-27 09:39:53 +08:00
|
|
|
bundleDir: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle",
|
|
|
|
|
),
|
2025-08-21 21:14:42 +08:00
|
|
|
},
|
|
|
|
|
win32: {
|
2025-08-22 07:21:22 +08:00
|
|
|
app: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
2025-08-27 09:39:36 +08:00
|
|
|
"src-tauri/target/x86_64-pc-windows-msvc/release/bundle/msi",
|
2025-08-22 07:21:22 +08:00
|
|
|
),
|
|
|
|
|
installer: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
2025-08-27 09:39:36 +08:00
|
|
|
"src-tauri/target/x86_64-pc-windows-msvc/release/bundle/msi",
|
2025-08-22 07:21:22 +08:00
|
|
|
),
|
2025-08-27 09:39:53 +08:00
|
|
|
bundleDir: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/x86_64-pc-windows-msvc/release/bundle",
|
|
|
|
|
),
|
2025-08-27 09:39:36 +08:00
|
|
|
// Alternative directories to check
|
|
|
|
|
altDirs: [
|
2025-08-27 09:39:53 +08:00
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle/msi",
|
|
|
|
|
),
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis",
|
|
|
|
|
),
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle/nsis",
|
|
|
|
|
),
|
2025-08-27 09:39:36 +08:00
|
|
|
],
|
2025-08-21 21:14:42 +08:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const platform = process.platform;
|
|
|
|
|
const expectedFiles = outputFiles[platform] || outputFiles.darwin;
|
|
|
|
|
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
`[Integration] Starting real build test for GitHub.com...`,
|
|
|
|
|
);
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`[Note] Platform: ${platform}`);
|
|
|
|
|
console.log(`[Note] Expected app directory: ${expectedFiles.app}`);
|
2025-08-27 09:39:53 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
`[Note] Expected installer directory: ${expectedFiles.installer}`,
|
2025-08-27 09:39:53 +08:00
|
|
|
);
|
2025-08-27 09:39:36 +08:00
|
|
|
if (expectedFiles.bundleDir) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`[Note] Bundle directory: ${expectedFiles.bundleDir}`);
|
2025-08-27 09:39:36 +08:00
|
|
|
}
|
|
|
|
|
if (expectedFiles.altDirs) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`[Note] Alternative directories to check:`);
|
2025-08-27 09:39:36 +08:00
|
|
|
expectedFiles.altDirs.forEach((dir, i) => {
|
|
|
|
|
console.log(` ${i + 1}. ${dir}`);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar`;
|
|
|
|
|
|
|
|
|
|
const child = spawn(command, {
|
|
|
|
|
shell: true,
|
|
|
|
|
cwd: config.PROJECT_ROOT,
|
|
|
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
|
|
|
env: {
|
|
|
|
|
...process.env,
|
|
|
|
|
PAKE_CREATE_APP: "1",
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let buildStarted = false;
|
|
|
|
|
let compilationStarted = false;
|
|
|
|
|
|
|
|
|
|
// Track progress without too much noise
|
|
|
|
|
child.stdout.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
|
|
|
|
if (output.includes("Installing package")) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Package] Installing dependencies...");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
if (output.includes("Building app")) {
|
|
|
|
|
buildStarted = true;
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Build] Build started...");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
if (output.includes("Compiling")) {
|
|
|
|
|
compilationStarted = true;
|
|
|
|
|
console.log(" ⚙️ Compiling...");
|
|
|
|
|
}
|
|
|
|
|
if (output.includes("Bundling")) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Package] Bundling...");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
if (output.includes("Built application at:")) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [PASS] Build completed!");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-08-22 08:07:34 +08:00
|
|
|
let errorOutput = "";
|
2025-08-21 15:29:19 +08:00
|
|
|
child.stderr.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
|
|
|
|
if (output.includes("Building app")) buildStarted = true;
|
|
|
|
|
if (output.includes("Compiling")) compilationStarted = true;
|
2025-08-21 20:34:10 +08:00
|
|
|
if (output.includes("Finished"))
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [PASS] Compilation finished!");
|
2025-08-22 08:27:06 +08:00
|
|
|
|
2025-08-22 08:07:34 +08:00
|
|
|
// Capture error output for debugging
|
2025-08-22 08:27:06 +08:00
|
|
|
if (
|
|
|
|
|
output.includes("error:") ||
|
|
|
|
|
output.includes("Error:") ||
|
|
|
|
|
output.includes("ERROR")
|
|
|
|
|
) {
|
2025-08-22 08:07:34 +08:00
|
|
|
errorOutput += output;
|
|
|
|
|
}
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Real timeout - 8 minutes for actual build
|
|
|
|
|
const timeout = setTimeout(() => {
|
2025-08-27 09:39:53 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Check] Build timeout reached, checking for output files...",
|
2025-08-27 09:39:53 +08:00
|
|
|
);
|
|
|
|
|
|
2025-08-27 10:19:01 +08:00
|
|
|
const foundFiles = this.findBuildOutputFiles(testName, platform);
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
if (foundFiles.length > 0) {
|
2025-08-21 21:14:42 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Success] Build completed successfully - found output files!",
|
2025-08-21 21:14:42 +08:00
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
foundFiles.forEach((file) => {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [App] Found: ${file.path} (${file.type})`);
|
2025-08-27 09:39:36 +08:00
|
|
|
});
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Success] Build artifacts tracked for cleanup");
|
2025-08-21 15:29:19 +08:00
|
|
|
child.kill("SIGTERM");
|
|
|
|
|
resolve(true);
|
|
|
|
|
} else {
|
2025-08-21 21:14:42 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Warn] Build process completed but no output files found",
|
2025-08-21 21:14:42 +08:00
|
|
|
);
|
2025-08-27 10:19:01 +08:00
|
|
|
this.debugBuildDirectories();
|
2025-08-21 15:29:19 +08:00
|
|
|
child.kill("SIGTERM");
|
2025-08-27 09:39:53 +08:00
|
|
|
reject(
|
|
|
|
|
new Error("Real build test timeout - no output files found"),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
}, 480000); // 8 minutes
|
|
|
|
|
|
|
|
|
|
child.on("close", (code) => {
|
|
|
|
|
clearTimeout(timeout);
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
` [Status] Build process finished with exit code: ${code}`,
|
|
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 10:19:01 +08:00
|
|
|
const foundFiles = this.findBuildOutputFiles(testName, platform);
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
if (foundFiles.length > 0) {
|
2025-08-22 08:27:06 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Success] Real build test SUCCESS: Build file(s) generated!",
|
2025-08-22 08:27:06 +08:00
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
foundFiles.forEach((file) => {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [App] ${file.type}: ${file.path}`);
|
2025-08-27 09:39:36 +08:00
|
|
|
try {
|
|
|
|
|
const stats = fs.statSync(file.path);
|
|
|
|
|
const size = (stats.size / 1024 / 1024).toFixed(1);
|
|
|
|
|
console.log(` Size: ${size}MB`);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.log(` (Could not get file size)`);
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Success] Build artifacts tracked for cleanup");
|
|
|
|
|
// Track files for cleanup
|
2025-12-25 06:54:04 +00:00
|
|
|
foundFiles.forEach((f) => this.trackTempFile(f.path));
|
2025-08-21 15:29:19 +08:00
|
|
|
resolve(true);
|
|
|
|
|
} else if (code === 0 && buildStarted && compilationStarted) {
|
2025-08-21 20:34:10 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Warn] Build process completed but no output files found",
|
2025-08-22 08:27:06 +08:00
|
|
|
);
|
2025-08-27 10:19:01 +08:00
|
|
|
this.debugBuildDirectories();
|
2025-08-21 15:29:19 +08:00
|
|
|
resolve(false);
|
|
|
|
|
} else {
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
` [FAIL] Build process failed with exit code: ${code}`,
|
|
|
|
|
);
|
2025-08-22 08:07:34 +08:00
|
|
|
if (buildStarted) {
|
2025-08-22 08:27:06 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Status] Build was started but failed during execution",
|
2025-08-22 08:27:06 +08:00
|
|
|
);
|
2025-08-22 08:07:34 +08:00
|
|
|
if (errorOutput.trim()) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Check] Error details:");
|
2025-08-22 08:27:06 +08:00
|
|
|
errorOutput.split("\n").forEach((line) => {
|
2025-08-22 08:07:34 +08:00
|
|
|
if (line.trim()) console.log(` ${line.trim()}`);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-27 10:19:01 +08:00
|
|
|
this.debugBuildDirectories();
|
2025-08-22 08:07:34 +08:00
|
|
|
} else {
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
" [Status] Build failed before starting compilation",
|
|
|
|
|
);
|
2025-08-22 08:07:34 +08:00
|
|
|
if (errorOutput.trim()) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Check] Error details:");
|
2025-08-22 08:27:06 +08:00
|
|
|
errorOutput.split("\n").forEach((line) => {
|
2025-08-22 08:07:34 +08:00
|
|
|
if (line.trim()) console.log(` ${line.trim()}`);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-21 15:29:19 +08:00
|
|
|
reject(new Error(`Real build test failed with code ${code}`));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.on("error", (error) => {
|
|
|
|
|
clearTimeout(timeout);
|
2025-08-21 20:34:10 +08:00
|
|
|
reject(
|
|
|
|
|
new Error(`Real build test process error: ${error.message}`),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.stdin.end();
|
|
|
|
|
});
|
|
|
|
|
},
|
2025-08-21 20:34:10 +08:00
|
|
|
500000, // 8+ minutes timeout
|
2025-08-21 15:29:19 +08:00
|
|
|
);
|
2025-08-14 11:17:19 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
async runMultiArchBuildTest() {
|
|
|
|
|
// Multi-arch build test specifically for macOS
|
|
|
|
|
await this.runTest(
|
|
|
|
|
"Multi-Arch GitHub.com Build (Universal Binary)",
|
|
|
|
|
async () => {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const testName = "GitHubMultiArch";
|
|
|
|
|
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
|
|
|
|
|
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
`[Integration] Starting multi-arch build test for GitHub.com...`,
|
|
|
|
|
);
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`[Note] Expected output: ${appFile}`);
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
`[Build] Building Universal Binary (Intel + Apple Silicon)`,
|
|
|
|
|
);
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar --multi-arch`;
|
|
|
|
|
|
|
|
|
|
const child = spawn(command, {
|
|
|
|
|
shell: true,
|
|
|
|
|
cwd: config.PROJECT_ROOT,
|
|
|
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
|
|
|
env: {
|
|
|
|
|
...process.env,
|
|
|
|
|
PAKE_CREATE_APP: "1",
|
2025-08-22 07:21:22 +08:00
|
|
|
HDIUTIL_QUIET: "1",
|
|
|
|
|
HDIUTIL_NO_AUTOOPEN: "1",
|
2025-08-21 15:29:19 +08:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let buildStarted = false;
|
|
|
|
|
let compilationStarted = false;
|
|
|
|
|
|
|
|
|
|
// Track progress
|
|
|
|
|
child.stdout.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
|
|
|
|
if (output.includes("Installing package")) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Package] Installing dependencies...");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
if (output.includes("Building app")) {
|
|
|
|
|
buildStarted = true;
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Build] Multi-arch build started...");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
if (output.includes("Compiling")) {
|
|
|
|
|
compilationStarted = true;
|
|
|
|
|
console.log(" ⚙️ Compiling for multiple architectures...");
|
|
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
if (
|
|
|
|
|
output.includes("universal-apple-darwin") ||
|
|
|
|
|
output.includes("Universal")
|
|
|
|
|
) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Multi] Universal binary target detected");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
if (output.includes("Bundling")) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Package] Bundling universal binary...");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
if (output.includes("Built application at:")) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [PASS] Multi-arch build completed!");
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.stderr.on("data", (data) => {
|
|
|
|
|
const output = data.toString();
|
|
|
|
|
if (output.includes("Building app")) buildStarted = true;
|
|
|
|
|
if (output.includes("Compiling")) compilationStarted = true;
|
2025-08-21 20:34:10 +08:00
|
|
|
if (output.includes("Finished"))
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [PASS] Multi-arch compilation finished!");
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
|
2025-08-29 00:00:50 +08:00
|
|
|
// Multi-arch builds take longer - 20 minutes timeout
|
2025-08-21 15:29:19 +08:00
|
|
|
const timeout = setTimeout(() => {
|
2025-08-27 09:39:53 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Check] Multi-arch build timeout reached, checking for output files...",
|
2025-08-27 09:39:53 +08:00
|
|
|
);
|
|
|
|
|
|
2025-08-27 10:19:01 +08:00
|
|
|
const foundFiles = this.findBuildOutputFiles(testName, "darwin");
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
if (foundFiles.length > 0) {
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
" [Success] Multi-arch build completed successfully!",
|
|
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
foundFiles.forEach((file) => {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [App] Found: ${file.path} (${file.type})`);
|
2025-08-27 09:39:36 +08:00
|
|
|
});
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
" [Multi] Universal binary preserved for inspection",
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
child.kill("SIGTERM");
|
|
|
|
|
resolve(true);
|
|
|
|
|
} else {
|
2025-08-21 20:34:10 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [FAIL] Multi-arch build timeout - no output files generated",
|
2025-08-21 20:34:10 +08:00
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
this.debugBuildDirectories(
|
|
|
|
|
{
|
|
|
|
|
app: appFile,
|
|
|
|
|
installer: dmgFile,
|
|
|
|
|
bundleDir: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/universal-apple-darwin/release/bundle",
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
"darwin",
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
child.kill("SIGTERM");
|
|
|
|
|
reject(new Error("Multi-arch build test timeout"));
|
|
|
|
|
}
|
2025-08-29 00:00:50 +08:00
|
|
|
}, 1200000); // 20 minutes for multi-arch
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
child.on("close", (code) => {
|
|
|
|
|
clearTimeout(timeout);
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-27 09:39:53 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
` [Status] Multi-arch build process finished with exit code: ${code}`,
|
2025-08-27 09:39:53 +08:00
|
|
|
);
|
|
|
|
|
|
2025-08-27 10:19:01 +08:00
|
|
|
const foundFiles = this.findBuildOutputFiles(testName, "darwin");
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
if (foundFiles.length > 0) {
|
2025-08-21 20:34:10 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Success] Multi-arch build test SUCCESS: Universal binary generated!",
|
2025-08-21 20:34:10 +08:00
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
foundFiles.forEach((file) => {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [App] ${file.type}: ${file.path}`);
|
2025-08-27 09:39:36 +08:00
|
|
|
});
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
" [Multi] Universal binary preserved for inspection",
|
|
|
|
|
);
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
// Verify it's actually a universal binary
|
2025-08-27 09:39:53 +08:00
|
|
|
const appFile = foundFiles.find((f) => f.type.includes("App"));
|
2025-08-27 09:39:36 +08:00
|
|
|
if (appFile) {
|
|
|
|
|
try {
|
2025-08-27 09:39:53 +08:00
|
|
|
const binaryPath = path.join(
|
|
|
|
|
appFile.path,
|
|
|
|
|
"Contents/MacOS/pake",
|
2025-08-21 20:34:10 +08:00
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
const fileOutput = execSync(`file "${binaryPath}"`, {
|
|
|
|
|
encoding: "utf8",
|
|
|
|
|
});
|
2025-08-27 09:39:36 +08:00
|
|
|
if (fileOutput.includes("universal binary")) {
|
|
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [PASS] Verified: Universal binary created successfully",
|
2025-08-27 09:39:36 +08:00
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Warn] Note: Binary architecture:",
|
2025-08-27 09:39:36 +08:00
|
|
|
fileOutput.trim(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
" [Warn] Could not verify binary architecture",
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-21 20:34:10 +08:00
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
resolve(true);
|
2025-08-22 07:21:22 +08:00
|
|
|
} else if (buildStarted && compilationStarted) {
|
|
|
|
|
// If build started and compilation happened, but no output files found
|
2025-08-21 20:34:10 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
" [Warn] Multi-arch build process completed but no output files found",
|
2025-08-21 20:34:10 +08:00
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
this.debugBuildDirectories(
|
|
|
|
|
{
|
|
|
|
|
app: appFile,
|
|
|
|
|
installer: dmgFile,
|
|
|
|
|
bundleDir: path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/universal-apple-darwin/release/bundle",
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
"darwin",
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
resolve(false);
|
|
|
|
|
} else {
|
2025-08-22 07:21:22 +08:00
|
|
|
// Only reject if the build never started or failed early
|
2025-08-21 20:34:10 +08:00
|
|
|
reject(
|
|
|
|
|
new Error(`Multi-arch build test failed with code ${code}`),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.on("error", (error) => {
|
|
|
|
|
clearTimeout(timeout);
|
2025-08-21 20:34:10 +08:00
|
|
|
reject(
|
|
|
|
|
new Error(
|
|
|
|
|
`Multi-arch build test process error: ${error.message}`,
|
|
|
|
|
),
|
|
|
|
|
);
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
child.stdin.end();
|
|
|
|
|
});
|
|
|
|
|
},
|
2025-08-29 00:00:50 +08:00
|
|
|
1250000, // 20+ minutes timeout
|
2025-08-21 15:29:19 +08:00
|
|
|
);
|
2025-08-14 20:51:42 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 09:57:31 +08:00
|
|
|
// Simplified build output detection - if build succeeds, check for any output files
|
2025-08-27 10:19:01 +08:00
|
|
|
findBuildOutputFiles(testName, platform) {
|
2025-08-27 09:39:36 +08:00
|
|
|
const foundFiles = [];
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [Check] Checking for ${platform} build outputs...`);
|
2025-08-27 09:57:31 +08:00
|
|
|
|
|
|
|
|
// Simple approach: look for common build artifacts in project root and common locations
|
|
|
|
|
const searchLocations = [
|
|
|
|
|
// Always check project root first (most builds output there)
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
// Platform-specific bundle directories
|
|
|
|
|
...(platform === "linux"
|
|
|
|
|
? [
|
|
|
|
|
path.join(config.PROJECT_ROOT, "src-tauri/target/release"),
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle/deb",
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(platform === "win32"
|
|
|
|
|
? [
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/x86_64-pc-windows-msvc/release/bundle/msi",
|
|
|
|
|
),
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle/msi",
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(platform === "darwin"
|
|
|
|
|
? [
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle/macos",
|
|
|
|
|
),
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/release/bundle/dmg",
|
|
|
|
|
),
|
|
|
|
|
path.join(
|
|
|
|
|
config.PROJECT_ROOT,
|
|
|
|
|
"src-tauri/target/universal-apple-darwin/release/bundle",
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Define what we're looking for based on platform
|
|
|
|
|
const buildPatterns = {
|
|
|
|
|
win32: [".msi", ".exe"],
|
|
|
|
|
linux: [".deb", ".appimage"],
|
|
|
|
|
darwin: [".dmg", ".app"],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const patterns = buildPatterns[platform] || buildPatterns.darwin;
|
|
|
|
|
|
|
|
|
|
for (const location of searchLocations) {
|
|
|
|
|
if (!fs.existsSync(location)) {
|
|
|
|
|
continue;
|
2025-08-27 09:39:36 +08:00
|
|
|
}
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:57:31 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
` [Dir] Checking: ${path.relative(config.PROJECT_ROOT, location)}`,
|
2025-08-27 09:57:31 +08:00
|
|
|
);
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
try {
|
2025-08-27 09:57:31 +08:00
|
|
|
const items = fs.readdirSync(location);
|
|
|
|
|
const buildFiles = items.filter((item) => {
|
|
|
|
|
const itemPath = path.join(location, item);
|
|
|
|
|
const stats = fs.statSync(itemPath);
|
|
|
|
|
|
|
|
|
|
// Skip common non-build directories
|
|
|
|
|
if (
|
|
|
|
|
stats.isDirectory() &&
|
|
|
|
|
[".git", ".github", "node_modules", "src", "bin", "tests"].includes(
|
|
|
|
|
item,
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:57:31 +08:00
|
|
|
// Check if it's a build artifact we care about
|
|
|
|
|
const lowerItem = item.toLowerCase();
|
2025-08-27 09:39:53 +08:00
|
|
|
return (
|
2025-08-27 09:57:31 +08:00
|
|
|
patterns.some((pattern) => lowerItem.endsWith(pattern)) ||
|
|
|
|
|
lowerItem.includes(testName.toLowerCase()) ||
|
|
|
|
|
(lowerItem.includes("github") && !item.startsWith(".")) || // Avoid .github directory
|
|
|
|
|
(platform === "linux" && item === "pake")
|
|
|
|
|
); // Linux binary
|
2025-08-27 09:39:36 +08:00
|
|
|
});
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:57:31 +08:00
|
|
|
buildFiles.forEach((file) => {
|
|
|
|
|
const fullPath = path.join(location, file);
|
2025-08-27 09:39:36 +08:00
|
|
|
const stats = fs.statSync(fullPath);
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:57:31 +08:00
|
|
|
let fileType = "Build Artifact";
|
|
|
|
|
if (file.endsWith(".msi")) fileType = "MSI Installer";
|
|
|
|
|
else if (file.endsWith(".exe")) fileType = "Windows Executable";
|
|
|
|
|
else if (file.endsWith(".deb")) fileType = "DEB Package";
|
|
|
|
|
else if (file.endsWith(".appimage")) fileType = "AppImage";
|
|
|
|
|
else if (file.endsWith(".dmg")) fileType = "DMG Image";
|
|
|
|
|
else if (file.endsWith(".app"))
|
|
|
|
|
fileType = stats.isDirectory() ? "macOS App Bundle" : "macOS App";
|
|
|
|
|
else if (file === "pake") fileType = "Linux Binary";
|
|
|
|
|
|
|
|
|
|
foundFiles.push({
|
|
|
|
|
path: fullPath,
|
|
|
|
|
type: fileType,
|
|
|
|
|
size: stats.isFile() ? stats.size : 0,
|
|
|
|
|
});
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:57:31 +08:00
|
|
|
const size =
|
|
|
|
|
stats.isFile() && stats.size > 0
|
|
|
|
|
? ` (${(stats.size / 1024 / 1024).toFixed(1)}MB)`
|
|
|
|
|
: "";
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [PASS] Found ${fileType}: ${file}${size}`);
|
2025-08-27 09:39:36 +08:00
|
|
|
});
|
2025-08-27 09:57:31 +08:00
|
|
|
|
|
|
|
|
// For Linux, also check inside architecture directories
|
|
|
|
|
if (platform === "linux") {
|
|
|
|
|
const archDirs = items.filter(
|
|
|
|
|
(item) => item.includes("amd64") || item.includes("x86_64"),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for (const archDir of archDirs) {
|
|
|
|
|
const archPath = path.join(location, archDir);
|
|
|
|
|
if (fs.statSync(archPath).isDirectory()) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [Check] Checking arch directory: ${archDir}`);
|
2025-08-27 09:57:31 +08:00
|
|
|
try {
|
|
|
|
|
const archFiles = fs.readdirSync(archPath);
|
|
|
|
|
archFiles
|
|
|
|
|
.filter((f) => f.endsWith(".deb"))
|
|
|
|
|
.forEach((debFile) => {
|
|
|
|
|
const debPath = path.join(archPath, debFile);
|
|
|
|
|
const debStats = fs.statSync(debPath);
|
|
|
|
|
foundFiles.push({
|
|
|
|
|
path: debPath,
|
|
|
|
|
type: "DEB Package",
|
|
|
|
|
size: debStats.size,
|
|
|
|
|
});
|
|
|
|
|
const size = `(${(debStats.size / 1024 / 1024).toFixed(1)}MB)`;
|
|
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
` [PASS] Found DEB Package: ${debFile} ${size}`,
|
2025-08-27 09:57:31 +08:00
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
` [Warn] Could not check ${archDir}: ${error.message}`,
|
2025-08-27 09:57:31 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-27 09:39:36 +08:00
|
|
|
} catch (error) {
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
` [Warn] Could not read ${location}: ${error.message}`,
|
|
|
|
|
);
|
2025-08-27 09:39:36 +08:00
|
|
|
}
|
2025-08-27 09:57:31 +08:00
|
|
|
}
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [Status] Found ${foundFiles.length} build artifact(s)`);
|
2025-08-27 09:39:36 +08:00
|
|
|
return foundFiles;
|
|
|
|
|
}
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
// Debug function to show directory structure
|
2025-08-27 10:19:01 +08:00
|
|
|
debugBuildDirectories() {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Check] Debug: Analyzing build directories...");
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
const targetDir = path.join(config.PROJECT_ROOT, "src-tauri/target");
|
|
|
|
|
if (fs.existsSync(targetDir)) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Check] Target directory structure:");
|
2025-08-27 09:39:36 +08:00
|
|
|
try {
|
|
|
|
|
this.listTargetContents(targetDir);
|
|
|
|
|
} catch (error) {
|
2025-12-25 06:54:04 +00:00
|
|
|
console.log(
|
|
|
|
|
` [Warn] Could not list target contents: ${error.message}`,
|
|
|
|
|
);
|
2025-08-27 09:39:36 +08:00
|
|
|
}
|
|
|
|
|
} else {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [FAIL] Target directory does not exist: ${targetDir}`);
|
2025-08-27 09:39:36 +08:00
|
|
|
}
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
// Check project root for direct outputs
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(" [Check] Project root files:");
|
2025-08-27 09:39:36 +08:00
|
|
|
try {
|
2025-08-27 09:39:53 +08:00
|
|
|
const rootFiles = fs
|
|
|
|
|
.readdirSync(config.PROJECT_ROOT)
|
|
|
|
|
.filter(
|
|
|
|
|
(file) =>
|
|
|
|
|
file.endsWith(".app") ||
|
|
|
|
|
file.endsWith(".dmg") ||
|
|
|
|
|
file.endsWith(".msi") ||
|
|
|
|
|
file.endsWith(".deb") ||
|
|
|
|
|
file.endsWith(".exe"),
|
2025-08-27 09:39:36 +08:00
|
|
|
);
|
|
|
|
|
if (rootFiles.length > 0) {
|
2025-08-27 09:39:53 +08:00
|
|
|
rootFiles.forEach((file) => {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [App] ${file}`);
|
2025-08-27 09:39:36 +08:00
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
console.log(` (No build artifacts in project root)`);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [FAIL] Error reading project root: ${error.message}`);
|
2025-08-27 09:39:36 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-27 09:39:53 +08:00
|
|
|
|
2025-08-22 08:07:34 +08:00
|
|
|
listTargetContents(targetDir, maxDepth = 3, currentDepth = 0) {
|
|
|
|
|
if (currentDepth >= maxDepth) return;
|
2025-08-22 08:27:06 +08:00
|
|
|
|
2025-08-22 08:07:34 +08:00
|
|
|
try {
|
|
|
|
|
const items = fs.readdirSync(targetDir);
|
2025-08-22 08:27:06 +08:00
|
|
|
items.forEach((item) => {
|
2025-08-22 08:07:34 +08:00
|
|
|
const fullPath = path.join(targetDir, item);
|
|
|
|
|
const relativePath = path.relative(config.PROJECT_ROOT, fullPath);
|
|
|
|
|
const indent = " ".repeat(currentDepth + 1);
|
2025-08-22 08:27:06 +08:00
|
|
|
|
2025-08-27 09:39:36 +08:00
|
|
|
try {
|
|
|
|
|
const stats = fs.statSync(fullPath);
|
|
|
|
|
if (stats.isDirectory()) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`${indent}[Dir] ${relativePath}/`);
|
2025-08-27 09:39:36 +08:00
|
|
|
// Show more directories for Windows debugging
|
2025-08-27 09:39:53 +08:00
|
|
|
if (
|
|
|
|
|
item === "bundle" ||
|
|
|
|
|
item === "release" ||
|
|
|
|
|
item === "msi" ||
|
|
|
|
|
item === "nsis" ||
|
|
|
|
|
item.includes("windows") ||
|
|
|
|
|
item.includes("msvc")
|
|
|
|
|
) {
|
2025-08-27 09:39:36 +08:00
|
|
|
this.listTargetContents(fullPath, maxDepth, currentDepth + 1);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-08-27 09:39:53 +08:00
|
|
|
const size =
|
|
|
|
|
stats.size > 0
|
|
|
|
|
? ` (${(stats.size / 1024 / 1024).toFixed(1)}MB)`
|
|
|
|
|
: "";
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(`${indent}[File] ${relativePath}${size}`);
|
2025-08-22 08:07:34 +08:00
|
|
|
}
|
2025-08-27 09:39:36 +08:00
|
|
|
} catch (statError) {
|
|
|
|
|
console.log(`${indent}❓ ${relativePath} (cannot stat)`);
|
2025-08-22 08:07:34 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
2025-08-27 09:39:53 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
` [Warn] Could not list contents of ${targetDir}: ${error.message}`,
|
2025-08-27 09:39:53 +08:00
|
|
|
);
|
2025-08-22 08:07:34 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
trackTempFile(filepath) {
|
|
|
|
|
this.tempFiles.push(filepath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trackTempDir(dirpath) {
|
|
|
|
|
this.tempDirs.push(dirpath);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-22 07:51:52 +08:00
|
|
|
cleanupTempIcons() {
|
|
|
|
|
// Clean up temporary icon files generated during tests
|
2025-08-22 08:07:34 +08:00
|
|
|
const iconsDir = path.join(config.PROJECT_ROOT, "src-tauri/icons");
|
2025-12-25 14:52:06 +08:00
|
|
|
const testNames = [
|
|
|
|
|
"urltest",
|
|
|
|
|
"githubapp",
|
|
|
|
|
"githubmultiarch",
|
|
|
|
|
"githubconfigtest",
|
|
|
|
|
"localapp",
|
2025-12-25 06:54:04 +00:00
|
|
|
"proxytest",
|
2025-12-25 14:52:06 +08:00
|
|
|
];
|
2025-08-22 08:07:34 +08:00
|
|
|
|
|
|
|
|
testNames.forEach((name) => {
|
2025-08-22 07:51:52 +08:00
|
|
|
const iconPath = path.join(iconsDir, `${name}.icns`);
|
|
|
|
|
try {
|
|
|
|
|
if (fs.existsSync(iconPath)) {
|
|
|
|
|
fs.unlinkSync(iconPath);
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [Clean] Cleaned up temporary icon: ${name}.icns`);
|
2025-08-22 07:51:52 +08:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn(`Warning: Could not clean up icon ${iconPath}`);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
cleanup() {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\nCleaning up test artifacts...");
|
|
|
|
|
|
2025-08-22 07:51:52 +08:00
|
|
|
// Clean up temporary icon files generated during tests
|
|
|
|
|
this.cleanupTempIcons();
|
2025-08-22 08:07:34 +08:00
|
|
|
|
2025-12-25 14:52:06 +08:00
|
|
|
// Clean up tracked files
|
2025-08-21 15:29:19 +08:00
|
|
|
this.tempFiles.forEach((file) => {
|
|
|
|
|
try {
|
|
|
|
|
if (fs.existsSync(file)) {
|
|
|
|
|
if (fs.statSync(file).isDirectory()) {
|
|
|
|
|
fs.rmSync(file, { recursive: true, force: true });
|
|
|
|
|
} else {
|
|
|
|
|
fs.unlinkSync(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2025-12-25 14:52:06 +08:00
|
|
|
// Ignore errors during cleanup
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.tempDirs.forEach((dir) => {
|
|
|
|
|
try {
|
|
|
|
|
if (fs.existsSync(dir)) {
|
|
|
|
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2025-12-25 14:52:06 +08:00
|
|
|
// Ignore errors
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
});
|
2025-12-25 14:52:06 +08:00
|
|
|
|
|
|
|
|
// Aggressive cleanup of known test artifacts in project root
|
|
|
|
|
const testPatterns = [
|
|
|
|
|
"GitHubRealBuild",
|
|
|
|
|
"GitHubApp",
|
|
|
|
|
"GitHubMultiArch",
|
|
|
|
|
"GitHubConfigTest",
|
|
|
|
|
"LocalApp",
|
|
|
|
|
"ProxyTest",
|
2025-12-25 06:54:04 +00:00
|
|
|
"URLTest",
|
2025-12-25 14:52:06 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const extensions = [".app", ".dmg", ".msi", ".deb", ".exe", ".AppImage"];
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const files = fs.readdirSync(config.PROJECT_ROOT);
|
2025-12-25 06:54:04 +00:00
|
|
|
files.forEach((file) => {
|
2025-12-25 14:52:06 +08:00
|
|
|
// Check if file matches any test name pattern and extension
|
2025-12-25 06:54:04 +00:00
|
|
|
const isTestArtifact =
|
|
|
|
|
testPatterns.some((pattern) => file.includes(pattern)) &&
|
|
|
|
|
(extensions.some((ext) => file.endsWith(ext)) ||
|
|
|
|
|
(!file.includes(".") &&
|
|
|
|
|
!fs
|
|
|
|
|
.statSync(path.join(config.PROJECT_ROOT, file))
|
|
|
|
|
.isDirectory())); // Linux binary often has no extension
|
2025-12-25 14:52:06 +08:00
|
|
|
|
|
|
|
|
if (isTestArtifact) {
|
|
|
|
|
const fullPath = path.join(config.PROJECT_ROOT, file);
|
|
|
|
|
console.log(` [Clean] Removing artifact: ${file}`);
|
|
|
|
|
fs.rmSync(fullPath, { recursive: true, force: true });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Also clean src-tauri/.pake directory if it exists
|
|
|
|
|
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
|
|
|
|
|
if (fs.existsSync(pakeDir)) {
|
2025-12-25 06:54:04 +00:00
|
|
|
fs.rmSync(pakeDir, { recursive: true, force: true });
|
2025-12-25 14:52:06 +08:00
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn(" [Warn] Cleanup warning:", e.message);
|
|
|
|
|
}
|
2025-08-21 15:29:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
displayFinalResults() {
|
|
|
|
|
const passed = this.results.filter((r) => r.passed).length;
|
|
|
|
|
const total = this.results.length;
|
|
|
|
|
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\nOverall Test Summary");
|
|
|
|
|
console.log("====================");
|
2025-08-21 15:29:19 +08:00
|
|
|
console.log(`Total: ${passed}/${total} tests passed`);
|
|
|
|
|
|
|
|
|
|
if (passed === total) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("All tests passed! CLI is ready for use.\n");
|
2025-08-21 15:29:19 +08:00
|
|
|
} else {
|
2025-08-21 20:34:10 +08:00
|
|
|
console.log(
|
2025-12-25 14:52:06 +08:00
|
|
|
`[FAIL] ${total - passed} test(s) failed. Please check the issues above.\n`,
|
2025-08-21 20:34:10 +08:00
|
|
|
);
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
// Show failed tests
|
|
|
|
|
const failed = this.results.filter((r) => !r.passed);
|
|
|
|
|
if (failed.length > 0) {
|
|
|
|
|
console.log("Failed tests:");
|
|
|
|
|
failed.forEach((result) => {
|
|
|
|
|
const error = result.error ? ` (${result.error})` : "";
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log(` [FAIL] ${result.name}${error}`);
|
2025-08-21 15:29:19 +08:00
|
|
|
});
|
|
|
|
|
console.log();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-13 13:14:49 +08:00
|
|
|
import ReleaseBuildTest from "./release.js";
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
// Command line interface
|
|
|
|
|
const args = process.argv.slice(2);
|
|
|
|
|
|
2025-08-22 12:47:37 +08:00
|
|
|
// Complete test suite by default - no more smart modes
|
2025-08-21 15:29:19 +08:00
|
|
|
const options = {
|
2025-08-22 12:47:37 +08:00
|
|
|
unit: !args.includes("--no-unit"),
|
|
|
|
|
integration: !args.includes("--no-integration"),
|
|
|
|
|
builder: !args.includes("--no-builder"),
|
2025-08-21 20:34:10 +08:00
|
|
|
pakeCliTests: args.includes("--pake-cli"),
|
2025-08-22 12:47:37 +08:00
|
|
|
e2e: args.includes("--e2e"),
|
|
|
|
|
realBuild: !args.includes("--no-build"), // Always include real build test
|
2025-12-13 13:14:49 +08:00
|
|
|
quick: false,
|
2025-08-21 15:29:19 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Help message
|
2025-08-21 20:34:10 +08:00
|
|
|
if (args.includes("--help") || args.includes("-h")) {
|
2025-08-21 15:29:19 +08:00
|
|
|
console.log(`
|
2025-12-25 14:52:06 +08:00
|
|
|
[Run] Pake CLI Test Suite
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-22 12:47:37 +08:00
|
|
|
Usage: npm test [-- options]
|
|
|
|
|
|
|
|
|
|
Complete Test Suite (Default):
|
2025-08-26 15:10:06 +08:00
|
|
|
pnpm test # Run complete test suite with real build (8-12 minutes)
|
2025-08-22 12:47:37 +08:00
|
|
|
|
|
|
|
|
Test Components:
|
2025-12-25 14:52:06 +08:00
|
|
|
[PASS] Unit Tests # CLI commands, validation, response time
|
|
|
|
|
[PASS] Integration Tests # Process spawning, file permissions, dependencies
|
|
|
|
|
[PASS] Builder Tests # Platform detection, architecture, file naming
|
|
|
|
|
[PASS] Real Build Test # Complete GitHub.com app build with packaging
|
2025-08-22 12:47:37 +08:00
|
|
|
|
|
|
|
|
Optional Components:
|
|
|
|
|
--e2e Add end-to-end configuration tests
|
|
|
|
|
--pake-cli Add pake-cli GitHub Actions tests
|
2025-12-13 13:14:49 +08:00
|
|
|
--release Run release workflow tests (Twitter/WeRead) - Slow!
|
2025-08-21 15:29:19 +08:00
|
|
|
|
2025-08-22 12:47:37 +08:00
|
|
|
Skip Components (if needed):
|
|
|
|
|
--no-unit Skip unit tests
|
|
|
|
|
--no-integration Skip integration tests
|
|
|
|
|
--no-builder Skip builder tests
|
|
|
|
|
--no-build Skip real build test
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
Examples:
|
2025-08-22 12:47:37 +08:00
|
|
|
npm test # Complete test suite (recommended)
|
2025-12-13 13:14:49 +08:00
|
|
|
npm test -- --release # Run everything including release workflow
|
2025-08-26 15:10:06 +08:00
|
|
|
pnpm test -- --no-build # Skip real build (faster for development)
|
2025-08-21 15:29:19 +08:00
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
|
CI=1 # Enable CI mode
|
|
|
|
|
DEBUG=1 # Enable debug output
|
|
|
|
|
PAKE_CREATE_APP=1 # Allow app creation in tests
|
|
|
|
|
`);
|
|
|
|
|
process.exit(0);
|
2025-08-14 11:17:19 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
// Run tests
|
|
|
|
|
const runner = new PakeTestRunner();
|
2025-08-21 20:34:10 +08:00
|
|
|
runner
|
|
|
|
|
.runAll(options)
|
2025-12-13 13:14:49 +08:00
|
|
|
.then(async (success) => {
|
|
|
|
|
// Run release workflow tests as part of the standard suite
|
|
|
|
|
// We skip this if builder tests are explicitly disabled (often used for quick checks)
|
|
|
|
|
if (success && options.realBuild) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.log("\n[Package] Running Release Workflow Test...");
|
2025-12-13 05:15:47 +00:00
|
|
|
console.log(
|
|
|
|
|
" (This mimics the GitHub Actions release process for popular apps)",
|
|
|
|
|
);
|
2025-12-13 13:14:49 +08:00
|
|
|
|
2025-12-13 05:15:47 +00:00
|
|
|
// Pass skipCliBuild=true since "npm test" already builds the CLI
|
|
|
|
|
const releaseTester = new ReleaseBuildTest();
|
|
|
|
|
const releaseSuccess = await releaseTester.run({ skipCliBuild: true });
|
2025-12-13 13:14:49 +08:00
|
|
|
|
2025-12-13 05:15:47 +00:00
|
|
|
if (!releaseSuccess) {
|
2025-12-25 14:52:06 +08:00
|
|
|
console.error("\n[FAIL] Release workflow tests failed");
|
2025-12-13 05:15:47 +00:00
|
|
|
process.exit(1);
|
|
|
|
|
}
|
2025-12-13 13:14:49 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-21 15:29:19 +08:00
|
|
|
process.exit(success ? 0 : 1);
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
console.error("Test runner failed:", error);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|
|
|
|
|
|
2025-08-21 20:34:10 +08:00
|
|
|
export default runner;
|