#!/usr/bin/env python3 """Offline Chromium test: sendfile toggle serializes in real admin bundle. It uses simulated config and a mocked saveSection; never claims native sendfile execution, Rust compilation or live server acceptance. """ from pathlib import Path import json import re from playwright.sync_api import sync_playwright from panel_html import render_admin_index ROOT = Path(__file__).resolve().parents[2] ROUTER = (ROOT / "src/admin/router.rs").read_text() start = re.search(r'fn admin_app_javascript\([^)]*\)[^{]*\{', ROUTER) assert start array = ROUTER[start.end():] array = array[:re.search(r'\]\s*\.join\("\\n"\)', array).start()] chunks = [] for line in array.splitlines(): line = line.strip() match = re.search(r'include_str!\("([^"]+)"\)', line) if match: chunks.append((ROOT / "src/admin" / match.group(1)).read_text()) elif line == 'admin_vhosts_javascript(),': chunks.append('(() => {\n' + '\n'.join( (ROOT / 'src/admin/web/vhosts' / (f + '.js')).read_text() for f in ('core', 'protocol', 'health', 'rates', 'editor', 'render')) + '\n})();') elif line.startswith('"') and line.endswith('",'): chunks.append(json.loads(line[:-1])) with sync_playwright() as p: browser = p.chromium.launch(headless=True, executable_path='/usr/bin/chromium', args=['--no-sandbox']) for width in (375, 1440): page = browser.new_page(viewport={'width': width, 'height': 950}) page.set_default_timeout(4500) errors = [] page.on('pageerror', lambda err: errors.append(str(err))) page.set_content(render_admin_index(ROOT)) page.add_style_tag(content=(ROOT / 'src/admin/web/style.css').read_text()) page.add_script_tag(content='\n'.join(chunks)) page.evaluate('''() => { envelope = {revision: 10, config: {web_services: [{ id: 'site-A', name: 'Static Site', document_root: '/srv/static', index: ['index.html'], php: {enabled: false} }], vhosts: [{id: 'vhost-A', keepalive: {max_connections: 8}}], php_fpm_profiles: []}}; currentPanel = 'web-server'; document.documentElement.classList.remove('app-loading', 'app-startup-failed'); document.getElementById('login').hidden = true; document.getElementById('workspace').hidden = false; document.getElementById('panel-web-server').hidden = false; window.__saved = []; saveSection = async (section, value) => { window.__saved.push({section, value: structuredClone(value)}); if (section === 'web-services') envelope.config.web_services = structuredClone(value); return true; }; window.rustProxyWebServer.render(); }''') page.evaluate("document.querySelector('#web-service-list .entity-actions button').click()") assert page.locator('#web-service-sendfile').input_value() == 'off' page.evaluate("document.getElementById('web-service-sendfile').value = 'auto'") page.evaluate('''() => { const form = document.getElementById('web-service-form'); if (!form.checkValidity()) throw new Error('invalid fields: ' + [...form.elements].filter(e=>!e.checkValidity()).map(e=>e.id).join(', ')); form.requestSubmit(); }''') page.wait_for_function('window.__saved.length === 1') result = page.evaluate('''() => ({ saved: window.__saved[0], cacheStillUnrelated: envelope.config.vhosts[0].keepalive.max_connections === 8, closed: !document.getElementById('web-service-dialog').open })''') assert result['saved']['section'] == 'web-services', result assert result['saved']['value'][0]['sendfile'] == 'auto', result assert result['saved']['value'][0]['document_root'] == '/srv/static', result assert result['cacheStillUnrelated'] and result['closed'], result page.evaluate("document.querySelector('#web-service-list .entity-actions button').click()") assert page.locator('#web-service-sendfile').input_value() == 'auto' page.evaluate("document.getElementById('web-service-sendfile').value = 'off'") page.evaluate('''() => { const form = document.getElementById('web-service-form'); if (!form.checkValidity()) throw new Error('invalid fields: ' + [...form.elements].filter(e=>!e.checkValidity()).map(e=>e.id).join(', ')); form.requestSubmit(); }''') page.wait_for_function('window.__saved.length === 2') assert page.evaluate('envelope.config.web_services[0].sendfile') == 'off' assert not errors, errors print(f'PASS simulated panel sendfile off -> auto -> off config save at {width}px') browser.close()