refactor(comparison): replace comparisonStore singleton with lazy getComparisonStore
Mirror the font-catalog change in ComparisonView: expose getComparisonStore() (plus __resetComparisonStore for tests) instead of an eager comparisonStore singleton, and consume getFontCatalog() internally. Update the model barrel and all UI consumers (Sidebar, FontList, Header, Line, SliderArea); Character no longer needs the store and reads everything from props. Update both specs to the accessor: comparisonStore.test mocks getFontCatalog with a writable stub (the real store's fonts is getter-only) and resets the catalog between cases; Sidebar.svelte.test resolves the store via the accessor. Also document Character's props.
This commit is contained in:
@@ -47,6 +47,10 @@ const mockStorage = vi.hoisted(() => {
|
||||
return storage;
|
||||
});
|
||||
|
||||
// Writable catalog stub — tests assign `.fonts` directly, which the real
|
||||
// FontCatalogStore forbids (getter-only). getFontCatalog returns this singleton.
|
||||
const mockFontCatalog = vi.hoisted(() => ({ fonts: [] as unknown[] }));
|
||||
|
||||
vi.mock('$shared/lib/helpers/createPersistentStore/createPersistentStore.svelte', () => ({
|
||||
createPersistentStore: vi.fn(() => mockStorage),
|
||||
}));
|
||||
@@ -65,7 +69,7 @@ vi.mock('$entities/Font/model', async importOriginal => {
|
||||
const actual = await importOriginal<typeof import('$entities/Font/model')>();
|
||||
return {
|
||||
...actual,
|
||||
fontCatalogStore: { fonts: [] },
|
||||
getFontCatalog: () => mockFontCatalog,
|
||||
fontLifecycleManager: {
|
||||
touch: vi.fn(),
|
||||
pin: vi.fn(),
|
||||
@@ -95,21 +99,23 @@ vi.mock('$features/AdjustTypography/model', () => ({
|
||||
|
||||
import * as proxyFonts from '$entities/Font/api/proxy/proxyFonts';
|
||||
import {
|
||||
fontCatalogStore,
|
||||
fontLifecycleManager,
|
||||
getFontCatalog,
|
||||
} from '$entities/Font/model';
|
||||
import { __resetFontCatalog } from '$entities/Font/model/store/fontCatalogStore/fontCatalogStore.svelte';
|
||||
import { ComparisonStore } from './comparisonStore.svelte';
|
||||
|
||||
describe('ComparisonStore', () => {
|
||||
const mockFontA: UnifiedFont = UNIFIED_FONTS.roboto; // id: 'roboto'
|
||||
const mockFontB: UnifiedFont = UNIFIED_FONTS.openSans; // id: 'open-sans'
|
||||
let fontCatalog = getFontCatalog();
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient.clear();
|
||||
vi.clearAllMocks();
|
||||
mockStorage._value = { fontAId: null, fontBId: null };
|
||||
mockStorage._clear.mockClear();
|
||||
(fontCatalogStore as any).fonts = [];
|
||||
(fontCatalog as any).fonts = [];
|
||||
|
||||
// Default: fetchFontsByIds returns empty so tests that don't care don't hang
|
||||
vi.spyOn(proxyFonts, 'fetchFontsByIds').mockResolvedValue([]);
|
||||
@@ -126,6 +132,10 @@ describe('ComparisonStore', () => {
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
__resetFontCatalog();
|
||||
});
|
||||
|
||||
describe('Initialization', () => {
|
||||
it('should create store with initial empty state', () => {
|
||||
const store = new ComparisonStore();
|
||||
@@ -164,7 +174,7 @@ describe('ComparisonStore', () => {
|
||||
|
||||
describe('Default Fallbacks', () => {
|
||||
it('should update storage with default IDs when storage is empty', async () => {
|
||||
(fontCatalogStore as any).fonts = [mockFontA, mockFontB];
|
||||
(fontCatalog as any).fonts = [mockFontA, mockFontB];
|
||||
vi.spyOn(proxyFonts, 'fetchFontsByIds').mockResolvedValue([mockFontA, mockFontB]);
|
||||
|
||||
new ComparisonStore();
|
||||
@@ -192,7 +202,7 @@ describe('ComparisonStore', () => {
|
||||
|
||||
// Catalog defaults differ from the stored selection — if the
|
||||
// effect mis-seeds, storage will flip to roboto / open-sans.
|
||||
(fontCatalogStore as any).fonts = [mockFontA, mockFontB];
|
||||
(fontCatalog as any).fonts = [mockFontA, mockFontB];
|
||||
|
||||
// Delay the batch so the catalog-driven effect runs first.
|
||||
vi.spyOn(proxyFonts, 'fetchFontsByIds').mockImplementation(
|
||||
|
||||
Reference in New Issue
Block a user