Files
NetMesh/domain/workspaceSidePanelTabRemap.test.ts
zhaolei 3c72efcb7f
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
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

223 lines
5.5 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
moveSidePanelTabMap,
moveSidePanelTabSet,
remapMountedSidePanelTabIds,
remapSidePanelTabMap,
} from './workspaceSidePanelTabRemap.ts';
test('promote copies preferred member open tool onto the new workspace tab', () => {
const source = new Map([
['term-a', 'ai'],
['term-b', 'sftp'],
]);
assert.deepEqual(
[...remapSidePanelTabMap(source, {
kind: 'promote',
fromTabIds: ['term-a', 'term-b'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
})],
[
['term-a', 'ai'],
['term-b', 'sftp'],
['ws-1', 'ai'],
],
);
});
test('promote copies split layouts onto the new workspace tab', () => {
const layoutA = { focusedPaneId: 'pane-a', root: { type: 'pane', id: 'pane-a', tool: 'ai' } };
const layoutB = { focusedPaneId: 'pane-b', root: { type: 'pane', id: 'pane-b', tool: 'sftp' } };
const source = new Map([
['term-a', layoutA],
['term-b', layoutB],
]);
const next = remapSidePanelTabMap(source, {
kind: 'promote',
fromTabIds: ['term-a', 'term-b'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
});
assert.equal(next.get('ws-1'), layoutA);
assert.equal(next.get('term-a'), layoutA);
});
test('promote is a no-op when the workspace tab already has an open tool', () => {
const source = new Map([
['term-a', 'ai'],
['ws-1', 'notes'],
]);
assert.equal(
remapSidePanelTabMap(source, {
kind: 'promote',
fromTabIds: ['term-a'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
}),
source,
);
});
test('demote copies workspace open tool onto the preferred orphan tab', () => {
const source = new Map([
['ws-1', 'ai'],
['term-b', 'sftp'],
]);
assert.deepEqual(
[...remapSidePanelTabMap(source, {
kind: 'demote',
fromTabId: 'ws-1',
toTabIds: ['term-a', 'term-b'],
preferredToTabId: 'term-a',
})],
[
['ws-1', 'ai'],
['term-b', 'sftp'],
['term-a', 'ai'],
],
);
});
test('demote overwrites a stale preferred member entry kept from merge', () => {
const source = new Map([
['ws-1', 'notes'],
['term-a', 'ai'],
]);
assert.deepEqual(
[...remapSidePanelTabMap(source, {
kind: 'demote',
fromTabId: 'ws-1',
toTabIds: ['term-a', 'term-b'],
preferredToTabId: 'term-a',
})],
[
['ws-1', 'notes'],
['term-a', 'notes'],
],
);
});
test('moveSidePanelTabMap promote relocates the source mount onto the workspace tab', () => {
const source = new Map([
['term-a', 'host-a'],
['term-b', 'host-b'],
]);
assert.deepEqual(
[...moveSidePanelTabMap(source, {
kind: 'promote',
fromTabIds: ['term-a', 'term-b'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
})],
[
['term-b', 'host-b'],
['ws-1', 'host-a'],
],
);
});
test('moveSidePanelTabMap demote relocates the workspace mount onto the survivor', () => {
const source = new Map([
['ws-1', 'host-a'],
['term-b', 'host-b'],
]);
assert.deepEqual(
[...moveSidePanelTabMap(source, {
kind: 'demote',
fromTabId: 'ws-1',
toTabIds: ['term-a', 'term-b'],
preferredToTabId: 'term-a',
})],
[
['term-b', 'host-b'],
['term-a', 'host-a'],
],
);
});
test('moveSidePanelTabSet promotes and demotes the closed-pane marker with ownership', () => {
const promoted = moveSidePanelTabSet(new Set(['term-b']), {
kind: 'promote',
fromTabIds: ['term-a', 'term-b'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
});
assert.deepEqual([...promoted], ['ws-1']);
const demoted = moveSidePanelTabSet(new Set(['ws-1']), {
kind: 'demote',
fromTabId: 'ws-1',
toTabIds: ['term-a', 'term-b'],
preferredToTabId: 'term-a',
});
assert.deepEqual([...demoted], ['term-a']);
});
test('moveSidePanelTabSet does not bind a marker to a different promoted SFTP owner', () => {
const marker = moveSidePanelTabSet(new Set(['term-b']), {
kind: 'promote',
fromTabIds: ['term-a', 'term-b'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
}, { ownerTabIds: new Set(['term-a', 'term-b']) });
assert.deepEqual([...marker], ['term-b']);
const preferredMarker = moveSidePanelTabSet(new Set(['term-a']), {
kind: 'promote',
fromTabIds: ['term-a', 'term-b'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
}, { ownerTabIds: new Set(['term-a', 'term-b']) });
assert.deepEqual([...preferredMarker], ['ws-1']);
const nonOwnerDemote = moveSidePanelTabSet(new Set(['term-b']), {
kind: 'demote',
fromTabId: 'ws-1',
toTabIds: ['term-a', 'term-b'],
preferredToTabId: 'term-a',
}, { ownerTabIds: new Set(['term-a']) });
assert.deepEqual([...nonOwnerDemote], ['term-b']);
const absentMarkerDemote = moveSidePanelTabSet(new Set(), {
kind: 'demote',
fromTabId: 'ws-1',
toTabIds: ['term-a', 'term-b'],
preferredToTabId: 'term-a',
}, { ownerTabIds: new Set(['ws-1']) });
assert.deepEqual([...absentMarkerDemote], []);
});
test('mounted tab ids gain the destination tab when the source was mounted', () => {
assert.deepEqual(
remapMountedSidePanelTabIds(['term-a'], {
kind: 'promote',
fromTabIds: ['term-a', 'term-b'],
toTabId: 'ws-1',
preferredFromTabId: 'term-a',
}),
['term-a', 'ws-1'],
);
assert.deepEqual(
remapMountedSidePanelTabIds(['ws-1'], {
kind: 'demote',
fromTabId: 'ws-1',
toTabIds: ['term-a', 'term-b'],
preferredToTabId: 'term-a',
}),
['ws-1', 'term-a'],
);
});