Files
feuerwerk/tools/e2e/14-overflow.mjs
T
rootandClaude Fable 5.1 69615c1f4b
game-maker / suite (push) Successful in 7m49s
Tab row: fit nine tabs inside the centre column
The ninth tab (Shader) pushed the row past the centre column: List
ended at 962 while the column ended at 925, so the last buttons sat
under the inspector and clickText('Container') hit the List tab
instead (CI runs 5 and 6, module 16). Tab buttons now use padding 4
via a new Button padding option; e2e step 14b guards the row width
using the widget box rather than getBounds(), which sees only the
label on an untoggled ghost button.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 23:09:30 +02:00

108 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Labels must be shortened to fit their control, not written past it. Runs last because it renames
* assets to absurd lengths to provoke the case.
*/
/** A name far wider than any 200 px picker, so a control that does not truncate must spill. */
const LONG_NAME = 'Player movement with jumping and coyote time';
export async function overflow(t) {
const { check, sleep, json, evaluate, shot, mutate } = t;
const pickerWidths = async () => {
const out = {};
for (const tab of ['graph', 'texture', 'container']) {
await evaluate(`__gm.showTab(${JSON.stringify(tab)})`);
await sleep(300);
out[tab] = await json(`__gm.${tab}.pickerWidth()`);
}
return out;
};
const before = await pickerWidths();
await mutate(`
for (const asset of __gm.state.project.assets) {
if (asset.type === 'behavior' || asset.type === 'texture' || asset.type === 'container')
asset.name = ${JSON.stringify(LONG_NAME)};
}
__gm.state.select(null)`);
await sleep(600);
// 14a. The pickers keep the width they were given instead of growing with the name they show.
const after = await pickerWidths();
for (const tab of ['graph', 'texture', 'container']) {
check(
`the ${tab} picker keeps its width when the name gets long`,
before[tab] === 200 && after[tab] === 200,
`before ${before[tab]}, after ${after[tab]}`,
);
}
// 14b. The tab row itself: a button past the centre column's edge sits under the inspector, and
// a click on it lands there (nine tabs on a 90 px floor did exactly that at 1280 px wide).
await evaluate("__gm.showTab('scene')");
await sleep(300);
const column = await json('__gm.viewportRect()');
const tabs = await json('__gm.tabBounds()');
const spilled = Object.entries(tabs).filter(([, b]) => b.right > column.x + column.w);
check(
'every tab button ends inside the centre column',
spilled.length === 0,
JSON.stringify({ spilled, columnRight: column.x + column.w }),
);
// 14c. Every tab, because each one owns a different set of controls.
for (const tab of ['scene', 'graph', 'texture', 'game', 'container', 'list']) {
await evaluate(`__gm.showTab(${JSON.stringify(tab)})`);
await sleep(400);
const spills = await json('__gm.textOverflows()');
check(
`no label is drawn past its control in the ${tab} tab`,
spills.length === 0,
JSON.stringify(spills),
);
}
// 14d. Shortened, not simply dropped: the value must still be readable and marked as cut.
await evaluate("__gm.showTab('graph')");
await sleep(400);
const shown = (await json('__gm.textOverflows(true)')).find((e) => e.text.startsWith('Player movement'));
check(
'a value too wide for its dropdown is cut with an ellipsis',
Boolean(shown) && shown.text.endsWith('…') && shown.text.length > 8,
JSON.stringify(shown),
);
await shot('36-long-labels');
// 14e. An inspector full of dropdowns – the parent row and the enum fields – with a selection
// whose asset name is now overlong too.
await evaluate("__gm.showTab('scene')");
await sleep(300);
await evaluate("__gm.state.select({ kind: 'object', objectId: 'otex' })");
await sleep(500);
const inspector = await json('__gm.textOverflows()');
check('no label spills in the inspector', inspector.length === 0, JSON.stringify(inspector));
// 14f. The other direction: a control narrow enough to swallow its whole label draws nothing
// at all, which the overflow walk cannot see – an empty text spills over no edge.
for (const tab of ['scene', 'graph', 'texture', 'container', 'list']) {
await evaluate(`__gm.showTab(${JSON.stringify(tab)})`);
await sleep(400);
const dropped = await json('__gm.labelsDropped()');
check(
`no button is left without its label in the ${tab} tab`,
dropped.length === 0,
JSON.stringify(dropped),
);
}
// The narrowest buttons in the editor sit on a behaviour's variable rows.
await evaluate("__gm.state.select({ kind: 'asset', assetId: 'mover' })");
await sleep(400);
const onVariables = await json('__gm.labelsDropped()');
check(
'the variable rows keep their buttons labelled',
onVariables.length === 0,
JSON.stringify(onVariables),
);
}