test(filters): add a unit runner and the filter dimension contract (#188)

This commit is contained in:
2026-08-25 14:58:21 -05:00
parent e695d91670
commit 5d0b66a982
6 changed files with 577 additions and 2 deletions
@@ -0,0 +1,57 @@
import { describe, it, expect } from 'vitest';
import { EMPTY_FILTERS, ItemFilters } from '../../src/filters';
import type { FilterContext } from '../../src/components/filters/dimension';
import { categoryDimension } from '../../src/components/filters/standardDimensions';
import type { Category, Tag as ItemTag } from '../../src/api';
const CATEGORIES: Category[] = [
{ id: 1, name: 'Furniture', parent_id: null, sort_order: 0, item_count: 0 },
{ id: 2, name: 'Tables', parent_id: 1, sort_order: 0, item_count: 0 },
{ id: 3, name: 'Decor', parent_id: null, sort_order: 0, item_count: 0 }
];
const TAGS: ItemTag[] = [
{ id: 10, name: 'vintage', color: 'red', item_count: 1 },
{ id: 11, name: 'oak', color: 'lime', item_count: 1 }
];
/** The last filters a dimension's onRemove produced, for asserting on. */
function contextFor(filters: Partial<ItemFilters>) {
const state: { latest: ItemFilters | null } = { latest: null };
const ctx: FilterContext = {
filters: { ...EMPTY_FILTERS, ...filters },
onChange: (next) => { state.latest = next; },
categories: CATEGORIES,
tags: TAGS,
priceRange: { min_cents: 0, max_cents: 100000 }
};
return { ctx, state };
}
describe('categoryDimension', () => {
it('reports no chips when nothing is selected', () => {
const { ctx } = contextFor({});
expect(categoryDimension.chips(ctx)).toEqual([]);
});
it('reports one chip per selected category, labelled with its full path', () => {
const { ctx } = contextFor({ categoryIds: [2, 3] });
expect(categoryDimension.chips(ctx).map((chip) => chip.label)).toEqual([
'Furniture / Tables',
'Decor'
]);
});
// The row renders before /api/filters resolves, and a chip with no label
// would be an empty box.
it('falls back to the id when the category is not loaded yet', () => {
const { ctx } = contextFor({ categoryIds: [99] });
expect(categoryDimension.chips(ctx)[0]?.label).toBe('Category 99');
});
it('removes only the chip that was closed', () => {
const { ctx, state } = contextFor({ categoryIds: [2, 3] });
categoryDimension.chips(ctx)[0]?.onRemove();
expect(state.latest?.categoryIds).toEqual([3]);
});
});