"""t100: new-world seed editing, random button and generation, in both looks.""" import pathlib, sys sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / 'tools')) from use_venv import ensure_playwright; ensure_playwright() from browser import launch, consume_gpu_option consume_gpu_option() root = pathlib.Path(__file__).resolve().parent.parent out = root / 'shots'; out.mkdir(exist_ok=True) fails = [] def check(name, ok): print(('PASS ' if ok else 'FAIL ') + name) if not ok: fails.append(name) with launch(viewport={'width': 1280, 'height': 800}) as (_, pg, url): errors = [] pg.on('pageerror', lambda e: errors.append(str(e))) pg.goto(url) pg.wait_for_function("!$('title').hidden && CAPS.ready") pg.click('#btn-new') seed = pg.locator('#nw-seed') seed.fill('12'); seed.press('Home'); pg.keyboard.type('a!') check('typed letters and symbols are ignored', seed.input_value() == '12') pg.keyboard.type('3') check('ignoring characters preserves the insertion point', seed.input_value() == '312') # Real clipboard paste exercises maxlength before the input event. pg.context.grant_permissions(['clipboard-read', 'clipboard-write']) def paste(text): seed.focus(); seed.press('ControlOrMeta+a') pg.evaluate('text => navigator.clipboard.writeText(text)', text) seed.press('ControlOrMeta+v') paste('ab12 cd34!56 ef78') check('paste keeps all digits even beyond ten source characters', seed.input_value() == '12345678') paste('4294967296') check('4294967296 clamps to max', seed.input_value() == '4294967295') paste('99999999999') check('eleven digits clamp to max', seed.input_value() == '4294967295') check('maxlength fits ten digits', seed.get_attribute('maxlength') == '10') check('clamp hint is shown by the box', pg.locator('#nw-seed-hint').count() == 1 and pg.is_visible('#nw-seed-hint')) for look in ['pixel', 'smooth']: pg.evaluate('look => SET.look = look', look) pg.screenshot(path=str(out / f't100-{look}.png')) # A drop with text transfer data uses the same editing path. seed.fill('') seed.evaluate("""e => { const data = new DataTransfer(); data.setData('text/plain', 'ab4294967296!'); e.dispatchEvent(new DragEvent('drop', {bubbles:true, cancelable:true, dataTransfer:data})); }""") check('dropped text is filtered and clamped', seed.input_value() == '4294967295') # Also exercise browser drag delivery rather than only a dispatched event. pg.evaluate("""() => { const source = document.createElement('div'); source.id = 'seed-drag'; source.textContent = 'Drag seed'; source.draggable = true; source.style = 'position:fixed;z-index:99999;top:0;left:0;padding:20px;background:white'; source.ondragstart = e => e.dataTransfer.setData('text/plain', 'seed: 1234!'); document.body.append(source); }""") seed.fill(''); pg.locator('#seed-drag').drag_to(seed) check('real text drag keeps only digits', seed.input_value() == '1234') pg.locator('#seed-drag').evaluate('e => e.remove()') seed.fill('0') check('zero stays zero', seed.input_value() == '0') # Record Generate's arguments without generating several large worlds. pg.evaluate("""() => { window.__start = startNewWorld; startNewWorld = (...args) => { window.__generated = args; }; window.__random = Math.random; Math.random = () => 0.5; }""") seed.press('Enter') check('Enter generates seed zero', pg.evaluate('__generated[0] === 0')) seed.fill('4294967295'); pg.click('#btn-generate') check('maximum seed generates without wrapping', pg.evaluate('__generated[0] === 4294967295')) seed.evaluate("e => e.value = '99999999999'"); pg.click('#btn-generate') check('Generate applies the same clamp even without an input event', pg.evaluate('__generated[0] === 4294967295')) seed.fill(''); pg.click('#btn-generate') check('empty generates a random six-digit seed', pg.evaluate('__generated[0] === 550000')) dice = pg.get_by_role('button', name='Random seed', exact=True) check('dice is a labeled button with tooltip', dice.count() == 1 and dice.get_attribute('title') == 'Random seed') if dice.count(): seed.fill('42'); dice.focus(); pg.keyboard.press('Enter') check('keyboard dice uses the same random rule', seed.input_value() == '550000') check('dice updates the automatic name', pg.evaluate("$('nw-name').value === claimName(550000, [])")) pg.fill('#nw-name', 'My camp'); pg.evaluate('Math.random = () => 0.25'); dice.click() check('dice changes seed and preserves a typed name', seed.input_value() == '325000' and pg.input_value('#nw-name') == 'My camp') check('valid input clears clamp hint', not pg.is_visible('#nw-seed-hint')) # Exercise the real UI-to-worldgen boundary once, including zero's stored seed. pg.evaluate('() => { startNewWorld = __start; Math.random = __random; SET.look = "pixel"; }') seed.fill('0'); pg.select_option('#nw-size', '2048x1024'); seed.press('Enter') pg.wait_for_function('GAME.running', timeout=60000) check('real generated world retains seed zero', pg.evaluate('worldSeed === 0')) check('no page errors', not errors) print('FAILS:', fails) sys.exit(bool(fails))