Files
feuerwerk/tools/e2e/10-text-and-enabled.mjs
T
rootandClaude Opus 5 631cf54c72 Give every behavior variable one row shape on asset and instance
buildStructBlock only covered structs, so a placed instance drew numbers,
text, bools and lists through createFieldRow on a 64 px name column while
its struct block sat on the asset's grid below it. variableRows.ts now
builds the row for every variable kind on both sides; the edit option
decides what the owner may change (asset: rename, x, item kind; instance:
revert and push). Label and Button take a fixed width so the mark column
no longer shifts names when a list shows its item-kind picker.

The two structFields calls that became dead with 9f48257 are gone. The
e2e steps locate the Enabled toggle through __gm.inspectorField instead
of clicking a fixed offset from its label.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 07:27:29 +02:00

120 lines
5.4 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.
/** Text assets rendered in the scene, and the enabled switch in the editor and in the running game. */
export async function textAndEnabled(t) {
const {
check,
sleep,
evaluate,
json,
shot,
click,
clickText,
locate,
mutate,
object,
play,
press,
stop,
typeText,
} = t;
const has = (text) => evaluate(`Boolean(__gm.locate(${JSON.stringify(text)}))`);
// 17. Text assets: created through the + menu, placed, and rendered as real text in the scene.
await clickText('+');
await clickText('Text');
await sleep(100);
const textAssetId = await evaluate(`(__gm.state.project.assets.find(a => a.type === 'text') || {}).id`);
check('+ menu creates a text asset', Boolean(textAssetId));
await mutate(`
const id = ${JSON.stringify(textAssetId)};
__gm.state.project.assets.find(a => a.id === id).props.text = 'Hello world';
// On the camera so the game view really renders it (outside the frame it would be culled).
const cam = __gm.state.activeScene.objects.find(o => o.id === 'o3').position;
__gm.state.activeScene.objects.push({ id: 'otext', assetId: id, name: '', position: { x: cam.x, y: cam.y, z: 5 }, editorOffset: { x: 0, y: 0 }, overrides: {}, parentId: '', instanceEdits: {} });
__gm.state.select({ kind: 'object', holderId: 'scene1', objectIds: ['otext'], objectId: 'otext' })`);
await sleep(100);
check('a placed text object draws its content in the scene', await has('Hello world'));
await shot('29-text-object');
// 17a. The enabled switch: every object has it, switching it off is a normal override, and a
// switched-off object disappears from the scene view too (it stays in the hierarchy).
const enabledRow = await json("__gm.inspectorField('Enabled')");
check('the inspector shows the Enabled switch for a scene object', Boolean(enabledRow));
const visibleBefore = (await json('__gm.viewportInfo()')).visibleItems;
const gizmoOf = async (id) => (await json('__gm.gizmos()')).find((g) => g.id === id) ?? null;
const gizmoOn = await gizmoOf('otext');
check('a selected object is framed at full strength', gizmoOn?.alpha === 1, JSON.stringify(gizmoOn));
await click(enabledRow.x, enabledRow.y);
await sleep(100);
const textObject = await object('otext');
check(
'clicking it writes an override instead of changing the asset',
textObject.overrides.enabled === false,
JSON.stringify(textObject.overrides),
);
check(
'a switched-off object is not drawn in the scene view',
!(await json('__gm.drawOrder()')).includes('otext'),
);
const visibleAfter = (await json('__gm.viewportInfo()')).visibleItems;
check(
'the scene view renders one item less',
visibleAfter === visibleBefore - 1,
`${visibleBefore} → ${visibleAfter}`,
);
check('it stays selectable in the hierarchy, so its switch stays reachable', await has('Enabled'));
await shot('30-disabled');
// 17a-2. It draws nothing, so its outline is the only thing left that says where it sits – which
// is the whole point of being able to pick it in the hierarchy. Selecting another object
// and coming back proves the outline follows the panel, not a leftover from before.
const gizmoOff = await gizmoOf('otext');
check(
'a switched-off object is still framed, dimmed',
gizmoOff?.primary === true && gizmoOff.alpha > 0 && gizmoOff.alpha < 1,
JSON.stringify(gizmoOff),
);
const otherRow = await evaluate(`__gm.hierarchyRow('o3')`);
await click(otherRow.x, otherRow.y);
await sleep(100);
check('selecting something else drops the frame', (await gizmoOf('otext')) === null);
const offRow = await evaluate(`__gm.hierarchyRow('otext')`);
await click(offRow.x, offRow.y);
await sleep(100);
const gizmoBack = await gizmoOf('otext');
check(
'picking the switched-off object in the hierarchy frames it again',
gizmoBack?.alpha > 0 && gizmoBack.alpha < 1,
JSON.stringify(gizmoBack),
);
check('and it is still not drawn', !(await json('__gm.drawOrder()')).includes('otext'));
await shot('30b-disabled-gizmo');
// 17b. In the running game a switched-off object does not exist: it is not rendered, and
// switching it back on brings it back.
await play();
await sleep(200);
const offItems = (await json('__gm.gameInfo()')).visibleItems;
await mutate(`__gm.state.activeScene.objects.find(o => o.id === 'otext').overrides.enabled = true`);
await sleep(200);
const onItems = (await json('__gm.gameInfo()')).visibleItems;
check(
'the game renders one item more once the object is switched on',
onItems === offItems + 1,
`${offItems} → ${onItems}`,
);
await stop();
check('stop leaves the play-mode switch behind', (await object('otext')).overrides.enabled === false);
// 17c. A field that shows no decimals must not store any either. Font size is such a field, so
// typing a fraction has to round: showing "33" while the project holds 32.6 would be a lie.
const fontLabel = await locate('Font size');
check('Font size reads as a whole number', Boolean(await has('32')) && !(await has('32.000')));
await click(fontLabel.x + 160, fontLabel.y);
await typeText('32.6');
await press('Enter');
await sleep(200);
const fontSize = (await object('otext')).overrides.fontSize;
check('typing a fraction into it rounds the stored value', fontSize === 33, String(fontSize));
check('and the field shows exactly what was stored', Boolean(await has('33')));
}