Files
feuerwerk/tools/e2e/10-text-and-enabled.mjs
T
rootandClaude Fable 5.1 6471671f7d Refactor round: ship web/index.html, drop the remote browser, fix stale comments and README
- `.gitignore` said `index.html` unanchored, which also caught the Vite source page;
  a fresh clone could neither `dev` nor `build`. Anchored to `/index.html`, page added.
- Removed GM_REMOTE (tools/remote/gm-browser.ps1 and the ssh/scp branch in browser.mjs):
  the Windows test machine is gone and the only flaky check that lived on it is closed (#37).
- Removed `npm run preview`, undocumented and unused.
- Comments: wrong number in collider.test.ts (250 → 200), the "declarations used to…"
  history in listItems.ts and friends, the 24 px/28 contradiction, section banners in
  nodes/index.ts, node-catalog.test.ts and api/index.php, name paraphrases, and the stale
  step numbers in tools/e2e/11-…23- from the old global count.
- README: asset types include `animation`, kind order Number/Text/Boolean, tagged colour
  and texture items, 6/5 kinds, the `Texture` node, `./build.sh`, PROJECT_FORMAT_VERSION,
  and the file tree (kinds.ts, listItems.ts, propertyPorts.ts, Breadcrumb.ts, beads.ts,
  tools/assets/).
- tests/helpers.ts takes the duplicated `findObject` and `sceneWithCamera`.

Proof: ./check.sh 797 tests, full e2e ALL PASSED 633 checks against this bundle.

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

120 lines
5.3 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,
has,
shot,
click,
clickText,
locate,
mutate,
object,
play,
press,
stop,
typeText,
} = t;
// 10a. 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');
// 10b. 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');
// 10c. 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);
// 10d. 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')));
}