101 lines
5.6 KiB
Python
101 lines
5.6 KiB
Python
"""Dev console confirmation, keyboard isolation, HUD, time controls and saved badge."""
|
|
import pathlib, sys
|
|
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / 'tools'))
|
|
from use_venv import ensure_playwright; ensure_playwright()
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
SHOTS = ROOT / 'shots'
|
|
SHOTS.mkdir(exist_ok=True)
|
|
fails = []
|
|
def check(name, ok):
|
|
print(('PASS ' if ok else 'FAIL ') + name)
|
|
if not ok: fails.append(name)
|
|
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch()
|
|
page = browser.new_page(viewport={'width': 1280, 'height': 760})
|
|
errors = []
|
|
page.on('pageerror', lambda e: errors.append(str(e)))
|
|
page.add_init_script("localStorage.setItem('deepgrain.settings', JSON.stringify({look:'pixel', sv:2}));")
|
|
page.goto((ROOT / 'dist/index.html').as_uri())
|
|
page.wait_for_function("!$('title').hidden")
|
|
page.evaluate("startNewWorld(424242, 512, 384, 'Console test')")
|
|
page.wait_for_function('GAME.running && !GAME.loading')
|
|
page.evaluate("document.querySelectorAll('.card, .toast').forEach(e => e.remove())")
|
|
page.keyboard.press('`')
|
|
check('backtick opens the first-use warning', page.is_visible('#m-dialog') and not page.is_visible('#dev-console'))
|
|
page.screenshot(path=str(SHOTS / 't66-warning.png'))
|
|
check('warning explains permanent marking and future achievements', 'permanently' in page.inner_text('#dlg-body') and 'achievements' in page.inner_text('#dlg-body'))
|
|
page.get_by_role('button', name='Cancel', exact=True).click()
|
|
check('cancel leaves the world unmarked and console closed', page.evaluate("!devWorld && $('dev-console').hidden && !GAME.paused"))
|
|
page.keyboard.press('`')
|
|
page.get_by_role('button', name='Enable dev console', exact=True).click()
|
|
page.wait_for_function("!$('dev-console').hidden && document.activeElement === $('dev-input')")
|
|
check('accepting marks the world and resumes play', page.evaluate('devWorld && !GAME.paused'))
|
|
check('build material chip stays stable across HUD refreshes', page.evaluate("""() => {
|
|
selectTool(2); renderSelCard();
|
|
const chip = $('selcard').querySelector('[data-wall-picker]');
|
|
renderSelCard();
|
|
const stable = chip === $('selcard').querySelector('[data-wall-picker]');
|
|
selectTool(0); return stable;
|
|
}"""))
|
|
old_money = page.evaluate('money')
|
|
page.fill('#dev-input', 'money 1000'); page.keyboard.press('Enter')
|
|
page.wait_for_function(f"money === {old_money + 1000} && $('wallet').textContent.includes(fmtMoney(money))")
|
|
check('money command changes the wallet HUD', True)
|
|
tool = page.evaluate('GAME.tool')
|
|
page.fill('#dev-input', ''); page.keyboard.type('1234wasd')
|
|
check('typing game keys does not switch tools or hold movement', page.evaluate(f'GAME.tool === {tool} && keys.size === 0'))
|
|
page.keyboard.press('Escape')
|
|
check('Escape closes console without opening pause menu', page.evaluate("$('dev-console').hidden && $('m-pause').hidden && !GAME.paused"))
|
|
page.keyboard.press('`')
|
|
check('marked worlds reopen without the warning', page.evaluate("!$('dev-console').hidden && $('m-dialog').hidden"))
|
|
page.keyboard.press('`')
|
|
check('backtick closes even with input focused', not page.is_visible('#dev-console'))
|
|
page.keyboard.press('`')
|
|
def command(text):
|
|
page.fill('#dev-input', text); page.keyboard.press('Enter')
|
|
command('pause')
|
|
tick = page.evaluate('tick')
|
|
page.wait_for_timeout(150)
|
|
check('dev pause freezes simulation ticks', page.evaluate('tick') == tick)
|
|
command('step 5')
|
|
page.wait_for_function(f'tick === {tick + 5} && devSteps === 0')
|
|
page.wait_for_timeout(150)
|
|
check('step advances exactly five ticks then stays paused', page.evaluate('tick') == tick + 5)
|
|
# Drive the actual frame accumulator with controlled elapsed time and no scheduled frames.
|
|
counts = page.evaluate('''() => {
|
|
requestAnimationFrame = () => 0;
|
|
GAME.paused = false; devPaused = false; SET.fpsCap = 0; SET.maxSteps = 3;
|
|
const counts = [];
|
|
for (const speed of [0.5, 1, 2, 8]) {
|
|
devSpeed = speed; acc = 0; const before = tick;
|
|
const t = performance.now(); lastT = t - 34; lastRender = t - 34; frame(t);
|
|
counts.push(tick - before);
|
|
}
|
|
return counts;
|
|
}''')
|
|
check('speed scales fixed ticks and respects maxSteps', counts == [1, 2, 3, 3])
|
|
page.evaluate('devCommand("debt clear"); runDevCommand("money 1"); openNotebook("Claims")')
|
|
page.wait_for_function("$('nb-body').textContent.includes('paid off')")
|
|
check('cleared debt is reflected in Claims', True)
|
|
page.evaluate('closeAllModals(); runDevCommand("debt 123"); openNotebook("Market")')
|
|
check('new debt is reflected in the Market', '$123' in page.inner_text('#nb-body'))
|
|
page.evaluate('closeAllModals()')
|
|
page.evaluate("async () => { await saveWorld('main', true); await renderWorlds(); }")
|
|
page.evaluate("openModal('m-worlds')")
|
|
check('world list entry stores and draws the dev badge', page.locator('#worlds-list .dev-badge').is_visible() and page.inner_text('#worlds-list .dev-badge') == 'Dev console')
|
|
page.screenshot(path=str(SHOTS / 't66-worlds.png'))
|
|
page.evaluate('closeAllModals()')
|
|
check('saving and loading preserves mark and log, resets runtime controls', page.evaluate('''async () => {
|
|
const sv = await worldNewest(GAME.worldId);
|
|
const count = devLog.length;
|
|
await startFromSave(sv);
|
|
return devWorld && devLog.length === count && devSpeed === 1 && !devPaused && !devFree && $('dev-console').hidden;
|
|
}'''))
|
|
check('no browser errors', not errors)
|
|
browser.close()
|
|
|
|
sys.exit(1 if fails else 0)
|