Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
119 lines
3.6 KiB
TypeScript
119 lines
3.6 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
|
|
import type { TerminalSession } from '../../domain/models.ts';
|
|
import {
|
|
EMPTY_SESSION_SNAPSHOT,
|
|
getSessionSnapshot,
|
|
getSessionSnapshotActions,
|
|
publishSessionSnapshot,
|
|
registerSessionSnapshotActions,
|
|
sessionSnapshotsEqual,
|
|
subscribeSessionSnapshot,
|
|
} from './sessionSnapshotStore.ts';
|
|
|
|
function makeSession(id: string): TerminalSession {
|
|
return { id, hostLabel: id, status: 'connected' } as TerminalSession;
|
|
}
|
|
|
|
test('sessionSnapshotStore notifies only when a field identity changes', () => {
|
|
const seen: number[] = [];
|
|
const unsubscribe = subscribeSessionSnapshot(() => {
|
|
seen.push(getSessionSnapshot().sessions.length);
|
|
});
|
|
|
|
const sessions = [makeSession('s1')];
|
|
const snapshot = { ...EMPTY_SESSION_SNAPSHOT, sessions, orphanSessions: sessions };
|
|
publishSessionSnapshot(snapshot);
|
|
assert.deepEqual(seen, [1]);
|
|
assert.equal(getSessionSnapshot().sessions, sessions);
|
|
|
|
publishSessionSnapshot({ ...snapshot });
|
|
assert.deepEqual(seen, [1]);
|
|
|
|
// Presentation-only fields still count: rename targets drive dialog state.
|
|
publishSessionSnapshot({ ...snapshot, sessionRenameTarget: sessions[0] });
|
|
assert.deepEqual(seen, [1, 1]);
|
|
assert.equal(getSessionSnapshot().sessionRenameTarget, sessions[0]);
|
|
|
|
unsubscribe();
|
|
publishSessionSnapshot(EMPTY_SESSION_SNAPSHOT);
|
|
assert.deepEqual(seen, [1, 1]);
|
|
});
|
|
|
|
test('sessionSnapshotsEqual compares every published field', () => {
|
|
assert.equal(
|
|
sessionSnapshotsEqual(EMPTY_SESSION_SNAPSHOT, { ...EMPTY_SESSION_SNAPSHOT }),
|
|
true,
|
|
);
|
|
assert.equal(
|
|
sessionSnapshotsEqual(EMPTY_SESSION_SNAPSHOT, {
|
|
...EMPTY_SESSION_SNAPSHOT,
|
|
draggingSessionId: 's1',
|
|
}),
|
|
false,
|
|
);
|
|
assert.equal(
|
|
sessionSnapshotsEqual(EMPTY_SESSION_SNAPSHOT, { ...EMPTY_SESSION_SNAPSHOT, logViews: [] }),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test('session actions register and unregister', () => {
|
|
assert.equal(getSessionSnapshotActions(), null);
|
|
const calls: string[] = [];
|
|
const noop = (() => {}) as never;
|
|
registerSessionSnapshotActions({
|
|
setActiveTabId: ((id: string) => calls.push(id)) as never,
|
|
closeSession: noop,
|
|
closeSessions: noop,
|
|
closeWorkspace: noop,
|
|
openLogView: noop,
|
|
closeLogView: noop,
|
|
setDraggingSessionId: noop,
|
|
startSessionRename: noop,
|
|
renameSessionInline: noop,
|
|
submitSessionRename: noop,
|
|
resetSessionRename: noop,
|
|
startWorkspaceRename: noop,
|
|
submitWorkspaceRename: noop,
|
|
resetWorkspaceRename: noop,
|
|
removeSessionFromWorkspace: noop,
|
|
setWorkspaceFocusedSession: noop,
|
|
toggleWorkspaceViewMode: noop,
|
|
createLocalTerminal: noop,
|
|
createSerialSession: noop,
|
|
connectToHost: noop,
|
|
updateSessionStatus: noop,
|
|
updateSessionFontSize: noop,
|
|
clearSessionFontSizeOverride: noop,
|
|
createWorkspaceWithHosts: noop,
|
|
createWorkspaceFromSessions: noop,
|
|
addSessionToWorkspace: noop,
|
|
appendHostToWorkspace: noop,
|
|
appendLocalTerminalToWorkspace: noop,
|
|
createWorkspaceFromTargets: noop,
|
|
updateSplitSizes: noop,
|
|
splitSession: noop,
|
|
reorderWorkspaceSessions: noop,
|
|
moveFocusInWorkspace: noop,
|
|
runSnippet: noop,
|
|
getOrderedWorkTabs: noop,
|
|
reorderTabs: noop,
|
|
toggleBroadcast: noop,
|
|
isBroadcastEnabled: noop,
|
|
copySession: noop,
|
|
copyWorkspace: noop,
|
|
createSessionFromCloneSource: noop,
|
|
updateSessionRestoreCwd: noop,
|
|
getSessionRestoreCwd: noop,
|
|
updateSessionDynamicTitle: noop,
|
|
updateSessionCodingCliProvider: noop,
|
|
});
|
|
getSessionSnapshotActions()?.setActiveTabId('vault');
|
|
assert.deepEqual(calls, ['vault']);
|
|
|
|
registerSessionSnapshotActions(null);
|
|
assert.equal(getSessionSnapshotActions(), null);
|
|
});
|