61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import { strict as assert } from 'node:assert';
|
|
import { test } from 'node:test';
|
|
|
|
/*
|
|
The selection logic, lifted out of the hook so it can be tested without React.
|
|
|
|
The rule that matters: a bulk action must only ever touch rows the person could
|
|
see when they chose them. Approving stock moves it, so acting on a row hidden
|
|
behind a filter is not a cosmetic bug.
|
|
*/
|
|
|
|
function chosenOf(visible: readonly number[], picked: ReadonlySet<number>) {
|
|
return visible.filter((id) => picked.has(id));
|
|
}
|
|
|
|
function afterToggleAll(visible: readonly number[], picked: ReadonlySet<number>) {
|
|
const next = new Set(picked);
|
|
const everyVisibleChosen = visible.length > 0 && visible.every((id) => next.has(id));
|
|
for (const id of visible) {
|
|
if (everyVisibleChosen) next.delete(id);
|
|
else next.add(id);
|
|
}
|
|
return next;
|
|
}
|
|
|
|
test('a bulk action never touches a row that was filtered away', () => {
|
|
// Ticked while the list showed everything, then the list was narrowed.
|
|
const picked = new Set([1, 2, 3]);
|
|
assert.deepEqual(chosenOf([2], picked), [2]);
|
|
});
|
|
|
|
test('narrowing and widening again does not untick the work', () => {
|
|
// The hidden ids stay in the set; they are simply not acted on while hidden.
|
|
const picked = new Set([1, 2, 3]);
|
|
assert.deepEqual(chosenOf([1, 2, 3], picked), [1, 2, 3]);
|
|
});
|
|
|
|
test('select all covers only what is on screen', () => {
|
|
const next = afterToggleAll([2, 3], new Set());
|
|
assert.deepEqual([...next].sort(), [2, 3]);
|
|
});
|
|
|
|
test('select all a second time clears exactly what it added', () => {
|
|
const picked = afterToggleAll([2, 3], new Set([9]));
|
|
const cleared = afterToggleAll([2, 3], picked);
|
|
// 9 was chosen elsewhere and is not on screen, so it survives.
|
|
assert.deepEqual([...cleared], [9]);
|
|
});
|
|
|
|
test('select all on an empty list does nothing', () => {
|
|
assert.equal(afterToggleAll([], new Set()).size, 0);
|
|
});
|
|
|
|
test('the header is only fully ticked when every visible row is', () => {
|
|
const visible = [1, 2];
|
|
const partial = chosenOf(visible, new Set([1]));
|
|
assert.equal(partial.length === visible.length, false);
|
|
const full = chosenOf(visible, new Set([1, 2]));
|
|
assert.equal(full.length === visible.length, true);
|
|
});
|