103 lines
6.4 KiB
Python
Executable File
103 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""All Overview widget labels and small values in simulated Chromium.
|
|
|
|
This is a DOM/CSS regression test, not a live RustProxy integration test.
|
|
"""
|
|
from pathlib import Path
|
|
import json
|
|
from panel_html import render_admin_index
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
HTML = render_admin_index(ROOT)
|
|
CSS = (ROOT / 'src/admin/web/style.css').read_text(encoding='utf-8')
|
|
PACKS = {name: json.loads((ROOT / f'langs/{name}.json').read_text(encoding='utf-8'))['translations']
|
|
for name in ('en_US', 'pl_pl')}
|
|
|
|
CHECK = r'''({density, lang, translations}) => {
|
|
document.documentElement.dataset.dashboardDensity = density;
|
|
document.documentElement.lang = lang === 'pl_pl' ? 'pl-PL' : 'en-US';
|
|
const grid = document.getElementById('dashboard-overview-grid');
|
|
grid.querySelectorAll('[data-i18n]').forEach(node => {
|
|
if (Object.hasOwn(translations, node.dataset.i18n)) node.textContent = translations[node.dataset.i18n];
|
|
});
|
|
const cards = [...grid.children].filter(node => node.hasAttribute('data-dashboard-widget'));
|
|
const font = value => getComputedStyle(value).fontFamily;
|
|
const probe = document.createElement('div');
|
|
grid.append(probe);
|
|
probe.style.fontFamily = 'var(--sans)'; const sans = font(probe);
|
|
probe.style.fontFamily = 'var(--mono)'; const mono = font(probe);
|
|
probe.remove();
|
|
|
|
const titleErrors = [];
|
|
const titles = [];
|
|
const labelErrors = [];
|
|
const numericErrors = [];
|
|
for (const card of cards) {
|
|
let title;
|
|
if (card.classList.contains('stat')) title = card.querySelector(':scope > span:first-child');
|
|
else if (card.classList.contains('system-card') || card.classList.contains('connection-card'))
|
|
title = card.querySelector('.overview-chart-heading');
|
|
else if (card.querySelector('.mini-heading > h3')) title = card.querySelector('.mini-heading > h3');
|
|
else title = card.querySelector('.card-heading h2');
|
|
if (!title) { titleErrors.push(`${card.dataset.dashboardWidget}: missing title`); continue; }
|
|
const style = getComputedStyle(title);
|
|
titles.push(title);
|
|
if (style.fontFamily !== sans || style.fontSize !== '12px' || style.textTransform !== 'none')
|
|
titleErrors.push(`${card.dataset.dashboardWidget}: ${style.fontFamily} ${style.fontSize} ${style.textTransform}`);
|
|
if (title.textContent.trim() === title.textContent.trim().toLocaleUpperCase('pl') &&
|
|
/[a-ząćęłńóśżź]{4}/i.test(title.textContent) &&
|
|
!/^(?:HIT|MISS|HTTP|CPU|RAM|WWW|RX|TX)/.test(title.textContent.trim()))
|
|
titleErrors.push(`${card.dataset.dashboardWidget}: all-uppercase title ${title.textContent.trim()}`);
|
|
for (const node of card.querySelectorAll(':scope > small, .mini-metrics dt, .mini-metrics dd, .mini-live-chart-head, .memory-line, .chart-footer, .meta, .small-label')) {
|
|
if (font(node) !== mono) labelErrors.push(`${card.dataset.dashboardWidget}: ${node.outerHTML.slice(0, 85)}`);
|
|
}
|
|
const readings = card.classList.contains('stat')
|
|
? [...card.querySelectorAll(':scope > strong'), ...card.querySelectorAll(':scope > small')]
|
|
: [...card.querySelectorAll('.mini-metrics dd')];
|
|
for (const node of readings) if (font(node) !== mono)
|
|
numericErrors.push(`${card.dataset.dashboardWidget}: ${node.outerHTML.slice(0, 85)}`);
|
|
}
|
|
const nested = [...grid.querySelectorAll('.mini-live-chart > .mini-live-chart-head > span:first-child')];
|
|
for (const node of nested) {
|
|
const style = getComputedStyle(node);
|
|
if (style.fontFamily !== mono || style.fontSize !== '10px' || style.textTransform !== 'none')
|
|
labelErrors.push(`mini-live-chart: ${style.fontFamily} ${style.fontSize} ${style.textTransform}`);
|
|
}
|
|
const systemNumeric = getComputedStyle(document.querySelector('#system-cpu'));
|
|
return {
|
|
cardCount: cards.length, titleCount: titles.length, secondaryCount: nested.length,
|
|
titleErrors, labelErrors, numericErrors,
|
|
systemNumericMono: systemNumeric.fontFamily === mono,
|
|
cpuLabel: document.querySelector('[data-dashboard-widget="system_chart"] .overview-chart-heading').textContent,
|
|
connectionsLabel: document.querySelector('[data-dashboard-widget="connection_chart"] .overview-chart-heading').textContent,
|
|
memoryLabel: document.querySelector('[data-dashboard-widget="memory"] > span:first-child').textContent,
|
|
backendLabel: document.querySelector('[data-dashboard-widget="backend_health"] > span:first-child').textContent,
|
|
diagnosticsTitle: document.querySelector('[data-dashboard-widget="process_diagnostics"] .mini-heading h3').textContent,
|
|
};
|
|
}'''
|
|
|
|
with sync_playwright() as playwright:
|
|
browser = playwright.chromium.launch(headless=True, executable_path='/usr/bin/chromium', args=['--no-sandbox'])
|
|
for width in (320, 375, 768, 1440, 1920):
|
|
page = browser.new_page(viewport={'width': width, 'height': 900})
|
|
page.set_content(HTML.replace('/assets/app___RUSTPROXY_ASSET_ID__.js', '')
|
|
.replace('/assets/style___RUSTPROXY_ASSET_ID__.css', ''))
|
|
page.add_style_tag(content=CSS)
|
|
for density in ('normal', 'compact', 'ultra'):
|
|
for lang in ('en_US', 'pl_pl'):
|
|
result = page.evaluate(CHECK, {'density': density, 'lang': lang, 'translations': PACKS[lang]})
|
|
descriptor = (width, density, lang)
|
|
assert result['cardCount'] == result['titleCount'] >= 75, (descriptor, result)
|
|
assert result['secondaryCount'] >= 6, descriptor
|
|
assert not result['titleErrors'], (descriptor, result['titleErrors'][:10])
|
|
assert not result['labelErrors'], (descriptor, result['labelErrors'][:10])
|
|
assert not result['numericErrors'], (descriptor, result['numericErrors'][:10])
|
|
assert result['systemNumericMono'], descriptor
|
|
expected = ('System load', 'Connection activity') if lang == 'en_US' else ('Obciążenie systemu', 'Aktywność połączeń')
|
|
assert (result['cpuLabel'], result['connectionsLabel']) == expected, (descriptor, result)
|
|
assert result['memoryLabel'] and result['backendLabel'] and result['diagnosticsTitle'], descriptor
|
|
print(f'PASS all Overview titles and small readings at {width}px (3 densities, 2 languages)')
|
|
page.close()
|
|
browser.close()
|