Files
johanleroy 9390b62249 fix(desktop): l'app démarre après une mise à jour, et parle quand elle ne peut pas
Installer une nouvelle version remplace les fichiers sur disque mais ne touche
pas le process en cours : l'ancienne instance gardait le port 7317, la version
fraîchement installée mourait sur EADDRINUSE avant son handshake, et le shell se
contentait d'un console.error suivi d'un app.quit(). Depuis le lanceur, cliquer
l'icône ne produisait donc rien du tout.

- Tout échec de démarrage ouvre un dialogue Retry / Show log / Quit
  (start-failure.ts, texte pur et testé) et la sortie du daemon est conservée
  dans <userData>/logs/daemon.log. Une mort du daemon APRÈS le handshake propose
  de le relancer, au lieu de laisser une fenêtre morte à l'écran.
- Le port est diagnostiqué avant le spawn (port-guard.ts, empreinte
  {pid, ownerPid, port}) : un daemon orphelin, dont l'Electron est mort, est
  repris (SIGTERM puis SIGKILL, en attendant un bind réellement possible) ;
  une instance vivante ou un tiers (service, npx) est annoncé avec l'action qui
  débloque, et jamais tué. La reprise exige deux preuves, l'empreinte orpheline
  ET l'identité du process (ps -ww), car un pidfile périmé peut désigner un pid
  recyclé entre-temps par un programme quelconque.
- Une mise à jour installée à chaud est signalée avec « Restart now »
  (upgrade-watch.ts), qui arrête le daemon avant app.relaunch() ; sans quoi le
  lock d'instance unique renvoyait silencieusement sur la fenêtre de l'ancienne
  version, et on croyait avoir migré.
- ARBORETUM_DESKTOP_PORT pour cohabiter avec un Arboretum qui occupe 7317 en
  permanence (service installé, ou daemon lancé en terminal).

24 tests dans packages/desktop/test, et quatre scénarios rejoués en dev sous
xvfb-run avec profil isolé : port tenu par un tiers, orphelin repris puis SPA
servie, instance vivante laissée intacte, pid recyclé épargné.
2026-08-05 09:10:43 +02:00

40 lines
2.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest';
import { DaemonStartError, describeStartFailure } from '../src/main/start-failure';
describe('describeStartFailure', () => {
it('port tenu par une autre instance : renvoie vers le tray, pas vers une trace technique', () => {
const err = new DaemonStartError('port-busy-instance', 'port 7317 is already in use');
const { message, detail } = describeStartFailure(err, 7317);
expect(message).toBe('Arboretum is already running');
expect(detail).toContain('7317');
expect(detail).toContain('system tray');
});
it('port tenu par un tiers : nomme les suspects et l’échappatoire (variable d’env)', () => {
const err = new DaemonStartError('port-busy-foreign', 'port 7317 is already in use', 'EADDRINUSE');
const { message, detail } = describeStartFailure(err, 7317);
expect(message).toBe('Port 7317 is already in use');
expect(detail).toContain('arboretum install');
expect(detail).toContain('ARBORETUM_DESKTOP_PORT');
expect(detail).toContain('EADDRINUSE');
});
it('échec de handshake : conserve le message et la queue de journal', () => {
const err = new DaemonStartError('handshake', 'daemon exited before handshake (code 1)', 'boom\nbadaboum');
const { message, detail } = describeStartFailure(err, 7317);
expect(message).toBe('Arboretum could not start its local server');
expect(detail).toContain('daemon exited before handshake (code 1)');
expect(detail).toContain('badaboum');
});
it('erreur quelconque (hors DaemonStartError) reste affichable', () => {
expect(describeStartFailure(new Error('ENOENT node'), 7317).detail).toContain('ENOENT node');
expect(describeStartFailure('cassé', 7317).detail).toContain('cassé');
});
it('sans queue de journal, aucun bloc « Server output » vide', () => {
const detail = describeStartFailure(new DaemonStartError('handshake', 'nope'), 7317).detail;
expect(detail).not.toContain('Server output');
});
});