Files
hermes-agent/apps/desktop/scripts/after-pack.test.mjs
Hermes Agent 496367f011 test(desktop): fail the pack when the bundled readiness parser goes stale
afterPack now verifies the packaged dist/electron-main.mjs still carries
the dual-token readiness matcher before any platform work, turning
source/packaged-artifact skew (#60772) into a build failure instead of a
user-side boot loop.

Co-authored-by: embwl0x <embwl0x@users.noreply.github.com>
2026-09-26 20:35:05 -05:00

91 lines
4.1 KiB
JavaScript

import {
assertPackagedBackendReadyArtifact,
assertBackendReadyArtifactSourceAcceptsBothTokens,
resolvePackagedAsarPath
} from './backend-ready-artifact.mjs'
import { mkdtemp, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'
import { createRequire } from 'node:module'
import os from 'node:os'
import path from 'node:path'
import { Platform, PlatformPackager } from 'app-builder-lib'
import { expect, it, vi } from 'vitest'
const require = createRequire(import.meta.url)
const desktopRoot = path.resolve(import.meta.dirname, '..')
// The builder config is electron-builder.config.cjs (package.json carries no `build` block).
const builderConfig = require(path.join(desktopRoot, 'electron-builder.config.cjs'))
async function configuredHook(context) {
const hook = await import(new URL(`../${builderConfig.afterPack}`, import.meta.url).href)
await hook.default(context)
}
// The afterPack readiness guard reads the packaged bundle's unpacked main;
// every fixture here packs a valid dual-token matcher so the tests keep
// exercising the locale/signing paths the hook also performs.
async function seedPackagedMain(context) {
const asarPath = resolvePackagedAsarPath(context)
await mkdir(path.dirname(asarPath), { recursive: true })
await writeFile(asarPath, 'stub archive')
await mkdir(path.join(`${asarPath}.unpacked`, 'dist'), { recursive: true })
await writeFile(
path.join(`${asarPath}.unpacked`, 'dist', 'electron-main.mjs'),
'const re = /HERMES_(?:BACKEND|DASHBOARD)_READY[^\\n]*port=(\\d+)/m\n'
)
}
function context(appOutDir, productFilename = 'Hermes Preview') {
// Use electron-builder's real bundle path resolution, including branding.
const packager = Object.assign(Object.create(PlatformPackager.prototype), {
platform: Platform.MAC,
appInfo: { productFilename },
info: { framework: { distMacOsAppName: 'Electron.app' } }
})
return { appOutDir, electronPlatformName: 'darwin', packager }
}
it('restores app localizations from the filtered framework without copying locale data', async () => {
const root = await mkdtemp(path.join(os.tmpdir(), 'hermes-locale-pack-'))
try {
const ctx = context(root)
await seedPackagedMain(ctx)
const framework = ctx.packager.getMacOsElectronFrameworkResourcesDir(root)
const resources = ctx.packager.getResourcesDir(root)
await mkdir(resources, { recursive: true })
for (const name of ['nb.lproj', 'en_GB.lproj', 'nb_FEMININE.lproj']) {
await mkdir(path.join(framework, name), { recursive: true })
await writeFile(path.join(framework, name, 'locale.pak'), 'untouched locale data')
}
await writeFile(path.join(framework, 'not-a-directory.lproj'), 'not a locale')
await mkdir(path.join(framework, 'other'), { recursive: true })
await configuredHook(ctx)
await configuredHook(ctx)
expect((await readdir(resources)).filter(name => name.endsWith('.lproj')).sort())
.toEqual(['en_GB.lproj', 'nb.lproj'])
expect(await readdir(path.join(resources, 'nb.lproj'))).toEqual([])
expect(await readFile(path.join(framework, 'nb.lproj', 'locale.pak'), 'utf8')).toBe('untouched locale data')
} finally {
await rm(root, { recursive: true, force: true })
}
})
it('leaves Linux alone and reports a missing framework without failing packaging', async () => {
const root = await mkdtemp(path.join(os.tmpdir(), 'hermes-locale-pack-'))
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
try {
// win32 is not a no-op here: the same hook sanitizes and batch-signs the PE tree.
const linuxCtx = { appOutDir: root, electronPlatformName: 'linux' }
await seedPackagedMain(linuxCtx)
await configuredHook(linuxCtx)
expect(warn).not.toHaveBeenCalled()
const ctx = context(root)
await seedPackagedMain(ctx)
await configuredHook(ctx)
expect(warn).toHaveBeenCalledWith(expect.stringContaining('macOS locale markers were not restored'))
expect((await readdir(root)).sort()).toEqual(['Hermes Preview.app', 'resources'])
} finally {
warn.mockRestore()
await rm(root, { recursive: true, force: true })
}
})