← Files Biological Sequence & Alignment ViewerARCHIVED FILE
src/msa/workbench-controller.test.ts
3.01 KB · Sep 30, 2026 · 23:01 UTC
import { describe, expect, it } from "vitest";
import { parseMsa } from "./parser";
import {
applyAlignmentEditRequest,
realignRows,
runAlignmentAnalysis,
} from "./workbench-controller";
describe("alignment workbench controller", () => {
it("builds graphical-tree data and a symmetric distance matrix", () => {
const document = fixture();
const treeResult = runAlignmentAnalysis({
document,
request: { algorithm: "neighbor-joining", analysis: "build-tree" },
});
expect(treeResult.tree).toMatchObject({
algorithm: "neighbor-joining",
distance: "uncorrected-p-distance",
});
const distances = runAlignmentAnalysis({
document,
request: { analysis: "distance-matrix" },
});
expect(distances.matrix).toEqual([
[0, expect.any(Number), expect.any(Number)],
[expect.any(Number), 0, expect.any(Number)],
[expect.any(Number), expect.any(Number), 0],
]);
});
it("applies alignment edits without mutating the source document", () => {
const document = fixture();
const result = applyAlignmentEditRequest({
document,
request: {
end: 4,
operation: "remove-alignment-columns",
start: 3,
},
tree: null,
});
expect("document" in result && result.document.alignedLength).toBe(6);
expect(document.alignedLength).toBe(8);
});
it("realigns a selected derived copy and invalidates stale tracks", () => {
const document = fixture();
const result = realignRows({
document,
rowIds: document.rows.slice(0, 2).map(({ id }) => id),
});
expect(result.document.rows).toHaveLength(2);
expect(result.document.annotations).toEqual([]);
expect(result.document.warnings.at(-1)?.code).toBe("realigned-copy");
expect(document.rows).toHaveLength(3);
});
it("requires a tree before tree-order sorting", () => {
expect(() =>
applyAlignmentEditRequest({
document: fixture(),
request: { mode: "tree", operation: "sort-alignment-rows" },
tree: null,
}),
).toThrow("guide tree");
});
it("groups exact rows and preserves their metadata through realignment", () => {
const document = fixture();
const selected = document.rows.slice(0, 2).map(({ id }) => id);
const grouped = applyAlignmentEditRequest({
document,
request: {
group: "responders",
operation: "assign-alignment-row-group",
rowIds: selected,
},
tree: null,
});
if (!("document" in grouped)) throw new Error("Expected a document edit.");
const realigned = realignRows({ document: grouped.document, rowIds: selected });
expect(
realigned.document.rows.map(
({ metadata }) => metadata?.sequenceViewerGroup,
),
).toEqual(["responders", "responders"]);
});
});
function fixture() {
const parsed = parseMsa(
">alpha\nACGTACGT\n>beta\nACG-ACGT\n>gamma\nATGTAC-T\n",
"workbench.aln.fasta",
);
if (parsed.status !== "success") throw new Error(parsed.message);
return parsed.document;
}
SHA-256: 4f7caa035f1616dc4799c4ca011c95724953d934cb53a60716ddd3c7b4eccb1c