Files
NetMesh/domain/toolbarItemLayout.test.ts

135 lines
4.1 KiB
TypeScript
Raw Normal View History

import test from 'node:test';
import assert from 'node:assert/strict';
import {
moveToolbarItem,
normalizeToolbarItemLayout,
partitionToolbarItems,
reorderToolbarItems,
resetToolbarItemLayout,
setToolbarItemPlacement,
type ToolbarItemLayoutDefaults,
} from './toolbarItemLayout.ts';
const defaults: ToolbarItemLayoutDefaults = {
order: ['a', 'b', 'c', 'd'],
placement: {
a: 'show',
b: 'show',
c: 'collapse',
d: 'hide',
},
lockedIds: ['a'],
};
test('normalize restores defaults for null/invalid values', () => {
assert.deepEqual(normalizeToolbarItemLayout(null, defaults), {
order: ['a', 'b', 'c', 'd'],
placement: { a: 'show', b: 'show', c: 'collapse', d: 'hide' },
});
assert.deepEqual(normalizeToolbarItemLayout('nope', defaults), resetToolbarItemLayout(defaults));
});
test('normalize accepts legacy order-only arrays', () => {
const layout = normalizeToolbarItemLayout(['d', 'a', 'b', 'c'], defaults);
assert.deepEqual(layout.order, ['d', 'a', 'b', 'c']);
assert.equal(layout.placement.a, 'show');
assert.equal(layout.placement.c, 'collapse');
assert.equal(layout.placement.d, 'hide');
});
test('normalize appends new default ids and drops unknown ones', () => {
const layout = normalizeToolbarItemLayout(
{ order: ['c', 'ghost', 'a'], placement: { c: 'show', a: 'collapse' } },
defaults,
);
assert.deepEqual(layout.order, ['c', 'a', 'b', 'd']);
assert.equal(layout.placement.a, 'collapse');
assert.equal(layout.placement.b, 'show');
});
test('locked ids cannot be hidden', () => {
const layout = normalizeToolbarItemLayout(
{ order: ['a', 'b', 'c', 'd'], placement: { a: 'hide', b: 'show', c: 'show', d: 'show' } },
defaults,
);
assert.equal(layout.placement.a, 'show');
const next = setToolbarItemPlacement(layout, 'a', 'hide', defaults);
assert.equal(next.placement.a, 'show');
});
test('partition filters by availability and placement', () => {
const layout = normalizeToolbarItemLayout(null, defaults);
assert.deepEqual(partitionToolbarItems(layout), {
shown: ['a', 'b'],
collapsed: ['c'],
hidden: ['d'],
});
assert.deepEqual(partitionToolbarItems(layout, ['a', 'c', 'd']), {
shown: ['a'],
collapsed: ['c'],
hidden: ['d'],
});
});
test('set placement forces at least one reachable item', () => {
const layout = normalizeToolbarItemLayout(
{
order: ['a', 'b'],
placement: { a: 'show', b: 'hide' },
},
{ order: ['a', 'b'], requireReachable: true },
);
const next = setToolbarItemPlacement(layout, 'a', 'hide', {
order: ['a', 'b'],
requireReachable: true,
});
// a was the only reachable; hide is refused via ensureReachable restoring a
assert.equal(next.placement.a, 'show');
});
test('requireReachable ignores unavailable filler ids', () => {
const layout = normalizeToolbarItemLayout(
{
order: ['a', 'b', 'serialOnly'],
placement: { a: 'hide', b: 'hide', serialOnly: 'show' },
},
{
order: ['a', 'b', 'serialOnly'],
requireReachable: true,
},
);
// serialOnly is still "show" but not available for this session — must restore a/b.
const next = setToolbarItemPlacement(
layout,
'a',
'hide',
{ order: ['a', 'b', 'serialOnly'], requireReachable: true },
['a', 'b'],
);
assert.equal(next.placement.a === 'show' || next.placement.b === 'show', true);
});
test('move skips unavailable neighbors when availableIds is provided', () => {
const layout = normalizeToolbarItemLayout(
{
order: ['a', 'serialOnly', 'b'],
placement: { a: 'show', serialOnly: 'show', b: 'show' },
},
{ order: ['a', 'serialOnly', 'b'] },
);
const moved = moveToolbarItem(layout, 'a', 'later', ['a', 'b']);
assert.deepEqual(moved.order, ['b', 'serialOnly', 'a']);
});
test('reorder and move preserve placement map', () => {
const layout = normalizeToolbarItemLayout(null, defaults);
const reordered = reorderToolbarItems(layout, 'c', 'a', 'before');
assert.deepEqual(reordered.order, ['c', 'a', 'b', 'd']);
assert.equal(reordered.placement.c, 'collapse');
const moved = moveToolbarItem(layout, 'b', 'later');
assert.deepEqual(moved.order, ['a', 'c', 'b', 'd']);
});