From 8394c5bed732b37f7ef7d58551cd6f75b80af43c Mon Sep 17 00:00:00 2001 From: jackwener Date: Tue, 11 Aug 2026 22:53:45 +0800 Subject: [PATCH] test: remove default script and desktop happy-path tests --- .github/workflows/ci.yml | 5 +- .github/workflows/windows-baseline.yml | 12 - CONTRIBUTING.md | 1 - CONTRIBUTING.zh-CN.md | 1 - README.md | 1 - README.zh-CN.md | 1 - apps/desktop/scripts/dev-app-runtime.test.mjs | 630 ------------------ .../__tests__/client-settings-tools.test.ts | 41 -- ...-host-desktop-candidate-dependency.test.ts | 46 -- .../runtime-host-project-catalog.test.ts | 44 -- .../runtime-host-settings-ipc-main.test.ts | 45 -- .../skill-invocation-feedback.test.ts | 41 -- .../workspace-readiness-recovery.test.ts | 44 -- package.json | 12 +- .../src/__tests__/package-import.test.ts | 15 - scripts/bundled-skill-catalog.test.mjs | 9 - scripts/ci-test-plan.mjs | 10 +- scripts/cu-e2e-scenarios.test.mjs | 38 -- scripts/electron-builder-config.test.mjs | 36 - scripts/electron-lifecycle.test.mjs | 86 --- scripts/prepare-maka-cu-provenance.test.mjs | 54 -- 21 files changed, 9 insertions(+), 1163 deletions(-) delete mode 100644 apps/desktop/scripts/dev-app-runtime.test.mjs delete mode 100644 apps/desktop/src/main/__tests__/client-settings-tools.test.ts delete mode 100644 apps/desktop/src/main/__tests__/runtime-host-desktop-candidate-dependency.test.ts delete mode 100644 apps/desktop/src/main/__tests__/runtime-host-project-catalog.test.ts delete mode 100644 apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts delete mode 100644 apps/desktop/src/main/__tests__/skill-invocation-feedback.test.ts delete mode 100644 apps/desktop/src/main/__tests__/workspace-readiness-recovery.test.ts delete mode 100644 packages/storage/src/__tests__/package-import.test.ts delete mode 100644 scripts/bundled-skill-catalog.test.mjs delete mode 100644 scripts/cu-e2e-scenarios.test.mjs delete mode 100644 scripts/electron-builder-config.test.mjs delete mode 100644 scripts/electron-lifecycle.test.mjs delete mode 100644 scripts/prepare-maka-cu-provenance.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0d95a7c37..613b3506ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,11 +116,8 @@ jobs: env: MAKA_REQUIRE_LINUX_SANDBOX_SMOKE: '1' run: npm exec -w @maka/runtime -- node --test dist/__tests__/linux-sandbox-smoke.test.js - - name: Run fast script tests - if: needs.changes.outputs.script_mode == 'fast' || needs.changes.outputs.script_mode == 'full' - run: npm run test:scripts - name: Run extended script tests - if: needs.changes.outputs.script_mode == 'extended' || needs.changes.outputs.script_mode == 'full' + if: needs.changes.outputs.script_mode == 'extended' run: npm run test:scripts:extended # Workspaces consume the dist built above. Selection includes reverse # dependencies, while bounded concurrency avoids both the old serial diff --git a/.github/workflows/windows-baseline.yml b/.github/workflows/windows-baseline.yml index 924262bd55..a9fe7f510e 100644 --- a/.github/workflows/windows-baseline.yml +++ b/.github/workflows/windows-baseline.yml @@ -136,17 +136,6 @@ jobs: Get-Content "$env:WINDOWS_BASELINE_LOG_DIR/inventory.log" exit $exitCode - - id: scripts - name: Run repository script tests - if: always() && steps.install.outcome == 'success' - continue-on-error: true - shell: pwsh - run: | - npm.cmd run test:scripts *> "$env:WINDOWS_BASELINE_LOG_DIR/script-tests.log" - $exitCode = $LASTEXITCODE - Get-Content "$env:WINDOWS_BASELINE_LOG_DIR/script-tests.log" - exit $exitCode - - id: smoke name: Run CLI and Electron startup smoke if: always() && steps.build.outcome == 'success' @@ -321,7 +310,6 @@ jobs: | Install | ${{ steps.install.outcome }} | | Build | ${{ steps.build.outcome }} | | Skip inventory | ${{ steps.inventory.outcome }} | - | Script tests | ${{ steps.scripts.outcome }} | | CLI / Electron smoke | ${{ steps.smoke.outcome }} | | Storage path/lock gates | ${{ steps.storage.outcome }} | | Runtime PTY input | ${{ steps.runtime_pty_input.outcome }} | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52ad8deb69..cd944985a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,7 +101,6 @@ trees, which fail on imports that no longer resolve. ```sh npm test # all workspaces npm --workspace @maka/core test # one workspace -npm run test:scripts # repository scripts npm --workspace @maka/desktop run e2e # Playwright ``` diff --git a/CONTRIBUTING.zh-CN.md b/CONTRIBUTING.zh-CN.md index e7b67725c0..bdb561bb34 100644 --- a/CONTRIBUTING.zh-CN.md +++ b/CONTRIBUTING.zh-CN.md @@ -92,7 +92,6 @@ npm --workspace @maka/desktop run build:renderer # 渲染层 ```sh npm test # 全部 workspace npm --workspace @maka/core test # 单个 workspace -npm run test:scripts # 仓库脚本 npm --workspace @maka/desktop run e2e # Playwright ``` diff --git a/README.md b/README.md index 92568d28b7..927a607138 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,6 @@ Use the following commands to update `packages/core/src/model-metadata.generated ```sh npm run sync:model-metadata -npm run test:scripts npm --workspace @maka/core test ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index c2c259e8ef..783f7dfa60 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -224,7 +224,6 @@ npm --workspace @maka/desktop test ```sh npm run sync:model-metadata -npm run test:scripts npm --workspace @maka/core test ``` diff --git a/apps/desktop/scripts/dev-app-runtime.test.mjs b/apps/desktop/scripts/dev-app-runtime.test.mjs deleted file mode 100644 index 718b77aed6..0000000000 --- a/apps/desktop/scripts/dev-app-runtime.test.mjs +++ /dev/null @@ -1,630 +0,0 @@ -import assert from 'node:assert/strict'; -import { - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - realpathSync, - rmSync, - statSync, - writeFileSync, -} from 'node:fs'; -import { createRequire } from 'node:module'; -import { tmpdir } from 'node:os'; -import { basename, join } from 'node:path'; -import test from 'node:test'; -import { - createBootstrapSource, - createDevelopmentEnvironmentFile, - createMacosDevelopmentLaunch, - createRuntimeMarker, - developmentAppPath, - developmentExecutablePath, - ensureNoRunningDevelopmentApp, - installBootstrap, - isDevelopmentAppRunning, - isDevelopmentRuntimeCurrent, - monitorDevelopmentApp, - quitMacosDevelopmentApp, - readPublishedViteUrl, - rebuildDevelopmentRuntime, - resolveMacosDevelopmentLaunch, - selectDevelopmentEnvironment, - shouldUseMacosDevelopmentApp, - splitDevelopmentCliArgs, - toProcessMatchPattern, - writeDevelopmentEnvironment, -} from './dev-app-runtime.mjs'; - -test('launches the signed development bundle through LaunchServices', () => { - assert.deepEqual(createMacosDevelopmentLaunch('/repo/Maka Dev.app'), { - command: 'open', - args: ['-n', '-a', '/repo/Maka Dev.app'], - }); - // The branch production always takes: LaunchServices detaches the app from - // this terminal's stdio, so without the redirect the log has nothing to - // follow and startup failures go only to Console.app. - assert.deepEqual(createMacosDevelopmentLaunch('/repo/Maka Dev.app', '/repo/app.log').args, [ - '-n', - '-a', - '/repo/Maka Dev.app', - '--stdout', - '/repo/app.log', - '--stderr', - '/repo/app.log', - ]); -}); - -test('keeps the signed bundle workflow opt-in', () => { - assert.equal(shouldUseMacosDevelopmentApp('darwin', { MAKA_DEV_TCC: '1' }), true); - assert.equal(shouldUseMacosDevelopmentApp('darwin', { MAKA_DEV_TCC: 'true' }), true); - assert.equal(shouldUseMacosDevelopmentApp('darwin', { MAKA_DEV_TCC: ' TRUE ' }), true); - assert.equal(shouldUseMacosDevelopmentApp('darwin', {}), false); - assert.equal(shouldUseMacosDevelopmentApp('darwin', { MAKA_DEV_TCC: '0' }), false); - assert.equal(shouldUseMacosDevelopmentApp('darwin', { MAKA_DEV_TCC: '' }), false); - // Opting in elsewhere must never reach codesign or LaunchServices. - assert.equal(shouldUseMacosDevelopmentApp('linux', { MAKA_DEV_TCC: '1' }), false); - assert.equal(shouldUseMacosDevelopmentApp('win32', { MAKA_DEV_TCC: 'true' }), false); -}); - -test('the opt-out path returns before preparing anything', async () => { - // The gate is only worth testing where it is actually consulted: this is the - // sole entry point, and inverting the check must not leave the suite green. - for (const env of [{}, { MAKA_DEV_TCC: '0' }, { MAKA_DEV_TCC: 'false' }, { MAKA_DEV_TCC: '' }]) { - assert.equal(await resolveMacosDevelopmentLaunch(env), null); - } -}); - -test('forwards application secrets but leaves PATH to the main process', () => { - const env = selectDevelopmentEnvironment( - { - OPENAI_API_KEY: 'openai-secret', - GH_TOKEN: 'github-secret', - GITHUB_TOKEN: 'github-fallback', - RIVE_BIN: '/tools/rive', - MAKA_MODEL: 'test-model', - CUA_ENDPOINT: 'http://cua', - API_SECRET: 'do-not-forward', - PATH: '/should/not/travel', - TERM: 'xterm-256color', - COLORTERM: 'truecolor', - }, - 'http://localhost:4173', - ); - assert.equal(env.VITE_DEV_SERVER_URL, 'http://localhost:4173'); - assert.equal(env.OPENAI_API_KEY, 'openai-secret'); - assert.equal(env.GH_TOKEN, 'github-secret'); - assert.equal(env.GITHUB_TOKEN, 'github-fallback'); - assert.equal(env.RIVE_BIN, '/tools/rive'); - assert.equal(env.MAKA_MODEL, 'test-model'); - assert.equal(env.CUA_ENDPOINT, 'http://cua'); - assert.equal('API_SECRET' in env, false); - // This content is persisted, so a recorded PATH would go stale. Worse, a - // recorded TERM would make shell-env.ts short-circuit on a Dock launch and - // leave launchd's minimal PATH in place — the exact case it exists for. - assert.equal('PATH' in env, false); - assert.equal('TERM' in env, false); - assert.equal('COLORTERM' in env, false); -}); - -/** - * Runs the generated bootstrap for real against a stub `electron` module and a - * stub main entry. Asserting on the source text only proves it mentions the - * right identifiers; `new Function` accepts a typo'd `setPathTYPO` or a - * nonexistent module. Executing it is what pins the behaviour. - */ -async function runBootstrap({ envFileContent, omitMainEntry } = {}) { - // realpath: macOS resolves /var to /private/var, which process.cwd() reports. - const root = realpathSync(mkdtempSync(join(tmpdir(), 'maka-boot-'))); - const desktopDir = join(root, 'desktop'); - const envFile = join(root, 'dev-env.json'); - const loadedFile = join(root, 'loaded.json'); - const calls = []; - mkdirSync(join(desktopDir, 'dist', 'main'), { recursive: true }); - mkdirSync(join(root, 'node_modules', 'electron'), { recursive: true }); - writeFileSync( - join(root, 'node_modules', 'electron', 'package.json'), - JSON.stringify({ name: 'electron', main: 'index.js' }), - ); - writeFileSync( - join(root, 'node_modules', 'electron', 'index.js'), - `const calls = globalThis.__makaCalls; - module.exports = { app: { - setAppPath: (p) => calls.push(['setAppPath', p]), - setPath: (k, v) => calls.push(['setPath', k, v]), - exit: (c) => calls.push(['exit', c]), - commandLine: { appendSwitch: (k, v) => calls.push(['switch', k, v ?? null]) }, - } };`, - ); - if (!omitMainEntry) { - writeFileSync( - join(desktopDir, 'dist', 'main', 'main.js'), - `import { writeFileSync } from 'node:fs'; - writeFileSync(${JSON.stringify(loadedFile)}, JSON.stringify({ - cwd: process.cwd(), viteUrl: process.env.VITE_DEV_SERVER_URL ?? null, - apiKey: process.env.OPENAI_API_KEY ?? null, - }));`, - ); - } - if (envFileContent !== undefined) writeFileSync(envFile, envFileContent); - const bootstrapFile = join(root, 'bootstrap.cjs'); - writeFileSync( - bootstrapFile, - createBootstrapSource(desktopDir, join(root, 'default-user-data'), envFile), - ); - const nodeModule = createRequire(join(root, 'x.cjs')); - globalThis.__makaCalls = calls; - // The bootstrap chdirs by design, and its dynamic import of the main entry - // resolves on a later tick — so the cwd must stay in place until that entry - // has run. Restore it only afterwards, so later tests are unaffected. - const previousCwd = process.cwd(); - // The bootstrap assigns into process.env, which is per-app in production but - // shared between these tests; snapshot it so cases stay independent. - const previousEnv = { ...process.env }; - try { - // Each run measures what the bootstrap assigns from its published file. - // Do not mistake the developer shell's forwarded values for that output. - const publishedEnvironmentKeys = new Set([ - ...Object.keys(selectDevelopmentEnvironment(process.env)), - 'VITE_DEV_SERVER_URL', - ]); - for (const key of publishedEnvironmentKeys) delete process.env[key]; - - nodeModule(bootstrapFile); - const cwd = process.cwd(); - // The import settles on the next tick; poll rather than guess a tick count. - for (let i = 0; i < 200 && !existsSync(loadedFile) && !calls.some(([k]) => k === 'exit'); i += 1) { - await new Promise((done) => setImmediate(done)); - } - const loaded = existsSync(loadedFile) ? JSON.parse(readFileSync(loadedFile, 'utf8')) : null; - return { root, desktopDir, calls, cwd, loaded }; - } finally { - process.chdir(previousCwd); - for (const key of Object.keys(process.env)) { - if (!(key in previousEnv)) delete process.env[key]; - } - Object.assign(process.env, previousEnv); - delete globalThis.__makaCalls; - rmSync(root, { recursive: true, force: true }); - } -} - -test('boots the repository app from constants alone, with no env file present', async () => { - const { desktopDir, calls, loaded, root, cwd } = await runBootstrap(); - // The central claim of the design: nothing but build-time constants. - assert.deepEqual(calls, [ - ['setAppPath', desktopDir], - ['setPath', 'userData', join(root, 'default-user-data')], - ]); - assert.equal(cwd, desktopDir); - assert.equal(loaded.cwd, desktopDir); - assert.equal(loaded.viteUrl, null); -}); - -test('adopts a published environment file: env, userData override, switches', async () => { - const { calls, loaded } = await runBootstrap({ - envFileContent: JSON.stringify( - createDevelopmentEnvironmentFile({ - argv: ['--enable-logging', '--user-data-dir=/tmp/override-profile'], - env: { OPENAI_API_KEY: 'secret' }, - viteUrl: 'http://localhost:5173', - }), - ), - }); - assert.deepEqual( - calls.filter(([kind]) => kind === 'switch'), - [['switch', 'enable-logging', null]], - ); - assert.deepEqual(calls.find(([kind]) => kind === 'setPath'), [ - 'setPath', - 'userData', - '/tmp/override-profile', - ]); - assert.equal(loaded.viteUrl, 'http://localhost:5173'); - assert.equal(loaded.apiKey, 'secret'); -}); - -test('ignores an unreadable or wrong-schema environment file instead of failing to boot', async () => { - const wrongSchema = JSON.stringify({ schemaVersion: 999, env: { OPENAI_API_KEY: 'leak' } }); - const previousApiKey = process.env.OPENAI_API_KEY; - const previousViteUrl = process.env.VITE_DEV_SERVER_URL; - process.env.OPENAI_API_KEY = 'ambient-openai-key'; - process.env.VITE_DEV_SERVER_URL = 'http://ambient.invalid'; - try { - for (const content of ['not json at all', wrongSchema]) { - const { calls, loaded, root } = await runBootstrap({ envFileContent: content }); - assert.deepEqual(calls.find(([kind]) => kind === 'setPath'), [ - 'setPath', - 'userData', - join(root, 'default-user-data'), - ]); - assert.equal(loaded.apiKey, null); - assert.equal(loaded.viteUrl, null); - } - } finally { - if (previousApiKey === undefined) delete process.env.OPENAI_API_KEY; - else process.env.OPENAI_API_KEY = previousApiKey; - if (previousViteUrl === undefined) delete process.env.VITE_DEV_SERVER_URL; - else process.env.VITE_DEV_SERVER_URL = previousViteUrl; - } -}); - -test('an empty --user-data-dir falls back to the per-worktree default', async () => { - const { calls, root } = await runBootstrap({ - envFileContent: JSON.stringify( - createDevelopmentEnvironmentFile({ argv: ['--user-data-dir='], env: {} }), - ), - }); - assert.deepEqual(calls.find(([kind]) => kind === 'setPath'), [ - 'setPath', - 'userData', - join(root, 'default-user-data'), - ]); -}); - -test('exits instead of hanging a windowless app when the main entry is missing', async () => { - // The most common developer state: dist/main/main.js not built yet. - const { calls } = await runBootstrap({ omitMainEntry: true }); - assert.deepEqual( - calls.filter(([kind]) => kind === 'exit'), - [['exit', 1]], - ); -}); - -test('installs the payload where Electron will actually load it', () => { - const bundle = mkdtempSync(join(tmpdir(), 'maka-bundle-')); - const payload = join(bundle, 'Contents', 'Resources', 'default_app.asar'); - mkdirSync(payload, { recursive: true }); - writeFileSync(join(payload, 'stale-from-an-older-build.js'), 'x'); - try { - installBootstrap(bundle); - // A plain directory, not an archive: that is what lets the payload occupy - // the path Electron searches without any asar tooling. - assert.equal(statSync(payload).isDirectory(), true); - const manifest = JSON.parse(readFileSync(join(payload, 'package.json'), 'utf8')); - assert.equal(existsSync(join(payload, manifest.main)), true); - assert.equal(existsSync(join(payload, 'stale-from-an-older-build.js')), false); - // Production constants, not test doubles, are what reach the bootstrap. - const source = readFileSync(join(payload, manifest.main), 'utf8'); - assert.match(source, /apps[/\\]+desktop/); - assert.match(source, /Maka Dev-[0-9a-f]{12}/); - } finally { - rmSync(bundle, { recursive: true, force: true }); - } -}); - -test('keeps the inner executable named Electron so app.isPackaged stays false', () => { - // isPackaged is native and computed as basename(execPath) !== 'electron'. - // Every dev-mode gate in the product hangs off it. - assert.equal(basename(developmentExecutablePath), 'Electron'); -}); - -test('publishes the environment file atomically and privately', () => { - const dir = mkdtempSync(join(tmpdir(), 'maka-dev-env-')); - const file = join(dir, 'dev-env.json'); - const content = createDevelopmentEnvironmentFile({ - env: { OPENAI_API_KEY: 'secret' }, - viteUrl: 'http://localhost:5173', - argv: ['--user-data-dir=/tmp/custom-profile', '--enable-logging', '--remote-debugging-port=9222'], - }); - try { - writeDevelopmentEnvironment(content, { file }); - const written = JSON.parse(readFileSync(file, 'utf8')); - assert.equal(written.env.OPENAI_API_KEY, 'secret'); - assert.equal(written.env.VITE_DEV_SERVER_URL, 'http://localhost:5173'); - assert.equal(written.userDataDir, '/tmp/custom-profile'); - assert.deepEqual(written.electronArgs, ['--enable-logging', '--remote-debugging-port=9222']); - if (process.platform !== 'win32') assert.equal(statSync(file).mode & 0o777, 0o600); - // Rewriting must not require any prior ownership handshake, must leave no - // temporary behind, and must not widen the mode. - writeDevelopmentEnvironment({ ...content, env: {} }, { file }); - assert.deepEqual(JSON.parse(readFileSync(file, 'utf8')).env, {}); - assert.deepEqual(readdirSync(dir), ['dev-env.json']); - if (process.platform !== 'win32') assert.equal(statSync(file).mode & 0o777, 0o600); - } finally { - rmSync(dir, { recursive: true, force: true }); - } -}); - -test('carries a live dev server URL across a reclaiming launch', () => { - // `npm start` publishes no URL of its own. Without this, reclaiming an app - // from a running `npm run dev` would drop it to the prebuilt renderer. - const dir = mkdtempSync(join(tmpdir(), 'maka-dev-env-')); - const file = join(dir, 'dev-env.json'); - try { - assert.equal(readPublishedViteUrl(file), undefined); - writeDevelopmentEnvironment( - createDevelopmentEnvironmentFile({ argv: [], env: {}, viteUrl: 'http://localhost:5173' }), - { file }, - ); - assert.equal(readPublishedViteUrl(file), 'http://localhost:5173'); - writeFileSync(file, JSON.stringify({ schemaVersion: 999, env: { VITE_DEV_SERVER_URL: 'x' } })); - assert.equal(readPublishedViteUrl(file), undefined); - } finally { - rmSync(dir, { recursive: true, force: true }); - } -}); - -test('reuses only a marker that matches every committed cache input', () => { - const expected = createRuntimeMarker('43.1.1'); - assert.equal(isDevelopmentRuntimeCurrent({ ...expected }, expected), true); - for (const [key, value] of Object.entries({ - schemaVersion: 999, - electronVersion: '44.0.0', - bundleId: 'com.other', - // A moved repo must rebuild: the bootstrap embeds the old absolute path. - desktopDir: '/moved', - })) { - assert.equal(isDevelopmentRuntimeCurrent({ ...expected, [key]: value }, expected), false, key); - } - const { schemaVersion: _omitted, ...markerWithoutSchema } = expected; - assert.equal(isDevelopmentRuntimeCurrent(markerWithoutSchema, expected), false); - assert.equal(isDevelopmentRuntimeCurrent(null, expected), false); -}); - -test('the marker this build writes is the marker the cache check accepts', () => { - // Writer and checker are separate code paths. A field renamed on one side - // alone would silently rebuild — and re-sign — on every single launch, - // churning the bundle the TCC grant is anchored to. - assert.equal( - isDevelopmentRuntimeCurrent(createRuntimeMarker('43.1.1'), createRuntimeMarker('43.1.1')), - true, - ); - assert.equal( - isDevelopmentRuntimeCurrent(createRuntimeMarker('43.1.1'), createRuntimeMarker('44.0.0')), - false, - ); - // Ad-hoc signatures designate a bare cdhash and TCC keys its rows on the - // identifier, so a shared identifier would make worktrees overwrite each - // other's grant. - assert.match(createRuntimeMarker('43.1.1').bundleId, /^com\.maka\.dev\.[0-9a-f]{12}$/); -}); - -test('does not commit a cache marker when runtime preparation fails', async () => { - const steps = []; - await assert.rejects( - rebuildDevelopmentRuntime({ - reset: () => steps.push('reset'), - build: () => { - steps.push('build'); - throw new Error('codesign failed'); - }, - writeMarker: () => steps.push('marker'), - }), - /codesign failed/, - ); - assert.deepEqual(steps, ['reset', 'build']); -}); - -test('shutdown targets this worktree bundle and escalates after a grace period', async () => { - const signals = []; - const delays = []; - const stopped = await quitMacosDevelopmentApp({ - platform: 'darwin', - executable: '/repo-a/.maka-dev/Maka Dev.app/Contents/MacOS/Electron', - graceMs: 3_000, - delay: (ms) => { - delays.push(ms); - return Promise.resolve(); - }, - signal: (name, executable) => { - signals.push([name, executable]); - return true; - }, - }); - assert.equal(stopped, true); - // Matching the worktree's own bundle path is what keeps a concurrent - // worktree's app untouched without tracking pids. - assert.deepEqual(signals, [ - ['TERM', '/repo-a/.maka-dev/Maka Dev.app/Contents/MacOS/Electron'], - ['KILL', '/repo-a/.maka-dev/Maka Dev.app/Contents/MacOS/Electron'], - ]); - assert.deepEqual(delays, [3_000]); -}); - -test('shutdown is inert when nothing matches or the platform differs', async () => { - const attempted = []; - assert.equal( - await quitMacosDevelopmentApp({ - platform: 'darwin', - signal: (name) => { - attempted.push(name); - return false; - }, - }), - false, - ); - assert.deepEqual(attempted, ['TERM'], 'a missed TERM must not escalate to KILL'); - assert.equal( - await quitMacosDevelopmentApp({ - platform: 'linux', - signal: () => assert.fail('must not signal off darwin'), - }), - false, - ); -}); - -test('escapes regex metacharacters so a path is matched literally', () => { - // pkill/pgrep -f take an extended regex. A repo under "~/Dropbox (Personal)" - // would otherwise match nothing, leaving the app impossible to stop. - assert.equal( - toProcessMatchPattern('/Users/x/Dropbox (Personal)/Maka Dev.app/Contents/MacOS/Electron'), - '/Users/x/Dropbox \\(Personal\\)/Maka Dev\\.app/Contents/MacOS/Electron', - ); - assert.equal(toProcessMatchPattern('/a[b]/c+d'), '/a\\[b\\]/c\\+d'); -}); - -test('the real probe survives a hostile bundle path', { skip: process.platform !== 'darwin' }, () => { - // Against the actual matcher, not a copy of the escaping regex: unescaped, - // the unbalanced '[' makes pgrep exit 2, which the probe turns into a throw. - assert.equal( - isDevelopmentAppRunning({ - executable: '/Users/x/Dropbox (Personal)/a[b/Maka Dev.app/Contents/MacOS/Electron', - }), - false, - ); - // Real pgrep against the real default executable path. - assert.equal(typeof isDevelopmentAppRunning({}), 'boolean'); -}); - -test('defaults target this worktree bundle executable', () => { - // Every other quit/liveness test injects around the real wiring; this one - // pins that the un-injected default is the bundle path we mean to match. - const expected = join(developmentAppPath, 'Contents', 'MacOS', 'Electron'); - let seen; - isDevelopmentAppRunning({ - probe: (path) => { - seen = path; - return false; - }, - }); - assert.equal(seen, expected); - let signalled; - return quitMacosDevelopmentApp({ - platform: 'darwin', - delay: () => Promise.resolve(), - signal: (_name, path) => { - signalled = path; - return false; - }, - }).then(() => { - assert.equal(signalled, expected); - }); -}); - -test('separates --user-data-dir from switches forwarded to Electron', () => { - assert.deepEqual(splitDevelopmentCliArgs(['--user-data-dir=/x', '--enable-logging']), { - userDataDir: '/x', - electronArgs: ['--enable-logging'], - }); - assert.deepEqual(splitDevelopmentCliArgs([]), { userDataDir: undefined, electronArgs: [] }); - assert.equal(splitDevelopmentCliArgs(['--user-data-dir=']).userDataDir, ''); -}); - -test('claims the app instance before launching or rebuilding', async () => { - // A leftover app would absorb the new launch via the single-instance lock, - // leaving the OLD window in front while liveness still reports success. - let alive = true; - const quits = []; - assert.equal( - await ensureNoRunningDevelopmentApp({ - isRunning: () => alive, - quit: () => { - quits.push('quit'); - alive = false; - return Promise.resolve(true); - }, - delay: () => Promise.resolve(), - }), - true, - ); - assert.deepEqual(quits, ['quit']); - // Nothing running: no quit attempt at all. - assert.equal( - await ensureNoRunningDevelopmentApp({ - isRunning: () => false, - quit: () => assert.fail('must not quit when nothing is running'), - }), - false, - ); - // Refuses to proceed rather than launching into a doomed single-instance lock. - await assert.rejects( - ensureNoRunningDevelopmentApp({ - isRunning: () => true, - quit: () => Promise.resolve(true), - delay: () => Promise.resolve(), - attempts: 2, - }), - /still running and could not be stopped/, - ); -}); - -test('liveness and shutdown compose through their own option shapes', async () => { - // One options object reaches two callees that accept different keys. Stubbing - // only the probe must not leave a real pkill wired up underneath, and the - // poll delay must not double as the SIGTERM grace period. - const executable = '/repo-a/.maka-dev/Maka Dev.app/Contents/MacOS/Electron'; - const probed = []; - const signals = []; - let alive = true; - assert.equal( - await ensureNoRunningDevelopmentApp({ - platform: 'darwin', - executable, - graceMs: 0, - probe: (path) => { - probed.push(path); - return alive; - }, - signal: (name, path) => { - signals.push([name, path]); - alive = false; - return true; - }, - delay: () => Promise.resolve(), - }), - true, - ); - assert.deepEqual([...new Set(probed)], [executable]); - assert.deepEqual(signals, [ - ['TERM', executable], - ['KILL', executable], - ]); - - // Pin what each callee is handed, not just the resulting behaviour: passing - // the whole object through happens to produce the same signals here, so only - // the forwarded shape itself can catch the regression. - let forwardedToQuit; - let running = true; - await ensureNoRunningDevelopmentApp({ - platform: 'darwin', - executable, - graceMs: 7, - isRunning: () => running, - delay: () => Promise.resolve(), - quit: (received) => { - forwardedToQuit = received; - running = false; - return Promise.resolve(true); - }, - }); - assert.deepEqual(Object.keys(forwardedToQuit).sort(), [ - 'executable', - 'graceMs', - 'platform', - 'signal', - ]); - assert.equal(forwardedToQuit.graceMs, 7); -}); - -test('distinguishes a failed launch, a slow launch, and an ordinary quit', async () => { - const delay = () => Promise.resolve(); - // `open` exits 0 at the handoff, so never appearing is the only real failure. - assert.equal( - await monitorDevelopmentApp({ isRunning: () => false, delay, startupAttempts: 3 }), - 'never-started', - ); - // A first launch of the freshly signed bundle is slow; it must be waited for - // rather than reported as a failure and killed by the shutdown that follows. - let attempts = 0; - assert.equal( - await monitorDevelopmentApp({ - isRunning: () => (attempts += 1) > 5, - delay, - startupAttempts: 20, - stopped: () => attempts > 6, - }), - 'stopped', - ); - // Appeared, then quit: an ordinary session end at any moment, not a failure. - let remaining = 3; - assert.equal( - await monitorDevelopmentApp({ isRunning: () => (remaining -= 1) > 0, delay }), - 'exited', - ); - assert.equal( - await monitorDevelopmentApp({ isRunning: () => true, delay, stopped: () => true }), - 'stopped', - ); -}); diff --git a/apps/desktop/src/main/__tests__/client-settings-tools.test.ts b/apps/desktop/src/main/__tests__/client-settings-tools.test.ts deleted file mode 100644 index bb3e428377..0000000000 --- a/apps/desktop/src/main/__tests__/client-settings-tools.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import assert from 'node:assert/strict'; -import { test } from 'node:test'; -import { createDefaultSettings, mergeSettings } from '@maka/core/settings'; -import { buildClientSettingsTools } from '../client-settings-tools.js'; - -test('the bound client confirms and applies only UI and operating-system settings', async () => { - let settings = createDefaultSettings(); - let proposed: readonly string[] = []; - const tools = buildClientSettingsTools({ - read: async () => settings, - update: async (patch) => { - settings = mergeSettings(settings, patch); - return settings; - }, - confirm: async (changes) => { - proposed = changes; - return true; - }, - }); - const update = tools.find(({ name }) => name === 'MakaClientSettingsUpdate'); - assert.ok(update); - - const result = await update.impl( - { - appearance: { theme: 'dark' }, - uiLocale: 'en', - system: { keepSystemAwake: true }, - }, - {} as never, - ); - - assert.deepEqual(proposed, [ - 'Theme: auto → dark', - 'UI language: auto → en', - 'Keep system awake: false → true', - ]); - assert.equal((result as { applied: boolean }).applied, true); - assert.equal(settings.appearance.theme, 'dark'); - assert.equal(settings.personalization.uiLocale, 'en'); - assert.equal(settings.system.keepSystemAwake, true); -}); diff --git a/apps/desktop/src/main/__tests__/runtime-host-desktop-candidate-dependency.test.ts b/apps/desktop/src/main/__tests__/runtime-host-desktop-candidate-dependency.test.ts deleted file mode 100644 index f468c057d1..0000000000 --- a/apps/desktop/src/main/__tests__/runtime-host-desktop-candidate-dependency.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import assert from 'node:assert/strict'; -import { basename, dirname, join, resolve } from 'node:path'; -import test from 'node:test'; -import { build } from 'esbuild'; - -const workingDirectory = process.cwd(); -const repositoryRoot = - basename(workingDirectory) === 'desktop' && basename(dirname(workingDirectory)) === 'apps' - ? resolve(workingDirectory, '..', '..') - : workingDirectory; -const candidateEntrypoint = join( - repositoryRoot, - 'apps', - 'desktop', - 'src', - 'main', - 'runtime-host-desktop-candidate.ts', -); - -test('the Desktop Host candidate stays on the Runtime Host client boundary', async () => { - const result = await build({ - absWorkingDir: repositoryRoot, - entryPoints: [candidateEntrypoint], - bundle: true, - format: 'esm', - metafile: true, - packages: 'external', - platform: 'node', - write: false, - }); - assert.ok(result.metafile); - - const externalImports = Object.values(result.metafile.inputs).flatMap(({ imports }) => - imports.filter(({ external }) => external).map(({ path }) => path), - ); - assert.deepEqual( - externalImports.filter( - (path) => - path === '@maka/runtime' || - path.startsWith('@maka/runtime/') || - path === '@maka/storage' || - path.startsWith('@maka/storage/'), - ), - [], - ); -}); diff --git a/apps/desktop/src/main/__tests__/runtime-host-project-catalog.test.ts b/apps/desktop/src/main/__tests__/runtime-host-project-catalog.test.ts deleted file mode 100644 index 5ba0bb564f..0000000000 --- a/apps/desktop/src/main/__tests__/runtime-host-project-catalog.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import assert from 'node:assert/strict'; -import { test } from 'node:test'; -import { createRuntimeHostProjectCatalog } from '../runtime-host-project-catalog.js'; - -test('reads every Project location through one stable Host catalog view', async () => { - const project = { - id: 'project-1', - aliases: [], - name: 'Project', - locationCount: 2, - archivedAt: null, - available: true, - locations: [ - { path: '/workspace/project', isWorktree: false }, - { path: '/workspace/worktree', isWorktree: true }, - ], - preferredPath: '/workspace/project', - } as const; - let listCalls = 0; - const catalog = createRuntimeHostProjectCatalog(() => - ({ - listProjects: async () => { - listCalls += 1; - return [project]; - }, - registerProject: async () => project, - }) as never, - ); - - const expected = { - id: 'project-1', - name: 'Project', - locations: [ - { path: '/workspace/project', isWorktree: false }, - { path: '/workspace/worktree', isWorktree: true }, - ], - preferredPath: '/workspace/project', - available: true, - }; - assert.deepEqual(await catalog.list(), [expected]); - assert.equal(listCalls, 1); - assert.deepEqual(await catalog.register('/workspace/project'), expected); - assert.equal(listCalls, 2); -}); diff --git a/apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts b/apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts deleted file mode 100644 index 70e511bf14..0000000000 --- a/apps/desktop/src/main/__tests__/runtime-host-settings-ipc-main.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import assert from 'node:assert/strict'; -import { mkdtemp, rm } from 'node:fs/promises'; -import { tmpdir } from 'node:os'; -import { join } from 'node:path'; -import test from 'node:test'; -import { createDefaultRuntimePolicy } from '@maka/core/runtime-policy'; -import { createSettingsStore } from '@maka/storage'; -import { - updateRuntimeHostSettings, - type RuntimeHostSettingsIpcDeps, -} from '../runtime-host-settings-ipc-main.js'; - -test('persists a project-only patch in the client-owned settings document', async () => { - const root = await mkdtemp(join(tmpdir(), 'maka-runtime-host-settings-')); - try { - const settingsStore = createSettingsStore(root); - const client = { - queryRuntimePolicy: async () => ({ revision: 0, policy: createDefaultRuntimePolicy() }), - queryCredential: async () => null, - deleteCredential: async () => { throw new Error('not used'); }, - setCredential: async () => { throw new Error('not used'); }, - testNetworkProxy: async () => { throw new Error('not used'); }, - updateRuntimePolicy: async () => { throw new Error('not used'); }, - } satisfies RuntimeHostSettingsIpcDeps['client']; - let appliedProjectId: string | undefined; - - const result = await updateRuntimeHostSettings( - { - ipcMain: { handle() {} }, - client, - settingsStore, - applyClientSettings: async (settings) => { - appliedProjectId = settings.projects.defaultProjectId; - }, - }, - { projects: { defaultProjectId: 'project-1' } }, - ); - - assert.equal(result.projects.defaultProjectId, 'project-1'); - assert.equal((await settingsStore.get()).projects.defaultProjectId, 'project-1'); - assert.equal(appliedProjectId, 'project-1'); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); diff --git a/apps/desktop/src/main/__tests__/skill-invocation-feedback.test.ts b/apps/desktop/src/main/__tests__/skill-invocation-feedback.test.ts deleted file mode 100644 index 2ff08ab67a..0000000000 --- a/apps/desktop/src/main/__tests__/skill-invocation-feedback.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { strict as assert } from 'node:assert'; -import { describe, it } from 'node:test'; -import { - showSkillInvocationFeedback, -} from '../../renderer/skill-invocation-feedback.js'; - -describe('Desktop Skill invocation feedback', () => { - it('renders request overflow as an aggregate failure without a synthetic Skill id', () => { - const errors: Array<{ title: string; description?: string }> = []; - showSkillInvocationFeedback( - 'en', - { - error: (title, description) => errors.push({ title, description }), - info: () => { - throw new Error('overflow must block rather than report partial success'); - }, - }, - { - loaded: [], - failed: [{ reason: 'too_many_requests', requestLimit: 50 }], - receipts: [ - { - invocation: 'explicit', - success: false, - reason: 'too_many_requests', - requestLimit: 50, - }, - ], - }, - ); - - assert.deepEqual(errors, [ - { - title: 'Skill invocation failed; message not sent', - description: - 'more than 50 distinct Skill invocation requests. Adjust the selection and try again.', - }, - ]); - assert.doesNotMatch(errors[0]?.description ?? '', /\/skill:/); - }); -}); diff --git a/apps/desktop/src/main/__tests__/workspace-readiness-recovery.test.ts b/apps/desktop/src/main/__tests__/workspace-readiness-recovery.test.ts deleted file mode 100644 index ed8a336d3d..0000000000 --- a/apps/desktop/src/main/__tests__/workspace-readiness-recovery.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import type { OnboardingState } from '@maka/core'; -import { deriveWorkspaceReadinessRecovery } from '../../renderer/workspace-readiness-recovery.js'; - -function derive(state: OnboardingState | undefined, overrides = {}) { - return deriveWorkspaceReadinessRecovery({ - state, - locale: 'zh', - activeSessionId: undefined, - showOnboardingHero: false, - ...overrides, - }); -} - -test('does not duplicate ready, onboarding, or active-session surfaces', () => { - assert.equal(derive(undefined), undefined); - assert.equal( - derive({ kind: 'ready_empty', connectionSlug: 'opencode-free', model: 'big-pickle' }), - undefined, - ); - assert.equal(derive({ kind: 'needs_connection' }, { showOnboardingHero: true }), undefined); - assert.equal(derive({ kind: 'needs_connection' }, { activeSessionId: 'session-1' }), undefined); -}); - -test('routes a missing model back to the affected connection', () => { - const recovery = derive({ kind: 'needs_model', connectionSlug: 'opencode-free' }); - - assert.equal(recovery?.tone, 'warning'); - assert.deepEqual(recovery?.target, { - kind: 'connection', - connectionSlug: 'opencode-free', - }); - assert.ok(recovery?.title); - assert.ok(recovery?.description); - assert.ok(recovery?.actionLabel); -}); - -test('routes an unhealthy workspace to model settings as a hard block', () => { - const recovery = derive({ kind: 'blocked', reason: 'all_connections_unhealthy' }); - - assert.equal(recovery?.tone, 'destructive'); - assert.deepEqual(recovery?.target, { kind: 'models' }); -}); diff --git a/package.json b/package.json index c8cef5ce59..0ef6d5c90d 100644 --- a/package.json +++ b/package.json @@ -27,14 +27,12 @@ "format": "biome format --write .", "format:check": "biome format .", "typecheck": "npm run typecheck --workspaces --if-present", - "test": "npm run build:test && npm run test:scripts && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", - "test:full": "npm run build:test && npm run test:scripts:full && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", - "test:dist": "npm run test:scripts:full && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", - "test:dist:serial": "npm run test:scripts:full && node scripts/run-workspace-tests-parallel.mjs --serial", - "test:fast": "npm run build:test && npm run test:scripts && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", - "test:scripts": "node --test scripts/electron-builder-config.test.mjs scripts/electron-lifecycle.test.mjs scripts/cu-e2e-scenarios.test.mjs scripts/prepare-maka-cu-provenance.test.mjs scripts/bundled-skill-catalog.test.mjs apps/desktop/scripts/dev-app-runtime.test.mjs", + "test": "npm run build:test && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", + "test:full": "npm run build:test && npm run test:scripts:extended && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", + "test:dist": "npm run test:scripts:extended && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", + "test:dist:serial": "npm run test:scripts:extended && node scripts/run-workspace-tests-parallel.mjs --serial", + "test:fast": "npm run build:test && node scripts/run-workspace-tests-parallel.mjs --concurrency=3", "test:scripts:extended": "node --test scripts/macos-arm64-release.test.mjs scripts/windows-x64-release.test.mjs", - "test:scripts:full": "npm run test:scripts && npm run test:scripts:extended", "dev": "npm --workspace @maka/desktop run dev:hmr --", "dev:full": "npm run build && npm --workspace @maka/desktop run start", "build": "npm --workspace @maka/code-mode run build && npm --workspace @maka/core run build && npm --workspace @maka/storage run build && npm --workspace @maka/mcp run build && npm --workspace @maka/runtime run build && npm --workspace @maka/runtime-host run build && npm --workspace @maka/computer-use run build && npm --workspace @maka/eval run build && npm --workspace maka-agent run build && npm --workspace @maka/ui run build && npm --workspace @maka/desktop run build", diff --git a/packages/storage/src/__tests__/package-import.test.ts b/packages/storage/src/__tests__/package-import.test.ts deleted file mode 100644 index d47f130bb6..0000000000 --- a/packages/storage/src/__tests__/package-import.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import assert from 'node:assert/strict'; -import { spawnSync } from 'node:child_process'; -import { test } from 'node:test'; - -test('top-level package import does not initialize node:sqlite', () => { - const packageEntry = new URL('../index.js', import.meta.url).href; - const result = spawnSync( - process.execPath, - ['--input-type=module', '--eval', `await import(${JSON.stringify(packageEntry)})`], - { encoding: 'utf8' }, - ); - - assert.equal(result.status, 0, result.stderr); - assert.equal(result.stderr, ''); -}); diff --git a/scripts/bundled-skill-catalog.test.mjs b/scripts/bundled-skill-catalog.test.mjs deleted file mode 100644 index e595eaca35..0000000000 --- a/scripts/bundled-skill-catalog.test.mjs +++ /dev/null @@ -1,9 +0,0 @@ -import { execFile } from 'node:child_process'; -import { promisify } from 'node:util'; -import test from 'node:test'; - -const execFileAsync = promisify(execFile); - -test('the generated Runtime Skill catalog matches its reviewable sources', async () => { - await execFileAsync(process.execPath, ['scripts/gen-bundled-skill-catalog.mjs', '--check']); -}); diff --git a/scripts/ci-test-plan.mjs b/scripts/ci-test-plan.mjs index f580b3319b..99b9a7d19d 100644 --- a/scripts/ci-test-plan.mjs +++ b/scripts/ci-test-plan.mjs @@ -230,7 +230,7 @@ export function planTests(changedFiles, options = {}) { e2e: true, full: true, runtimeSandbox: graph.dirs.includes('packages/cli'), - scriptMode: 'full', + scriptMode: 'extended', // A complete functional suite is still the default release/main gate. // Stress multipliers and native child-process lock probes run only when // their owning storage seam changes; making --full imply stress turned @@ -261,7 +261,7 @@ export function planTests(changedFiles, options = {}) { if (RELEASE_CONFIG_FILES.has(path)) { code = true; directWorkspaces.add('apps/desktop'); - if (scriptMode === 'none') scriptMode = 'fast'; + scriptMode = 'extended'; continue; } const workspace = graph.dirs.find((dir) => path === dir || path.startsWith(`${dir}/`)); @@ -272,11 +272,7 @@ export function planTests(changedFiles, options = {}) { } if (path.startsWith('scripts/')) { code = true; - scriptMode = EXTENDED_SCRIPT_FILES.has(path) - ? 'extended' - : scriptMode === 'none' - ? 'fast' - : scriptMode; + if (EXTENDED_SCRIPT_FILES.has(path)) scriptMode = 'extended'; continue; } if (path.startsWith('skills/')) { diff --git a/scripts/cu-e2e-scenarios.test.mjs b/scripts/cu-e2e-scenarios.test.mjs deleted file mode 100644 index 9f1d6e18b0..0000000000 --- a/scripts/cu-e2e-scenarios.test.mjs +++ /dev/null @@ -1,38 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; - -import { getCuE2eScenario, validateCuE2eScenario } from './cu-e2e-scenarios.mjs'; - -test('validation rejects unsafe action, matcher, budget, and expected-failure declarations', () => { - const base = structuredClone(getCuE2eScenario('l1-single-click')); - const invalid = [ - [{ ...base, allowedActions: ['screenshot', 'shell'] }, /unknown action/], - [{ ...base, forbiddenEffects: [] }, /forbiddenEffects must be non-empty/], - [ - { - ...base, - expectedState: [{ ...base.expectedState[0], greaterThan: 0 }], - }, - /exactly one matcher/, - ], - [ - { - ...base, - minimumActionCounts: { observe: 3 }, - maxActionCounts: { observe: 2 }, - }, - /minimum exceeds maximum/, - ], - [ - { - ...base, - expectedFailures: [{ action: 'left_click', error: 'stale_frame' }], - }, - /allowed action and error pairs/, - ], - ]; - - for (const [scenario, pattern] of invalid) { - assert.throws(() => validateCuE2eScenario(scenario), pattern); - } -}); diff --git a/scripts/electron-builder-config.test.mjs b/scripts/electron-builder-config.test.mjs deleted file mode 100644 index 5f52e9b96e..0000000000 --- a/scripts/electron-builder-config.test.mjs +++ /dev/null @@ -1,36 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; - -// electron-builder rejects an unknown option outright (its schema sets -// `additionalProperties: false`), and the release workflow is the only thing -// that ever loads this config — so a misspelled or removed option is invisible -// until release day, on both platforms at once, because macOS and Windows share -// one config object. This asserts the config against electron-builder's own -// validator rather than restating its rules. If a future electron-builder moves -// this module, update the path here; the version is pinned in package.json. -const { validateConfiguration } = await import( - new URL('../node_modules/app-builder-lib/out/util/config/config.js', import.meta.url) -); - -// `validateConfiguration` only reads the config, so it is passed as loaded — a -// structured clone would throw on the function hooks electron-builder configs -// are allowed to carry, turning a valid config into a failing test. -const loadConfig = async () => - (await import(new URL('../apps/desktop/electron-builder.config.mjs', import.meta.url))).default; - -test('the desktop release config is valid for the installed electron-builder', async () => { - await validateConfiguration(await loadConfig(), { add: () => {} }); -}); - -test('an unknown release option is rejected rather than ignored', async () => { - const config = await loadConfig(); - - // electron-builder 26.15 flattens ajv oneOf errors, so the message no - // longer names the offending property — it reports the enclosing path - // ("configuration.win should be one of these"). The contract that still - // matters is that an unknown option rejects at all. - await assert.rejects( - validateConfiguration({ ...config, win: { ...config.win, sign: false } }, { add: () => {} }), - /(?:Error: )?Invalid configuration object\. electron-builder \d+\.\d+\.\d+ has been initialized using a configuration object that does not match the API schema\.\n - configuration\.win/, - ); -}); diff --git a/scripts/electron-lifecycle.test.mjs b/scripts/electron-lifecycle.test.mjs deleted file mode 100644 index 8e31ddfd54..0000000000 --- a/scripts/electron-lifecycle.test.mjs +++ /dev/null @@ -1,86 +0,0 @@ -import { strict as assert } from 'node:assert'; -import { EventEmitter } from 'node:events'; -import { describe, it } from 'node:test'; -import { closeElectronApplication } from './electron-lifecycle.mjs'; - -// Bounded teardown is harness behavior, not product behavior: it drives a fake -// process handle and never launches Electron. It lives here beside -// fixture-window.test.mjs rather than in the Playwright suite, which would pay -// a real Electron boot slot to run assertions that need none. - -class FakeElectronProcess extends EventEmitter { - exitCode = null; - signalCode = null; - killedWith = undefined; - - kill(signal) { - this.killedWith = signal; - queueMicrotask(() => { - this.signalCode = signal; - this.emit('exit'); - }); - return true; - } -} - -/** An app whose graceful close never settles, so every test exercises the deadline. */ -function wedgedApp(child) { - return { - close: () => new Promise(() => {}), - process: () => child, - }; -} - -describe('closeElectronApplication', () => { - it('treats an already-disconnected Electron application as closed', async () => { - let closeCalled = false; - await closeElectronApplication( - { - close: async () => { - closeCalled = true; - }, - process: () => { - throw new TypeError('application process channel is closed'); - }, - }, - 10, - ); - - assert.equal(closeCalled, true); - }); - - it('force-kills Electron when graceful teardown does not settle', async () => { - const child = new FakeElectronProcess(); - let terminatedTree = false; - - const settled = await Promise.race([ - closeElectronApplication(wedgedApp(child), 0, async (target, signal) => { - assert.equal(target, child); - assert.equal(signal, 'SIGKILL'); - terminatedTree = true; - child.signalCode = signal; - child.emit('exit'); - return true; - }).then(() => true), - new Promise((resolve) => setTimeout(() => resolve(false), 25)), - ]); - - assert.equal(settled, true); - assert.equal(terminatedTree, true); - assert.equal(child.killedWith, undefined); - }); - - it('falls back to a direct SIGKILL when the group kill misses the root', async () => { - // The tree terminator signals the child's process group; on a child that is - // not a group leader the group signal reports ESRCH and the terminator - // returns as if the tree were gone while the root lives on. The bounded - // close must then land a kill on the root itself — measured for real with - // the smoke gate's visible window, which also ignores SIGTERM. - const child = new FakeElectronProcess(); - - await closeElectronApplication(wedgedApp(child), 0, async () => true); - - assert.equal(child.killedWith, 'SIGKILL'); - assert.equal(child.signalCode, 'SIGKILL'); - }); -}); diff --git a/scripts/prepare-maka-cu-provenance.test.mjs b/scripts/prepare-maka-cu-provenance.test.mjs deleted file mode 100644 index 7f9c87f6a4..0000000000 --- a/scripts/prepare-maka-cu-provenance.test.mjs +++ /dev/null @@ -1,54 +0,0 @@ -import assert from 'node:assert/strict'; -import { test } from 'node:test'; - -import { resolveMakaCuSourceBranch } from './prepare-maka-cu-provenance.mjs'; - -test('an attached source branch is recorded directly', () => { - assert.equal( - resolveMakaCuSourceBranch({ - currentBranch: 'codex/webcontent-native-actions', - remoteBranches: ['origin/maka/base'], - }), - 'codex/webcontent-native-actions', - ); -}); - -test('a detached source commit records its one matching remote branch', () => { - assert.equal( - resolveMakaCuSourceBranch({ - currentBranch: 'HEAD', - remoteBranches: ['origin', 'origin/HEAD', 'origin/maka/base'], - }), - 'maka/base', - ); -}); - -test('an explicit source branch overrides detached ambiguity', () => { - assert.equal( - resolveMakaCuSourceBranch({ - currentBranch: 'HEAD', - remoteBranches: ['origin/maka/base', 'fork/release'], - explicitBranch: 'maka/base', - }), - 'maka/base', - ); -}); - -test('a detached source commit fails closed without a unique branch', () => { - assert.throws( - () => - resolveMakaCuSourceBranch({ - currentBranch: 'HEAD', - remoteBranches: [], - }), - /no matching remote branch/, - ); - assert.throws( - () => - resolveMakaCuSourceBranch({ - currentBranch: 'HEAD', - remoteBranches: ['origin/maka/base', 'fork/release'], - }), - /multiple remote branches/, - ); -});