import { describe, it, expect } from 'vitest' import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { pickPrimaryDelimiter, splitMulti, detectClass, buildClassSchema, composeGroups, } from '../../../composables/autoGroup' const FIXTURE = resolve(__dirname, '../../fixtures/auto-group/mixed-lc-ms-batch.txt') describe('mixed LC-MS batch integration', () => { const samples = readFileSync(FIXTURE, 'utf-8').trim().split('\n') const delim = pickPrimaryDelimiter(samples) const tokenized = samples.map(s => splitMulti(s, delim)) const classes = detectClass(tokenized, {}) it('detects exactly 81 Biological/Tissues samples', () => { const c = classes.find(c => c.kind === 'biological' && c.subKind === 'Tissues') expect(c?.members.length).toBe(81) }) it('detects exactly 81 Biological/Plasma samples', () => { const c = classes.find(c => c.kind === 'biological' && c.subKind === 'Plasma') expect(c?.members.length).toBe(81) }) it('detects exactly 3 IQC and 3 EQC samples', () => { const iqc = classes.find(c => c.kind === 'iqc') const eqc = classes.find(c => c.kind === 'eqc') expect(iqc?.members.length).toBe(3) expect(eqc?.members.length).toBe(3) }) it('totals biological + QC overlay + excluded === 187', () => { const tissues = classes.find(c => c.kind === 'biological' && c.subKind === 'Tissues') const plasma = classes.find(c => c.kind === 'biological' && c.subKind === 'Plasma') const overlayKinds = ['iqc', 'eqc', 'standard', 'spike-in', 'stock', 'blank'] const overlayCount = classes .filter(c => overlayKinds.includes(c.kind)) .reduce((acc, c) => acc + c.members.length, 0) const unknownCount = classes .filter(c => c.kind === 'unknown') .reduce((acc, c) => acc + c.members.length, 0) expect((tissues?.members.length ?? 0) + (plasma?.members.length ?? 0) + overlayCount + unknownCount).toBe(187) }) it('default workspace produces 3 Kidney/Liver/Tumor groups of 27 each', () => { const tissuesClass = classes.find(c => c.kind === 'biological' && c.subKind === 'Tissues')! const tissuesTokens = tissuesClass.members.map(i => tokenized[i]) const schema = buildClassSchema( tissuesTokens, 'biological', 'Tissues', tissuesClass.classTagPositions, ) // The Tissue column should be a factor with 3 unique values. const tissueCol = schema.columns.find(c => c.uniqueValues.length === 3 && c.role === 'factor') expect(tissueCol).toBeDefined() const result = composeGroups({ tokenizedSamples: tokenized, sampleNames: samples, schemas: { 'biological:Tissues': { ...schema, groupBy: [tissueCol!.index] } }, classes: [tissuesClass], }) expect(result.experimentalGroups!.length).toBe(3) expect(result.experimentalGroups!.every(g => g.samples.length === 27)).toBe(true) const names = result.experimentalGroups!.map(g => g.name).sort() // Only the Tissues class is passed here, so no disambiguating class prefix // is applied: the organ factor is the first (major) hierarchy layer. expect(names).toEqual(['Kidney', 'Liver', 'Tumor']) }) })