Progress bar and steps while generating, loading, opening claims and travelling; saving chip (t30)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,24 @@ with sync_playwright() as p:
|
||||
catch (e) { return await DB.get('abort-test') === undefined; }
|
||||
return false;
|
||||
}"""))
|
||||
check('async generation preserves the world and yields frames with labels', pg.evaluate("""async () => {
|
||||
const hash = a => { let h = 2166136261; for (const v of a) h = Math.imul(h ^ v, 16777619); return h; };
|
||||
generateWorld(424242, 2048, 1024); const want = hash(mat);
|
||||
let frames = 0, active = true, labels = [];
|
||||
const frameCount = () => { if (active) { frames++; requestAnimationFrame(frameCount); } };
|
||||
requestAnimationFrame(frameCount);
|
||||
showLoading(true, 0, '', 'Generating world');
|
||||
try {
|
||||
await generateWorldAsync(424242, 2048, 1024, (f, s) => { showLoading(true, f, s); labels.push($('loadstep').textContent); });
|
||||
return hash(mat) === want && frames > 1 && labels.includes('Settling loose ground') && labels.every(Boolean);
|
||||
} finally { active = false; showLoading(false); }
|
||||
}"""))
|
||||
# Record progress at the browser's own frame boundaries, without slowing the operation.
|
||||
pg.add_init_script("""
|
||||
window.__loads = [];
|
||||
const watch = () => { if (typeof GAME !== 'undefined' && GAME.loading) __loads.push([$('loading').querySelector('.label').textContent, $('loadstep').textContent, $('loadbar').style.width]); requestAnimationFrame(watch); };
|
||||
requestAnimationFrame(watch);
|
||||
""")
|
||||
# Migrate a real legacy save before starting the play-through.
|
||||
pg.evaluate("generateWorld(12345, 512, 384, null)")
|
||||
pg.evaluate("async () => { const s = serializeWorld(); await DB.put('main', { ...s, savedAt: Date.now(), playTime: 3661 }); }")
|
||||
@@ -39,7 +57,18 @@ with sync_playwright() as p:
|
||||
pg.reload(); pg.wait_for_function("!$('title').hidden && !$('btn-continue').hidden")
|
||||
check('legacy save becomes World 1 and retires its old key', pg.evaluate("async () => { const w = await listWorlds(); return w.length === 1 && w[0].name === 'World 1' && await DB.get('main') === undefined; }"))
|
||||
pg.click('#btn-continue'); pg.wait_for_function('GAME.running')
|
||||
check('Continue paints loading steps', pg.evaluate("__loads.some(([t, s]) => t === 'Loading world' && s === 'Building the world') && !GAME.loading && $('loading').hidden"))
|
||||
check('Continue loads the migrated seed and playtime', pg.evaluate('worldSeed === 12345 && GAME.playTime >= 3661 && !!GAME.worldId'))
|
||||
pg.evaluate("""() => {
|
||||
window.__pack = packBuffers;
|
||||
packBuffers = async b => { await new Promise(r => setTimeout(r, 600)); return __pack(b); };
|
||||
window.__saving = saveWorld('main', true);
|
||||
}""")
|
||||
pg.locator('#saving').wait_for(state='visible')
|
||||
pg.screenshot(path=str(out / 'saving-progress.png'))
|
||||
check('slow save shows the saving chip', pg.is_visible('#saving'))
|
||||
pg.evaluate('async () => { await __saving; packBuffers = __pack; }')
|
||||
check('saving chip hides when the save ends', not pg.is_visible('#saving'))
|
||||
pg.evaluate('quitToTitle()')
|
||||
names = {}
|
||||
for seed in [222, 333]:
|
||||
@@ -53,6 +82,7 @@ with sync_playwright() as p:
|
||||
pg.screenshot(path=str(out / 'new-world.png'))
|
||||
pg.fill('#nw-seed', str(seed)); pg.press('#nw-name' if seed == 222 else '#nw-seed', 'Enter')
|
||||
pg.wait_for_function('GAME.running', timeout=20000)
|
||||
check(f'new world {seed} paints a moving generation bar', pg.evaluate("__loads.some(([t, s, w]) => t === 'Generating world' && parseFloat(w) > 0 && parseFloat(w) < 90) && !GAME.loading"))
|
||||
check(f'new world {seed} shows the Welcome card', pg.evaluate("[...$('cards').children].some(c => c.textContent.includes('Welcome'))"))
|
||||
check(f'pause menu shows world {seed} name', names[seed] in pg.evaluate("() => { openPause(); return $('pause-meta').textContent; }"))
|
||||
pg.evaluate('quitToTitle()')
|
||||
@@ -1058,6 +1088,8 @@ with sync_playwright() as p:
|
||||
check('the size menu offers small, medium, large and huge', pg2.evaluate("[...document.querySelectorAll('#nw-size option')].map(o => o.value).join(',')") == '2048x1024,3072x1280,4096x1536,6144x2048', pg2.evaluate("[...document.querySelectorAll('#nw-size option')].map(o => o.value).join(',')"))
|
||||
check('Medium remains the default size', pg2.input_value('#nw-size') == '3072x1280')
|
||||
pg2.click('#btn-new'); pg2.fill('#nw-seed', '4242'); pg2.select_option('#nw-size', '6144x2048'); pg2.click('#btn-generate')
|
||||
pg2.wait_for_function("GAME.loading && parseFloat($('loadbar').style.width) > 10 && parseFloat($('loadbar').style.width) < 85", timeout=30000)
|
||||
pg2.screenshot(path=str(out / 'generation-progress.png'))
|
||||
pg2.wait_for_function('GAME.running === true', timeout=90000)
|
||||
check('huge world generates', pg2.evaluate('W === 6144 && H === 2048'), pg2.evaluate('[W, H]'))
|
||||
pg2.evaluate("bot.x = 2000; bot.y = magmaY[2000] - 60; snapCamera();"); pg2.wait_for_timeout(800)
|
||||
|
||||
@@ -6,6 +6,15 @@ const { check, done } = suite();
|
||||
const fresh = () => { flatWorld(run, 240, 160, 100); run('player.tankTier = 3; saplings = []; stats.grown = 0;'); };
|
||||
const box = (x0, y0, x1, y1, m) => rect(run, x0, y0, x1, y1, m);
|
||||
|
||||
const { createHash } = require('node:crypto');
|
||||
const worldHash = () => { const hash = createHash('sha256'); for (const k of ['mat', 'temp', 'flags']) { const a = run(k); hash.update(new Uint8Array(a.buffer, a.byteOffset, a.byteLength)); } return hash.digest('hex'); };
|
||||
run('generateWorld(4242, 512, 384)');
|
||||
const generatedHash = worldHash();
|
||||
const progress = [];
|
||||
run('generateWorld')(4242, 512, 384, (f, label) => progress.push([f, label]));
|
||||
check('generation progress rises to 1 with named steps', progress.length > 10 && progress[0][0] === 0 && progress.at(-1)[0] === 1 && progress.every(([f, label], i) => f >= 0 && f <= 1 && (!i || f >= progress[i - 1][0]) && typeof label === 'string' && label.length > 0));
|
||||
check('generation callback keeps the same world', worldHash() === generatedHash);
|
||||
|
||||
// 1. acorns sprout on soil under open sky and grow into a tree
|
||||
fresh();
|
||||
box(100, 100, 140, 103, run('DIRT'));
|
||||
|
||||
Reference in New Issue
Block a user