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
+9
-73
@@ -6,6 +6,7 @@ export async function graph(t) {
|
||||
const {
|
||||
check,
|
||||
sleep,
|
||||
saved,
|
||||
evaluate,
|
||||
json,
|
||||
find,
|
||||
@@ -26,6 +27,7 @@ export async function graph(t) {
|
||||
api,
|
||||
navigate,
|
||||
projectId,
|
||||
showTab,
|
||||
} = t;
|
||||
const nodeOf = async (id) => (await asset('mover')).graph.nodes.find((n) => n.id === id);
|
||||
const graphCounts = async () => {
|
||||
@@ -36,8 +38,7 @@ export async function graph(t) {
|
||||
|
||||
// 6a. Selecting the Mover asset binds the graph; the Behavior tab shows it.
|
||||
await clickText('Mover');
|
||||
await evaluate(`__gm.showTab('graph')`);
|
||||
await sleep(250);
|
||||
await showTab('graph');
|
||||
check(
|
||||
'graph editor shows the selected behavior',
|
||||
(await evaluate(`__gm.graph.current()`)) === 'mover' && (await evaluate('__gm.tab()')) === 'graph',
|
||||
@@ -79,13 +80,10 @@ export async function graph(t) {
|
||||
const bare = await json('__gm.graph.emptySpot()');
|
||||
const beforeClickPick = await graphCounts();
|
||||
await click(bare.x, bare.y, 'right');
|
||||
await sleep(100);
|
||||
check('node palette opens (row-click case)', Boolean(await evaluate(`__gm.locate('Search nodes…')`)));
|
||||
await typeText('stop');
|
||||
await sleep(150);
|
||||
const stopRow = await locate('Stop game'); // nothing else on screen shows this label
|
||||
await click(stopRow.x, stopRow.y);
|
||||
await sleep(100);
|
||||
const afterClickPick = await graphCounts();
|
||||
check(
|
||||
'clicking a palette row adds exactly one node',
|
||||
@@ -99,7 +97,6 @@ export async function graph(t) {
|
||||
// 6d. Right-click the empty canvas → palette → search "log" → Enter adds a Log node.
|
||||
const before13 = await graphCounts();
|
||||
await click(bare.x, bare.y, 'right');
|
||||
await sleep(100);
|
||||
check('node palette opens', Boolean(await evaluate(`__gm.locate('Search nodes…')`)));
|
||||
// Unfiltered the palette holds far more nodes than fit, so it grows to the full height it may
|
||||
// have – and that height is the canvas minus a tenth at each end. Shifting it up to fit used to
|
||||
@@ -116,9 +113,7 @@ export async function graph(t) {
|
||||
JSON.stringify({ gapAbove, gapBelow, paletteMargin, paletteScreenH }),
|
||||
);
|
||||
await typeText('log');
|
||||
await sleep(100);
|
||||
await press('Enter');
|
||||
await sleep(250);
|
||||
const after13 = await graphCounts();
|
||||
s = await state();
|
||||
const newNode = s.selection?.kind === 'node' ? await nodeOf(s.selection.nodeId) : null;
|
||||
@@ -134,9 +129,7 @@ export async function graph(t) {
|
||||
// Enter the first row alphabetically, which was `Run behavior`.
|
||||
const beforeRank = await graphCounts();
|
||||
await click(bare.x, bare.y, 'right');
|
||||
await sleep(100);
|
||||
await typeText('variable');
|
||||
await sleep(150);
|
||||
const ranked = await json('__gm.graph.paletteRows()');
|
||||
const hits = (row) => `${row.label} ${row.type}`.toLowerCase().includes('variable');
|
||||
const lastNamed = ranked.map(hits).lastIndexOf(true);
|
||||
@@ -147,7 +140,6 @@ export async function graph(t) {
|
||||
JSON.stringify(ranked),
|
||||
);
|
||||
await press('Enter');
|
||||
await sleep(250);
|
||||
s = await state();
|
||||
const rankPick = s.selection?.kind === 'node' ? await nodeOf(s.selection.nodeId) : null;
|
||||
check(
|
||||
@@ -156,7 +148,6 @@ export async function graph(t) {
|
||||
JSON.stringify(rankPick),
|
||||
);
|
||||
await undo();
|
||||
await sleep(150);
|
||||
check('undo removes it again', (await graphCounts()).nodes === beforeRank.nodes);
|
||||
|
||||
// 6e. Connect: drag from the Move node's exec output onto the Log node's exec input. An
|
||||
@@ -240,7 +231,6 @@ export async function graph(t) {
|
||||
await shot('18c-drop-into-empty');
|
||||
const clampRow = await locate('Clamp');
|
||||
await click(clampRow.x, clampRow.y);
|
||||
await sleep(200);
|
||||
const afterDrop = await graphCounts();
|
||||
const wired = await state();
|
||||
const clampEdge = (await asset('mover')).graph.edges.find(
|
||||
@@ -272,7 +262,6 @@ export async function graph(t) {
|
||||
await mouse('mouseReleased', empty.x, empty.y);
|
||||
await sleep(150);
|
||||
await press('Escape');
|
||||
await sleep(150);
|
||||
const cancelled = await graphCounts();
|
||||
check(
|
||||
'escaping the palette clears the edge and adds nothing',
|
||||
@@ -284,10 +273,8 @@ export async function graph(t) {
|
||||
|
||||
// 6f. Delete removes the selected node together with its edge; undo brings both back.
|
||||
await select({ kind: 'node', assetId: 'mover', nodeId: newNode.id });
|
||||
await sleep(200);
|
||||
check('the node inspector has no delete button of its own', !(await t.has('Delete node')));
|
||||
await press('Delete');
|
||||
await sleep(150);
|
||||
const deleted = await graphCounts();
|
||||
check(
|
||||
'Delete removes the node and its edge',
|
||||
@@ -324,8 +311,7 @@ export async function graph(t) {
|
||||
typeof fpsPlay === 'number' && fpsPlay > 0,
|
||||
`fps=${fpsPlay}`,
|
||||
);
|
||||
await evaluate(`__gm.showTab('graph')`);
|
||||
await sleep(100);
|
||||
await showTab('graph');
|
||||
const holding = holdKey('ArrowRight', 300);
|
||||
await sleep(250);
|
||||
await shot('19-graph-live');
|
||||
@@ -334,10 +320,8 @@ export async function graph(t) {
|
||||
|
||||
// 6h. Variables: the "+ Variable" dropdown → Number adds "var1" with default 0; undo removes it.
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(150);
|
||||
await clickText('+ Variable');
|
||||
await clickText('Number');
|
||||
await sleep(100);
|
||||
check(
|
||||
'adding a variable declares it on the behavior',
|
||||
(await variableKeys()) === 'speed,var1',
|
||||
@@ -358,13 +342,11 @@ export async function graph(t) {
|
||||
);
|
||||
check('the header has no Add node button – the right-click palette is the way', !(await find('Add node…')));
|
||||
await select(null);
|
||||
await sleep(100);
|
||||
check(
|
||||
'graph editor keeps its behavior when nothing is selected',
|
||||
(await evaluate(`__gm.graph.current()`)) === 'mover',
|
||||
);
|
||||
await select({ kind: 'asset', assetId: 'cam' });
|
||||
await sleep(100);
|
||||
check(
|
||||
'graph editor keeps its behavior for a non-behavior asset',
|
||||
(await evaluate(`__gm.graph.current()`)) === 'mover',
|
||||
@@ -372,17 +354,14 @@ export async function graph(t) {
|
||||
// The picker is the *last* "Mover" on screen: the assets panel shows one too.
|
||||
const pickerAt = await locate('Mover', true);
|
||||
await click(pickerAt.x, pickerAt.y);
|
||||
await sleep(150);
|
||||
const spawnerRow = await locate('Spawner', true);
|
||||
await click(spawnerRow.x, spawnerRow.y);
|
||||
await sleep(200);
|
||||
check(
|
||||
'the header picker switches the graph to another behavior',
|
||||
(await evaluate(`__gm.graph.current()`)) === 'spawner',
|
||||
String(await evaluate(`__gm.graph.current()`)),
|
||||
);
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(100);
|
||||
check(
|
||||
'graph editor rebinds when a behavior is selected again',
|
||||
(await evaluate(`__gm.graph.current()`)) === 'mover',
|
||||
@@ -391,7 +370,6 @@ export async function graph(t) {
|
||||
// 6j. Mouse behaviour, as in the scene view: the middle button pans from anywhere – a node
|
||||
// under it included – and the left button no longer pans at all.
|
||||
await clickText('Fit');
|
||||
await sleep(250);
|
||||
const positions = async () =>
|
||||
(await asset('mover')).graph.nodes.map((n) => `${n.id}:${n.x},${n.y}`).join(' ');
|
||||
const area = await json('__gm.graph.canvasRect()');
|
||||
@@ -415,7 +393,6 @@ export async function graph(t) {
|
||||
|
||||
// Fit again: the pan just now pushed a node out of view, and a band takes only what it sees.
|
||||
await clickText('Fit');
|
||||
await sleep(250);
|
||||
// An empty spot: after a fit every node sits at least a margin away from the corner.
|
||||
const corner = { x: area.x + 6, y: area.y + 6 };
|
||||
const opposite = { x: area.x + area.w - 6, y: area.y + area.h - 6 };
|
||||
@@ -464,7 +441,6 @@ export async function graph(t) {
|
||||
const snapLabel = await locate('Snap');
|
||||
// The checkbox sits right of the "Snap" label; locate() gives the label's text centre.
|
||||
await click(snapLabel.x + 30, snapLabel.y);
|
||||
await sleep(150);
|
||||
check(
|
||||
'the toggle switches it on without moving a single node',
|
||||
(await json('__gm.graph.snapping()')) === true && (await positions()) === before13i,
|
||||
@@ -473,7 +449,6 @@ export async function graph(t) {
|
||||
|
||||
// A single node: dropped between two grid lines, it lands on the nearer one.
|
||||
await click(corner.x, corner.y);
|
||||
await sleep(150);
|
||||
const snapPre = await nodeOf('n-axis');
|
||||
const snapFrom = await json(`__gm.graph.nodeAt('n-axis')`);
|
||||
const snapBy = await units(50);
|
||||
@@ -521,9 +496,7 @@ export async function graph(t) {
|
||||
|
||||
// Switching it off has to give the pointer its exact drop position back.
|
||||
await click(snapLabel.x + 30, snapLabel.y);
|
||||
await sleep(150);
|
||||
await click(corner.x, corner.y);
|
||||
await sleep(150);
|
||||
const offPre = await nodeOf('n-axis');
|
||||
const offFrom = await json(`__gm.graph.nodeAt('n-axis')`);
|
||||
const offBy = await units(50);
|
||||
@@ -538,13 +511,11 @@ export async function graph(t) {
|
||||
`${offPre.x},${offPre.y} → ${offPost.x},${offPost.y}`,
|
||||
);
|
||||
await undo();
|
||||
await sleep(150);
|
||||
|
||||
// 6m. Delete acts on the selection, not just the primary node.
|
||||
await drag(corner.x, corner.y, opposite.x, opposite.y, { steps: 16 });
|
||||
const beforeDelete = await graphCounts();
|
||||
await press('Delete');
|
||||
await sleep(200);
|
||||
const afterDelete = await graphCounts();
|
||||
check(
|
||||
'Delete removes every selected node, edges with them',
|
||||
@@ -563,7 +534,6 @@ export async function graph(t) {
|
||||
// and a click cannot miss one that the earlier pan pushed over the edge.
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await clickText('Fit');
|
||||
await sleep(250);
|
||||
const axisRow = await json(`__gm.graph.nodeAt('n-axis')`);
|
||||
await click(axisRow.x, axisRow.y);
|
||||
const second = (await asset('mover')).graph.nodes.find((n) => n.id !== 'n-axis');
|
||||
@@ -591,7 +561,6 @@ export async function graph(t) {
|
||||
);
|
||||
await sleep(250);
|
||||
await clickText('Fit');
|
||||
await sleep(300);
|
||||
const rects = [];
|
||||
for (const node of (await asset('mover')).graph.nodes)
|
||||
rects.push(await json(`__gm.graph.nodeRect(${JSON.stringify(node.id)})`));
|
||||
@@ -614,14 +583,12 @@ export async function graph(t) {
|
||||
`(() => { const n = __gm.state.project.assets.find(a => a.id === 'mover').graph.nodes.find(n => n.id === 'n-axis'); n.x -= ${park}; __gm.state.preview(); })()`,
|
||||
);
|
||||
await clickText('Fit');
|
||||
await sleep(250);
|
||||
check('the parked node is back where it started', (await positions()) === before13i, await positions());
|
||||
|
||||
// 6p. Hiding a link: it stops being drawn across the graph but keeps carrying its value, and
|
||||
// comes back while either of its two nodes is selected.
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await clickText('Fit');
|
||||
await sleep(250);
|
||||
const allEdges = (await asset('mover')).graph.edges;
|
||||
const edge = allEdges.find((e) => e.from.port !== 'exec') ?? allEdges[0];
|
||||
const id = JSON.stringify(edge.id);
|
||||
@@ -633,12 +600,9 @@ export async function graph(t) {
|
||||
`__gm.graph.portAt(${JSON.stringify(edge.from.node)}, ${JSON.stringify(edge.from.port)}, true)`,
|
||||
);
|
||||
await click(outPort.x, outPort.y, 'right');
|
||||
await sleep(150);
|
||||
check('right-clicking a port offers hiding its link', Boolean(await evaluate(`__gm.locate('Hide link')`)));
|
||||
await clickText('Hide link');
|
||||
await sleep(250);
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(150);
|
||||
const hidden = await edgeNow();
|
||||
check(
|
||||
'hiding changes nothing but a flag – the connection is still there',
|
||||
@@ -660,21 +624,17 @@ export async function graph(t) {
|
||||
// Selecting either end lends the curve back – the source first, then the target.
|
||||
const sourceAt = await json(`__gm.graph.nodeAt(${JSON.stringify(edge.from.node)})`);
|
||||
await click(sourceAt.x, sourceAt.y);
|
||||
await sleep(200);
|
||||
check('selecting the node at one end brings the curve back', (await drawn()) === true);
|
||||
const targetAt = await json(`__gm.graph.nodeAt(${JSON.stringify(edge.to.node)})`);
|
||||
await click(targetAt.x, targetAt.y);
|
||||
await sleep(200);
|
||||
check('selecting the node at the other end does too', (await drawn()) === true);
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(200);
|
||||
check('deselecting hides it again', (await drawn()) === false);
|
||||
|
||||
// The mark is the handle: clicking it selects the node at the far end, which is also what
|
||||
// puts the curve back – so it answers "where does this go?" in one click.
|
||||
const mark2 = await json(`__gm.graph.foldMark(${id}, true)`);
|
||||
await click(mark2.x, mark2.y);
|
||||
await sleep(200);
|
||||
check(
|
||||
'clicking the mark jumps to the node at the far end',
|
||||
JSON.stringify(await json('__gm.graph.selected()')) === JSON.stringify([edge.to.node]),
|
||||
@@ -684,7 +644,6 @@ export async function graph(t) {
|
||||
|
||||
await undo();
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(250);
|
||||
const shown = await edgeNow();
|
||||
check(
|
||||
'undo unhides the link, with nothing left behind',
|
||||
@@ -737,12 +696,9 @@ export async function graph(t) {
|
||||
);
|
||||
|
||||
await click(forkPort.x, forkPort.y, 'right');
|
||||
await sleep(150);
|
||||
check('the port menu counts what it would hide', Boolean(await evaluate(`__gm.locate('Hide 2 links')`)));
|
||||
await clickText('Hide 2 links');
|
||||
await sleep(250);
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(200);
|
||||
const ids = forked.map((e) => JSON.stringify(e.id));
|
||||
const markA = await json(`__gm.graph.foldMark(${ids[0]}, true)`);
|
||||
const markB = await json(`__gm.graph.foldMark(${ids[1]}, true)`);
|
||||
@@ -767,7 +723,6 @@ export async function graph(t) {
|
||||
// The bundled mark is still a handle: one click selects every far end, which is also what
|
||||
// lends all of its curves back at once.
|
||||
await click(markA.x, markA.y);
|
||||
await sleep(250);
|
||||
const picked = await json('__gm.graph.selected()');
|
||||
check(
|
||||
'clicking a bundled mark selects every node the port feeds',
|
||||
@@ -781,15 +736,12 @@ export async function graph(t) {
|
||||
);
|
||||
|
||||
await click(markA.x, markA.y, 'right');
|
||||
await sleep(150);
|
||||
check(
|
||||
'the mark menu shows both links back in one go',
|
||||
Boolean(await evaluate(`__gm.locate('Show 2 links')`)),
|
||||
);
|
||||
await clickText('Show 2 links');
|
||||
await sleep(250);
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(200);
|
||||
const unfolded = (await asset('mover')).graph.edges.filter(
|
||||
(e) => e.from.node === edge.from.node && e.from.port === edge.from.port,
|
||||
);
|
||||
@@ -801,7 +753,6 @@ export async function graph(t) {
|
||||
// One step of undo takes both back – hiding two links was one command, so it is one undo.
|
||||
await undo();
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(250);
|
||||
const refolded = (await asset('mover')).graph.edges.filter(
|
||||
(e) => e.from.node === edge.from.node && e.from.port === edge.from.port,
|
||||
);
|
||||
@@ -811,7 +762,6 @@ export async function graph(t) {
|
||||
JSON.stringify(refolded.map((e) => e.folded)),
|
||||
);
|
||||
await undo();
|
||||
await sleep(200);
|
||||
|
||||
const forkedNow = async () =>
|
||||
(await asset('mover')).graph.edges.filter(
|
||||
@@ -821,13 +771,11 @@ export async function graph(t) {
|
||||
`__gm.graph.portAt(${JSON.stringify(edge.from.node)}, ${JSON.stringify(edge.from.port)}, true)`,
|
||||
);
|
||||
await click(portNow.x, portNow.y, 'right');
|
||||
await sleep(150);
|
||||
const offered = await find('Disconnect 2 links');
|
||||
if (offered) await click(offered.x, offered.y);
|
||||
await sleep(250);
|
||||
const cut = await forkedNow();
|
||||
await undo();
|
||||
await sleep(250);
|
||||
check(
|
||||
'disconnecting both links at a port is one undo step',
|
||||
Boolean(offered) && cut === 0 && (await forkedNow()) === 2,
|
||||
@@ -838,12 +786,10 @@ export async function graph(t) {
|
||||
// link lands on it until it is expanded, and the state is saved with the project.
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await clickText('Fit');
|
||||
await sleep(250);
|
||||
const edgesBefore13q = (await graphCounts()).edges;
|
||||
const openRect = await json(`__gm.graph.nodeRect('n-move')`);
|
||||
const chevron = await json(`__gm.graph.chevronAt('n-move')`);
|
||||
await click(chevron.x, chevron.y);
|
||||
await sleep(200);
|
||||
const shut = await json(`__gm.graph.nodeRect('n-move')`);
|
||||
const zoom = openRect.w / 176;
|
||||
check(
|
||||
@@ -902,12 +848,9 @@ export async function graph(t) {
|
||||
for (const port of ['x', 'y']) {
|
||||
const at = await json(`__gm.graph.portAt('n-axis', '${port}', true)`);
|
||||
await click(at.x, at.y, 'right');
|
||||
await sleep(150);
|
||||
await clickText('Hide link');
|
||||
await sleep(200);
|
||||
}
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await sleep(200);
|
||||
const markDx = await json(`__gm.graph.foldMark('e3', false)`);
|
||||
const markDy = await json(`__gm.graph.foldMark('e4', false)`);
|
||||
check(
|
||||
@@ -919,9 +862,7 @@ export async function graph(t) {
|
||||
await undo();
|
||||
|
||||
await select({ kind: 'node', assetId: 'mover', nodeId: 'n-move', nodeIds: ['n-speed', 'n-move'] });
|
||||
await sleep(150);
|
||||
await click(title.x, title.y, 'right');
|
||||
await sleep(150);
|
||||
check(
|
||||
'a mixed selection is offered both ways',
|
||||
Boolean(await evaluate(`__gm.locate('Collapse node', false)`)) &&
|
||||
@@ -929,14 +870,11 @@ export async function graph(t) {
|
||||
);
|
||||
await press('Escape');
|
||||
await undo();
|
||||
await sleep(150);
|
||||
check('undo expands it again', (await nodeOf('n-move')).collapsed === undefined);
|
||||
|
||||
await select({ kind: 'node', assetId: 'mover', nodeId: 'n-move', nodeIds: ['n-speed', 'n-move'] });
|
||||
await sleep(150);
|
||||
const openTitle = await json(`__gm.graph.nodeAt('n-move')`);
|
||||
await click(openTitle.x, openTitle.y, 'right');
|
||||
await sleep(150);
|
||||
const collapseBoth = await json(`__gm.locate('Collapse 2 nodes', false)`);
|
||||
check('two expanded nodes are offered as one', collapseBoth !== null);
|
||||
if (collapseBoth) await click(collapseBoth.x, collapseBoth.y);
|
||||
@@ -945,7 +883,6 @@ export async function graph(t) {
|
||||
const both = async () => [(await nodeOf('n-speed')).collapsed, (await nodeOf('n-move')).collapsed];
|
||||
check('the menu collapses the whole selection', JSON.stringify(await both()) === '[true,true]');
|
||||
await undo();
|
||||
await sleep(150);
|
||||
check(
|
||||
'and one undo takes all of it back',
|
||||
JSON.stringify(await both()) === '[null,null]',
|
||||
@@ -957,16 +894,15 @@ export async function graph(t) {
|
||||
const again = await json(`__gm.graph.chevronAt('n-move')`);
|
||||
await click(again.x, again.y);
|
||||
const savedMove = async () => {
|
||||
for (let i = 0; i < 30 && (await state()).save !== 'saved'; i++) await sleep(300);
|
||||
const saved = await api(`projects/${projectId}`);
|
||||
return saved.project.assets.find((a) => a.id === 'mover').graph.nodes.find((n) => n.id === 'n-move');
|
||||
await saved();
|
||||
const doc = await api(`projects/${projectId}`);
|
||||
return doc.project.assets.find((a) => a.id === 'mover').graph.nodes.find((n) => n.id === 'n-move');
|
||||
};
|
||||
check('the collapse reaches the saved file', (await savedMove()).collapsed === true);
|
||||
await navigate();
|
||||
await sleep(500);
|
||||
await select({ kind: 'asset', assetId: 'mover' });
|
||||
await evaluate(`__gm.showTab('graph')`);
|
||||
await sleep(250);
|
||||
await showTab('graph');
|
||||
const reloaded = await json(`__gm.graph.nodeRect('n-move')`);
|
||||
check(
|
||||
'and a reloaded project draws it collapsed again',
|
||||
@@ -977,5 +913,5 @@ export async function graph(t) {
|
||||
await click(reopen.x, reopen.y);
|
||||
check('expanding leaves no trace in the file', !('collapsed' in (await savedMove())));
|
||||
|
||||
await evaluate(`__gm.showTab('scene')`);
|
||||
await showTab('scene');
|
||||
}
|
||||
Reference in new issue
Block a user