Add Serial and Wi-Fi quick settings
Reuse the existing settings view and typed controllers for accessible quick editing while keeping network credentials out of quick mode. Expand browser and layout coverage for focus, dismissal, bounds, and expiry.
This commit is contained in:
@@ -45,6 +45,17 @@ def check_layout(html):
|
||||
if cls in classes(node):
|
||||
return node
|
||||
raise AssertionError(cls)
|
||||
for domain in ('serial', 'network'):
|
||||
trigger = ids['quick-' + domain]
|
||||
assert trigger['tag'] == 'button' and trigger['attrs']['type'] == 'button'
|
||||
assert trigger['attrs']['aria-controls'] == 'serial-settings'
|
||||
assert trigger['attrs']['aria-expanded'] == 'false'
|
||||
assert trigger['attrs']['aria-haspopup'] == 'dialog'
|
||||
assert trigger['attrs']['aria-label'] and 'disabled' in trigger['attrs']
|
||||
assert ids['quick-full']['tag'] == 'a' and ids['quick-full']['attrs']['href'] == '#serial-settings'
|
||||
assert 'hidden' in ids['quick-header']['attrs']
|
||||
assert ids['network-password']['parent'] is ids['network-password-label']
|
||||
assert ids['network-password-mode']['parent'] is ids['network-password-mode-label']
|
||||
for ident in ('settings-values', 'accounts-list', 'account-keys-list', 'network-summary', 'display-values', 'broker-values'):
|
||||
assert ids[ident]['tag'] == 'dl'
|
||||
assert 'settings-values' in classes(ids[ident])
|
||||
@@ -103,8 +114,10 @@ def check_browser_layout(html, tmp, executable):
|
||||
fixture = re.sub(r'<link\b[^>]*>|<img\b[^>]*>', '', fixture)
|
||||
probe = r'''
|
||||
const cases = [];
|
||||
for (const width of [320, 600, 1200]) for (const view of ['serial-settings-content', 'account-settings', 'network-settings', 'display-settings']) {
|
||||
const frame = document.createElement('iframe'); frame.style.width = width + 'px'; frame.style.height = '900px';
|
||||
for (const width of [320, 600, 1200]) for (const view of ['serial-settings-content', 'account-settings', 'network-settings', 'display-settings']) for (const quick of [false, true]) {
|
||||
if (quick && !['serial-settings-content', 'network-settings'].includes(view)) continue;
|
||||
const height = quick ? 360 : 900;
|
||||
const frame = document.createElement('iframe'); frame.style.width = width + 'px'; frame.style.height = height + 'px';
|
||||
cases.push(new Promise(resolve => {
|
||||
frame.onload = () => {
|
||||
const d = frame.contentDocument, win = frame.contentWindow;
|
||||
@@ -122,6 +135,17 @@ def check_browser_layout(html, tmp, executable):
|
||||
});
|
||||
section.querySelectorAll('input:not([type=checkbox]),textarea').forEach(n => n.value = 'x'.repeat(96));
|
||||
const errors = [];
|
||||
if (quick) {
|
||||
const host = d.getElementById('serial-settings'); host.dataset.quick = 'true';
|
||||
d.getElementById('quick-header').hidden = false;
|
||||
const rect = host.getBoundingClientRect();
|
||||
if (rect.left < 0 || rect.top < 0 || rect.right > width || rect.bottom > height) errors.push('popover viewport overflow');
|
||||
if (host.scrollWidth > host.clientWidth + 1) errors.push('popover horizontal overflow');
|
||||
if (win.getComputedStyle(host).overflowY !== 'auto') errors.push('popover not scrollable');
|
||||
for (const id of ['settings-navigation', 'network-password-mode-label', 'network-password-label', 'network-password-status']) {
|
||||
if (d.getElementById(id).getBoundingClientRect().width) errors.push('quick hidden content:' + id);
|
||||
}
|
||||
}
|
||||
for (const node of section.querySelectorAll('dl,input,select,textarea,.settings-edit,.serial-edit,.serial-actions')) {
|
||||
const rect = node.getBoundingClientRect();
|
||||
if (!rect.width) continue;
|
||||
@@ -132,7 +156,7 @@ def check_browser_layout(html, tmp, executable):
|
||||
}
|
||||
// Measure glyph ranges, not the full-width grid cell or textContent.
|
||||
// The normal-whitespace control proves the pair detects collapsing.
|
||||
for (const dd of section.querySelectorAll('dl dd:first-of-type')) {
|
||||
for (const dd of quick ? [] : section.querySelectorAll('dl dd:first-of-type')) {
|
||||
const original = dd.textContent;
|
||||
const measureSSID = spaces => {
|
||||
dd.textContent = 'SSID: ' + JSON.stringify('office' + ' '.repeat(spaces) + 'wifi');
|
||||
@@ -147,7 +171,7 @@ def check_browser_layout(html, tmp, executable):
|
||||
if (Math.abs(measureSSID(2) - measureSSID(1)) > 0.1) errors.push('invalid whitespace control');
|
||||
dd.style.removeProperty('white-space'); dd.textContent = original;
|
||||
}
|
||||
resolve({width, view, errors});
|
||||
resolve({width, height, view, quick, errors});
|
||||
};
|
||||
}));
|
||||
frame.srcdoc = FIXTURE; document.body.append(frame);
|
||||
@@ -166,6 +190,6 @@ def check_browser_layout(html, tmp, executable):
|
||||
assert result.returncode == 0, result.stderr
|
||||
parsed = Document(result.stdout)
|
||||
results = json.loads(parsed.ids['layout-results']['text'])
|
||||
assert len(results) == 12
|
||||
assert len(results) == 18
|
||||
assert all(not case['errors'] for case in results), results
|
||||
print('PASS Chromium layout: all four settings views at 320/600/1200px; bounded controls, summaries, inline checkboxes and rendered consecutive-space distinction (fixture data, not live app)')
|
||||
print('PASS Chromium layout: four full views plus Serial/Wi-Fi popovers at 320/600/1200px (quick height360); viewport/overflow/secret exclusion and full-page whitespace checks (fixtures, not live app)')
|
||||
Reference in New Issue
Block a user