test(filters): add a unit runner and the filter dimension contract (#188)
This commit is contained in:
@@ -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]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user