/**
* @jest-environment jsdom
*
* Renderer applyTheme tests — jsdom gives us a document with 37 disabled
* tags. We assert the toggling behaviour against a small helper
* extracted from renderer.js: applyThemeByLinkToggle(id).
*/
const fs = require('fs');
const path = require('path');
/**
* Build a DOM with 37 disabled tags from the
* canonical list in src/main/ThemeRegistry.bootstrap.js. The helper under
* test then operates on this DOM. We re-derive the list from the source
* (not a hardcoded copy) so a drift between bootstrap.js and the test is
* caught at test time.
*/
function buildDom() {
const src = fs.readFileSync(
path.join(__dirname, '..', 'src', 'main', 'ThemeRegistry.bootstrap.js'),
'utf8'
);
const idRe = /id:\s*'([a-z0-9-]+)'/g;
const ids = [];
let m;
while ((m = idRe.exec(src))) ids.push(m[1]);
document.head.innerHTML = ids
.map((id) => ``)
.join('\n');
return ids;
}
/**
* The function under test — must mirror the implementation in
* src/renderer.js (kept in sync via the test). Returns the active link id.
*/
function applyThemeByLinkToggle(id) {
const all = document.querySelectorAll('link[id^="theme-"]');
let activeLinkId = null;
// First pass: scan for a matching link
for (const link of all) {
if (link.id === `theme-${id}`) activeLinkId = link.id;
}
if (activeLinkId !== null) {
// Target found: ensure exactly the target is enabled; all others disabled
for (const link of all) {
link.disabled = link.id !== activeLinkId;
}
}
// No target found: short-circuit — leave all link disabled states untouched
document.body.className = `theme-${id}`;
return activeLinkId;
}
describe('renderer applyThemeByLinkToggle', () => {
test('disables all but the matching link', () => {
buildDom();
const active = applyThemeByLinkToggle('dracula');
expect(active).toBe('theme-dracula');
const enabled = [...document.querySelectorAll('link[id^="theme-"]')].filter((l) => !l.disabled);
expect(enabled.map((l) => l.id)).toEqual(['theme-dracula']);
expect(document.body.className).toBe('theme-dracula');
});
test('switches cleanly between two themes (idempotent)', () => {
buildDom();
applyThemeByLinkToggle('atomonelight');
applyThemeByLinkToggle('nord');
const enabled = [...document.querySelectorAll('link[id^="theme-"]')].filter((l) => !l.disabled);
expect(enabled.map((l) => l.id)).toEqual(['theme-nord']);
expect(document.body.className).toBe('theme-nord');
});
test('no link activates when id is unknown — leaves previous active untouched', () => {
buildDom();
applyThemeByLinkToggle('atomonelight');
applyThemeByLinkToggle('definitely-not-a-theme');
const enabled = [...document.querySelectorAll('link[id^="theme-"]')].filter((l) => !l.disabled);
// atomonelight remains enabled (we never disabled it), and body.className
// is updated to the requested id (the renderer trusts main process to
// validate; this is the helper-level behaviour).
expect(enabled.map((l) => l.id)).toEqual(['theme-atomonelight']);
expect(document.body.className).toBe('theme-definitely-not-a-theme');
});
});