mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-10-23 17:32:27 +00:00
Fixes #518, Fixes #514, Fixes #515, Fixes #516 ## Summary Fixes all customizer v2 bugs from the consolidated tracker (#518). Both server and client changes. ## Server Changes (`routes.go`) - **typeColors defaults** — added all 10 type color defaults matching `roles.js` `TYPE_COLORS`. Previously returned `{}`, causing all type colors to render as black. - **themeDark defaults** — added 22 dark mode color defaults matching the Default preset. Previously returned `{}`, causing dark mode to have no server-side defaults. ## Client Changes (`customize-v2.js`) - [x] **P0: Phantom override cleanup on init** — new `_cleanPhantomOverrides()` runs on startup, scanning `cs-theme-overrides` and removing any values that match server defaults (arrays via `JSON.stringify`, scalars via `===`). - [x] **P1: `setOverride` auto-prunes matching defaults** — after debounced write, iterates the delta and removes any key whose value matches the server default. Prevents phantom overrides from accumulating. - [x] **P1: `_countOverrides` counts only real diffs** — now iterates keys and calls `_isOverridden()` instead of blindly counting `Object.keys().length`. Badge count reflects actual overrides only. - [x] **P1: `_isOverridden` handles arrays/objects** — uses `JSON.stringify` comparison for non-scalar values (home.steps, home.checklist, etc.). - [x] **P1: Type color fallback** — `_renderNodes()` falls back to `window.TYPE_COLORS` when effective typeColors are empty, preventing black color swatches. - [x] **P1: Dark/light toggle re-renders panel** — MutationObserver on `data-theme` now calls `_refreshPanel()` when panel is open, so switching modes updates the Theme tab immediately. ## Tests 6 new unit tests added to `test-customizer-v2.js`: - Phantom scalar overrides cleaned on init - Phantom array overrides cleaned on init - Real overrides preserved after cleanup - `isOverridden` handles matching arrays (returns false) - `isOverridden` handles differing arrays (returns true) - `setOverride` prunes value matching server default All 48 tests pass. Go tests pass. --------- Co-authored-by: you <you@example.com>
This commit is contained in:
1 parent
58f791266d
commit
34489e0446
4 files changed
+292
-13
No files matched your search
+58
-2
@@ -284,6 +284,26 @@ func (s *Server) handleConfigTheme(w http.ResponseWriter, r *http.Request) {
|
||||
"accentHover": "#6db3ff",
|
||||
"navBg": "#0f0f23",
|
||||
"navBg2": "#1a1a2e",
|
||||
"navText": "#ffffff",
|
||||
"navTextMuted": "#cbd5e1",
|
||||
"background": "#f4f5f7",
|
||||
"text": "#1a1a2e",
|
||||
"textMuted": "#5b6370",
|
||||
"border": "#e2e5ea",
|
||||
"surface1": "#ffffff",
|
||||
"surface2": "#ffffff",
|
||||
"surface3": "#ffffff",
|
||||
"sectionBg": "#eef2ff",
|
||||
"cardBg": "#ffffff",
|
||||
"contentBg": "#f4f5f7",
|
||||
"detailBg": "#ffffff",
|
||||
"inputBg": "#ffffff",
|
||||
"rowStripe": "#f9fafb",
|
||||
"rowHover": "#eef2ff",
|
||||
"selectedBg": "#dbeafe",
|
||||
"statusGreen": "#22c55e",
|
||||
"statusYellow": "#eab308",
|
||||
"statusRed": "#ef4444",
|
||||
}, s.cfg.Theme, theme.Theme)
|
||||
|
||||
nodeColors := mergeMap(map[string]interface{}{
|
||||
@@ -294,8 +314,44 @@ func (s *Server) handleConfigTheme(w http.ResponseWriter, r *http.Request) {
|
||||
"observer": "#8b5cf6",
|
||||
}, s.cfg.NodeColors, theme.NodeColors)
|
||||
|
||||
themeDark := mergeMap(map[string]interface{}{}, s.cfg.ThemeDark, theme.ThemeDark)
|
||||
typeColors := mergeMap(map[string]interface{}{}, s.cfg.TypeColors, theme.TypeColors)
|
||||
themeDark := mergeMap(map[string]interface{}{
|
||||
"accent": "#4a9eff",
|
||||
"accentHover": "#6db3ff",
|
||||
"navBg": "#0f0f23",
|
||||
"navBg2": "#1a1a2e",
|
||||
"navText": "#ffffff",
|
||||
"navTextMuted": "#cbd5e1",
|
||||
"background": "#0f0f23",
|
||||
"text": "#e2e8f0",
|
||||
"textMuted": "#a8b8cc",
|
||||
"border": "#334155",
|
||||
"surface1": "#1a1a2e",
|
||||
"surface2": "#232340",
|
||||
"cardBg": "#1a1a2e",
|
||||
"contentBg": "#0f0f23",
|
||||
"detailBg": "#232340",
|
||||
"inputBg": "#1e1e34",
|
||||
"rowStripe": "#1e1e34",
|
||||
"rowHover": "#2d2d50",
|
||||
"selectedBg": "#1e3a5f",
|
||||
"statusGreen": "#22c55e",
|
||||
"statusYellow": "#eab308",
|
||||
"statusRed": "#ef4444",
|
||||
"surface3": "#2d2d50",
|
||||
"sectionBg": "#1e1e34",
|
||||
}, s.cfg.ThemeDark, theme.ThemeDark)
|
||||
typeColors := mergeMap(map[string]interface{}{
|
||||
"ADVERT": "#22c55e",
|
||||
"GRP_TXT": "#3b82f6",
|
||||
"TXT_MSG": "#f59e0b",
|
||||
"ACK": "#6b7280",
|
||||
"REQUEST": "#a855f7",
|
||||
"RESPONSE": "#06b6d4",
|
||||
"TRACE": "#ec4899",
|
||||
"PATH": "#14b8a6",
|
||||
"ANON_REQ": "#f43f5e",
|
||||
"UNKNOWN": "#6b7280",
|
||||
}, s.cfg.TypeColors, theme.TypeColors)
|
||||
|
||||
var home interface{}
|
||||
if theme.Home != nil {
|
||||
|
||||
+103
-5
@@ -290,6 +290,7 @@
|
||||
|
||||
/** @type {object|null} server defaults, set during init */
|
||||
var _serverDefaults = null;
|
||||
var _initDone = false;
|
||||
var _saveStatus = 'saved'; // 'saved' | 'saving' | 'error'
|
||||
var _writeTimer = null;
|
||||
|
||||
@@ -578,7 +579,29 @@
|
||||
delta[sec] = _pendingOverrides[sec];
|
||||
}
|
||||
}
|
||||
var pendingKeys = _pendingOverrides;
|
||||
_pendingOverrides = {};
|
||||
// Spec Decision #7: don't silently prune existing overrides.
|
||||
// Only prevent redundant NEW writes: if a value just written matches
|
||||
// the server default, don't store it (clearOverride semantics).
|
||||
var server = _serverDefaults || {};
|
||||
for (var ps in pendingKeys) {
|
||||
if (typeof pendingKeys[ps] === 'object' && pendingKeys[ps] !== null && OBJECT_SECTIONS.indexOf(ps) >= 0) {
|
||||
var serverSec = server[ps] || {};
|
||||
if (delta[ps]) {
|
||||
for (var pk in pendingKeys[ps]) {
|
||||
var ov = delta[ps][pk];
|
||||
var sv = serverSec[pk];
|
||||
var match = (typeof ov === 'object' || typeof sv === 'object')
|
||||
? JSON.stringify(ov) === JSON.stringify(sv) : ov === sv;
|
||||
if (match) delete delta[ps][pk];
|
||||
}
|
||||
if (Object.keys(delta[ps]).length === 0) delete delta[ps];
|
||||
}
|
||||
} else if (SCALAR_SECTIONS.indexOf(ps) >= 0 && delta[ps] === server[ps]) {
|
||||
delete delta[ps];
|
||||
}
|
||||
}
|
||||
writeOverrides(delta);
|
||||
_runPipeline();
|
||||
_refreshPanel();
|
||||
@@ -742,17 +765,33 @@
|
||||
if (section) {
|
||||
if (!overrides[section] || !overrides[section].hasOwnProperty(key)) return false;
|
||||
var serverSection = server[section] || {};
|
||||
return overrides[section][key] !== serverSection[key];
|
||||
var ov = overrides[section][key];
|
||||
var sv = serverSection[key];
|
||||
// Deep compare for arrays/objects
|
||||
if (typeof ov === 'object' || typeof sv === 'object') {
|
||||
return JSON.stringify(ov) !== JSON.stringify(sv);
|
||||
}
|
||||
return ov !== sv;
|
||||
}
|
||||
if (!overrides.hasOwnProperty(key)) return false;
|
||||
return overrides[key] !== server[key];
|
||||
var ov2 = overrides[key];
|
||||
var sv2 = server[key];
|
||||
if (typeof ov2 === 'object' || typeof sv2 === 'object') {
|
||||
return JSON.stringify(ov2) !== JSON.stringify(sv2);
|
||||
}
|
||||
return ov2 !== sv2;
|
||||
}
|
||||
|
||||
/** Count overridden fields in a section */
|
||||
/** Count overridden fields in a section (only those that differ from server defaults) */
|
||||
function _countOverrides(section) {
|
||||
var overrides = _getOverrides();
|
||||
if (!overrides[section] || typeof overrides[section] !== 'object') return 0;
|
||||
return Object.keys(overrides[section]).length;
|
||||
var count = 0;
|
||||
var keys = Object.keys(overrides[section]);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (_isOverridden(section, keys[i])) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
function _overrideDot(section, key) {
|
||||
@@ -962,11 +1001,12 @@
|
||||
'<span class="cust-hex">' + val + '</span></div>';
|
||||
}
|
||||
|
||||
var fallbackTC = (typeof window !== 'undefined' && window.TYPE_COLORS) || {};
|
||||
var tc = eff.typeColors || {};
|
||||
var stc = server.typeColors || {};
|
||||
var typeRows = '';
|
||||
for (var tkey in TYPE_LABELS) {
|
||||
var tval = tc[tkey] || '#000000';
|
||||
var tval = tc[tkey] || fallbackTC[tkey] || '#000000';
|
||||
typeRows += '<div class="cust-color-row">' +
|
||||
'<div><label>' + (TYPE_EMOJI[tkey] || '') + ' ' + TYPE_LABELS[tkey] + _overrideDot('typeColors', tkey) + '</label>' +
|
||||
'<div class="cust-hint">' + (TYPE_HINTS[tkey] || '') + '</div></div>' +
|
||||
@@ -1113,6 +1153,59 @@
|
||||
_bindEvents(container);
|
||||
}
|
||||
|
||||
/** Remove phantom overrides that match server defaults on startup */
|
||||
function _cleanPhantomOverrides() {
|
||||
var delta = readOverrides();
|
||||
if (!delta || Object.keys(delta).length === 0) return;
|
||||
var server = _serverDefaults || {};
|
||||
var changed = false;
|
||||
|
||||
// Clean object sections
|
||||
for (var i = 0; i < OBJECT_SECTIONS.length; i++) {
|
||||
var sec = OBJECT_SECTIONS[i];
|
||||
if (!delta[sec] || typeof delta[sec] !== 'object') continue;
|
||||
var serverSec = server[sec];
|
||||
// If server has no defaults for this section, only remove values that
|
||||
// are clearly phantom (empty arrays/objects or undefined equivalents).
|
||||
// Non-trivial values may be legitimate user choices.
|
||||
if (!serverSec) {
|
||||
var dKeys = Object.keys(delta[sec]);
|
||||
for (var di = 0; di < dKeys.length; di++) {
|
||||
var dv = delta[sec][dKeys[di]];
|
||||
var isPhantom = (Array.isArray(dv) && dv.length === 0) ||
|
||||
(typeof dv === 'object' && dv !== null && !Array.isArray(dv) && Object.keys(dv).length === 0);
|
||||
if (isPhantom) { delete delta[sec][dKeys[di]]; changed = true; }
|
||||
}
|
||||
if (Object.keys(delta[sec]).length === 0) { delete delta[sec]; changed = true; }
|
||||
continue;
|
||||
}
|
||||
var keys = Object.keys(delta[sec]);
|
||||
for (var j = 0; j < keys.length; j++) {
|
||||
var k = keys[j];
|
||||
var ov = delta[sec][k];
|
||||
var sv = serverSec[k];
|
||||
var match = false;
|
||||
if (typeof ov === 'object' || typeof sv === 'object') {
|
||||
match = JSON.stringify(ov) === JSON.stringify(sv);
|
||||
} else {
|
||||
match = ov === sv;
|
||||
}
|
||||
if (match) { delete delta[sec][k]; changed = true; }
|
||||
}
|
||||
if (Object.keys(delta[sec]).length === 0) { delete delta[sec]; changed = true; }
|
||||
}
|
||||
|
||||
// Clean scalar sections
|
||||
for (var si = 0; si < SCALAR_SECTIONS.length; si++) {
|
||||
var sk = SCALAR_SECTIONS[si];
|
||||
if (delta.hasOwnProperty(sk) && delta[sk] === server[sk]) {
|
||||
delete delta[sk]; changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) writeOverrides(delta);
|
||||
}
|
||||
|
||||
function _refreshPanel() {
|
||||
if (!_panelEl) return;
|
||||
var inner = _panelEl.querySelector('.cust-inner');
|
||||
@@ -1474,6 +1567,7 @@
|
||||
// Watch dark/light mode toggle and re-apply
|
||||
new MutationObserver(function () {
|
||||
_runPipeline();
|
||||
if (_panelEl && !_panelEl.classList.contains('hidden')) _refreshPanel();
|
||||
}).observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
||||
});
|
||||
|
||||
@@ -1486,8 +1580,12 @@
|
||||
window._customizerV2 = {
|
||||
init: function (serverConfig) {
|
||||
_serverDefaults = serverConfig || {};
|
||||
_cleanPhantomOverrides();
|
||||
_runPipeline();
|
||||
_initDone = true;
|
||||
},
|
||||
/** True after init() has been called with server config and pipeline has run */
|
||||
get initDone() { return _initDone; },
|
||||
readOverrides: readOverrides,
|
||||
writeOverrides: writeOverrides,
|
||||
computeEffective: computeEffective,
|
||||
|
||||
@@ -403,6 +403,115 @@ test('returns true when server has no default for overridden key', () => {
|
||||
assert.strictEqual(api.isOverridden('theme', 'accent'), true);
|
||||
});
|
||||
|
||||
// ── Bug #518 Fixes ──
|
||||
|
||||
test('phantom overrides cleaned on init — matching scalars removed', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { theme: { accent: '#4a9eff', border: '#e2e5ea' }, typeColors: { ADVERT: '#22c55e' } };
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({ theme: { accent: '#4a9eff' }, typeColors: { ADVERT: '#22c55e' } }));
|
||||
api.init(server);
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides') || '{}');
|
||||
assert.ok(!delta.theme, 'phantom theme override should be cleaned');
|
||||
assert.ok(!delta.typeColors, 'phantom typeColors override should be cleaned');
|
||||
});
|
||||
|
||||
test('phantom overrides cleaned on init — matching arrays removed', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { home: { steps: [{ emoji: '📡', title: 'Go', description: 'Do it' }] } };
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({ home: { steps: [{ emoji: '📡', title: 'Go', description: 'Do it' }] } }));
|
||||
api.init(server);
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides') || '{}');
|
||||
assert.ok(!delta.home, 'phantom home array override should be cleaned');
|
||||
});
|
||||
|
||||
test('real overrides preserved after init cleanup', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { theme: { accent: '#4a9eff' } };
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({ theme: { accent: '#ff0000' } }));
|
||||
api.init(server);
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides'));
|
||||
assert.strictEqual(delta.theme.accent, '#ff0000');
|
||||
});
|
||||
|
||||
test('isOverridden handles array comparison via JSON.stringify', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { home: { steps: [{ emoji: '📡', title: 'Go', description: 'Do' }] } };
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({ home: { steps: [{ emoji: '📡', title: 'Go', description: 'Do' }] } }));
|
||||
api.init(server);
|
||||
assert.strictEqual(api.isOverridden('home', 'steps'), false, 'matching array should not be overridden');
|
||||
});
|
||||
|
||||
test('isOverridden returns true for differing arrays', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { home: { steps: [{ emoji: '📡', title: 'Go', description: 'Do' }] } };
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({ home: { steps: [{ emoji: '🚀', title: 'New', description: 'Changed' }] } }));
|
||||
api.init(server);
|
||||
assert.strictEqual(api.isOverridden('home', 'steps'), true, 'differing array should be overridden');
|
||||
});
|
||||
|
||||
test('setOverride prunes value matching server default', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { theme: { accent: '#4a9eff' } };
|
||||
api.init(server);
|
||||
api.setOverride('theme', 'accent', '#4a9eff');
|
||||
// debounce fires synchronously in sandbox
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides') || '{}');
|
||||
assert.ok(!delta.theme || !delta.theme.accent, 'matching value should be pruned after setOverride');
|
||||
});
|
||||
|
||||
// ── Fix #2: _cleanPhantomOverrides when server has no section ──
|
||||
|
||||
test('phantom overrides cleaned when server has NO home section', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
// Server has theme but NO home — the common deployment case
|
||||
const server = { theme: { accent: '#4a9eff' } };
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({ home: { checklist: [], steps: [] } }));
|
||||
api.init(server);
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides') || '{}');
|
||||
assert.ok(!delta.home, 'phantom home override should be removed when server has no home section');
|
||||
});
|
||||
|
||||
test('phantom overrides cleaned when server section is undefined — empty arrays removed', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { theme: { accent: '#4a9eff' }, nodeColors: { repeater: '#dc2626' } };
|
||||
// timestamps has actual values (not phantom), home has empty arrays (phantom)
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({
|
||||
timestamps: { defaultMode: 'ago', timezone: 'local' },
|
||||
home: { checklist: [], steps: [] }
|
||||
}));
|
||||
api.init(server);
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides') || '{}');
|
||||
assert.ok(!delta.home, 'phantom home with empty arrays should be removed');
|
||||
// timestamps has non-empty values — preserved even without server section
|
||||
assert.ok(delta.timestamps, 'timestamps with actual values should be preserved');
|
||||
assert.strictEqual(delta.timestamps.defaultMode, 'ago');
|
||||
});
|
||||
|
||||
// ── Fix #4: setOverride with value matching server default is NOT stored ──
|
||||
|
||||
test('setOverride with value matching server default is not stored', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { theme: { accent: '#4a9eff', border: '#e2e5ea' } };
|
||||
api.init(server);
|
||||
// Set override to same value as server default
|
||||
api.setOverride('theme', 'accent', '#4a9eff');
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides') || '{}');
|
||||
assert.ok(!delta.theme || !delta.theme.accent, 'value matching server default should not be stored');
|
||||
});
|
||||
|
||||
test('existing user overrides are NOT pruned by setOverride on other keys', () => {
|
||||
const { api, ls } = loadCustomizer();
|
||||
const server = { theme: { accent: '#4a9eff', border: '#e2e5ea' } };
|
||||
// User previously chose a custom accent (different from server default)
|
||||
ls.setItem('cs-theme-overrides', JSON.stringify({ theme: { accent: '#ff0000' } }));
|
||||
api.init(server);
|
||||
// Now user changes border — accent should be preserved
|
||||
api.setOverride('theme', 'border', '#00ff00');
|
||||
const delta = JSON.parse(ls.getItem('cs-theme-overrides') || '{}');
|
||||
assert.strictEqual(delta.theme.accent, '#ff0000', 'pre-existing custom override should be preserved');
|
||||
assert.strictEqual(delta.theme.border, '#00ff00', 'new non-matching override should be stored');
|
||||
});
|
||||
|
||||
// ── Summary ──
|
||||
console.log(`\n${passed + failed} tests: ${passed} passed, ${failed} failed\n`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
+22
-6
@@ -1067,20 +1067,29 @@ async function run() {
|
||||
await test('Customizer v2: setOverride persists and applies CSS', async () => {
|
||||
await page.goto(BASE, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForSelector('nav, .navbar, .nav, [class*="nav"]');
|
||||
// Force light mode — CI headless browsers may default to dark mode,
|
||||
// and in dark mode themeDark.accent overwrites theme.accent in applyCSS
|
||||
await page.evaluate(() => {
|
||||
localStorage.setItem('meshcore-theme', 'light');
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
});
|
||||
// Clear any existing overrides
|
||||
await page.evaluate(() => localStorage.removeItem('cs-theme-overrides'));
|
||||
// Wait for init() to complete (server config fetch + full pipeline) before
|
||||
// setting override, so _runPipeline from init doesn't overwrite our value.
|
||||
await page.waitForFunction(() => {
|
||||
return window._customizerV2 && window._customizerV2.initDone;
|
||||
}, { timeout: 5000 });
|
||||
// Set an override via the API
|
||||
const result = await page.evaluate(() => {
|
||||
if (!window._customizerV2) return { error: 'customizerV2 not loaded' };
|
||||
window._customizerV2.setOverride('theme', 'accent', '#ff0000');
|
||||
// Wait for debounce
|
||||
// Wait for debounce (300ms) + buffer
|
||||
return new Promise(resolve => setTimeout(() => {
|
||||
const stored = JSON.parse(localStorage.getItem('cs-theme-overrides') || '{}');
|
||||
const cssVal = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim();
|
||||
resolve({ stored, cssVal });
|
||||
}, 500));
|
||||
});
|
||||
assert(!result.error, result.error || '');
|
||||
assert(result.stored.theme && result.stored.theme.accent === '#ff0000',
|
||||
'Override not persisted to localStorage');
|
||||
assert(result.cssVal === '#ff0000',
|
||||
@@ -1092,9 +1101,17 @@ async function run() {
|
||||
await test('Customizer v2: clearOverride resets to server default', async () => {
|
||||
await page.goto(BASE, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForSelector('nav, .navbar, .nav, [class*="nav"]');
|
||||
// Force light mode for consistent CSS testing
|
||||
await page.evaluate(() => {
|
||||
localStorage.setItem('meshcore-theme', 'light');
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
});
|
||||
// Wait for init() to complete so _serverDefaults is populated
|
||||
await page.waitForFunction(() => {
|
||||
return window._customizerV2 && window._customizerV2.initDone;
|
||||
}, { timeout: 5000 });
|
||||
const result = await page.evaluate(() => {
|
||||
if (!window._customizerV2) return { error: 'customizerV2 not loaded' };
|
||||
// Get the server default accent
|
||||
// Set the server default accent
|
||||
window._customizerV2.setOverride('theme', 'accent', '#ff0000');
|
||||
return new Promise(resolve => setTimeout(() => {
|
||||
window._customizerV2.clearOverride('theme', 'accent');
|
||||
@@ -1103,7 +1120,6 @@ async function run() {
|
||||
resolve({ hasAccent });
|
||||
}, 500));
|
||||
});
|
||||
assert(!result.error, result.error || '');
|
||||
assert(!result.hasAccent, 'accent should be removed from overrides after clearOverride');
|
||||
await page.evaluate(() => localStorage.removeItem('cs-theme-overrides'));
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user