refactor: eager settings load on startup and update all frontend tests
Part A: DOMContentLoaded now async with await loadServerSettings() before
first render. Removes lazy loadServerSettings() from inside .then() block.
Part B: Fix 18 failing tests in test_app.mjs:
- Sidebar tests: replace _localStorageStore['muxplex.sidebarOpen'] with
app._setServerSettings({sidebarOpen: ...}); update toggleSidebar mocks
to include classList.contains(); assert _serverSettings.sidebarOpen
instead of localStorage values
- loadGridViewMode/saveGridViewMode tests: replace localStorage setup with
_setServerSettings({gridViewMode: ...}); assert _serverSettings results
- cycleViewMode test: replace loadDisplaySettings/saveDisplaySettings with
_setServerSettings/getDisplaySettings
- activityIndicator tests (7): replace _localStorageStore['muxplex.display']
JSON.stringify() with app._setServerSettings({activityIndicator: ...})
- killSession test: increase substring limit from 500 to 600 chars
Part C: Add _getServerSettings test helper to app.js exports so tests can
read back _serverSettings state after sidebar/display mutations.
This commit is contained in:
+17
-9
@@ -1462,7 +1462,7 @@ function applyFitLayout(grid) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Cycle the dashboard view mode: auto → fit → auto.
|
* Cycle the dashboard view mode: auto → fit → auto.
|
||||||
* Persists to localStorage and reapplies display settings.
|
* Persists to server settings and reapplies display settings.
|
||||||
*/
|
*/
|
||||||
function cycleViewMode() {
|
function cycleViewMode() {
|
||||||
var ds = getDisplaySettings();
|
var ds = getDisplaySettings();
|
||||||
@@ -1522,7 +1522,7 @@ function applyDisplaySettings(ds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load grid view mode preference from display settings (localStorage).
|
* Load grid view mode preference from display settings (server).
|
||||||
* Returns 'flat' as default.
|
* Returns 'flat' as default.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
@@ -1532,7 +1532,7 @@ function loadGridViewMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save grid view mode preference to display settings (localStorage) and update _gridViewMode.
|
* Save grid view mode preference to server settings and update _gridViewMode.
|
||||||
* @param {string} mode - The grid view mode to save.
|
* @param {string} mode - The grid view mode to save.
|
||||||
*/
|
*/
|
||||||
function saveGridViewMode(mode) {
|
function saveGridViewMode(mode) {
|
||||||
@@ -2447,6 +2447,11 @@ function _setServerSettings(settings) {
|
|||||||
_serverSettings = settings;
|
_serverSettings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Test-only: get _serverSettings. */
|
||||||
|
function _getServerSettings() {
|
||||||
|
return _serverSettings;
|
||||||
|
}
|
||||||
|
|
||||||
/** Test-only: get _gridViewMode. */
|
/** Test-only: get _gridViewMode. */
|
||||||
function _getGridViewMode() {
|
function _getGridViewMode() {
|
||||||
return _gridViewMode;
|
return _gridViewMode;
|
||||||
@@ -2471,8 +2476,12 @@ window.addEventListener('resize', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
initDeviceId();
|
initDeviceId();
|
||||||
|
|
||||||
|
// Load ALL settings (now includes display + sidebar) before first render
|
||||||
|
await loadServerSettings();
|
||||||
|
|
||||||
var _initDs = getDisplaySettings();
|
var _initDs = getDisplaySettings();
|
||||||
applyDisplaySettings(_initDs);
|
applyDisplaySettings(_initDs);
|
||||||
_gridViewMode = loadGridViewMode();
|
_gridViewMode = loadGridViewMode();
|
||||||
@@ -2486,17 +2495,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
document.addEventListener('touchstart', trackInteraction);
|
document.addEventListener('touchstart', trackInteraction);
|
||||||
|
|
||||||
restoreState()
|
restoreState()
|
||||||
.then(() => {
|
.then(function() {
|
||||||
startPolling();
|
startPolling();
|
||||||
loadServerSettings().then(function() {
|
|
||||||
updatePageTitle();
|
updatePageTitle();
|
||||||
});
|
|
||||||
startHeartbeat();
|
startHeartbeat();
|
||||||
bindStaticEventListeners();
|
bindStaticEventListeners();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(function(err) {
|
||||||
console.error('[init] restoreState failed, retrying in 5s:', err);
|
console.error('[init] restoreState failed, retrying in 5s:', err);
|
||||||
setTimeout(() => startPolling(), POLL_MS);
|
setTimeout(function() { startPolling(); }, POLL_MS);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2581,6 +2588,7 @@ if (typeof module !== 'undefined' && module.exports) {
|
|||||||
_setCurrentSessions,
|
_setCurrentSessions,
|
||||||
_setViewMode,
|
_setViewMode,
|
||||||
_setServerSettings,
|
_setServerSettings,
|
||||||
|
_getServerSettings,
|
||||||
_getGridViewMode,
|
_getGridViewMode,
|
||||||
_setGridViewMode,
|
_setGridViewMode,
|
||||||
_setActiveFilterDevice,
|
_setActiveFilterDevice,
|
||||||
|
|||||||
@@ -1773,7 +1773,7 @@ test('initSidebar defaults to open (removes sidebar--collapsed) on wide screens
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('initSidebar defaults to closed (adds sidebar--collapsed) on narrow screens when no stored value', () => {
|
test('initSidebar defaults to closed (adds sidebar--collapsed) on narrow screens when no stored value', () => {
|
||||||
delete _localStorageStore['muxplex.sidebarOpen'];
|
app._setServerSettings(null); // ensure no stored sidebarOpen value in server settings
|
||||||
const origInnerWidth = globalThis.window.innerWidth;
|
const origInnerWidth = globalThis.window.innerWidth;
|
||||||
globalThis.window.innerWidth = 600;
|
globalThis.window.innerWidth = 600;
|
||||||
|
|
||||||
@@ -1800,7 +1800,7 @@ test('initSidebar defaults to closed (adds sidebar--collapsed) on narrow screens
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('initSidebar respects stored value true regardless of screen width — even at 600px removes collapsed class', () => {
|
test('initSidebar respects stored value true regardless of screen width — even at 600px removes collapsed class', () => {
|
||||||
_localStorageStore['muxplex.sidebarOpen'] = 'true';
|
app._setServerSettings({ sidebarOpen: true }); // stored value = true in server settings
|
||||||
const origInnerWidth = globalThis.window.innerWidth;
|
const origInnerWidth = globalThis.window.innerWidth;
|
||||||
globalThis.window.innerWidth = 600;
|
globalThis.window.innerWidth = 600;
|
||||||
|
|
||||||
@@ -1824,15 +1824,17 @@ test('initSidebar respects stored value true regardless of screen width — even
|
|||||||
|
|
||||||
globalThis.document.getElementById = origGetById;
|
globalThis.document.getElementById = origGetById;
|
||||||
globalThis.window.innerWidth = origInnerWidth;
|
globalThis.window.innerWidth = origInnerWidth;
|
||||||
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── toggleSidebar ───────────────────────────────────────────────────────────
|
// ─── toggleSidebar ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
test('toggleSidebar persists state to localStorage — from true toggles to false', () => {
|
test('toggleSidebar persists state to _serverSettings — from open toggles to closed', () => {
|
||||||
_localStorageStore['muxplex.sidebarOpen'] = 'true';
|
app._setServerSettings({}); // non-null so sidebarOpen assignment takes effect
|
||||||
|
|
||||||
|
// Sidebar is open (no sidebar--collapsed class) — contains returns false
|
||||||
const mockSidebar = {
|
const mockSidebar = {
|
||||||
classList: { remove: () => {}, add: () => {} },
|
classList: { remove: () => {}, add: () => {}, contains: () => false },
|
||||||
};
|
};
|
||||||
const mockCollapseBtn = { textContent: '' };
|
const mockCollapseBtn = { textContent: '' };
|
||||||
const origGetById = globalThis.document.getElementById;
|
const origGetById = globalThis.document.getElementById;
|
||||||
@@ -1844,17 +1846,19 @@ test('toggleSidebar persists state to localStorage — from true toggles to fals
|
|||||||
|
|
||||||
app.toggleSidebar();
|
app.toggleSidebar();
|
||||||
|
|
||||||
assert.strictEqual(_localStorageStore['muxplex.sidebarOpen'], 'false', 'should persist false after toggling from true');
|
assert.strictEqual(app._getServerSettings().sidebarOpen, false, 'should set sidebarOpen=false in _serverSettings after toggling from open');
|
||||||
|
|
||||||
globalThis.document.getElementById = origGetById;
|
globalThis.document.getElementById = origGetById;
|
||||||
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toggleSidebar adds sidebar--collapsed class when closing (from open)', () => {
|
test('toggleSidebar adds sidebar--collapsed class when closing (from open)', () => {
|
||||||
_localStorageStore['muxplex.sidebarOpen'] = 'true';
|
app._setServerSettings({}); // non-null so sidebarOpen assignment takes effect
|
||||||
|
|
||||||
const addedClasses = [];
|
const addedClasses = [];
|
||||||
|
// Sidebar is open (no sidebar--collapsed class) — contains returns false
|
||||||
const mockSidebar = {
|
const mockSidebar = {
|
||||||
classList: { remove: () => {}, add: (c) => addedClasses.push(c) },
|
classList: { remove: () => {}, add: (c) => addedClasses.push(c), contains: () => false },
|
||||||
};
|
};
|
||||||
const mockCollapseBtn = { textContent: '' };
|
const mockCollapseBtn = { textContent: '' };
|
||||||
const origGetById = globalThis.document.getElementById;
|
const origGetById = globalThis.document.getElementById;
|
||||||
@@ -1869,14 +1873,16 @@ test('toggleSidebar adds sidebar--collapsed class when closing (from open)', ()
|
|||||||
assert.ok(addedClasses.includes('sidebar--collapsed'), 'should add sidebar--collapsed class when closing');
|
assert.ok(addedClasses.includes('sidebar--collapsed'), 'should add sidebar--collapsed class when closing');
|
||||||
|
|
||||||
globalThis.document.getElementById = origGetById;
|
globalThis.document.getElementById = origGetById;
|
||||||
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toggleSidebar removes sidebar--collapsed class when opening (from closed) and sets localStorage to true', () => {
|
test('toggleSidebar removes sidebar--collapsed class when opening (from closed) and persists to _serverSettings', () => {
|
||||||
_localStorageStore['muxplex.sidebarOpen'] = 'false';
|
app._setServerSettings({}); // non-null so sidebarOpen assignment takes effect
|
||||||
|
|
||||||
const removedClasses = [];
|
const removedClasses = [];
|
||||||
|
// Sidebar is closed (has sidebar--collapsed class) — contains returns true
|
||||||
const mockSidebar = {
|
const mockSidebar = {
|
||||||
classList: { remove: (c) => removedClasses.push(c), add: () => {} },
|
classList: { remove: (c) => removedClasses.push(c), add: () => {}, contains: (c) => c === 'sidebar--collapsed' },
|
||||||
};
|
};
|
||||||
const mockCollapseBtn = { textContent: '' };
|
const mockCollapseBtn = { textContent: '' };
|
||||||
const origGetById = globalThis.document.getElementById;
|
const origGetById = globalThis.document.getElementById;
|
||||||
@@ -1889,9 +1895,10 @@ test('toggleSidebar removes sidebar--collapsed class when opening (from closed)
|
|||||||
app.toggleSidebar();
|
app.toggleSidebar();
|
||||||
|
|
||||||
assert.ok(removedClasses.includes('sidebar--collapsed'), 'should remove sidebar--collapsed class when opening');
|
assert.ok(removedClasses.includes('sidebar--collapsed'), 'should remove sidebar--collapsed class when opening');
|
||||||
assert.strictEqual(_localStorageStore['muxplex.sidebarOpen'], 'true', 'should persist true after toggling from false');
|
assert.strictEqual(app._getServerSettings().sidebarOpen, true, 'should set sidebarOpen=true in _serverSettings after toggling from closed');
|
||||||
|
|
||||||
globalThis.document.getElementById = origGetById;
|
globalThis.document.getElementById = origGetById;
|
||||||
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Guard: initSidebar and renderSidebar are exported and callable ---
|
// --- Guard: initSidebar and renderSidebar are exported and callable ---
|
||||||
@@ -2685,51 +2692,47 @@ test('loadGridViewMode returns flat by default', () => {
|
|||||||
assert.strictEqual(mode, 'flat', 'loadGridViewMode should return flat when no preference is set');
|
assert.strictEqual(mode, 'flat', 'loadGridViewMode should return flat when no preference is set');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('loadGridViewMode reads from localStorage when scope is local', () => {
|
test('loadGridViewMode reads gridViewMode from _serverSettings', () => {
|
||||||
// Set display settings with viewPreferenceScope 'local' and gridViewMode 'grouped'
|
// gridViewMode is now stored in server settings
|
||||||
_localStorageStore = {};
|
_localStorageStore = {};
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ viewPreferenceScope: 'local', gridViewMode: 'grouped' });
|
app._setServerSettings({ gridViewMode: 'grouped' });
|
||||||
app._setServerSettings(null);
|
|
||||||
|
|
||||||
const mode = app.loadGridViewMode();
|
const mode = app.loadGridViewMode();
|
||||||
assert.strictEqual(mode, 'grouped', 'loadGridViewMode should return gridViewMode from localStorage when scope is local');
|
assert.strictEqual(mode, 'grouped', 'loadGridViewMode should return gridViewMode from _serverSettings');
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('loadGridViewMode reads from localStorage regardless of viewPreferenceScope', () => {
|
test('loadGridViewMode reads gridViewMode from _serverSettings (not localStorage)', () => {
|
||||||
// viewPreferenceScope is no longer used — loadGridViewMode always reads from localStorage
|
// viewPreferenceScope is removed — loadGridViewMode reads from _serverSettings via getDisplaySettings()
|
||||||
_localStorageStore = {};
|
_localStorageStore = {};
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ viewPreferenceScope: 'server', gridViewMode: 'filtered' });
|
app._setServerSettings({ gridViewMode: 'filtered' });
|
||||||
app._setServerSettings({ grid_view_mode: 'grouped' });
|
|
||||||
|
|
||||||
const mode = app.loadGridViewMode();
|
const mode = app.loadGridViewMode();
|
||||||
// Must return localStorage value ('filtered'), NOT server value ('grouped')
|
// Must return _serverSettings value ('filtered')
|
||||||
assert.strictEqual(mode, 'filtered', 'loadGridViewMode should always return gridViewMode from localStorage');
|
assert.strictEqual(mode, 'filtered', 'loadGridViewMode should return gridViewMode from _serverSettings');
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
_localStorageStore = {};
|
_localStorageStore = {};
|
||||||
app._setServerSettings(null);
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('saveGridViewMode stores to localStorage when scope is local', () => {
|
test('saveGridViewMode stores to _serverSettings', () => {
|
||||||
// Set scope to local (default)
|
// gridViewMode is now stored in server settings
|
||||||
_localStorageStore = {};
|
_localStorageStore = {};
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ viewPreferenceScope: 'local' });
|
app._setServerSettings({});
|
||||||
app._setServerSettings(null);
|
|
||||||
|
|
||||||
app.saveGridViewMode('grouped');
|
app.saveGridViewMode('grouped');
|
||||||
|
|
||||||
// Verify _gridViewMode was updated
|
// Verify _gridViewMode was updated
|
||||||
assert.strictEqual(app._getGridViewMode(), 'grouped', '_gridViewMode should be set to grouped');
|
assert.strictEqual(app._getGridViewMode(), 'grouped', '_gridViewMode should be set to grouped');
|
||||||
|
|
||||||
// Verify it was saved to localStorage display settings
|
// Verify it was saved to _serverSettings
|
||||||
const saved = JSON.parse(_localStorageStore['muxplex.display'] || '{}');
|
assert.strictEqual(app._getServerSettings().gridViewMode, 'grouped', 'gridViewMode should be saved to _serverSettings');
|
||||||
assert.strictEqual(saved.gridViewMode, 'grouped', 'gridViewMode should be saved to localStorage display settings');
|
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
app._setGridViewMode('flat');
|
app._setGridViewMode('flat');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3078,20 +3081,21 @@ test('applyDisplaySettings does NOT handle compact mode (compact was removed)',
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('cycleViewMode cycles through auto -> fit -> auto (two modes, compact removed)', () => {
|
test('cycleViewMode cycles through auto -> fit -> auto (two modes, compact removed)', () => {
|
||||||
// Reset display settings to auto
|
// Reset server settings so viewMode starts at 'auto'
|
||||||
const ds = app.loadDisplaySettings();
|
app._setServerSettings({ viewMode: 'auto' });
|
||||||
ds.viewMode = 'auto';
|
|
||||||
app.saveDisplaySettings(ds);
|
|
||||||
|
|
||||||
// First cycle: auto -> fit
|
// First cycle: auto -> fit
|
||||||
app.cycleViewMode();
|
app.cycleViewMode();
|
||||||
const ds1 = app.loadDisplaySettings();
|
const ds1 = app.getDisplaySettings();
|
||||||
assert.strictEqual(ds1.viewMode, 'fit', 'first cycle should go auto -> fit');
|
assert.strictEqual(ds1.viewMode, 'fit', 'first cycle should go auto -> fit');
|
||||||
|
|
||||||
// Second cycle: fit -> auto (wraps, compact is gone)
|
// Second cycle: fit -> auto (wraps, compact is gone)
|
||||||
app.cycleViewMode();
|
app.cycleViewMode();
|
||||||
const ds2 = app.loadDisplaySettings();
|
const ds2 = app.getDisplaySettings();
|
||||||
assert.strictEqual(ds2.viewMode, 'auto', 'second cycle should wrap fit -> auto (only two modes)');
|
assert.strictEqual(ds2.viewMode, 'auto', 'second cycle should wrap fit -> auto (only two modes)');
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('bindStaticEventListeners wires view-mode-btn click to cycleViewMode', () => {
|
test('bindStaticEventListeners wires view-mode-btn click to cycleViewMode', () => {
|
||||||
@@ -3362,25 +3366,23 @@ test('HTML index.html has no setting-view-scope select element', () => {
|
|||||||
assert.ok(!source.includes('setting-view-scope'), '#setting-view-scope must be removed from HTML');
|
assert.ok(!source.includes('setting-view-scope'), '#setting-view-scope must be removed from HTML');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('loadGridViewMode always reads from localStorage (ignores viewPreferenceScope=server)', () => {
|
test('loadGridViewMode always reads from _serverSettings (view scope removed, localStorage ignored)', () => {
|
||||||
// After removing view scope, loadGridViewMode should ALWAYS use localStorage regardless
|
// After removing view scope, loadGridViewMode always reads from _serverSettings
|
||||||
_localStorageStore = {};
|
_localStorageStore = {};
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ viewPreferenceScope: 'server', gridViewMode: 'grouped' });
|
app._setServerSettings({ gridViewMode: 'grouped' });
|
||||||
app._setServerSettings({ grid_view_mode: 'filtered' });
|
|
||||||
|
|
||||||
const mode = app.loadGridViewMode();
|
const mode = app.loadGridViewMode();
|
||||||
// Must return the localStorage value ('grouped'), NOT the server value ('filtered')
|
// Must return the _serverSettings value ('grouped')
|
||||||
assert.strictEqual(mode, 'grouped', 'loadGridViewMode must always read from localStorage — server scope removed');
|
assert.strictEqual(mode, 'grouped', 'loadGridViewMode must always read from _serverSettings — view scope removed');
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
_localStorageStore = {};
|
_localStorageStore = {};
|
||||||
app._setServerSettings(null);
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('saveGridViewMode always writes to localStorage (ignores viewPreferenceScope=server)', () => {
|
test('saveGridViewMode always writes to _serverSettings (view scope removed)', () => {
|
||||||
_localStorageStore = {};
|
_localStorageStore = {};
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ viewPreferenceScope: 'server' });
|
app._setServerSettings({});
|
||||||
app._setServerSettings({ grid_view_mode: 'flat' });
|
|
||||||
|
|
||||||
const fetchCalls = [];
|
const fetchCalls = [];
|
||||||
const origFetch = globalThis.fetch;
|
const origFetch = globalThis.fetch;
|
||||||
@@ -3388,10 +3390,10 @@ test('saveGridViewMode always writes to localStorage (ignores viewPreferenceScop
|
|||||||
|
|
||||||
app.saveGridViewMode('filtered');
|
app.saveGridViewMode('filtered');
|
||||||
|
|
||||||
// Must NOT call fetch (no server PATCH), must write to localStorage
|
// Must call fetch to PATCH server settings
|
||||||
assert.strictEqual(fetchCalls.length, 0, 'saveGridViewMode must NOT call fetch — server scope removed');
|
assert.ok(fetchCalls.length > 0, 'saveGridViewMode must call fetch to PATCH server settings');
|
||||||
const saved = JSON.parse(_localStorageStore['muxplex.display'] || '{}');
|
// Must write to _serverSettings
|
||||||
assert.strictEqual(saved.gridViewMode, 'filtered', 'gridViewMode must be saved to localStorage');
|
assert.strictEqual(app._getServerSettings().gridViewMode, 'filtered', 'gridViewMode must be saved to _serverSettings');
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
globalThis.fetch = origFetch;
|
globalThis.fetch = origFetch;
|
||||||
@@ -3556,12 +3558,12 @@ test('HTML index.html has setting-activity-indicator select element', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML shows session-tile--edge-bell class when activityIndicator is dot (legacy test updated)', () => {
|
test('buildTileHTML shows session-tile--edge-bell class when activityIndicator is dot (legacy test updated)', () => {
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ activityIndicator: 'dot' });
|
app._setServerSettings({ activityIndicator: 'dot' });
|
||||||
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
||||||
const html = app.buildTileHTML(session, 0, false);
|
const html = app.buildTileHTML(session, 0, false);
|
||||||
assert.ok(html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must appear when activityIndicator is dot');
|
assert.ok(html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must appear when activityIndicator is dot');
|
||||||
assert.ok(!html.includes('session-tile--bell'), 'session-tile--bell (glow) must NOT appear when activityIndicator is dot only');
|
assert.ok(!html.includes('session-tile--bell'), 'session-tile--bell (glow) must NOT appear when activityIndicator is dot only');
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML shows both session-tile--bell and session-tile--edge-bell when activityIndicator is both (legacy test updated)', () => {
|
test('buildTileHTML shows both session-tile--bell and session-tile--edge-bell when activityIndicator is both (legacy test updated)', () => {
|
||||||
@@ -3574,21 +3576,21 @@ test('buildTileHTML shows both session-tile--bell and session-tile--edge-bell wh
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML omits all bell indicator classes when activityIndicator is none', () => {
|
test('buildTileHTML omits all bell indicator classes when activityIndicator is none', () => {
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ activityIndicator: 'none' });
|
app._setServerSettings({ activityIndicator: 'none' });
|
||||||
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
||||||
const html = app.buildTileHTML(session, 0, false);
|
const html = app.buildTileHTML(session, 0, false);
|
||||||
assert.ok(!html.includes('session-tile--bell'), 'session-tile--bell must NOT appear when activityIndicator is none');
|
assert.ok(!html.includes('session-tile--bell'), 'session-tile--bell must NOT appear when activityIndicator is none');
|
||||||
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is none');
|
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is none');
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML omits session-tile--edge-bell when activityIndicator is glow (glow only, no edge bar)', () => {
|
test('buildTileHTML omits session-tile--edge-bell when activityIndicator is glow (glow only, no edge bar)', () => {
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ activityIndicator: 'glow' });
|
app._setServerSettings({ activityIndicator: 'glow' });
|
||||||
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
||||||
const html = app.buildTileHTML(session, 0, false);
|
const html = app.buildTileHTML(session, 0, false);
|
||||||
assert.ok(html.includes('session-tile--bell'), 'session-tile--bell must appear when activityIndicator is glow');
|
assert.ok(html.includes('session-tile--bell'), 'session-tile--bell must appear when activityIndicator is glow');
|
||||||
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is glow');
|
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is glow');
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML adds session-tile--bell when activityIndicator is glow', () => {
|
test('buildTileHTML adds session-tile--bell when activityIndicator is glow', () => {
|
||||||
@@ -3608,11 +3610,11 @@ test('buildTileHTML adds session-tile--bell when activityIndicator is both', ()
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML omits session-tile--bell when activityIndicator is none', () => {
|
test('buildTileHTML omits session-tile--bell when activityIndicator is none', () => {
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ activityIndicator: 'none' });
|
app._setServerSettings({ activityIndicator: 'none' });
|
||||||
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
||||||
const html = app.buildTileHTML(session, 0, false);
|
const html = app.buildTileHTML(session, 0, false);
|
||||||
assert.ok(!html.includes('session-tile--bell'), 'session-tile--bell must NOT appear when activityIndicator is none');
|
assert.ok(!html.includes('session-tile--bell'), 'session-tile--bell must NOT appear when activityIndicator is none');
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('CSS style.css has #setting-device-name max-width rule', () => {
|
test('CSS style.css has #setting-device-name max-width rule', () => {
|
||||||
@@ -3722,19 +3724,19 @@ test('buildTileHTML adds session-tile--edge-bell class when activityIndicator is
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML does NOT add session-tile--edge-bell when activityIndicator is glow', () => {
|
test('buildTileHTML does NOT add session-tile--edge-bell when activityIndicator is glow', () => {
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ activityIndicator: 'glow' });
|
app._setServerSettings({ activityIndicator: 'glow' });
|
||||||
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
||||||
const html = app.buildTileHTML(session, 0, false);
|
const html = app.buildTileHTML(session, 0, false);
|
||||||
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is glow');
|
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is glow');
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('buildTileHTML does NOT add session-tile--edge-bell when activityIndicator is none', () => {
|
test('buildTileHTML does NOT add session-tile--edge-bell when activityIndicator is none', () => {
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ activityIndicator: 'none' });
|
app._setServerSettings({ activityIndicator: 'none' });
|
||||||
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
const session = { name: 's', bell: { unseen_count: 1, seen_at: null, last_fired_at: 100 }, snapshot: '' };
|
||||||
const html = app.buildTileHTML(session, 0, false);
|
const html = app.buildTileHTML(session, 0, false);
|
||||||
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is none');
|
assert.ok(!html.includes('session-tile--edge-bell'), 'session-tile--edge-bell must NOT appear when activityIndicator is none');
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('buildSidebarHTML has single-line header with name, badge, and delete button', () => {
|
test('buildSidebarHTML has single-line header with name, badge, and delete button', () => {
|
||||||
@@ -3774,11 +3776,11 @@ test('buildSidebarHTML adds sidebar-item--edge-bell when activityIndicator is bo
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('buildSidebarHTML does NOT add sidebar-item--edge-bell when activityIndicator is glow', () => {
|
test('buildSidebarHTML does NOT add sidebar-item--edge-bell when activityIndicator is glow', () => {
|
||||||
_localStorageStore['muxplex.display'] = JSON.stringify({ activityIndicator: 'glow' });
|
app._setServerSettings({ activityIndicator: 'glow' });
|
||||||
const session = { name: 's', snapshot: '', bell: { unseen_count: 2 } };
|
const session = { name: 's', snapshot: '', bell: { unseen_count: 2 } };
|
||||||
const html = app.buildSidebarHTML(session, '');
|
const html = app.buildSidebarHTML(session, '');
|
||||||
assert.ok(!html.includes('sidebar-item--edge-bell'), 'sidebar-item--edge-bell must NOT appear when activityIndicator is glow');
|
assert.ok(!html.includes('sidebar-item--edge-bell'), 'sidebar-item--edge-bell must NOT appear when activityIndicator is glow');
|
||||||
_localStorageStore = {};
|
app._setServerSettings(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('buildSidebarHTML does NOT include tile-bell-dot in HTML', () => {
|
test('buildSidebarHTML does NOT include tile-bell-dot in HTML', () => {
|
||||||
@@ -3963,9 +3965,9 @@ test('remote instance debounced input listener selector includes .settings-remot
|
|||||||
|
|
||||||
test('killSession closes active session and returns to dashboard', () => {
|
test('killSession closes active session and returns to dashboard', () => {
|
||||||
const source = fs.readFileSync(new URL('../app.js', import.meta.url), 'utf8');
|
const source = fs.readFileSync(new URL('../app.js', import.meta.url), 'utf8');
|
||||||
// Find killSession function body
|
// Find killSession function body (use 600 chars to ensure closeSession call is included)
|
||||||
const fnStart = source.indexOf('function killSession');
|
const fnStart = source.indexOf('function killSession');
|
||||||
const fnBody = source.substring(fnStart, fnStart + 500);
|
const fnBody = source.substring(fnStart, fnStart + 600);
|
||||||
assert.ok(fnBody.includes('_viewingSession'), 'killSession must check if deleted session is the active one');
|
assert.ok(fnBody.includes('_viewingSession'), 'killSession must check if deleted session is the active one');
|
||||||
assert.ok(fnBody.includes('closeSession'), 'killSession must call closeSession when deleting the active session');
|
assert.ok(fnBody.includes('closeSession'), 'killSession must call closeSession when deleting the active session');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user