Files
feuerwerk/tests/editor/tab-row.test.ts
T
DeveloperandClaude Opus 5 f83c568999
game-maker / suite (push) Successful in 9m18s
Tab row: what does not fit goes behind a menu, the active tab always stays (#84)
Nine tabs need 631 px; at 1280x800 the centre column offers 666 px, so the tenth
tab would have spilled under the inspector - the same overflow CI caught in run 5.

TabStrip replaces the bare HStack: it fits the longest prefix that stays inside
the budget, always appends the active tab, and offers the rest behind a fixed
28 px button. The button's width is fixed on purpose - deriving it from the
number of hidden tabs would make width depend on the count and the count on the
width.

The rule itself is a pure function (tabRow.ts), so it is checked without a
browser. setActive() calls relayout() itself because Widget.resize only lays out
on a changed size, and switching tabs does not change any size.

Adding a tab now needs no space arithmetic - only a line in TAB_ORDER,
TAB_LABELS and panes, all three Record<CentreTab, ...>, so forgetting one is a
type error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 22:06:46 +02:00

50 lines
1.7 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { tabRowLayout } from '../../src/editor/tabRow';
/** The nine tabs as measured in the browser at padding 4, in their editor order. */
const TABS = [
{ key: 'scene', width: 53 },
{ key: 'game', width: 50 },
{ key: 'graph', width: 74 },
{ key: 'statemachine', width: 114 },
{ key: 'shader', width: 61 },
{ key: 'texture', width: 64 },
{ key: 'animation', width: 83 },
{ key: 'container', width: 81 },
{ key: 'list', width: 35 },
];
const layout = (available: number, active: string) =>
tabRowLayout({ tabs: TABS, available, gap: 2, overflowWidth: 28, active });
describe('tab row', () => {
it('hides nothing while the row fits', () => {
const { shown, hidden } = layout(631, 'scene');
expect(hidden).toEqual([]);
expect(shown).toHaveLength(9);
});
it('hides the tail one pixel short of fitting', () => {
expect(layout(630, 'scene').hidden).toEqual(['list']);
});
it('keeps the tabs in order', () => {
expect(layout(400, 'scene').shown).toEqual(['scene', 'game', 'graph', 'statemachine', 'shader']);
});
it('shows the active tab even when it sits past the room there is', () => {
const { shown, hidden } = layout(400, 'container');
expect(shown).toContain('container');
expect(hidden).toContain('shader');
// It went in at the back, so the row still reads left to right.
expect(shown[shown.length - 1]).toBe('container');
});
it('gives up every other tab before it drops the active one', () => {
expect(layout(60, 'animation')).toEqual({
shown: ['animation'],
hidden: ['scene', 'game', 'graph', 'statemachine', 'shader', 'texture', 'container', 'list'],
});
});
});