mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
Test the rails' new layout and translate the edge switch
CCTV and Context take the full right column when open, so the hysteresis tests use a content-sized panel, and a test covers the full-height rule. Co-authored-by: Manjunath Paparaju <[email protected]>
This commit is contained in:
1 parent
d0b614d88e
commit
c54ead9432
16 files changed
+187
-53
No files matched your search
+127
-36
@@ -4,18 +4,31 @@ import { _selectContextMode } from './ui/contextTransactions.js';
|
||||
import { _initGlobalContextPanel } from './ui/contextBindings.js';
|
||||
import { clearSelectedLayers } from './ui/contextActions.js';
|
||||
import { readFileSync as readRadioSource } from 'node:fs';
|
||||
const radioBindings = readRadioSource(new URL('./ui/radioBindings.js', import.meta.url), 'utf8');
|
||||
const contextView = readRadioSource(new URL('./ui/views/ContextView.vue', import.meta.url), 'utf8');
|
||||
const radioBindings = readRadioSource(
|
||||
new URL('./ui/radioBindings.js', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
const contextView = readRadioSource(
|
||||
new URL('./ui/views/ContextView.vue', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
const html = await renderApplicationHtml(readFileSync(new URL('../index.html', import.meta.url), 'utf8'));
|
||||
const html = await renderApplicationHtml(
|
||||
readFileSync(new URL('../index.html', import.meta.url), 'utf8'),
|
||||
);
|
||||
const css = readStylesheet(new URL('../style.css', import.meta.url));
|
||||
|
||||
test('Contacts and Space Missions both participate in the ordinary Tab sequence', () => {
|
||||
for (const id of ['global-context-flights-btn', 'global-context-missions-btn']) {
|
||||
const button = html.match(new RegExp(`<button id="${id}"[\\s\\S]*?</button>`));
|
||||
for (const id of [
|
||||
'global-context-flights-btn',
|
||||
'global-context-missions-btn',
|
||||
]) {
|
||||
const button = html.match(
|
||||
new RegExp(`<button id="${id}"[\\s\\S]*?</button>`),
|
||||
);
|
||||
assert.ok(button, `${id} is missing`);
|
||||
assert.match(button[0], /role="tab"/);
|
||||
assert.match(button[0], /tabindex="0"/);
|
||||
@@ -23,7 +36,10 @@ test('Contacts and Space Missions both participate in the ordinary Tab sequence'
|
||||
|
||||
// The view keeps both tabs' tabindex static and never disables them; the
|
||||
// transition itself is covered over happy-dom in ui/contextPanel.test.mjs.
|
||||
for (const id of ['global-context-flights-btn', 'global-context-missions-btn']) {
|
||||
for (const id of [
|
||||
'global-context-flights-btn',
|
||||
'global-context-missions-btn',
|
||||
]) {
|
||||
const tag = contextView.match(new RegExp(`<button id="${id}"[^>]*>`))?.[0];
|
||||
assert.ok(tag, `${id} is missing from the view`);
|
||||
assert.doesNotMatch(tag, /:tabindex|:disabled|\sdisabled/);
|
||||
@@ -34,9 +50,22 @@ test('Context activation and Clear All never native-disable tabs and guard repea
|
||||
const init = _initGlobalContextPanel.toString();
|
||||
const select = _selectContextMode.toString();
|
||||
const clear = clearSelectedLayers.toString();
|
||||
assert.equal((init.match(/if \(\s*this\.destroyed\s*\|\|\s*this\._contextModeChanging\s*\|\|\s*this\._clearSelectedLayersPromise\s*\)\s*return;/g) || []).length, 2);
|
||||
assert.doesNotMatch(select, /_globalContext(?:Flights|Missions)Btn\.disabled\s*=\s*true/);
|
||||
assert.doesNotMatch(clear, /_globalContext(?:Flights|Missions)Btn\.disabled\s*=\s*true/);
|
||||
assert.equal(
|
||||
(
|
||||
init.match(
|
||||
/if \(\s*this\.destroyed\s*\|\|\s*this\._contextModeChanging\s*\|\|\s*this\._clearSelectedLayersPromise\s*\)\s*return;/g,
|
||||
) || []
|
||||
).length,
|
||||
2,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
select,
|
||||
/_globalContext(?:Flights|Missions)Btn\.disabled\s*=\s*true/,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
clear,
|
||||
/_globalContext(?:Flights|Missions)Btn\.disabled\s*=\s*true/,
|
||||
);
|
||||
});
|
||||
|
||||
test('Context tablist retains Left, Right, Home, and End keyboard navigation', () => {
|
||||
@@ -45,40 +74,62 @@ test('Context tablist retains Left, Right, Home, and End keyboard navigation', (
|
||||
assert.match(initSource, /event\.key === 'ArrowLeft'/);
|
||||
assert.match(initSource, /event\.key === 'Home'/);
|
||||
assert.match(initSource, /event\.key === 'End'/);
|
||||
assert.match(initSource, /contextTabs\[nextIndex\]\.focus\(\{ preventScroll: true \}\)/);
|
||||
assert.match(
|
||||
initSource,
|
||||
/contextTabs\[nextIndex\]\.focus\(\{ preventScroll: true \}\)/,
|
||||
);
|
||||
assert.match(initSource, /contextTabs\[nextIndex\]\.click\(\)/);
|
||||
});
|
||||
|
||||
test('Context tabs draw a visible keyboard-focus outline including active tabs', () => {
|
||||
const rules = [...css.matchAll(/([^{}]+)\{([^{}]*)\}/g)];
|
||||
const focusRule = rules.find(([, selector, body]) => (
|
||||
selector.trim().endsWith('.context-mode-button:focus-visible')
|
||||
&& /outline:\s*2px solid var\(--text-primary\)/.test(body)
|
||||
));
|
||||
assert.ok(focusRule, 'Context focus-visible rule must draw a two-pixel outline');
|
||||
const focusRule = rules.find(
|
||||
([, selector, body]) =>
|
||||
selector.trim().endsWith('.context-mode-button:focus-visible') &&
|
||||
/outline:\s*2px solid var\(--text-primary\)/.test(body),
|
||||
);
|
||||
assert.ok(
|
||||
focusRule,
|
||||
'Context focus-visible rule must draw a two-pixel outline',
|
||||
);
|
||||
assert.match(focusRule[2], /outline-offset:\s*-3px/);
|
||||
|
||||
const activeRule = rules.find(([, selector]) => selector.trim().endsWith('.context-mode-button.active'));
|
||||
const activeRule = rules.find(([, selector]) =>
|
||||
selector.trim().endsWith('.context-mode-button.active'),
|
||||
);
|
||||
assert.ok(activeRule, 'Context active-state rule is missing');
|
||||
assert.doesNotMatch(activeRule[2], /outline:\s*none/);
|
||||
});
|
||||
|
||||
test('Context async action buttons remain focused while busy', () => {
|
||||
const init = _initGlobalContextPanel.toString();
|
||||
const radio = radioBindings.slice(radioBindings.indexOf('const toggleRadio = async (trigger) => {'), radioBindings.indexOf('this._storeToken = this.store?.connect?.('));
|
||||
const radioPanel = readFileSync(new URL('./ui/views/panels/RadioPanel.vue', import.meta.url), 'utf8');
|
||||
const radio = radioBindings.slice(
|
||||
radioBindings.indexOf('const toggleRadio = async (trigger) => {'),
|
||||
radioBindings.indexOf('this._storeToken = this.store?.connect?.('),
|
||||
);
|
||||
const radioPanel = readFileSync(
|
||||
new URL('./ui/views/panels/RadioPanel.vue', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
const clear = clearSelectedLayers.toString();
|
||||
|
||||
assert.match(init, /if \(this\._installationsSearchBusy\) return;/);
|
||||
assert.doesNotMatch(init, /\.disabled\s*=\s*true/);
|
||||
const search = contextView.match(/<button id="installations-search-btn"[^>]*>/)?.[0];
|
||||
const search = contextView.match(
|
||||
/<button id="installations-search-btn"[^>]*>/,
|
||||
)?.[0];
|
||||
assert.ok(search, 'nearby sites search is missing');
|
||||
assert.doesNotMatch(search, /:disabled|\sdisabled/);
|
||||
assert.match(search, /:aria-busy=/);
|
||||
assert.match(radio, /trigger\.getAttribute\('aria-busy'\) === 'true'/);
|
||||
assert.doesNotMatch(radio, /trigger\.disabled\s*=\s*true/);
|
||||
const cockpitRadio = readFileSync(new URL('./ui/views/panels/CockpitUtilityControls.vue', import.meta.url), 'utf8');
|
||||
const cockpitEnable = cockpitRadio.match(/<UiButton id="cockpit-radio-enable-btn"[^>]*>/)?.[0];
|
||||
const cockpitRadio = readFileSync(
|
||||
new URL('./ui/views/panels/CockpitUtilityControls.vue', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
const cockpitEnable = cockpitRadio.match(
|
||||
/<UiButton id="cockpit-radio-enable-btn"[^>]*>/,
|
||||
)?.[0];
|
||||
assert.ok(cockpitEnable, 'Cockpit Radio Enable button is missing');
|
||||
assert.doesNotMatch(cockpitEnable, /disabled(?!=")|:disabled/);
|
||||
assert.match(cockpitEnable, /:aria-busy=/);
|
||||
@@ -89,44 +140,84 @@ test('Context async action buttons remain focused while busy', () => {
|
||||
assert.match(enable, /:aria-busy=/);
|
||||
assert.match(clear, /this\.setClearBusy\(true\)/);
|
||||
// The globe actions view marks the clear button busy, never disabled.
|
||||
const globeActions = readFileSync(new URL('./ui/views/panels/GlobeActions.vue', import.meta.url), 'utf8');
|
||||
const clearButton = globeActions.match(/<button id="clear-selected-layers"[^>]*>/)?.[0];
|
||||
const globeActions = readFileSync(
|
||||
new URL('./ui/views/panels/GlobeActions.vue', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
const clearButton = globeActions.match(
|
||||
/<button id="clear-selected-layers"[^>]*>/,
|
||||
)?.[0];
|
||||
assert.ok(clearButton, 'Clear selected layers button is missing');
|
||||
assert.doesNotMatch(clearButton, /disabled(?!=")|:disabled=/);
|
||||
assert.match(clearButton, /:aria-busy=/);
|
||||
});
|
||||
|
||||
test('Context header holds only its title and collapse control', () => {
|
||||
const panel = html.match(/<div id="global-context-panel"[\s\S]*?<div class="cyber-panel-body[ "]/);
|
||||
test('Context header holds only its title, edge switch and collapse control', () => {
|
||||
const panel = html.match(
|
||||
/<div id="global-context-panel"[\s\S]*?<div class="cyber-panel-body[ "]/,
|
||||
);
|
||||
assert.ok(panel, 'Global Context panel is missing');
|
||||
const header = panel[0].match(/<div class="ui-panel__head panel-header">([\s\S]*?)<\/div>\s*<div class="cyber-panel-body[ "]/);
|
||||
const header = panel[0].match(
|
||||
/<div class="ui-panel__head panel-header">([\s\S]*?)<\/div>\s*<div class="cyber-panel-body[ "]/,
|
||||
);
|
||||
assert.ok(header, 'Global Context header is missing');
|
||||
// The kit's own ui-* classes carry no Core styles.
|
||||
const tags = [...header[1].matchAll(/<(\w+)\s+(?:type="button"\s+)?class="([^"]+)"/g)].map(([, tag, cls]) =>
|
||||
`${tag}.${cls.split(' ').filter((name) => !/^ui-/.test(name)).join(' ')}`);
|
||||
assert.deepEqual(tags, ['span.panel-title', 'span.panel-divider', 'button.panel-collapse-btn']);
|
||||
const tags = [
|
||||
...header[1].matchAll(/<(\w+)\s+(?:type="button"\s+)?class="([^"]+)"/g),
|
||||
].map(
|
||||
([, tag, cls]) =>
|
||||
`${tag}.${cls
|
||||
.split(' ')
|
||||
.filter((name) => !/^ui-/.test(name))
|
||||
.join(' ')}`,
|
||||
);
|
||||
assert.deepEqual(tags, [
|
||||
'span.panel-title',
|
||||
'span.panel-divider',
|
||||
'button.panel-edge-btn',
|
||||
'span.material-symbols-outlined',
|
||||
'button.panel-collapse-btn',
|
||||
]);
|
||||
});
|
||||
|
||||
test('Context reads as one segmented control with legible type and no halo', () => {
|
||||
const rules = [...css.matchAll(/([^{}]+)\{([^{}]*)\}/g)];
|
||||
const clean = (selector) => selector.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\s+/g, ' ').trim();
|
||||
const rule = (selector) => rules.find(([, s]) => clean(s) === selector)?.[2] || '';
|
||||
const px = (body, prop) => Number(body.match(new RegExp(`${prop}:[^;]*?(\\d+(?:\\.\\d+)?)px`))?.[1] || 0);
|
||||
const clean = (selector) =>
|
||||
selector
|
||||
.replace(/\/\*[\s\S]*?\*\//g, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
const rule = (selector) =>
|
||||
rules.find(([, s]) => clean(s) === selector)?.[2] || '';
|
||||
const px = (body, prop) =>
|
||||
Number(
|
||||
body.match(new RegExp(`${prop}:[^;]*?(\\d+(?:\\.\\d+)?)px`))?.[1] || 0,
|
||||
);
|
||||
|
||||
assert.match(rule('#global-context-panel .panel-glow'), /display:\s*none/);
|
||||
const modes = rule('.global-context-modes');
|
||||
assert.match(modes, /border:\s*1px solid/);
|
||||
assert.match(modes, /padding:\s*2px/);
|
||||
assert.ok(px(rule('.context-mode-button'), 'font') >= 10, 'mode labels must stay at least 10px');
|
||||
assert.ok(
|
||||
px(rule('.context-mode-button'), 'font') >= 10,
|
||||
'mode labels must stay at least 10px',
|
||||
);
|
||||
assert.doesNotMatch(rule('.context-mode-button.active'), /box-shadow/);
|
||||
const standby = rule('.context-mode-standby');
|
||||
assert.ok(px(standby, 'font') >= 10, 'standby guidance must stay at least 10px');
|
||||
assert.ok(
|
||||
px(standby, 'font') >= 10,
|
||||
'standby guidance must stay at least 10px',
|
||||
);
|
||||
assert.doesNotMatch(standby, /dashed/);
|
||||
assert.ok(px(rule('.global-context-actions .panel-layer-toggle'), 'font-size') >= 10);
|
||||
assert.ok(
|
||||
px(rule('.global-context-actions .panel-layer-toggle'), 'font-size') >= 10,
|
||||
);
|
||||
// The shared rail title colour (brighter than --text-secondary) keeps the
|
||||
// open Context title legible; no Context-only rule dims it again.
|
||||
assert.equal(
|
||||
rule(":root:not([data-ui-theme='cyber']) #global-context-panel:not(.collapsed) .panel-title"),
|
||||
rule(
|
||||
":root:not([data-ui-theme='cyber']) #global-context-panel:not(.collapsed) .panel-title",
|
||||
),
|
||||
'',
|
||||
);
|
||||
});
|
||||
@@ -3967,5 +3967,7 @@
|
||||
"Cable car": "ترام كابلي",
|
||||
"Monorail": "قطار أحادي السكة",
|
||||
"Funicular": "قطار جبلي مائل",
|
||||
"Gondola": "تلفريك"
|
||||
"Gondola": "تلفريك",
|
||||
"Move panels back beside the rail": "إعادة اللوحات إلى جانب الشريط",
|
||||
"Move panels over the rail, to the edge": "نقل اللوحات فوق الشريط إلى الحافة"
|
||||
}
|
||||
@@ -3619,5 +3619,7 @@
|
||||
"Cable car": "Kabelstraßenbahn",
|
||||
"Monorail": "Einschienenbahn",
|
||||
"Funicular": "Standseilbahn",
|
||||
"Gondola": "Gondelbahn"
|
||||
"Gondola": "Gondelbahn",
|
||||
"Move panels back beside the rail": "Bedienfelder zurück neben die Leiste",
|
||||
"Move panels over the rail, to the edge": "Bedienfelder über die Leiste an den Rand verschieben"
|
||||
}
|
||||
@@ -3706,5 +3706,7 @@
|
||||
"Cable car": "Tranvía de cable",
|
||||
"Monorail": "Monorraíl",
|
||||
"Funicular": "Funicular",
|
||||
"Gondola": "Góndola"
|
||||
"Gondola": "Góndola",
|
||||
"Move panels back beside the rail": "Devolver los paneles junto a la barra",
|
||||
"Move panels over the rail, to the edge": "Mover los paneles sobre la barra, hasta el borde"
|
||||
}
|
||||
@@ -3706,5 +3706,7 @@
|
||||
"Cable car": "Tramway à câble",
|
||||
"Monorail": "Monorail",
|
||||
"Funicular": "Funiculaire",
|
||||
"Gondola": "Télécabine"
|
||||
"Gondola": "Télécabine",
|
||||
"Move panels back beside the rail": "Remettre les panneaux à côté de la barre",
|
||||
"Move panels over the rail, to the edge": "Déplacer les panneaux par-dessus la barre, jusqu’au bord"
|
||||
}
|
||||
@@ -3706,5 +3706,7 @@
|
||||
"Cable car": "חשמלית כבלים",
|
||||
"Monorail": "מונורייל",
|
||||
"Funicular": "פוניקולר",
|
||||
"Gondola": "רכבל"
|
||||
"Gondola": "רכבל",
|
||||
"Move panels back beside the rail": "החזרת הלוחות לצד הסרגל",
|
||||
"Move panels over the rail, to the edge": "הזזת הלוחות מעל הסרגל, אל הקצה"
|
||||
}
|
||||
@@ -3706,5 +3706,7 @@
|
||||
"Cable car": "Tram a fune",
|
||||
"Monorail": "Monorotaia",
|
||||
"Funicular": "Funicolare",
|
||||
"Gondola": "Cabinovia"
|
||||
"Gondola": "Cabinovia",
|
||||
"Move panels back beside the rail": "Riporta i pannelli accanto alla barra",
|
||||
"Move panels over the rail, to the edge": "Sposta i pannelli sopra la barra, fino al bordo"
|
||||
}
|
||||
@@ -3532,5 +3532,7 @@
|
||||
"Cable car": "ケーブルトラム",
|
||||
"Monorail": "モノレール",
|
||||
"Funicular": "ケーブルカー",
|
||||
"Gondola": "ゴンドラ"
|
||||
"Gondola": "ゴンドラ",
|
||||
"Move panels back beside the rail": "パネルをレールの横に戻す",
|
||||
"Move panels over the rail, to the edge": "パネルをレールの上、画面端へ移動"
|
||||
}
|
||||
@@ -3706,5 +3706,7 @@
|
||||
"Cable car": "Bonde a cabo",
|
||||
"Monorail": "Monotrilho",
|
||||
"Funicular": "Funicular",
|
||||
"Gondola": "Teleférico"
|
||||
"Gondola": "Teleférico",
|
||||
"Move panels back beside the rail": "Voltar os painéis para junto da barra",
|
||||
"Move panels over the rail, to the edge": "Mover os painéis sobre a barra, até a borda"
|
||||
}
|
||||
@@ -3793,5 +3793,7 @@
|
||||
"Cable car": "Канатный трамвай",
|
||||
"Monorail": "Монорельс",
|
||||
"Funicular": "Фуникулёр",
|
||||
"Gondola": "Канатная дорога"
|
||||
"Gondola": "Канатная дорога",
|
||||
"Move panels back beside the rail": "Вернуть панели к боковой панели",
|
||||
"Move panels over the rail, to the edge": "Переместить панели поверх боковой панели к краю"
|
||||
}
|
||||
@@ -3619,5 +3619,7 @@
|
||||
"Cable car": "Kabelspårvagn",
|
||||
"Monorail": "Enskensbana",
|
||||
"Funicular": "Bergbana",
|
||||
"Gondola": "Kabinbana"
|
||||
"Gondola": "Kabinbana",
|
||||
"Move panels back beside the rail": "Flytta tillbaka panelerna bredvid listen",
|
||||
"Move panels over the rail, to the edge": "Flytta panelerna över listen, till kanten"
|
||||
}
|
||||
@@ -3793,5 +3793,7 @@
|
||||
"Cable car": "Канатний трамвай",
|
||||
"Monorail": "Монорейка",
|
||||
"Funicular": "Фунікулер",
|
||||
"Gondola": "Канатна дорога"
|
||||
"Gondola": "Канатна дорога",
|
||||
"Move panels back beside the rail": "Повернути панелі до бічної смуги",
|
||||
"Move panels over the rail, to the edge": "Перемістити панелі поверх бічної смуги до краю"
|
||||
}
|
||||
@@ -3532,5 +3532,7 @@
|
||||
"Cable car": "缆索电车",
|
||||
"Monorail": "单轨列车",
|
||||
"Funicular": "缆索铁路",
|
||||
"Gondola": "缆车"
|
||||
"Gondola": "缆车",
|
||||
"Move panels back beside the rail": "将面板移回侧栏旁",
|
||||
"Move panels over the rail, to the edge": "将面板移到侧栏上方,贴靠边缘"
|
||||
}
|
||||
@@ -3532,5 +3532,7 @@
|
||||
"Cable car": "纜索電車",
|
||||
"Monorail": "單軌列車",
|
||||
"Funicular": "纜索鐵路",
|
||||
"Gondola": "纜車"
|
||||
"Gondola": "纜車",
|
||||
"Move panels back beside the rail": "將面板移回側欄旁",
|
||||
"Move panels over the rail, to the edge": "將面板移到側欄上方,貼齊邊緣"
|
||||
}
|
||||
@@ -141,6 +141,7 @@ test("UiPanel draws Core's panel markup and asks for the other state", async (t)
|
||||
'demo-badge',
|
||||
'panel-divider',
|
||||
'demo-action',
|
||||
'panel-edge-btn',
|
||||
'panel-collapse-btn',
|
||||
],
|
||||
);
|
||||
|
||||
@@ -456,13 +456,17 @@ test('natural height includes visible content, margins and wrapper chrome, exclu
|
||||
// Outside measurement, CCTV is 391 px in focus and 629 px in normal mode;
|
||||
// Removing only the allocation leaves focus CSS active: its next reading is
|
||||
// 422 px, so the old decision exits focus and then re-enters on the 629 px read.
|
||||
function thrashingRightRail({ focused = false, weatherOpen = false } = {}) {
|
||||
function thrashingRightRail({
|
||||
focused = false,
|
||||
weatherOpen = false,
|
||||
tallId = 'cctv-panel',
|
||||
} = {}) {
|
||||
const f = fixture('right');
|
||||
f.options.windowRef.innerHeight = 920;
|
||||
f.options.leftStack.rect.top = 439.6;
|
||||
f.stack.computed.rowGap = '8px';
|
||||
const display = element('pp-toggles', { collapsed: true });
|
||||
const cctv = element('cctv-panel', { height: 629 });
|
||||
const cctv = element(tallId, { height: 629 });
|
||||
const weather = element('weather-panel', {
|
||||
height: 444,
|
||||
collapsed: !weatherOpen,
|
||||
@@ -533,8 +537,10 @@ for (const focused of [false, true]) {
|
||||
});
|
||||
}
|
||||
|
||||
// The hysteresis applies to panels that size to their content; CCTV and
|
||||
// Context take the column's full height whenever they are open.
|
||||
test('right rail keeps focus through 30 px content growth inside the hysteresis band', () => {
|
||||
const f = thrashingRightRail();
|
||||
const f = thrashingRightRail({ tallId: 'news-panel' });
|
||||
f.run();
|
||||
// Header + gap contribute 52 px: need moves 420 -> 450 -> 420.
|
||||
for (const height of [368, 398, 368, 398, 368]) {
|
||||
@@ -551,7 +557,7 @@ test('right rail keeps focus through 30 px content growth inside the hysteresis
|
||||
});
|
||||
|
||||
test('right rail enters focus only above available height and leaves below the full deadband', () => {
|
||||
const f = thrashingRightRail();
|
||||
const f = thrashingRightRail({ tallId: 'news-panel' });
|
||||
f.options.windowRef.innerHeight = 1000;
|
||||
f.options.leftStack.rect.top = 500;
|
||||
f.cctv.intrinsicHeight = 408; // Need equals available (460 px).
|
||||
@@ -568,6 +574,16 @@ test('right rail enters focus only above available height and leaves below the f
|
||||
assert.equal(f.stack.classList.contains('layout-focus'), false);
|
||||
});
|
||||
|
||||
test('an open CCTV panel takes the full column however short its content', () => {
|
||||
const f = thrashingRightRail();
|
||||
f.cctv.intrinsicHeight = 200;
|
||||
f.run();
|
||||
assert.equal(f.stack.classList.contains('layout-focus'), true);
|
||||
f.cctv.classList.add('collapsed');
|
||||
f.run();
|
||||
assert.equal(f.stack.classList.contains('layout-focus'), false);
|
||||
});
|
||||
|
||||
test('right rail settles a second tall panel through the accordion in one pass', () => {
|
||||
const f = thrashingRightRail({ weatherOpen: true });
|
||||
const modes = [];
|
||||
|
||||
Reference in new issue
Block a user