feat(frontend): pure helpers for cross-subject plot interactions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Experiments DB Dev
2026-06-01 09:27:38 -04:00
parent d77b6c1528
commit 0f7f6fbbe3
2 changed files with 134 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
import {
sortPayloadByValueDesc,
toggleInSet,
setIdsHidden,
groupVisibilityState,
groupLines,
} from '../src/lib/crossSubjectChart';
describe('sortPayloadByValueDesc', () => {
it('sorts by value descending and drops null/undefined values', () => {
const payload = [
{ dataKey: 'a', value: 40 },
{ dataKey: 'b', value: null },
{ dataKey: 'c', value: 92 },
{ dataKey: 'd', value: 78 },
];
expect(sortPayloadByValueDesc(payload).map((p) => p.dataKey)).toEqual(['c', 'd', 'a']);
});
it('returns [] for non-array input', () => {
expect(sortPayloadByValueDesc(undefined)).toEqual([]);
});
it('does not mutate the input array', () => {
const payload = [{ dataKey: 'a', value: 1 }, { dataKey: 'b', value: 2 }];
sortPayloadByValueDesc(payload);
expect(payload.map((p) => p.dataKey)).toEqual(['a', 'b']);
});
});
describe('toggleInSet', () => {
it('adds a missing id and removes a present id, returning a new Set', () => {
const a = new Set(['x']);
const added = toggleInSet(a, 'y');
expect([...added].sort()).toEqual(['x', 'y']);
expect(added).not.toBe(a);
const removed = toggleInSet(added, 'x');
expect([...removed]).toEqual(['y']);
});
});
describe('setIdsHidden', () => {
it('adds all ids when hidden=true', () => {
expect([...setIdsHidden(new Set(['a']), ['b', 'c'], true)].sort()).toEqual(['a', 'b', 'c']);
});
it('removes all ids when hidden=false', () => {
expect([...setIdsHidden(new Set(['a', 'b', 'c']), ['b', 'c'], false)]).toEqual(['a']);
});
it('returns a new Set', () => {
const s = new Set();
expect(setIdsHidden(s, ['a'], true)).not.toBe(s);
});
});
describe('groupVisibilityState', () => {
it("returns 'all' when none of the ids are hidden", () => {
expect(groupVisibilityState(['a', 'b'], new Set())).toBe('all');
});
it("returns 'none' when all ids are hidden", () => {
expect(groupVisibilityState(['a', 'b'], new Set(['a', 'b']))).toBe('none');
});
it("returns 'some' when a subset is hidden", () => {
expect(groupVisibilityState(['a', 'b'], new Set(['a']))).toBe('some');
});
it("returns 'none' for an empty group", () => {
expect(groupVisibilityState([], new Set())).toBe('none');
});
});
describe('groupLines', () => {
it('groups by .group preserving first-seen group order and within-group order', () => {
const lines = [
{ id: '1', group: 'B' },
{ id: '2', group: 'A' },
{ id: '3', group: 'B' },
];
const out = groupLines(lines);
expect(out.map((g) => g.group)).toEqual(['B', 'A']);
expect(out[0].subjects.map((s) => s.id)).toEqual(['1', '3']);
});
it("uses '—' for lines with no group", () => {
expect(groupLines([{ id: '1' }])[0].group).toBe('—');
});
});