diff --git a/package-lock.json b/package-lock.json index f895cc4..f782a69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "codex-proxy", - "version": "2.0.25", + "version": "2.0.37", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codex-proxy", - "version": "2.0.25", + "version": "2.0.37", "hasInstallScript": true, "workspaces": [ "packages/*" @@ -1224,6 +1224,22 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", + "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.59.0", "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", @@ -5622,6 +5638,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/plist": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", @@ -6985,7 +7048,7 @@ }, "node_modules/vitest": { "version": "3.2.4", - "resolved": "https://registry.npmmirror.com/vitest/-/vitest-3.2.4.tgz", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", @@ -7364,14 +7427,17 @@ }, "packages/electron": { "name": "@codex-proxy/electron", - "version": "2.0.25", + "version": "2.0.37", "dependencies": { "electron-updater": "^6.3.0" }, "devDependencies": { + "@playwright/test": "^1.50.1", "electron": "^35.7.5", "electron-builder": "^26.0.0", - "esbuild": "^0.25.12" + "esbuild": "^0.25.12", + "playwright": "^1.50.1", + "vitest": "^3.2.4" } }, "packages/electron/node_modules/@esbuild/aix-ppc64": { diff --git a/packages/electron/__tests__/launch.test.ts b/packages/electron/__tests__/launch.test.ts new file mode 100644 index 0000000..eba5906 --- /dev/null +++ b/packages/electron/__tests__/launch.test.ts @@ -0,0 +1,92 @@ +import { test, expect } from "vitest"; +import { _electron as electron } from "playwright"; +import * as path from "path"; +import * as fs from "fs"; +import { execSync } from "child_process"; + +test("builds, packages, and launches Electron app", async () => { + // 1. Build & Pack using platform defaults (relies on electron-builder's current OS detection) + console.log(`Building & Packaging for platform: ${process.platform}`); + execSync("npm run build", { cwd: path.join(__dirname, ".."), stdio: "inherit" }); + execSync("npm run pack", { cwd: path.join(__dirname, ".."), stdio: "inherit" }); + + // Determine the expected output directory + let unpackedDirName = ""; + if (process.platform === "win32") { + unpackedDirName = "win-unpacked"; + } else if (process.platform === "darwin") { + unpackedDirName = "mac"; + } else { + unpackedDirName = "linux-unpacked"; + } + + const unpackedDir = path.join(__dirname, "..", "release", unpackedDirName); + expect(fs.existsSync(unpackedDir)).toBe(true); + + // 2. Locate the executable dynamically based on OS conventions + let executablePath = ""; + if (process.platform === "darwin") { + // App bundle on macOS + const files = fs.readdirSync(unpackedDir); + const appName = files.find(f => f.endsWith(".app")); + expect(appName).toBeDefined(); + // Typically the binary is within Contents/MacOS/ + const binName = appName!.replace(".app", ""); + executablePath = path.join(unpackedDir, appName!, "Contents", "MacOS", binName); + } else if (process.platform === "win32") { + // .exe on Windows + const files = fs.readdirSync(unpackedDir); + const exeName = files.find(f => f.endsWith(".exe")); + expect(exeName).toBeDefined(); + executablePath = path.join(unpackedDir, exeName!); + } else { + // Linux executable without extension + const files = fs.readdirSync(unpackedDir); + const binaryName = files.find(f => + !f.includes(".") && + f !== "locales" && + f !== "resources" && + f !== "chrome-sandbox" && + f !== "chrome_crashpad_handler" && + !fs.statSync(path.join(unpackedDir, f)).isDirectory() + ); + expect(binaryName).toBeDefined(); + executablePath = path.join(unpackedDir, binaryName!); + } + + expect(fs.existsSync(executablePath)).toBe(true); + + // Setup dummy user data directory to bypass prompt/setup state + const userDataDir = path.join(__dirname, "..", "test-user-data"); + try { fs.rmSync(userDataDir, { recursive: true, force: true }); } catch (e) {} + + // Create a local.yaml overlay in the test data dir to bypass native issues + const dataDir = path.join(userDataDir, "data"); + fs.mkdirSync(dataDir, { recursive: true }); + fs.writeFileSync(path.join(dataDir, "local.yaml"), "tls:\n transport: curl-cli\n"); + + // 3. Launch the app using Playwright + console.log(`Launching ${executablePath}...`); + const electronApp = await electron.launch({ + executablePath, + args: ["--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage", `--user-data-dir=${userDataDir}`], + env: { ...process.env, DISABLE_NATIVE_TRANSPORT: "1" } + }); + + try { + // Wait for the main window to open + const window = await electronApp.firstWindow(); + expect(window).toBeDefined(); + + const title = await window.title(); + console.log(`Window title: ${title}`); + expect(title).toBe("Codex Proxy Developer Dashboard"); + } catch (e) { + console.error(e); + throw e; + } finally { + // 4. Clean exit + await electronApp.close(); + try { fs.rmSync(userDataDir, { recursive: true, force: true }); } catch (e) {} + } +}, 120000); diff --git a/packages/electron/package.json b/packages/electron/package.json index 5ee28f6..eda3098 100644 --- a/packages/electron/package.json +++ b/packages/electron/package.json @@ -9,18 +9,22 @@ "build": "node electron/build.mjs", "dev": "cd ../.. && npm run build && cd packages/electron && npm run build && electron .", "prepack": "node electron/prepare-pack.mjs", - "pack": "npx electron-builder --config electron-builder.yml", + "pack": "npx electron-builder --config electron-builder.yml --dir", "postpack": "node electron/prepare-pack.mjs --clean", "pack:win": "npm run prepack && npx electron-builder --config electron-builder.yml --win && npm run postpack", "pack:mac": "npm run prepack && npx electron-builder --config electron-builder.yml --mac && npm run postpack", - "pack:linux": "npm run prepack && npx electron-builder --config electron-builder.yml --linux && npm run postpack" + "pack:linux": "npm run prepack && npx electron-builder --config electron-builder.yml --linux && npm run postpack", + "test": "vitest run" }, "dependencies": { "electron-updater": "^6.3.0" }, "devDependencies": { + "@playwright/test": "^1.50.1", "electron": "^35.7.5", "electron-builder": "^26.0.0", - "esbuild": "^0.25.12" + "esbuild": "^0.25.12", + "playwright": "^1.50.1", + "vitest": "^3.2.4" } }