refactor(GetFonts): tighten mapManagerToParams + add coverage
Collapse the three duplicated getGroup/map/length-guard chains into a single selectedIn helper. Drop the unnecessary `as string[]` casts — Property<TValue extends string>.value already yields string at the call site. Add unit tests covering empty query, populated query, missing group, empty group, single + multi selection, unknown group ids, and the combined param shape.
This commit is contained in:
@@ -0,0 +1,127 @@
|
|||||||
|
import type { Property } from '$shared/lib';
|
||||||
|
import {
|
||||||
|
describe,
|
||||||
|
expect,
|
||||||
|
it,
|
||||||
|
} from 'vitest';
|
||||||
|
import { createFilterManager } from '../../model/store/filterManager/filterManager.svelte';
|
||||||
|
import { mapManagerToParams } from './mapManagerToParams';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a Property with explicit selection state.
|
||||||
|
*/
|
||||||
|
function prop(value: string, selected = false): Property<string> {
|
||||||
|
return { id: value, name: value, value, selected };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a filter group with a known id and a list of (value, selected) entries.
|
||||||
|
*/
|
||||||
|
function group(id: string, props: Array<[string, boolean]>) {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
label: id,
|
||||||
|
properties: props.map(([value, selected]) => prop(value, selected)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mapManagerToParams', () => {
|
||||||
|
describe('search query', () => {
|
||||||
|
it('omits q when query is empty', () => {
|
||||||
|
const manager = createFilterManager({ queryValue: '', groups: [] });
|
||||||
|
expect(mapManagerToParams(manager).q).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes the debounced query through as q', () => {
|
||||||
|
// Constructor seeds both immediate and debounced synchronously.
|
||||||
|
const manager = createFilterManager({ queryValue: 'roboto', groups: [] });
|
||||||
|
expect(mapManagerToParams(manager).q).toBe('roboto');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('group selections', () => {
|
||||||
|
it('omits a group entirely when no group with that id exists', () => {
|
||||||
|
const manager = createFilterManager({ queryValue: '', groups: [] });
|
||||||
|
const params = mapManagerToParams(manager);
|
||||||
|
expect(params.providers).toBeUndefined();
|
||||||
|
expect(params.categories).toBeUndefined();
|
||||||
|
expect(params.subsets).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('omits a group when it exists but has no selections', () => {
|
||||||
|
const manager = createFilterManager({
|
||||||
|
queryValue: '',
|
||||||
|
groups: [group('providers', [['google', false], ['fontshare', false]])],
|
||||||
|
});
|
||||||
|
expect(mapManagerToParams(manager).providers).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the selected values for a single group', () => {
|
||||||
|
const manager = createFilterManager({
|
||||||
|
queryValue: '',
|
||||||
|
groups: [group('providers', [['google', true], ['fontshare', false]])],
|
||||||
|
});
|
||||||
|
expect(mapManagerToParams(manager).providers).toEqual(['google']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns multiple selected values in selection order', () => {
|
||||||
|
const manager = createFilterManager({
|
||||||
|
queryValue: '',
|
||||||
|
groups: [
|
||||||
|
group('categories', [
|
||||||
|
['serif', true],
|
||||||
|
['sans-serif', false],
|
||||||
|
['display', true],
|
||||||
|
['monospace', true],
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(mapManagerToParams(manager).categories).toEqual(['serif', 'display', 'monospace']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('maps each of the three recognized group ids independently', () => {
|
||||||
|
const manager = createFilterManager({
|
||||||
|
queryValue: '',
|
||||||
|
groups: [
|
||||||
|
group('providers', [['google', true]]),
|
||||||
|
group('categories', [['serif', true], ['sans-serif', true]]),
|
||||||
|
group('subsets', [['latin', true]]),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const params = mapManagerToParams(manager);
|
||||||
|
expect(params.providers).toEqual(['google']);
|
||||||
|
expect(params.categories).toEqual(['serif', 'sans-serif']);
|
||||||
|
expect(params.subsets).toEqual(['latin']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores groups whose id does not match providers/categories/subsets', () => {
|
||||||
|
const manager = createFilterManager({
|
||||||
|
queryValue: '',
|
||||||
|
groups: [group('weights', [['400', true], ['700', true]])],
|
||||||
|
});
|
||||||
|
const params = mapManagerToParams(manager);
|
||||||
|
expect(params.providers).toBeUndefined();
|
||||||
|
expect(params.categories).toBeUndefined();
|
||||||
|
expect(params.subsets).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('combined output', () => {
|
||||||
|
it('produces a complete param object when query and selections coexist', () => {
|
||||||
|
const manager = createFilterManager({
|
||||||
|
queryValue: 'inter',
|
||||||
|
groups: [
|
||||||
|
group('providers', [['google', true]]),
|
||||||
|
group('categories', [['sans-serif', true]]),
|
||||||
|
group('subsets', [['latin', false]]),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(mapManagerToParams(manager)).toEqual({
|
||||||
|
q: 'inter',
|
||||||
|
providers: ['google'],
|
||||||
|
categories: ['sans-serif'],
|
||||||
|
subsets: undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -29,25 +29,20 @@ import type { FilterManager } from '../../model';
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function mapManagerToParams(manager: FilterManager): Partial<ProxyFontsParams> {
|
export function mapManagerToParams(manager: FilterManager): Partial<ProxyFontsParams> {
|
||||||
const providers = manager.getGroup('providers')?.instance.selectedProperties.map(p => p.value);
|
/**
|
||||||
const categories = manager.getGroup('categories')?.instance.selectedProperties.map(p => p.value);
|
* Return the list of selected values for a group, or undefined when
|
||||||
const subsets = manager.getGroup('subsets')?.instance.selectedProperties.map(p => p.value);
|
* the group is missing or has no selection — matches the API's
|
||||||
|
* "omit empty filters" contract.
|
||||||
|
*/
|
||||||
|
const selectedIn = (id: string): string[] | undefined => {
|
||||||
|
const values = manager.getGroup(id)?.instance.selectedProperties.map(p => p.value);
|
||||||
|
return values && values.length > 0 ? values : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Search query (debounced)
|
|
||||||
q: manager.debouncedQueryValue || undefined,
|
q: manager.debouncedQueryValue || undefined,
|
||||||
|
providers: selectedIn('providers'),
|
||||||
// NEW: Support arrays - send all selected values
|
categories: selectedIn('categories'),
|
||||||
providers: providers && providers.length > 0
|
subsets: selectedIn('subsets'),
|
||||||
? providers as string[]
|
|
||||||
: undefined,
|
|
||||||
|
|
||||||
categories: categories && categories.length > 0
|
|
||||||
? categories as string[]
|
|
||||||
: undefined,
|
|
||||||
|
|
||||||
subsets: subsets && subsets.length > 0
|
|
||||||
? subsets as string[]
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user