import { Page } from '@playwright/test'; /** * Log in to LuCI with empty root password. * Handles the "No password set" notification if it appears. */ export async function login(page: Page): Promise { await page.goto('/cgi-bin/luci'); // Wait for the JS framework to finish instantiating the login view. await page.waitForFunction(() => { const view = document.querySelector('#view'); return view && !view.querySelector('.spinning'); }, { timeout: 30_000, polling: 500 }); await page.waitForSelector('#luci_username', { state: 'visible', timeout: 30_000 }); await page.fill('#luci_username', 'root'); await page.fill('#luci_password', ''); await page.click('.cbi-button-positive'); // Wait for navigation into the admin overview. await page.waitForURL(/\/cgi-bin\/luci\//, { timeout: 30_000 }); // LuCI admin page can take ~15s on first cold load; give it time to render. await page.waitForFunction(() => { const view = document.querySelector('#view'); return view && !view.querySelector('.spinning'); }, { timeout: 30_000, polling: 500 }); // Dismiss "No password set" modal/notification if present. const closeBtn = page.locator('.alert-message .close, .alert-message button, [data-dismiss="alert"]').first(); try { await closeBtn.click({ timeout: 2_000 }); } catch { // No notification to dismiss. } } /** * Reset the active gateway back to amsterdam via direct ubus RPC. */ export async function resetToAmsterdam(page: Page): Promise { const loginRes = await page.request.post('/ubus', { data: { jsonrpc: '2.0', id: 1, method: 'call', params: ['00000000000000000000000000000000', 'session', 'login', { username: 'root', password: '' }], }, }); const loginData = await loginRes.json(); const token = loginData.result?.[1]?.ubus_rpc_session; if (!token) throw new Error('ubus login failed'); await page.request.post('/ubus', { data: { jsonrpc: '2.0', id: 2, method: 'call', params: [token, 'zt-gateway', 'switch', { region: 'amsterdam', mode: 'force' }], }, }); }