fix(updater): verify native host version and report restart failures

Complete #3227 by keeping browser completion polls on the native updater, checking the requested version, and preserving retry access after a failed restart.
This commit is contained in:
Bohdan Triapitsyn
2026-09-07 20:38:00 +03:00
parent c82aa7879b
commit f9d6b5c479
6 changed files with 229 additions and 85 deletions
@@ -71,6 +71,43 @@ afterEach(() => {
});
describe('OpenChamber desktop host update route', () => {
it('reports a restart rejection until the user retries installation', async () => {
const desktopUpdater = {
check: vi.fn(async () => ({ available: true, currentVersion: '1.17.0', version: '1.17.1' })),
install: vi.fn(async () => ({ available: true, version: '1.17.1' })),
restart: vi.fn().mockRejectedValueOnce(new Error('Signature rejected')).mockResolvedValue(undefined),
};
const { app } = createApp({ environment: { OPENCHAMBER_RUNTIME: 'desktop' }, desktopUpdater });
const logError = vi.spyOn(console, 'error').mockImplementation(() => {});
await request(app).post('/api/openchamber/update-install').expect(200);
await new Promise(resolve => setImmediate(resolve));
await request(app).get('/api/openchamber/update-check?appType=web&reportUsage=false&updateStatus=true').expect(503, {
code: 'DESKTOP_UPDATE_RESTART_FAILED', error: 'Signature rejected',
});
expect(desktopUpdater.check).not.toHaveBeenCalled();
expect(logError).toHaveBeenCalledOnce();
// Availability remains reachable after a browser reload, so users can retry.
await request(app).get('/api/openchamber/update-check?appType=web&reportUsage=false').expect(200);
await request(app).post('/api/openchamber/update-install').expect(200);
await new Promise(resolve => setImmediate(resolve));
const response = await request(app).get('/api/openchamber/update-check?appType=web&reportUsage=false').expect(200);
expect(response.body.currentVersion).toBe('1.17.0');
expect(response.body.updateOwner).toBe('electron-updater');
expect(packageManager.checkForUpdates).not.toHaveBeenCalled();
});
it('rejects native checks without a bridge and preserves explicit non-web checks', async () => {
const { app } = createApp({ environment: { OPENCHAMBER_RUNTIME: 'desktop' } });
await request(app).get('/api/openchamber/update-check?appType=web').expect(503, {
available: false, code: 'DESKTOP_UPDATER_UNAVAILABLE', error: 'The desktop updater is not available.',
});
expect(packageManager.checkForUpdates).not.toHaveBeenCalled();
await request(app).get('/api/openchamber/update-check?appType=desktop-electron').expect(200);
expect(packageManager.checkForUpdates).toHaveBeenCalledOnce();
});
it('uses electron-updater to check for Web client updates', async () => {
const desktopUpdater = {
check: vi.fn(async () => ({