Files
OpenTerminal/tests/build-bundles.cjs
Bill 2653ab1820 feat(i18n): tab auto titles follow the UI language
Titles are stored display text (layout templates, session snapshot,
broadcast registry), so a pane used to keep the wording of the language it
was opened in, and nextTerminalTitle could not even parse the number back
out of another language's pattern (numbering restarted, duplicates).

New pure module src/shared/terminalTitle.ts: resolution tries all four
languages' patterns, rendering uses the active one; i18n gains tFor(lang)
for off-language rendering. Workspace retitles auto-numbered local tabs in
place on language switch, snapshot restore and template apply; SSH panels
(user-typed connection names) are never touched. dockview's title-change
event propagates the new title to the broadcast registry and the snapshot
save with no extra wiring.

New test terminal-title.mjs (16 writer/reader language pairs, non-auto
title boundaries, gap filling); offline suite grows 17 -> 18.
2026-10-08 00:11:20 +08:00

92 lines
4.9 KiB
JavaScript

/* Rebuild every esbuild bundle the tests load, so a test run can never exercise
a stale bundle. `npm test` calls this first; run it standalone when you only
want fresh bundles.
The aliases live here (and nowhere else) so every bundle resolves `electron`
and `@shared` the same way. A bundle built without
`--alias:@shared=./src/shared` does not even compile: pty.ts reaches
@shared/theme through settingsStore.ts -> windowChrome.ts.
Usage: node tests/build-bundles.cjs */
const path = require('node:path')
const esbuild = require('esbuild')
const ROOT = path.join(__dirname, '..')
/** Loader tweaks every bundle shares: `?asset` imports land on text loaders. */
const LOADERS = { '.png': 'text' }
const BUNDLES = [
// Real session layer: pty.ts also re-exports the ssh + sysinfo engines.
{ entry: 'src/main/pty.ts', out: 'tests/.session-e2e.cjs', external: ['@lydell/node-pty', 'ssh2'] },
// The real SSH service on its own (no electron surface at all), so the
// loopback harness can exercise the shipped connect/verify/shell code
// instead of a hand-copied ConnectConfig.
{ entry: 'src/main/ssh.ts', out: 'tests/.ssh.cjs', external: ['ssh2'] },
// ESM (`.mjs`): tests/sftp-*.mjs load it with `await import()`.
{ entry: 'src/main/sftp.ts', out: 'tests/.sftp-svc.mjs', format: 'esm', external: ['ssh2'] },
{ entry: 'src/main/commands.ts', out: 'tests/.commands-store.cjs' },
// SSH bookmarks store: CRUD, the public/secret split, corrupt-file backup.
// Its electron surface is `safeStorage` (already in the stub, unavailable ->
// the store's `plain:` dev fallback).
{ entry: 'src/main/connectionsStore.ts', out: 'tests/.connections-store.cjs' },
// Known-hosts store: TOFU / changed / unreadable fail-closed behavior.
{ entry: 'src/main/knownHosts.ts', out: 'tests/.known-hosts.cjs' },
{ entry: 'src/main/settingsStore.ts', out: 'tests/.settings-store.cjs' },
// Local-path admission (grants): pure fs/path, no electron surface at all.
{ entry: 'src/main/localPathGrants.ts', out: 'tests/.local-path-grants.cjs' },
// Lock-password store: scrypt verifier, round trip, damaged-file handling.
{ entry: 'src/main/lockStore.ts', out: 'tests/.lock-store.cjs' },
// Lock controller: cooldown ladder, serialized attempts, persisted flags.
// Pulls in settingsStore + broadcast, which is why the electron stub needs
// powerMonitor as well.
{ entry: 'src/main/lockController.ts', out: 'tests/.lock-controller.cjs' },
// Lock keyboard classifier: pure, so the bundle needs no electron surface.
{ entry: 'src/main/lockShortcuts.ts', out: 'tests/.lock-shortcuts.cjs' },
// Reserved-accelerator table shared by the settings recorder and main's
// registration guard: pure, table-tested.
{ entry: 'src/shared/reservedAccelerators.ts', out: 'tests/.reserved-accelerators.cjs' },
// Auto terminal-tab titles: the pattern table is shared by the renderer's
// numbering and its language-switch retitle pass. Pure + dictionary-only.
{ entry: 'tests/terminal-title.mjs', out: 'tests/.terminal-title.cjs' },
// Update service: feed probe/fallback. `electron-updater` is aliased to a
// stub (the real package boots Electron), and the shell half (tray.ts) pulls
// a `?asset` import, hence LOADERS.
{ entry: 'src/main/updater.ts', out: 'tests/.updater.cjs', alias: { 'electron-updater': './tests/electron-updater-stub.cjs' } },
// IPC sender-frame guard: driven through the real registerIpc registration
// path (the stub records handlers instead of dropping them).
{
entry: 'src/main/ipc.ts',
out: 'tests/.ipc.cjs',
external: ['ssh2', '@lydell/node-pty', 'font-list', 'cpu-features']
},
// Session-log plain-text transformer: ANSI state machine + alt-screen folding.
{ entry: 'src/main/logSanitizer.ts', out: 'tests/.log-sanitizer.cjs' },
// Channel-name constants, so a test can name channels instead of inlining
// string literals that would silently drift from src/shared/ipc.ts.
{ entry: 'src/shared/ipc.ts', out: 'tests/.ipc-channels.cjs' },
// zmodem.js stays bundled (NOT external) — the test drives a second in-process
// Sentry from the same library.
{ entry: 'src/main/zmodem.ts', out: 'tests/.zmodem-e2e.cjs', external: ['ssh2'] },
// The smoke test imports the renderer engine (.ts), so it needs bundling too.
{ entry: 'tests/hl-split-smoke.mjs', out: 'tests/.hl-split-smoke.cjs' },
// Preset-rule assertions (word boundaries, case flag) over the same engine.
{ entry: 'tests/hl-rules.mjs', out: 'tests/.hl-rules.cjs' }
]
for (const { entry, out, format = 'cjs', external = [], alias = {} } of BUNDLES) {
esbuild.buildSync({
absWorkingDir: ROOT,
entryPoints: [path.join(ROOT, entry)],
outfile: path.join(ROOT, out),
bundle: true,
platform: 'node',
format,
external,
loader: LOADERS,
alias: { electron: './tests/electron-stub.cjs', '@shared': './src/shared', ...alias },
logLevel: 'warning'
})
console.log(`built ${out}`)
}