feat(export): subject/parameter members + dimension dispatcher

This commit is contained in:
Experiments DB Dev
2026-07-19 13:19:15 -04:00
parent a411d59305
commit 7d112de0d7
2 changed files with 82 additions and 0 deletions
+46
View File
@@ -220,3 +220,49 @@ describe('buildStatusIndex', () => {
expect(idx.get('2026-07-01').get('a2').analysis_summary.total).toBe(3);
});
});
import { listSubjectMembers, listParameterMembers, listDimensionMembers } from '../src/lib/dataExport';
describe('listSubjectMembers', () => {
const animals = [
{ id: 'a2', animal_name: 'Beta', animal_id_string: 'R-002', subject_info: { grp: 'Drug' } },
{ id: 'a1', animal_name: 'Alpha', animal_id_string: 'R-001', subject_info: { grp: 'Control' } },
{ id: 'a3', animal_name: 'Gamma', animal_id_string: 'R-003', subject_info: { grp: 'Control' } },
];
it('orders by name and carries group=null when no group field', () => {
const m = listSubjectMembers(animals, '__none__');
expect(m.map((s) => s.label)).toEqual(['Alpha', 'Beta', 'Gamma']);
expect(m.every((s) => s.group === null)).toBe(true);
expect(m[0]).toMatchObject({ id: 'a1', animalId: 'a1' });
});
it('clusters by group value then name when grouping is on', () => {
const m = listSubjectMembers(animals, 'grp');
expect(m.map((s) => [s.group, s.label])).toEqual([
['Control', 'Alpha'], ['Control', 'Gamma'], ['Drug', 'Beta'],
]);
});
it('disambiguates duplicate names with the id string', () => {
const dup = [
{ id: 'a1', animal_name: 'Rat', animal_id_string: 'R-001' },
{ id: 'a2', animal_name: 'Rat', animal_id_string: 'R-002' },
];
expect(listSubjectMembers(dup, '__none__').map((s) => s.label)).toEqual(['Rat (R-001)', 'Rat (R-002)']);
});
});
describe('listParameterMembers / listDimensionMembers', () => {
const dailyTemplate = [{ fieldId: 'b-vitals', key: 'vitals', label: 'Vitals', builtin: true, active: true }];
const statuses = [{ date: '2026-07-01T00:00:00.000Z', animal_id: 'a1', analysis_summary: { total: 1 } }];
const animals = [{ id: 'a1', animal_name: 'Alpha', animal_id_string: 'R-001' }];
it('wraps params with id/label/param/group', () => {
const m = listParameterMembers(dailyTemplate, statuses);
expect(m[0]).toMatchObject({ id: '__total__', label: 'Total attempts', group: 'metrics' });
expect(m[0].param).toMatchObject({ kind: 'total' });
});
it('dispatches by dimension', () => {
const ctx = { statuses, animals, dailyTemplate, groupField: '__none__' };
expect(listDimensionMembers('date', ctx).map((d) => d.id)).toEqual(['2026-07-01']);
expect(listDimensionMembers('subject', ctx).map((d) => d.id)).toEqual(['a1']);
expect(listDimensionMembers('parameter', ctx)[0].id).toBe('__total__');
});
});