fix(review): thickness band derived from thickness_in (#88); MultiSelect shows selected names + commits on toggle settle (#90)
#88 — thickness band is now display-only, derived deterministically from thickness_in against the synced Woo thickness terms (TV-9 / QUALITY-95). Replaces the <select> with a read-only div. New pure function deriveThicknessTermId + 6 unit tests. Docs (UAT-PRACTICE, contracts/UX) updated to reflect the band is not an owner control. #90 — MultiSelect closed state now shows the selected option names (truncated to 2 + +N) instead of just a count. onCommit prop wired so multi-select changes persist + re-review immediately (250ms debounce, flush on Done, cleanup on destroy). Single-select binds use string vars (speciesSel/edgeSel/gradeSel) to fix the number/string mismatch with <option value={id}>; a tick()-deferred syncSelects() keeps the DOM option in sync after programmatic writes (AI prefill, reload hydrate) that Svelte's own select_option would otherwise reset.
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
import { deriveThicknessTermId, type ThicknessBand } from './thicknessBand';
|
||||
|
||||
// Synced-Woo-shaped bands (id + name). The e2e fixture uses a single "2-4 in" band.
|
||||
const BANDS: ThicknessBand[] = [
|
||||
{ id: 39, name: '2-4 in' },
|
||||
];
|
||||
|
||||
test('TV-9 / QUALITY-95: 1 in rounds up into the enclosing synced band', () => {
|
||||
const bands: ThicknessBand[] = [
|
||||
{ id: 10, name: '1-2 in' },
|
||||
{ id: 39, name: '2-4 in' },
|
||||
];
|
||||
assert.equal(deriveThicknessTermId(1, bands), 10);
|
||||
assert.equal(deriveThicknessTermId(1.5, bands), 10);
|
||||
// 2.0 is exactly the upper bound of the 1-2 band → belongs to it.
|
||||
assert.equal(deriveThicknessTermId(2.0, bands), 10);
|
||||
// 2.01 falls into 2-4.
|
||||
assert.equal(deriveThicknessTermId(2.25, bands), 39);
|
||||
assert.equal(deriveThicknessTermId(4, bands), 39);
|
||||
});
|
||||
|
||||
test('e2e fixture: thickness_in 2 → the single "2-4 in" band (id 39)', () => {
|
||||
assert.equal(deriveThicknessTermId(2, BANDS), 39);
|
||||
});
|
||||
|
||||
test('above every band → empty (no invented band; upstream thickness fix resolves it)', () => {
|
||||
assert.equal(deriveThicknessTermId(5, BANDS), '');
|
||||
});
|
||||
|
||||
test('no thickness / non-finite → empty', () => {
|
||||
assert.equal(deriveThicknessTermId(null, BANDS), '');
|
||||
assert.equal(deriveThicknessTermId(undefined, BANDS), '');
|
||||
assert.equal(deriveThicknessTermId(0, BANDS), '');
|
||||
assert.equal(deriveThicknessTermId(NaN, BANDS), '');
|
||||
assert.equal(deriveThicknessTermId(2, []), '');
|
||||
});
|
||||
|
||||
test('band names are parsed from the synced names, never hardcoded (order-independent)', () => {
|
||||
// Reverse the array: the derivation must still pick the right band by bound.
|
||||
const bands: ThicknessBand[] = [
|
||||
{ id: 39, name: '2-4 in' },
|
||||
{ id: 10, name: '1-2 in' },
|
||||
];
|
||||
assert.equal(deriveThicknessTermId(1.5, bands), 10);
|
||||
assert.equal(deriveThicknessTermId(3, bands), 39);
|
||||
});
|
||||
|
||||
test('malformed band names are skipped without throwing', () => {
|
||||
const bands: ThicknessBand[] = [
|
||||
{ id: 1, name: 'N/A' },
|
||||
{ id: 2, name: '4-2 in' }, // inverted, unusable
|
||||
{ id: 39, name: '2-4 in' },
|
||||
];
|
||||
assert.equal(deriveThicknessTermId(3, bands), 39);
|
||||
});
|
||||
Reference in New Issue
Block a user