112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
import {
|
|||
|
|
describe,
|
||
|
|
expect,
|
||
|
|
it,
|
||
|
|
} from 'vitest';
|
||
|
|
import type { UnifiedFont } from '../../model/types';
|
||
|
|
import { createFontLoadRequestContfig } from './createFontLoadRequestContfig';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Minimal UnifiedFont mock — override only the fields a case exercises.
|
||
|
|
*/
|
||
|
|
function createMockFont(overrides: Partial<UnifiedFont> = {}): UnifiedFont {
|
||
|
|
const baseFont: UnifiedFont = {
|
||
|
|
id: 'test-font',
|
||
|
|
name: 'Test Font',
|
||
|
|
provider: 'google',
|
||
|
|
category: 'sans-serif',
|
||
|
|
subsets: ['latin'],
|
||
|
|
variants: [],
|
||
|
|
styles: {},
|
||
|
|
metadata: {
|
||
|
|
cachedAt: Date.now(),
|
||
|
|
},
|
||
|
|
features: {
|
||
|
|
isVariable: false,
|
||
|
|
tags: [],
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
return { ...baseFont, ...overrides };
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('createFontLoadRequestContfig', () => {
|
||
|
|
it('builds a single-element config when a URL resolves', () => {
|
||
|
|
const font = createMockFont({
|
||
|
|
id: 'roboto',
|
||
|
|
name: 'Roboto',
|
||
|
|
styles: { variants: { '400': 'https://example.com/roboto-400.woff2' } },
|
||
|
|
});
|
||
|
|
|
||
|
|
const result = createFontLoadRequestContfig(font, 400);
|
||
|
|
|
||
|
|
expect(result).toEqual([
|
||
|
|
{
|
||
|
|
id: 'roboto',
|
||
|
|
name: 'Roboto',
|
||
|
|
weight: 400,
|
||
|
|
url: 'https://example.com/roboto-400.woff2',
|
||
|
|
isVariable: false,
|
||
|
|
},
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('returns an empty array when no URL resolves (flatMap drops the font)', () => {
|
||
|
|
const font = createMockFont({ styles: {} });
|
||
|
|
|
||
|
|
expect(createFontLoadRequestContfig(font, 400)).toEqual([]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('forwards isVariable from font features', () => {
|
||
|
|
const font = createMockFont({
|
||
|
|
features: { isVariable: true, tags: [] },
|
||
|
|
styles: { variants: { '700': 'https://example.com/inter-vf.woff2' } },
|
||
|
|
});
|
||
|
|
|
||
|
|
const [config] = createFontLoadRequestContfig(font, 700);
|
||
|
|
|
||
|
|
expect(config.isVariable).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('sets isVariable to undefined when features is absent', () => {
|
||
|
|
// features is non-optional on UnifiedFont, but upstream data can be partial —
|
||
|
|
// the optional chain must not throw, and isVariable stays undefined.
|
||
|
|
const font = createMockFont({
|
||
|
|
styles: { variants: { '400': 'https://example.com/font.woff2' } },
|
||
|
|
});
|
||
|
|
// @ts-expect-error — deliberately drop the guaranteed field to exercise the optional chain
|
||
|
|
font.features = undefined;
|
||
|
|
|
||
|
|
const [config] = createFontLoadRequestContfig(font, 400);
|
||
|
|
|
||
|
|
expect(config.isVariable).toBeUndefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('uses the resolved fallback URL, not just exact matches', () => {
|
||
|
|
// getFontUrl falls back to styles.regular when the exact weight is missing;
|
||
|
|
// the config must carry whatever URL actually resolved.
|
||
|
|
const font = createMockFont({
|
||
|
|
styles: { regular: 'https://example.com/font-regular.woff2' },
|
||
|
|
});
|
||
|
|
|
||
|
|
const [config] = createFontLoadRequestContfig(font, 900);
|
||
|
|
|
||
|
|
expect(config.url).toBe('https://example.com/font-regular.woff2');
|
||
|
|
expect(config.weight).toBe(900);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('carries the requested weight even when the URL is a shared fallback', () => {
|
||
|
|
const font = createMockFont({
|
||
|
|
styles: { variants: { '400': 'https://example.com/shared.woff2' } },
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(createFontLoadRequestContfig(font, 700)[0].weight).toBe(700);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('propagates the invalid-weight error from getFontUrl', () => {
|
||
|
|
const font = createMockFont();
|
||
|
|
|
||
|
|
expect(() => createFontLoadRequestContfig(font, 450)).toThrow('Invalid weight: 450');
|
||
|
|
});
|
||
|
|
});
|