Files
openchamber/packages/electron/scripts/verify-update-manifest.test.mjs
T
502c96630e feat(desktop): Linux AppImage polish — window controls, updater UX, docs (#2144)
* feat(electron): add Linux AppImage releases

* ci: cache Linux OpenCode CLI artifacts

* fix(ci): await Linux release inventory check

* fix(electron): add frameless window controls on Linux desktop

Linux AppImages were created without native WM decorations and without
in-app controls, leaving users unable to close the window with a mouse.

Treat Linux like Windows: frameless BrowserWindow plus the existing
WindowsWindowControls header buttons and app-menu entry. macOS keeps
hidden title bar with traffic lights unchanged.

Shared usesFramelessElectronChrome() helper drives main window, mini
chat, header insets, and titlebar controls.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* feat(desktop): add configurable window controls position by OS

Add desktopWindowControlsPosition setting (auto/left/right) with OS-aware
defaults: Linux left, Windows right. Wire frameless chrome controls in
Header, TitlebarLeftControls, and MiniChatLayout, plus a Sessions settings
control for Windows and Linux desktop shells.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* fix(desktop): address Linux AppImage release review findings

Propagate updater capability errors to the UI, treat missing
latest-linux.yml feeds as no-update, stop installed-apps IPC spam on
Linux, document FUSE/AppImage limits, add CHANGELOG entry, migrate
remaining btriapitsyn URLs, and run Electron Linux unit tests on PRs.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

---------

Co-authored-by: jibanez-staticduo <staticduo@gmail.com>
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-07-13 08:59:31 +03:00

75 lines
2.7 KiB
JavaScript

import assert from 'node:assert/strict';
import crypto from 'node:crypto';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import test from 'node:test';
import { verifyUpdateManifest } from './verify-update-manifest.mjs';
const fixture = (manifestName, artifactName, fields) => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-manifest-test-'));
const artifactPath = path.join(root, artifactName);
const manifestPath = path.join(root, manifestName);
const bytes = Buffer.from(`artifact:${artifactName}`);
fs.writeFileSync(artifactPath, bytes);
fs.writeFileSync(manifestPath, [
'version: 1.15.0',
'files:',
...(fields || [
` - url: ${artifactName}`,
` sha512: ${crypto.createHash('sha512').update(bytes).digest('base64')}`,
` size: ${bytes.length}`,
]),
`path: ${artifactName}`,
'releaseDate: 2026-07-10T00:00:00.000Z',
'',
].join('\n'));
return { root, artifactPath, manifestPath };
};
for (const [manifestName, artifactName] of [
['latest-linux.yml', 'OpenChamber-1.15.0-linux-x86_64.AppImage'],
['latest-linux-arm64.yml', 'OpenChamber-1.15.0-linux-arm64.AppImage'],
]) {
test(`validates architecture-specific ${manifestName}`, () => {
const value = fixture(manifestName, artifactName);
try {
assert.equal(verifyUpdateManifest({ ...value, expectedVersion: '1.15.0' }).name, artifactName);
} finally {
fs.rmSync(value.root, { recursive: true, force: true });
}
});
}
test('accepts electron-builder field ordering and optional blockMapSize', () => {
const artifactName = 'OpenChamber-1.15.0-linux-x86_64.AppImage';
const bytes = Buffer.from(`artifact:${artifactName}`);
const value = fixture('latest-linux.yml', artifactName, [
` - sha512: ${crypto.createHash('sha512').update(bytes).digest('base64')}`,
` size: ${bytes.length}`,
' blockMapSize: 1234',
` url: ${artifactName}`,
]);
try {
assert.equal(verifyUpdateManifest({ ...value, expectedVersion: '1.15.0' }).name, artifactName);
} finally {
fs.rmSync(value.root, { recursive: true, force: true });
}
});
test('rejects a manifest that points at the other architecture artifact', () => {
const value = fixture('latest-linux-arm64.yml', 'OpenChamber-1.15.0-linux-arm64.AppImage');
try {
const x64Artifact = path.join(value.root, 'OpenChamber-1.15.0-linux-x86_64.AppImage');
fs.copyFileSync(value.artifactPath, x64Artifact);
assert.throws(() => verifyUpdateManifest({
manifestPath: value.manifestPath,
artifactPath: x64Artifact,
expectedVersion: '1.15.0',
}), /artifact mismatch/);
} finally {
fs.rmSync(value.root, { recursive: true, force: true });
}
});