mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-05 21:51:23 +02:00
Two regressions reported in #1336: 1. spoolMatchesQuery did not include spool.id in the predicate, so typing a numeric Spoolman ID into the Assign Spool dialog or the Inventory page search returned no matches. Predicate now also tests String(spool.id).includes(q). 2. The Unassign button in the spool edit modal was permanently disabled for Spoolman-mode spools. The modal only ever queried the legacy spool_assignments table (keyed by spool_id), but in Spoolman mode the assignment lives in spoolman_slot_assignments (keyed by spoolman_spool_id). Both the lookup query and the unassign mutation now branch on the spoolmanMode prop and call the Spoolman-flavored endpoints.
118 lines
3.8 KiB
TypeScript
118 lines
3.8 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { spoolMatchesQuery, filterSpoolsByQuery } from '../../utils/inventorySearch';
|
|
import type { InventorySpool } from '../../api/client';
|
|
|
|
function makeSpool(overrides: Partial<InventorySpool> = {}): InventorySpool {
|
|
return {
|
|
id: 1,
|
|
material: 'PLA',
|
|
subtype: 'Basic',
|
|
color_name: 'Red',
|
|
rgba: 'FF0000FF',
|
|
brand: 'Bambu Lab',
|
|
label_weight: 1000,
|
|
core_weight: 250,
|
|
core_weight_catalog_id: null,
|
|
weight_used: 0,
|
|
slicer_filament: null,
|
|
slicer_filament_name: null,
|
|
nozzle_temp_min: 220,
|
|
nozzle_temp_max: 240,
|
|
note: null,
|
|
added_full: null,
|
|
last_used: null,
|
|
encode_time: null,
|
|
tag_uid: null,
|
|
tray_uuid: null,
|
|
data_origin: 'local',
|
|
tag_type: null,
|
|
archived_at: null,
|
|
created_at: '2024-01-01T00:00:00Z',
|
|
updated_at: '2024-01-01T00:00:00Z',
|
|
cost_per_kg: null,
|
|
last_scale_weight: null,
|
|
last_weighed_at: null,
|
|
category: null,
|
|
low_stock_threshold_pct: null,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('spoolMatchesQuery', () => {
|
|
it('returns true for empty query', () => {
|
|
expect(spoolMatchesQuery(makeSpool(), '')).toBe(true);
|
|
});
|
|
|
|
it('matches on material (case-insensitive)', () => {
|
|
const spool = makeSpool({ material: 'PETG' });
|
|
expect(spoolMatchesQuery(spool, 'petg')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, 'PET')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, 'pla')).toBe(false);
|
|
});
|
|
|
|
it('matches on brand (case-insensitive)', () => {
|
|
const spool = makeSpool({ brand: 'Prusament' });
|
|
expect(spoolMatchesQuery(spool, 'prusa')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, 'PRUSA')).toBe(true);
|
|
});
|
|
|
|
it('matches on color_name (case-insensitive)', () => {
|
|
const spool = makeSpool({ color_name: 'Galaxy Black' });
|
|
expect(spoolMatchesQuery(spool, 'galaxy')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, 'GALAXY')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, 'blue')).toBe(false);
|
|
});
|
|
|
|
it('matches on subtype (case-insensitive)', () => {
|
|
const spool = makeSpool({ subtype: 'Matte' });
|
|
expect(spoolMatchesQuery(spool, 'matt')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, 'MATTE')).toBe(true);
|
|
});
|
|
|
|
it('returns false when null optional fields do not match', () => {
|
|
const spool = makeSpool({ brand: null, color_name: null, subtype: null });
|
|
expect(spoolMatchesQuery(spool, 'bambu')).toBe(false);
|
|
});
|
|
|
|
it('matches on numeric id (#1336)', () => {
|
|
const spool = makeSpool({ id: 42, material: 'PLA', brand: null, color_name: null, subtype: null, note: null });
|
|
expect(spoolMatchesQuery(spool, '42')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, '4')).toBe(true);
|
|
expect(spoolMatchesQuery(spool, '99')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('filterSpoolsByQuery', () => {
|
|
const spools = [
|
|
makeSpool({ id: 1, material: 'PLA', brand: 'Bambu Lab', color_name: 'Red' }),
|
|
makeSpool({ id: 2, material: 'PETG', brand: 'Prusament', color_name: 'Blue' }),
|
|
makeSpool({ id: 3, material: 'ABS', brand: null, color_name: 'Black', subtype: 'Matte' }),
|
|
];
|
|
|
|
it('returns all spools for empty query', () => {
|
|
expect(filterSpoolsByQuery(spools, '')).toHaveLength(3);
|
|
});
|
|
|
|
it('filters by material', () => {
|
|
const result = filterSpoolsByQuery(spools, 'pla');
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].id).toBe(1);
|
|
});
|
|
|
|
it('filters by brand', () => {
|
|
const result = filterSpoolsByQuery(spools, 'prusa');
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].id).toBe(2);
|
|
});
|
|
|
|
it('filters by subtype', () => {
|
|
const result = filterSpoolsByQuery(spools, 'matte');
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].id).toBe(3);
|
|
});
|
|
|
|
it('returns empty array when no match', () => {
|
|
expect(filterSpoolsByQuery(spools, 'nylon')).toHaveLength(0);
|
|
});
|
|
});
|