Files
gods-eye-view/src/keyboardFocusStyles.test.mjs
T

88 lines
3.2 KiB
JavaScript

import { readStylesheet } from './testSupport/readStylesheet.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
const css = readStylesheet(new URL('../style.css', import.meta.url));
function ruleBody(selector) {
const start = css.indexOf(selector);
assert.ok(start >= 0, `${selector} rule exists`);
const open = css.indexOf('{', start);
const close = css.indexOf('}', open);
return css.slice(open + 1, close);
}
function ruleText(selector) {
const start = css.indexOf(selector);
assert.ok(start >= 0, `${selector} rule exists`);
const close = css.indexOf('}', css.indexOf('{', start));
return css.slice(start, close + 1);
}
function ruleBodyContaining(selector, declaration) {
let start = -1;
while ((start = css.indexOf(selector, start + 1)) >= 0) {
const open = css.indexOf('{', start);
const close = css.indexOf('}', open);
const body = css.slice(open + 1, close);
if (body.includes(declaration)) return body;
}
assert.fail(`${selector} rule containing ${declaration} exists`);
}
test('the global keyboard ring survives local active and outline-reset rules', () => {
const rule = ruleText(':where(\n button,');
assert.match(rule, /outline:\s*2px solid var\(--text-primary\) !important;/);
for (const selector of [
"[role='button']",
"[role='radio']",
"[role='slider']",
"[role='tab']",
'[tabindex]',
'a[href]',
]) assert.ok(rule.includes(selector), `${selector} receives the global ring`);
});
test('Location city, POI, search toggle and search field use an inset ring', () => {
const rule = ruleText('.location-pill:focus-visible,');
assert.match(rule, /\.poi-pill:focus-visible/);
assert.match(rule, /\.search-toggle-btn:focus-visible/);
assert.match(rule, /#location-search:focus-visible/);
assert.match(rule, /outline:\s*2px solid var\(--text-primary\)/);
assert.match(rule, /outline-offset:\s*-3px/);
for (const selector of ['.location-pill {', '.poi-pill {', '.search-toggle-btn {']) {
assert.doesNotMatch(ruleBody(selector), /transition:\s*all\b/);
}
});
test('Cockpit Display and Radio launcher glyphs have a complete inset ring', () => {
const body = ruleBody('.cockpit-utility-glyph:focus-visible');
assert.match(body, /outline:\s*2px solid var\(--text-primary\)/);
assert.match(body, /outline-offset:\s*-3px/);
assert.doesNotMatch(body, /outline:\s*none/);
});
test('focusable controls do not animate the global outline', () => {
for (const selector of [
'.panel-collapse-btn {',
'#top-center-actions button {',
'.data-toggle-chip {',
'.scene-btn {',
'.gev-action-button--compact {',
]) {
assert.doesNotMatch(
ruleBody(selector),
/transition:\s*all\b/,
`${selector} must leave the focus outline immediate`,
);
}
});
test('opening a dock popover makes its controls keyboard-reachable immediately', () => {
const base = ruleBodyContaining('#command-dock .dock-popover-content {', 'visibility: hidden');
assert.match(base, /visibility\s+0s\s+linear\s+180ms/);
const open = ruleText('#command-dock #location-bar:not(.collapsed) .dock-popover-content,');
assert.match(open, /transition-delay:\s*0s/);
});