Tooling: - Prettier as the single formatting authority (110 columns, single quotes, measured against the existing style); Markdown excluded because table-cell padding turns the README glossary into 1000-character lines. - Type-aware ESLint ending in eslint-config-prettier, so a rule always means "this is a bug", never "this looks different". - .editorconfig and an `npm run check` that runs typecheck, lint, format and tests in one go. Findings fixed on the first run: three more duplicate imports, four String(unknown) calls (parameter types narrowed instead of casts), two dead initialisers, two redundant casts, a console.log for a real error. Two warnings were false here and are disabled with a reason in place. Tests 132 -> 269: - node-catalog.test.ts covers every node with a run(), with a guard that fails when a new node has no row. - behavior-events.test.ts covers the ten event nodes through a running World, checking timing rather than existence. - Input's state machine (press/release/releaseAll) is reachable without DOM events now; the DOM handlers are thin adapters. Compare fell back to == without a configured operator although the schema default is <; aligned. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
66 lines
3.3 KiB
JavaScript
66 lines
3.3 KiB
JavaScript
/** 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, mutate, object, play, stop } = 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: '', templateId: '' });
|
|
__gm.state.select({ kind: 'object', sceneId: '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 evaluate(`__gm.locate('Enabled')`);
|
|
check('the inspector shows the Enabled switch for a scene object', Boolean(enabledRow));
|
|
const visibleBefore = (await json('__gm.viewportInfo()')).visibleItems;
|
|
// The checkbox sits right of the 64 px label column; locate() gives the label's text centre.
|
|
await click(enabledRow.x + 55, 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');
|
|
|
|
// 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);
|
|
}
|