mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-07-29 02:39:22 +00:00
## Summary `🗑️ Reset All Customizations` only stripped `cs-theme-overrides`, leaving CB-preset, encrypted-channel toggle, dark-tile pick, marker-stroke vars and the per-role `--mc-role-*` body.style writes from PRs #1361/#1430/#1448/#1454/#1488 stuck. Operators had to clear localStorage by hand to actually reset. Single source of truth lands as `_resetAll()` in `public/customize-v2.js` (exposed on `_customizerV2.resetAll` for tests). The Reset button delegates to it. Future customizer features extend ONE function — not 12 scattered call-sites. ## What is cleared | surface | keys / props | |---|---| | localStorage | `cs-theme-overrides`, `meshcore-cb-preset`, `channels-show-encrypted`, `mc-dark-tile-provider` | | body attr | `data-cb-preset` | | body.style | `--mc-role-{role}`, `--mc-role-{role}-text` for repeater/companion/room/sensor/observer | | :root style | `--mc-role-*`, `--mc-role-*-text`, `--node-*`, `--mc-marker-stroke-{color,width,opacity}`, `--mc-mb-{confirmed,suspected,unknown}`, `--mc-rt-ramp-{0..4}`, `--logo-accent`, `--logo-accent-hi`, every value in `THEME_CSS_MAP` | CB-preset teardown delegates to `MeshCorePresets.clearPreset()` so `cb-preset-changed` fires and downstream consumers re-sync to server config without a reload. Tile-provider teardown re-applies the active id (which now falls through to server default / `carto-dark`) so `mc-tile-provider-changed` fires and the live map swaps tiles, then re-clears the just-rewritten localStorage entry. ## What is explicitly preserved (per issue body) - `meshcore-theme` — separate user preference, not a customization - `meshcore-gesture-hints-*` — has its own dedicated Reset button - `meshcore-favorites` — operator's favorites list, not a customizer pick - `mc-channels-*` — channel selection state, not a customization ## TDD - Red commit (`7a986fce`): adds `test-issue-1496-reset-all-complete.js` + a stub `resetAll: function () {}` so the test fails on assertions (9 of 14), not on a missing symbol. The 5 "must NOT clear" assertions pass trivially against the stub. - Green commit (`45c88154`): wires `_resetAll()`; all 14 pass. ``` 14 passed, 0 failed ``` Existing customizer tests (`test-customize-display-e2e.js` shape only; `test-issue-1361-cb-presets.js` 82/82; `test-issue-1412-customizer-no-override.js` 13/13) unaffected. Two pre-existing failures in `test-customizer-v2.js` and `test-issue-1438-customizer-mcrole.js` reproduce on `origin/master` without this change. Closes #1496 --------- Co-authored-by: mc-bot <bot@meshcore.local>
This commit is contained in:
+124
-2
@@ -2294,11 +2294,13 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Reset All
|
||||
// Reset All — #1496: clear every customizer-touched piece of state,
|
||||
// not just STORAGE_KEY. Implementation lives in resetAll() on the
|
||||
// public API so tests can drive it without a DOM button.
|
||||
var resetBtn = document.getElementById('cv2ResetAll');
|
||||
if (resetBtn) resetBtn.addEventListener('click', function () {
|
||||
if (!confirm('Reset all customizations to server defaults?')) return;
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
_resetAll();
|
||||
_runPipeline();
|
||||
_renderPanel(container);
|
||||
});
|
||||
@@ -2449,6 +2451,124 @@
|
||||
}).observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
||||
});
|
||||
|
||||
// ── Reset All (#1496) ──
|
||||
//
|
||||
// The original "Reset All" only cleared STORAGE_KEY (cs-theme-overrides),
|
||||
// leaving CB-preset, encrypted-channel toggle, dark-tile pick, marker
|
||||
// stroke vars and per-role body.style writes stuck — each subsequent
|
||||
// customizer feature (PRs #1430, #1454, #1488, #1448) added its own
|
||||
// out-of-band side effect and forgot to teach Reset about it.
|
||||
//
|
||||
// Single source of truth: this function. Adding a new customizer
|
||||
// feature requires adding its teardown here. Each removal is wrapped
|
||||
// in try/catch because we run before/after page lifecycle in tests
|
||||
// and operators' browsers where any one surface (localStorage,
|
||||
// document, body) could be missing.
|
||||
function _resetAll() {
|
||||
// 1. localStorage — customizer-owned keys ONLY. Theme / favorites /
|
||||
// gesture hints / channel selection state are explicitly preserved
|
||||
// (see issue #1496 "Out of scope").
|
||||
var CUSTOMIZER_LS_KEYS = [
|
||||
STORAGE_KEY, // 'cs-theme-overrides'
|
||||
'meshcore-cb-preset', // #1361 CB preset id
|
||||
'channels-show-encrypted', // #1454 encrypted-channel toggle
|
||||
'mc-dark-tile-provider' // #1430 dark-tile provider pick
|
||||
];
|
||||
for (var i = 0; i < CUSTOMIZER_LS_KEYS.length; i++) {
|
||||
try { localStorage.removeItem(CUSTOMIZER_LS_KEYS[i]); } catch (_e) { /* ignore */ }
|
||||
}
|
||||
|
||||
// 2. CB preset — body[data-cb-preset] + CSS var teardown lives in
|
||||
// MeshCorePresets.clearPreset(). Prefer the canonical helper so
|
||||
// the dispatch (cb-preset-changed event) fires and downstream
|
||||
// consumers re-sync to server config without a reload.
|
||||
try {
|
||||
var MCP = (typeof window !== 'undefined') && window.MeshCorePresets;
|
||||
if (MCP && typeof MCP.clearPreset === 'function') {
|
||||
MCP.clearPreset();
|
||||
} else if (typeof document !== 'undefined' && document.body) {
|
||||
// Defensive fallback (e.g. cb-presets.js failed to load).
|
||||
document.body.removeAttribute('data-cb-preset');
|
||||
}
|
||||
} catch (_e) { /* ignore */ }
|
||||
|
||||
// 3. body.style — #1446/#1448 wrote --mc-role-{role} / -text with
|
||||
// !important so they trump :root. Strip per role + text role.
|
||||
try {
|
||||
if (typeof document !== 'undefined' && document.body && document.body.style) {
|
||||
['repeater', 'companion', 'room', 'sensor', 'observer'].forEach(function (role) {
|
||||
document.body.style.removeProperty('--mc-role-' + role);
|
||||
document.body.style.removeProperty('--mc-role-' + role + '-text');
|
||||
});
|
||||
}
|
||||
} catch (_e) { /* ignore */ }
|
||||
|
||||
// 4. :root style — everything the customizer pipeline + cb-presets
|
||||
// + marker-stroke + tile providers ever wrote onto documentElement.
|
||||
// A fresh _runPipeline() will re-set whatever server config /
|
||||
// remaining (theme-only) preferences dictate.
|
||||
try {
|
||||
if (typeof document !== 'undefined' && document.documentElement && document.documentElement.style) {
|
||||
var rs = document.documentElement.style;
|
||||
['repeater', 'companion', 'room', 'sensor', 'observer'].forEach(function (role) {
|
||||
rs.removeProperty('--mc-role-' + role);
|
||||
rs.removeProperty('--mc-role-' + role + '-text');
|
||||
rs.removeProperty('--node-' + role);
|
||||
});
|
||||
// #1488 marker stroke vars.
|
||||
rs.removeProperty('--mc-marker-stroke-color');
|
||||
rs.removeProperty('--mc-marker-stroke-width');
|
||||
rs.removeProperty('--mc-marker-stroke-opacity');
|
||||
// CB-preset MB / RT-ramp vars (also cleared by clearPreset above
|
||||
// but stripped here defensively in case clearPreset is absent).
|
||||
['confirmed', 'suspected', 'unknown'].forEach(function (k) {
|
||||
rs.removeProperty('--mc-mb-' + k);
|
||||
});
|
||||
for (var ri = 0; ri < 5; ri++) rs.removeProperty('--mc-rt-ramp-' + ri);
|
||||
// Theme vars the customizer might have stamped onto :root via
|
||||
// applyCSS (logo accents + every entry in THEME_CSS_MAP).
|
||||
rs.removeProperty('--logo-accent');
|
||||
rs.removeProperty('--logo-accent-hi');
|
||||
for (var tkey in THEME_CSS_MAP) {
|
||||
if (Object.prototype.hasOwnProperty.call(THEME_CSS_MAP, tkey)) {
|
||||
rs.removeProperty(THEME_CSS_MAP[tkey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_e) { /* ignore */ }
|
||||
|
||||
// 5. Tile provider — clearing the localStorage key (step 1) takes
|
||||
// care of persistence, but a live consumer needs the
|
||||
// mc-tile-provider-changed event to swap back to the server
|
||||
// default. Re-applying the effective active id achieves that
|
||||
// without forcing a particular value (it falls through to the
|
||||
// server default / DEFAULT_ID inside getActiveId()).
|
||||
try {
|
||||
if (typeof window !== 'undefined' &&
|
||||
typeof window.MC_setDarkTileProvider === 'function' &&
|
||||
typeof window.MC_getDarkTileProvider === 'function') {
|
||||
window.MC_setDarkTileProvider(window.MC_getDarkTileProvider());
|
||||
// Re-clear so we don't re-persist the just-re-applied value.
|
||||
try { localStorage.removeItem('mc-dark-tile-provider'); } catch (_e) {}
|
||||
}
|
||||
} catch (_e) { /* ignore */ }
|
||||
|
||||
// 6. Encrypted-channel toggle — removing the LS key (step 1) fixes
|
||||
// persistence, but channels.js subscribes to
|
||||
// mc-channels-show-encrypted-changed for live re-render. Fire it
|
||||
// explicitly with on:false so the channels list reverts to "hide
|
||||
// encrypted" without a page reload.
|
||||
try {
|
||||
if (typeof window !== 'undefined' &&
|
||||
typeof window.dispatchEvent === 'function' &&
|
||||
typeof window.CustomEvent === 'function') {
|
||||
window.dispatchEvent(new window.CustomEvent('mc-channels-show-encrypted-changed', {
|
||||
detail: { on: false }
|
||||
}));
|
||||
}
|
||||
} catch (_e) { /* ignore */ }
|
||||
}
|
||||
|
||||
// ── Public API for app.js integration ──
|
||||
|
||||
/**
|
||||
@@ -2474,6 +2594,8 @@
|
||||
applyCSS: applyCSS,
|
||||
isValidColor: isValidColor,
|
||||
isOverridden: _isOverridden,
|
||||
// #1496 — full reset (not just STORAGE_KEY). See _resetAll() above.
|
||||
resetAll: _resetAll,
|
||||
THEME_CSS_MAP: THEME_CSS_MAP
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* #1496 — "Reset All Customizations" must clear every customizer-touched
|
||||
* piece of state, not just `cs-theme-overrides`.
|
||||
*
|
||||
* Coverage:
|
||||
* - localStorage keys: cs-theme-overrides, meshcore-cb-preset,
|
||||
* channels-show-encrypted, mc-dark-tile-provider
|
||||
* - body attribute: data-cb-preset
|
||||
* - body.style: --mc-role-{role}, --mc-role-{role}-text
|
||||
* - root.style: --mc-role-{role}, --mc-role-{role}-text, --node-{role},
|
||||
* --mc-marker-stroke-{color,width,opacity}, --mc-mb-{confirmed,suspected,unknown},
|
||||
* --mc-rt-ramp-{0..4}, --logo-accent, --logo-accent-hi, theme vars
|
||||
*
|
||||
* Must NOT touch:
|
||||
* - localStorage: meshcore-theme (theme light/dark),
|
||||
* meshcore-gesture-hints-* (own button), meshcore-favorites,
|
||||
* mc-channels-* selection state
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const vm = require('vm');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
let passed = 0, failed = 0;
|
||||
function test(name, fn) {
|
||||
try { fn(); passed++; console.log(' ✅ ' + name); }
|
||||
catch (e) { failed++; console.log(' ❌ ' + name + ': ' + e.message); }
|
||||
}
|
||||
|
||||
function makeSandbox() {
|
||||
const storage = {};
|
||||
const localStorage = {
|
||||
getItem(k) { return k in storage ? storage[k] : null; },
|
||||
setItem(k, v) { storage[k] = String(v); },
|
||||
removeItem(k) { delete storage[k]; },
|
||||
clear() { for (const k in storage) delete storage[k]; },
|
||||
_data: storage,
|
||||
};
|
||||
|
||||
// Fake CSSStyleDeclaration with property tracking
|
||||
function makeStyle() {
|
||||
const props = {};
|
||||
return {
|
||||
_props: props,
|
||||
setProperty(name, value /*, priority */) { props[name] = String(value); },
|
||||
removeProperty(name) { delete props[name]; },
|
||||
getPropertyValue(name) { return props[name] || ''; },
|
||||
get cssText() {
|
||||
return Object.keys(props).map(k => k + ': ' + props[k]).join('; ');
|
||||
},
|
||||
set cssText(v) {
|
||||
for (const k in props) delete props[k];
|
||||
// very loose parser — only used to reset to empty
|
||||
if (!v) return;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const rootStyle = makeStyle();
|
||||
const bodyAttrs = {};
|
||||
const bodyStyle = makeStyle();
|
||||
|
||||
const docEl = {
|
||||
style: rootStyle,
|
||||
dataset: { theme: 'dark' },
|
||||
getAttribute: (n) => n === 'data-theme' ? 'dark' : null,
|
||||
setAttribute: () => {},
|
||||
removeAttribute: () => {},
|
||||
};
|
||||
const body = {
|
||||
style: bodyStyle,
|
||||
_attrs: bodyAttrs,
|
||||
setAttribute(n, v) { bodyAttrs[n] = v; },
|
||||
getAttribute(n) { return bodyAttrs[n] || null; },
|
||||
removeAttribute(n) { delete bodyAttrs[n]; },
|
||||
hasAttribute(n) { return n in bodyAttrs; },
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
window: {
|
||||
addEventListener: () => {},
|
||||
_events: [],
|
||||
dispatchEvent(ev) { this._events.push({ type: ev && ev.type, detail: ev && ev.detail }); },
|
||||
SITE_CONFIG: {},
|
||||
_SITE_CONFIG_ORIGINAL_HOME: null,
|
||||
},
|
||||
document: {
|
||||
readyState: 'loading',
|
||||
createElement: () => ({
|
||||
id: '', textContent: '', innerHTML: '', className: '',
|
||||
setAttribute: () => {}, appendChild: () => {},
|
||||
style: makeStyle(), addEventListener: () => {},
|
||||
querySelectorAll: () => [], querySelector: () => null,
|
||||
}),
|
||||
head: { appendChild: () => {} },
|
||||
body: body,
|
||||
getElementById: () => null,
|
||||
addEventListener: () => {},
|
||||
querySelectorAll: () => [],
|
||||
querySelector: () => null,
|
||||
documentElement: docEl,
|
||||
},
|
||||
console,
|
||||
localStorage,
|
||||
setTimeout: (fn) => fn(),
|
||||
clearTimeout: () => {},
|
||||
Date, Math, Array, Object, JSON, String, Number, Boolean,
|
||||
parseInt, parseFloat, isNaN, Infinity, NaN, undefined,
|
||||
MutationObserver: class { observe() {} },
|
||||
HashChangeEvent: class {},
|
||||
CustomEvent: class { constructor(type, opts) { this.type = type; this.detail = opts && opts.detail; } },
|
||||
getComputedStyle: () => ({ getPropertyValue: () => '' }),
|
||||
};
|
||||
ctx.window.localStorage = localStorage;
|
||||
ctx.window.CustomEvent = ctx.CustomEvent;
|
||||
ctx.self = ctx.window;
|
||||
return { ctx, body, rootStyle, bodyStyle, localStorage, bodyAttrs };
|
||||
}
|
||||
|
||||
function loadCustomizer() {
|
||||
const env = makeSandbox();
|
||||
// Provide a stub MeshCorePresets.clearPreset so resetAll can call it.
|
||||
let clearPresetCalls = 0;
|
||||
env.ctx.window.MeshCorePresets = {
|
||||
clearPreset() {
|
||||
clearPresetCalls++;
|
||||
env.localStorage.removeItem('meshcore-cb-preset');
|
||||
env.body.removeAttribute('data-cb-preset');
|
||||
// Mirror real cb-presets.js: strip preset CSS vars from :root
|
||||
['repeater', 'companion', 'room', 'sensor', 'observer'].forEach(function (role) {
|
||||
env.rootStyle.removeProperty('--mc-role-' + role);
|
||||
env.rootStyle.removeProperty('--mc-role-' + role + '-text');
|
||||
});
|
||||
['confirmed', 'suspected', 'unknown'].forEach(function (k) {
|
||||
env.rootStyle.removeProperty('--mc-mb-' + k);
|
||||
});
|
||||
for (var i = 0; i < 5; i++) env.rootStyle.removeProperty('--mc-rt-ramp-' + i);
|
||||
},
|
||||
get _calls() { return clearPresetCalls; },
|
||||
list: [],
|
||||
currentPreset: () => null,
|
||||
};
|
||||
// Tile provider stubs.
|
||||
let tpCalls = 0;
|
||||
env.ctx.window.MC_setDarkTileProvider = (id) => {
|
||||
tpCalls++;
|
||||
if (id) env.localStorage.setItem('mc-dark-tile-provider', id);
|
||||
return true;
|
||||
};
|
||||
env.ctx.window.MC_getDarkTileProvider = () => env.localStorage.getItem('mc-dark-tile-provider') || 'carto-dark';
|
||||
|
||||
const code = fs.readFileSync(path.join(__dirname, 'public', 'customize-v2.js'), 'utf8');
|
||||
vm.createContext(env.ctx);
|
||||
vm.runInContext(code, env.ctx, { filename: 'customize-v2.js' });
|
||||
env.api = env.ctx.window._customizerV2;
|
||||
return env;
|
||||
}
|
||||
|
||||
console.log('\n📋 Issue #1496 — Reset All Customizations completeness\n');
|
||||
|
||||
test('resetAll function is exposed on _customizerV2 API', () => {
|
||||
const env = loadCustomizer();
|
||||
assert.strictEqual(typeof env.api.resetAll, 'function', 'expected api.resetAll to be a function');
|
||||
});
|
||||
|
||||
test('clears cs-theme-overrides localStorage key', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('cs-theme-overrides', JSON.stringify({ theme: { accent: '#ff0000' } }));
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('cs-theme-overrides'), null);
|
||||
});
|
||||
|
||||
test('clears meshcore-cb-preset localStorage key', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('meshcore-cb-preset', 'deut');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('meshcore-cb-preset'), null);
|
||||
});
|
||||
|
||||
test('clears channels-show-encrypted localStorage key', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('channels-show-encrypted', 'true');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('channels-show-encrypted'), null);
|
||||
});
|
||||
|
||||
test('clears mc-dark-tile-provider localStorage key', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('mc-dark-tile-provider', 'voyager-inverted');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('mc-dark-tile-provider'), null);
|
||||
});
|
||||
|
||||
test('removes data-cb-preset body attribute', () => {
|
||||
const env = loadCustomizer();
|
||||
env.body.setAttribute('data-cb-preset', 'deut');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.body.hasAttribute('data-cb-preset'), false);
|
||||
});
|
||||
|
||||
test('clears per-role --mc-role-* writes from body.style', () => {
|
||||
const env = loadCustomizer();
|
||||
env.bodyStyle.setProperty('--mc-role-repeater', '#abcdef');
|
||||
env.bodyStyle.setProperty('--mc-role-companion', '#123456');
|
||||
env.bodyStyle.setProperty('--mc-role-repeater-text', '#ffffff');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.bodyStyle.getPropertyValue('--mc-role-repeater'), '');
|
||||
assert.strictEqual(env.bodyStyle.getPropertyValue('--mc-role-companion'), '');
|
||||
assert.strictEqual(env.bodyStyle.getPropertyValue('--mc-role-repeater-text'), '');
|
||||
});
|
||||
|
||||
test('clears per-role --mc-role-* and --node-* from root.style', () => {
|
||||
const env = loadCustomizer();
|
||||
['repeater','companion','room','sensor','observer'].forEach((r) => {
|
||||
env.rootStyle.setProperty('--mc-role-' + r, '#abcdef');
|
||||
env.rootStyle.setProperty('--node-' + r, '#abcdef');
|
||||
});
|
||||
env.api.resetAll();
|
||||
['repeater','companion','room','sensor','observer'].forEach((r) => {
|
||||
assert.strictEqual(env.rootStyle.getPropertyValue('--mc-role-' + r), '', '--mc-role-' + r);
|
||||
assert.strictEqual(env.rootStyle.getPropertyValue('--node-' + r), '', '--node-' + r);
|
||||
});
|
||||
});
|
||||
|
||||
test('clears marker stroke vars from root.style', () => {
|
||||
const env = loadCustomizer();
|
||||
env.rootStyle.setProperty('--mc-marker-stroke-color', '#ff0000');
|
||||
env.rootStyle.setProperty('--mc-marker-stroke-width', '3');
|
||||
env.rootStyle.setProperty('--mc-marker-stroke-opacity', '0.5');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.rootStyle.getPropertyValue('--mc-marker-stroke-color'), '');
|
||||
assert.strictEqual(env.rootStyle.getPropertyValue('--mc-marker-stroke-width'), '');
|
||||
assert.strictEqual(env.rootStyle.getPropertyValue('--mc-marker-stroke-opacity'), '');
|
||||
});
|
||||
|
||||
test('clears --mc-mb-* and --mc-rt-ramp-* preset vars from root.style', () => {
|
||||
const env = loadCustomizer();
|
||||
['confirmed','suspected','unknown'].forEach((k) => env.rootStyle.setProperty('--mc-mb-' + k, '#abcdef'));
|
||||
for (let i = 0; i < 5; i++) env.rootStyle.setProperty('--mc-rt-ramp-' + i, '#abcdef');
|
||||
env.api.resetAll();
|
||||
['confirmed','suspected','unknown'].forEach((k) => {
|
||||
assert.strictEqual(env.rootStyle.getPropertyValue('--mc-mb-' + k), '', '--mc-mb-' + k);
|
||||
});
|
||||
for (let i = 0; i < 5; i++) {
|
||||
assert.strictEqual(env.rootStyle.getPropertyValue('--mc-rt-ramp-' + i), '', '--mc-rt-ramp-' + i);
|
||||
}
|
||||
});
|
||||
|
||||
test('does NOT clear theme (meshcore-theme) localStorage key', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('meshcore-theme', 'dark');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('meshcore-theme'), 'dark');
|
||||
});
|
||||
|
||||
test('does NOT clear meshcore-gesture-hints-* keys', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('meshcore-gesture-hints-row-swipe', '1');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('meshcore-gesture-hints-row-swipe'), '1');
|
||||
});
|
||||
|
||||
test('does NOT clear meshcore-favorites', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('meshcore-favorites', '["abc"]');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('meshcore-favorites'), '["abc"]');
|
||||
});
|
||||
|
||||
test('does NOT clear mc-channels-* selection state', () => {
|
||||
const env = loadCustomizer();
|
||||
env.localStorage.setItem('mc-channels-selection', 'foo');
|
||||
env.api.resetAll();
|
||||
assert.strictEqual(env.localStorage.getItem('mc-channels-selection'), 'foo');
|
||||
});
|
||||
|
||||
test('dispatches mc-channels-show-encrypted-changed with on:false (live re-render)', () => {
|
||||
const env = loadCustomizer();
|
||||
env.ctx.window._events.length = 0;
|
||||
env.api.resetAll();
|
||||
const ev = env.ctx.window._events.find(e => e.type === 'mc-channels-show-encrypted-changed');
|
||||
assert.ok(ev, 'expected mc-channels-show-encrypted-changed event');
|
||||
assert.strictEqual(ev.detail && ev.detail.on, false, 'expected detail.on === false');
|
||||
});
|
||||
|
||||
console.log('\n' + passed + ' passed, ' + failed + ' failed\n');
|
||||
if (failed > 0) process.exit(1);
|
||||
Reference in New Issue
Block a user