"""Exercise the actual browser editor, with no model inference.""" import argparse import functools import http.server import json import re from pathlib import Path import tempfile import threading from playwright.sync_api import sync_playwright, expect ROOT = Path(__file__).parent def main(): parser = argparse.ArgumentParser() parser.add_argument('--base-url') parser.add_argument('--artifacts', type=Path) args = parser.parse_args() server = None if args.base_url: base_url = args.base_url.rstrip('/') + '/' else: class QuietHandler(http.server.SimpleHTTPRequestHandler): def log_message(self, *unused): pass handler = functools.partial(QuietHandler, directory=str(ROOT)) server = http.server.ThreadingHTTPServer(('127.0.0.1', 0), handler) threading.Thread(target=server.serve_forever, daemon=True).start() base_url = f'http://127.0.0.1:{server.server_port}/' checks = [] errors = [] requests = [] try: with sync_playwright() as p: launch_options = {'headless': True, 'args': ['--no-sandbox']} if Path('/usr/bin/chromium').is_file(): launch_options['executable_path'] = '/usr/bin/chromium' browser = p.chromium.launch(**launch_options) try: context = browser.new_context(viewport={'width': 1440, 'height': 1100}, reduced_motion='reduce', accept_downloads=True) page = context.new_page() page.on('pageerror', lambda error: errors.append(str(error))) page.on('request', lambda request: requests.append(request.url)) page.goto(base_url, wait_until='networkidle') page.wait_for_function('() => document.getElementById("json-output").value.startsWith("{")') def output(): return json.loads(page.locator('#json-output').input_value()) def tab(name): page.locator('#tab-' + name).click() def check(name): checks.append(name) first = output() assert first['bbox_coord_space'] == 'abs_centralized' assert first['bbox_format'] == 'yxyx' assert 'width' not in first and 'height' not in first assert first['items'][0]['bbox'] == [-416, -384, -288, 384] assert first['items'][2]['text'] == 'まだ見ぬ場所へ' check('initial compiled layout and centered coordinates') for example in ['poster', 'cup', 'type']: page.locator(f'[data-example="{example}"]').click() compiled = output() assert compiled['items'] and all(item['label'] in ['text', 'object', 'character'] for item in compiled['items']) assert all('id' not in item for item in compiled['items']) tab('draft') draft = output() assert draft['width'] % 16 == draft['height'] % 16 == 0 assert draft['bbox_coord_space'] == 'abs' and draft['bbox_format'] == 'xyxy' if example == 'cup': assert compiled['items'][0]['bbox'] == [-288, -592, 352, 32] assert draft['items'][1]['text'] == '把日常,过成诗。' assert draft['items'][2]['text'] == '一杯温暖\n一刻从容' with tempfile.TemporaryDirectory() as directory: path = Path(directory) / 'draft.json' path.write_text(json.dumps(draft, ensure_ascii=False)) page.locator('#import').set_input_files(path) page.wait_for_function('() => document.getElementById("status").textContent.startsWith("Layout imported")') assert output() == draft tab('prompt') assert output() == compiled check('all three presets and exact editable JSON round trips') page.locator('[data-example="poster"]').click() box = page.locator('.layout-box').first box.focus() box.press('ArrowRight') assert page.locator('#box-x').input_value() == '129' box.press('Shift+ArrowDown') assert page.locator('#box-y').input_value() == '106' box.press('Alt+ArrowRight') assert page.locator('#box-w').input_value() == '769' page.locator('#undo').click() assert page.locator('#box-w').input_value() == '768' page.locator('#redo').click() assert page.locator('#box-w').input_value() == '769' box = page.locator('.layout-box').nth(1) box.focus() assert box.get_attribute('aria-pressed') == 'true' assert page.locator('.layout-box[aria-pressed=true]').count() == 1 check('keyboard movement, resizing, focus selection, undo and redo') page.locator('[data-example="poster"]').click() box = page.locator('.layout-box').first rect = box.bounding_box() page.mouse.move(rect['x'] + rect['width'] / 2, rect['y'] + rect['height'] / 2) page.mouse.down() page.mouse.move(rect['x'] + rect['width'] / 2 + 22, rect['y'] + rect['height'] / 2 + 12, steps=4) page.mouse.up() assert float(page.locator('#box-x').input_value()) > 128 handle = page.locator('.layout-box').first.locator('.resize-handle').bounding_box() old_w = float(page.locator('#box-w').input_value()) page.mouse.move(handle['x'] + handle['width'] / 2, handle['y'] + handle['height'] / 2) page.mouse.down() page.mouse.move(handle['x'] + handle['width'] / 2 - 18, handle['y'] + handle['height'] / 2 + 10, steps=3) page.mouse.up() assert float(page.locator('#box-w').input_value()) < old_w check('pointer dragging and corner resizing') before_x = page.locator('#box-x').input_value() page.locator('#box-x').fill('999999') page.locator('#box-x').press('Tab') assert page.locator('#box-x').input_value() == before_x assert 'inside the canvas' in page.locator('#status').inner_text() page.locator('#scene-caption').fill('') page.locator('#scene-caption').press('Tab') assert page.locator('#copy').is_disabled() and page.locator('#download').is_disabled() page.locator('#scene-caption').fill('A test composition with exact words.') page.locator('#scene-caption').press('Tab') assert page.locator('#copy').is_enabled() check('invalid geometry rejected and incomplete export disabled') page.locator('[data-example="poster"]').click() page.locator('#canvas-width').fill('1536') page.locator('#apply-size').click() assert page.locator('#box-x').input_value() == '192' assert page.locator('#box-w').input_value() == '1152' page.locator('#scale-boxes').uncheck() page.locator('#canvas-width').fill('1024') page.locator('#apply-size').click() assert 'fall outside' in page.locator('#status').inner_text() assert page.locator('#canvas-readout').inner_text() == '1536 × 1024 px' page.locator('#canvas-width').fill('2048') page.locator('#apply-size').click() assert page.locator('#box-x').input_value() == '192' assert page.locator('#box-w').input_value() == '1152' page.locator('#scale-boxes').check() check('explicit proportional resize and preserved pixel positions') page.locator('[data-example="cup"]').click() tab('draft') expected = page.locator('#json-output').input_value() + '\n' with page.expect_download() as event: page.locator('#download').click() download = event.value assert download.suggested_filename == 'moss-draft-1536x1024.json' assert Path(download.path()).read_text() == expected page.evaluate('Object.defineProperty(navigator,"clipboard",{configurable:true,value:{writeText:()=>Promise.reject(new Error("denied"))}})') page.locator('#copy').click() assert 'JSON is selected' in page.locator('#status').inner_text() assert page.locator('#json-output').evaluate('(el)=>el.selectionEnd-el.selectionStart') == len(expected.rstrip('\n')) check('exact Unicode download and clipboard denial fallback') safe = output() safe['summary']['palette'] = ['ivory', 'green'] safe['summary']['meta'] = ['print, editorial', 'studio\nphotography'] safe['items'][0]['tags'] = ['ceramic', 'handmade'] safe['items'][0]['palette'] = ['ivory'] safe['items'][1]['text'] = '\nمرحبا 🌿' with tempfile.TemporaryDirectory() as directory: path = Path(directory) / 'draft.json' path.write_text(json.dumps(safe, ensure_ascii=False)) page.locator('#import').set_input_files(path) page.wait_for_function('() => document.getElementById("status").textContent.startsWith("Layout imported")') assert output() == safe assert page.locator('#stage img').count() == 0 assert page.evaluate('window.xss') is None assert ' document.getElementById("status").textContent.startsWith("Import failed")') assert output() == safe path.write_text('{"width":1024,"width":2048}') page.locator('#import').set_input_files(path) expect(page.locator('#status')).to_contain_text(re.compile('duplicate', re.I)) check('strict imports, optional fields preserved, literal HTML cannot execute') page.locator('#add-character').click() assert page.locator('#item-label').input_value() == 'character' count = page.locator('.layout-box').count() page.locator('#duplicate').click() assert page.locator('.layout-box').count() == count + 1 page.locator('#delete').click() assert page.locator('.layout-box').count() == count page.locator('#undo').click() assert page.locator('.layout-box').count() == count + 1 check('add, duplicate, remove and restore elements') page.locator('[data-example="poster"]').click() tab('prompt') if args.artifacts: args.artifacts.mkdir(parents=True, exist_ok=True) page.evaluate('document.activeElement?.blur(); document.getElementById("json-output").scrollTop=0; window.scrollTo(0,0)') page.screenshot(path=str(args.artifacts / 'moss-desktop.png'), full_page=True) mobile = browser.new_context(viewport={'width': 390, 'height': 844}, device_scale_factor=1, is_mobile=True, has_touch=True, reduced_motion='reduce') phone = mobile.new_page() phone.on('pageerror', lambda error: errors.append(str(error))) phone.on('request', lambda request: requests.append(request.url)) phone.goto(base_url, wait_until='networkidle') phone.wait_for_function('() => document.getElementById("json-output").value.startsWith("{")') assert phone.evaluate('document.documentElement.scrollWidth <= window.innerWidth') phone.locator('.layout-box').first.scroll_into_view_if_needed() r = phone.locator('.layout-box').first.bounding_box() cdp = mobile.new_cdp_session(phone) x, y = r['x'] + r['width'] / 2, r['y'] + r['height'] / 2 cdp.send('Input.dispatchTouchEvent', {'type': 'touchStart', 'touchPoints': [{'x': x, 'y': y}]}) cdp.send('Input.dispatchTouchEvent', {'type': 'touchMove', 'touchPoints': [{'x': x + 14, 'y': y + 12}]}) cdp.send('Input.dispatchTouchEvent', {'type': 'touchEnd', 'touchPoints': []}) assert float(phone.locator('#box-x').input_value()) > 128 phone.locator('.layout-box').first.scroll_into_view_if_needed() r = phone.locator('.layout-box').first.locator('.resize-handle').bounding_box() old_w = float(phone.locator('#box-w').input_value()) x, y = r['x'] + r['width'] / 2, r['y'] + r['height'] / 2 cdp.send('Input.dispatchTouchEvent', {'type': 'touchStart', 'touchPoints': [{'x': x, 'y': y}]}) cdp.send('Input.dispatchTouchEvent', {'type': 'touchMove', 'touchPoints': [{'x': x - 15, 'y': y + 10}]}) cdp.send('Input.dispatchTouchEvent', {'type': 'touchEnd', 'touchPoints': []}) assert float(phone.locator('#box-w').input_value()) < old_w assert phone.evaluate('document.documentElement.scrollWidth <= window.innerWidth') phone.locator('[data-example="type"]').click() phone.locator('.layout-box').first.scroll_into_view_if_needed() board = phone.locator('#stage').bounding_box() assert abs(board['width'] / board['height'] - 1024 / 1280) < .01 check('mobile layout, actual touch drag and resize, portrait aspect ratio') if args.artifacts: phone.evaluate('document.activeElement?.blur(); document.getElementById("json-output").scrollTop=0; window.scrollTo(0,0)') phone.screenshot(path=str(args.artifacts / 'moss-phone.png'), full_page=True) mobile.close() allowed_origin = '/'.join(base_url.split('/')[:3]) foreign = [url for url in requests if not url.startswith(allowed_origin + '/') and not url.startswith('blob:') and not url.startswith('data:')] assert not foreign, foreign assert not errors, errors check('no external network requests or browser runtime errors') context.close() finally: browser.close() finally: if server: server.shutdown() server.server_close() print(json.dumps({'passed': len(checks), 'checks': checks, 'runtime_errors': errors, 'base_url': args.base_url or 'local'}, indent=2)) if __name__ == '__main__': main()