chore: phase 2 and 3 refactors

This commit is contained in:
2026-02-21 18:02:20 +01:00
parent 40892b9302
commit 87200a8ad9
24 changed files with 411 additions and 74 deletions

View File

@@ -0,0 +1,40 @@
import { describe, expect, it, vi } from 'vitest';
import { activateSidebarSection } from '../../../src/renderer/navigation/sectionActivation';
describe('sectionActivation', () => {
it('opens editor first and delays section activation when editor is not active', () => {
const ensureEditor = vi.fn();
const activateSection = vi.fn();
const schedule = vi.fn((callback: () => void) => callback());
activateSidebarSection({
isEditorTabActive: false,
ensureEditorTabActive: ensureEditor,
activateSection,
schedule,
delayWhenOpeningEditorMs: 100,
});
expect(ensureEditor).toHaveBeenCalledTimes(1);
expect(schedule).toHaveBeenCalledTimes(1);
expect(schedule).toHaveBeenCalledWith(expect.any(Function), 100);
expect(activateSection).toHaveBeenCalledTimes(1);
});
it('activates section immediately when editor tab is already active', () => {
const ensureEditor = vi.fn();
const activateSection = vi.fn();
const schedule = vi.fn((callback: () => void) => callback());
activateSidebarSection({
isEditorTabActive: true,
ensureEditorTabActive: ensureEditor,
activateSection,
schedule,
});
expect(ensureEditor).not.toHaveBeenCalled();
expect(schedule).toHaveBeenCalledWith(expect.any(Function), 0);
expect(activateSection).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,14 @@
import { describe, expect, it } from 'vitest';
import { getPersistedSidebarSection, setPersistedSidebarSection } from '../../../src/renderer/navigation/sidebarUiPersistence';
describe('sidebarUiPersistence', () => {
it('persists and reads section ids by sidebar key', () => {
setPersistedSidebarSection('settings', 'project');
expect(getPersistedSidebarSection('settings')).toBe('project');
});
it('returns null for missing persisted section', () => {
expect(getPersistedSidebarSection('tags')).toBeNull();
});
});

View File

@@ -0,0 +1,30 @@
import { describe, expect, it } from 'vitest';
import {
DEFAULT_SIDEBAR_VIEW,
SIDEBAR_VIEW_REGISTRY,
isSidebarView,
} from '../../../src/renderer/navigation/sidebarViewRegistry';
describe('sidebarViewRegistry', () => {
it('defines all supported sidebar views in one canonical registry', () => {
expect(SIDEBAR_VIEW_REGISTRY).toEqual([
'posts',
'pages',
'media',
'settings',
'tags',
'chat',
'import',
'git',
]);
});
it('uses posts as default sidebar view', () => {
expect(DEFAULT_SIDEBAR_VIEW).toBe('posts');
});
it('validates sidebar view values', () => {
expect(isSidebarView('tags')).toBe(true);
expect(isSidebarView('unknown')).toBe(false);
});
});

View File

@@ -0,0 +1,27 @@
import { describe, expect, it } from 'vitest';
import type { SiteValidationReport } from '../../../src/main/shared/electronApi';
import {
getPersistedSiteValidationReport,
persistSiteValidationReport,
} from '../../../src/renderer/navigation/siteValidationPersistence';
const report: SiteValidationReport = {
sitemapPath: '/tmp/sitemap.xml',
sitemapChanged: false,
missingUrlPaths: ['/foo'],
extraUrlPaths: ['/bar'],
expectedUrlCount: 10,
existingHtmlUrlCount: 9,
};
describe('siteValidationPersistence', () => {
it('persists and loads site validation report by project', () => {
persistSiteValidationReport('project-1', report);
expect(getPersistedSiteValidationReport('project-1')).toEqual(report);
});
it('returns null when project has no persisted report', () => {
expect(getPersistedSiteValidationReport('missing-project')).toBeNull();
});
});

View File

@@ -0,0 +1,25 @@
import { describe, expect, it } from 'vitest';
import { getSingletonToolTabSpec, openSingletonToolTab } from '../../../src/renderer/navigation/tabPolicy';
describe('tabPolicy', () => {
it('provides canonical singleton tab specs', () => {
expect(getSingletonToolTabSpec('settings')).toEqual({ type: 'settings', id: 'settings', isTransient: false });
expect(getSingletonToolTabSpec('tags')).toEqual({ type: 'tags', id: 'tags', isTransient: false });
expect(getSingletonToolTabSpec('style')).toEqual({ type: 'style', id: 'style', isTransient: false });
expect(getSingletonToolTabSpec('documentation')).toEqual({ type: 'documentation', id: 'documentation', isTransient: false });
expect(getSingletonToolTabSpec('metadata-diff')).toEqual({ type: 'metadata-diff', id: 'metadata-diff', isTransient: false });
expect(getSingletonToolTabSpec('site-validation')).toEqual({ type: 'site-validation', id: 'site-validation', isTransient: false });
});
it('opens singleton tool tabs using canonical tab spec', () => {
const openTab = (tab: { type: string; id: string; isTransient: boolean }) => {
captured = tab;
};
let captured: { type: string; id: string; isTransient: boolean } | null = null;
openSingletonToolTab(openTab, 'site-validation');
expect(captured).toEqual({ type: 'site-validation', id: 'site-validation', isTransient: false });
});
});