fix(web): repeindre les terminaux au retour-visible + flush ACK ciblé
Un terminal caché dans une grille de groupe (ou hors-écran) n'était pas repeint au retour — `visibilitychange` ne couvre que l'onglet — d'où l'écran noir avec curseur ; et son ACK ne progressait plus (callback xterm.write throttlé) → le serveur mettait le PTY en pause → sortie « par à-coups ». Ajoute un IntersectionObserver (repaint + flushAck ciblé au retour-visible) et expose Attachment.flushAck (factorisé avec flushAcks).
This commit is contained in:
53
packages/web/test/ws-client.test.ts
Normal file
53
packages/web/test/ws-client.test.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
// Flush ACK ciblé (Attachment.flushAck) : relance un PTY mis en pause au retour-visible d'une cellule.
|
||||
// On teste la logique d'ACK sans WebSocket réel (sendControl est public → stubbable).
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { WsClient, Attachment, type TerminalSink } from '../src/lib/ws-client';
|
||||
|
||||
const sink: TerminalSink = {
|
||||
write: () => {},
|
||||
reset: () => {},
|
||||
onDetached: () => {},
|
||||
onControlChanged: () => {},
|
||||
};
|
||||
|
||||
describe('ws-client — flush ACK ciblé (Attachment.flushAck)', () => {
|
||||
it('envoie un unique ACK cumulatif du reliquat traité, puis est idempotent', () => {
|
||||
const client = new WsClient();
|
||||
const send = vi.spyOn(client, 'sendControl').mockImplementation(() => {});
|
||||
const att = new Attachment(client, 'sid', 'interactive', sink, 80, 24);
|
||||
att.channel = 2;
|
||||
att.processedBytes = 1000;
|
||||
|
||||
att.flushAck();
|
||||
expect(send).toHaveBeenCalledTimes(1);
|
||||
expect(send).toHaveBeenCalledWith({ type: 'ack', channel: 2, bytes: 1000 });
|
||||
expect(att.lastAckBytes).toBe(1000);
|
||||
|
||||
// rien de neuf traité → aucun ACK supplémentaire (n'ACK QUE du réellement traité)
|
||||
att.flushAck();
|
||||
expect(send).toHaveBeenCalledTimes(1);
|
||||
|
||||
// nouveau reliquat traité → ACK cumulatif mis à jour
|
||||
att.processedBytes = 1500;
|
||||
att.flushAck();
|
||||
expect(send).toHaveBeenCalledTimes(2);
|
||||
expect(send).toHaveBeenLastCalledWith({ type: 'ack', channel: 2, bytes: 1500 });
|
||||
});
|
||||
|
||||
it('no-op si le canal n’est pas attaché (-1) ou si l’attachment est fermé', () => {
|
||||
const client = new WsClient();
|
||||
const send = vi.spyOn(client, 'sendControl').mockImplementation(() => {});
|
||||
|
||||
const notAttached = new Attachment(client, 'a', 'interactive', sink, 80, 24); // channel = -1
|
||||
notAttached.processedBytes = 500;
|
||||
notAttached.flushAck();
|
||||
|
||||
const closed = new Attachment(client, 'b', 'interactive', sink, 80, 24);
|
||||
closed.channel = 3;
|
||||
closed.processedBytes = 500;
|
||||
closed.closed = true;
|
||||
closed.flushAck();
|
||||
|
||||
expect(send).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user