mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart fonts: self-hosted roster + document.fonts.load render gate
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
||||
CURRENT_THEME_VERSION,
|
||||
THEME_FONT_OPTIONS,
|
||||
applyFontToConfig,
|
||||
collectFontFamilies,
|
||||
createCustomTheme,
|
||||
} from './custom-theme';
|
||||
import { THEME_PREVIEW_SPECS } from './theme-preview-specs';
|
||||
@@ -62,13 +63,63 @@ describe('applyFontToConfig', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('collectFontFamilies', () => {
|
||||
it('collects the top-level font and every *Font slot', () => {
|
||||
const config = {
|
||||
font: 'Inter',
|
||||
axis: { labelFont: 'Spectral', titleFont: 'Spectral' },
|
||||
legend: { labelFont: 'Caveat' },
|
||||
};
|
||||
expect(collectFontFamilies(config)).toEqual(new Set(['Inter', 'Spectral', 'Caveat']));
|
||||
});
|
||||
|
||||
it('walks arrays (layered specs)', () => {
|
||||
const spec = { layer: [{ mark: { font: 'A' } }, { mark: { font: 'B' } }] };
|
||||
expect(collectFontFamilies(spec)).toEqual(new Set(['A', 'B']));
|
||||
});
|
||||
|
||||
it('skips data and datasets (rows are never fonts)', () => {
|
||||
const spec = {
|
||||
data: { values: [{ font: 'NotAFont', x: 1 }] },
|
||||
datasets: { d: [{ titleFont: 'AlsoNot' }] },
|
||||
config: { font: 'Real' },
|
||||
};
|
||||
expect(collectFontFamilies(spec)).toEqual(new Set(['Real']));
|
||||
});
|
||||
|
||||
it('ignores non-string font values', () => {
|
||||
expect(collectFontFamilies({ font: 42, fontSize: 11 })).toEqual(new Set());
|
||||
});
|
||||
|
||||
it('returns family stacks verbatim (the render gate loads them as-is)', () => {
|
||||
expect(collectFontFamilies({ font: '"Inter", system-ui, sans-serif' })).toEqual(
|
||||
new Set(['"Inter", system-ui, sans-serif']),
|
||||
);
|
||||
});
|
||||
|
||||
it('finds the font a theme applies (round-trip with applyFontToConfig)', () => {
|
||||
const applied = applyFontToConfig({ axis: { labelFont: 'Old' } }, 'New');
|
||||
expect(collectFontFamilies(applied)).toEqual(new Set(['New']));
|
||||
});
|
||||
});
|
||||
|
||||
describe('THEME_FONT_OPTIONS', () => {
|
||||
it('offers distinct, non-empty CSS stacks', () => {
|
||||
expect(THEME_FONT_OPTIONS.length).toBeGreaterThanOrEqual(4);
|
||||
const values = THEME_FONT_OPTIONS.map((f) => f.value);
|
||||
const labels = THEME_FONT_OPTIONS.map((f) => f.label);
|
||||
expect(new Set(values).size).toBe(values.length);
|
||||
expect(new Set(labels).size).toBe(labels.length);
|
||||
expect(values.every((v) => v.trim().length > 0)).toBe(true);
|
||||
});
|
||||
|
||||
it('every self-hosted family (quoted primary) carries a category fallback', () => {
|
||||
// A quoted primary that hasn't loaded must degrade to a sensible system font,
|
||||
// so each roster stack lists at least one fallback after the primary.
|
||||
for (const { value } of THEME_FONT_OPTIONS.filter((o) => o.value.startsWith('"'))) {
|
||||
expect(value).toContain(',');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('THEME_PREVIEW_SPECS', () => {
|
||||
|
||||
Reference in New Issue
Block a user