A test that waits for a deadline somebody guessed is waiting for the wrong thing, so it waits for the editor (#93)
game-maker / suite (push) Successful in 6m48s
game-maker / suite (push) Successful in 6m48s
The suite spent 88% of its step time asleep: 564 s of steps, 496 s of
them in sleep(n) - fixed spans estimated by hand and then copied from
step to step. That is why it was slow, and why it flickered.
The signal is afterFrames(count, timeout) in ui/render.ts, exposed as
__gm.afterFrames(). It wakes the loop itself, because an editor that
draws nothing would never redeem a promise of a frame, and it gives up
after a timeout instead of hanging the run. settle() in the harness
waits two drawn frames (~32 ms) instead of 150-300 ms and falls back to
sleep(150) when the hook is missing (an old build): silently not
waiting would make every later check a coin toss.
Every action goes through it now - click, doubleClick, wheel, drag,
dragAsset, press, typeText, select, mutate, undo, redo - and with that
about 550 sleep() calls behind those actions became redundant, helpers
that are nothing but a mutate in a coat included. What a frame cannot
answer got its own condition instead: waitUntil(expr), play()/stop()
waiting on __gm.state.mode rather than on 300 ms, saved() for the
autosave (the two hand-written polling loops sampled at 300 ms for
something that arrives after a second), and showTab() as a real tool -
47 places called evaluate("__gm.showTab(...)") raw, and 24 of them
waited for nothing at all and read the old panel.
564 s -> 243 s of step time, the waiting share 88% -> 76%. Three kinds
of wait were kept, and each one bit when it was taken away: loading
bytes (textures, fonts), game time that a repaint cannot stand in for
(time scale, shader and particle clocks, the live values a running
graph carries), and the inertia the scroll step measures on purpose.
Two things the new speed uncovered, both real: 25-animation read the
frame menu unfiltered and had frozen an incomplete list (the CI failure
on c990dbc), and 33-render-on-change measured idleness while the
autosave of the step before was still painting - it waits for
saveStatus to leave dirty/saving now, so it measures that nothing
happens any more instead of that it waited long enough.
This commit is contained in:
1 parent
c990dbcb26
commit
7e5003b590
41 files changed
+362
-732
No files matched your search
@@ -42,7 +42,6 @@ export async function structVariable(t) {
|
||||
});
|
||||
__gm.state.select({ kind: 'asset', assetId: 'structy' });
|
||||
`);
|
||||
await sleep(150);
|
||||
|
||||
// 22a. The declaration is what the inspector draws: a head that can add fields, a row per field.
|
||||
check('a struct variable carries the add-a-field control', (await find('+ Field')) !== null);
|
||||
@@ -62,7 +61,6 @@ export async function structVariable(t) {
|
||||
await click(xField.x, xField.y);
|
||||
await typeText('42');
|
||||
await press('Enter');
|
||||
await sleep(200);
|
||||
check('typing in a field writes that field', (await piece()).x === 42, JSON.stringify(await piece()));
|
||||
|
||||
const tagField = await json("__gm.inspectorField('tag')");
|
||||
@@ -70,7 +68,6 @@ export async function structVariable(t) {
|
||||
await press('a', { ctrl: true });
|
||||
await typeText('ell');
|
||||
await press('Enter');
|
||||
await sleep(200);
|
||||
check(
|
||||
'and the next field edited keeps the one before it',
|
||||
JSON.stringify(await piece()) === '{"x":42,"tag":"ell"}',
|
||||
@@ -85,7 +82,6 @@ export async function structVariable(t) {
|
||||
|
||||
// 22d. Adding a field reaches the declaration and the value at once.
|
||||
await clickText('+ Field');
|
||||
await sleep(150);
|
||||
await pickKind('Boolean');
|
||||
await sleep(250);
|
||||
const grown = await piece();
|
||||
@@ -93,7 +89,6 @@ export async function structVariable(t) {
|
||||
check('and the new field has a row', (await find('field1')) !== null);
|
||||
await shot('02-field-added');
|
||||
await undo();
|
||||
await sleep(200);
|
||||
check('undo takes it out of the value too', !('field1' in (await piece())), JSON.stringify(await piece()));
|
||||
|
||||
// 22e. Renaming a field carries its value along.
|
||||
@@ -102,7 +97,6 @@ export async function structVariable(t) {
|
||||
await press('a', { ctrl: true });
|
||||
await typeText('column');
|
||||
await press('Enter');
|
||||
await sleep(250);
|
||||
check(
|
||||
'renaming a field keeps its value',
|
||||
JSON.stringify(await piece()) === '{"column":30,"tag":"tee"}',
|
||||
@@ -112,11 +106,9 @@ export async function structVariable(t) {
|
||||
// 22f. A field may itself be a list. Its row is the same "n items" button a list property has,
|
||||
// and it opens the List tab one level down – on the field, not on the whole bundle.
|
||||
await clickText('+ Field');
|
||||
await sleep(150);
|
||||
// "List" is also the tab bar's own label, so the menu entry is reached as the last drawn one.
|
||||
const listOption = await json(`__gm.locate('List', true)`);
|
||||
await click(listOption.x, listOption.y);
|
||||
await sleep(250);
|
||||
check(
|
||||
'+ Field ▸ List gives the bundle an empty list',
|
||||
Array.isArray((await piece()).field1),
|
||||
@@ -126,7 +118,6 @@ export async function structVariable(t) {
|
||||
check('and that field reads as an item count', itemsButton !== null);
|
||||
|
||||
await click(itemsButton.x, itemsButton.y);
|
||||
await sleep(250);
|
||||
check('clicking it opens the List tab', (await json('__gm.tab()')) === 'list');
|
||||
const info = await json('__gm.list.info()');
|
||||
check('whose title names the field inside the bundle', info.title.endsWith('· field1'), info.title);
|
||||
@@ -134,7 +125,6 @@ export async function structVariable(t) {
|
||||
// The depth the stored value goes ends here: this list sits in a struct field, so a struct item
|
||||
// would be dropped by the next write. It is left out of the menu rather than doing nothing.
|
||||
await clickText('+ Item');
|
||||
await sleep(150);
|
||||
check(
|
||||
'the menu of a list in a struct field leaves the struct kind out',
|
||||
(await find('Number')) !== null && (await find('Struct')) === null,
|
||||
@@ -150,7 +140,6 @@ export async function structVariable(t) {
|
||||
await shot('03-list-field');
|
||||
await undo();
|
||||
await undo();
|
||||
await sleep(200);
|
||||
check(
|
||||
'undo takes the list field back out of the bundle',
|
||||
!('field1' in (await piece())),
|
||||
@@ -158,7 +147,6 @@ export async function structVariable(t) {
|
||||
);
|
||||
|
||||
await mutate('__gm.state.openList(null)');
|
||||
await sleep(200);
|
||||
|
||||
// 22g. The same bundle on a placed object. An override is sparse – it starts out unset – while a
|
||||
// field edit rebuilds the whole bundle, so the untouched fields have to come from what the row
|
||||
@@ -177,7 +165,6 @@ export async function structVariable(t) {
|
||||
});
|
||||
`);
|
||||
await select({ kind: 'object', holderId: 'scene1', objectId: 'ostruct' });
|
||||
await sleep(200);
|
||||
check('a placed behavior shows its bundle, filled from the asset', (await find('tee')) !== null);
|
||||
|
||||
// 22h. It reads exactly like the asset does: a head carrying the struct mark, then one row per
|
||||
@@ -236,7 +223,6 @@ export async function structVariable(t) {
|
||||
await press('a', { ctrl: true });
|
||||
await typeText('7');
|
||||
await press('Enter');
|
||||
await sleep(250);
|
||||
check(
|
||||
'the first override of one field keeps the asset values of the others',
|
||||
JSON.stringify(await placed()) === '{"column":7,"tag":"tee"}',
|
||||
@@ -245,7 +231,6 @@ export async function structVariable(t) {
|
||||
await shot('04-object-override');
|
||||
|
||||
await undo();
|
||||
await sleep(200);
|
||||
check(
|
||||
'and undo takes the override away again, not just the one field',
|
||||
(await json("__gm.state.activeScene.objects.find((o) => o.id === 'ostruct').overrides.piece")) === null,
|
||||
@@ -260,7 +245,6 @@ export async function structVariable(t) {
|
||||
__gm.state.select(null);
|
||||
__gm.state.preview();
|
||||
`);
|
||||
await sleep(200);
|
||||
const left = await json(
|
||||
'__gm.state.project.assets.filter((a) => a.id === "structy").length +' +
|
||||
' __gm.state.activeScene.objects.filter((o) => o.id === "ostruct").length',
|
||||
|
||||
Reference in new issue
Block a user