Files
gitmost/packages/editor-ext/src/lib/table/utils/get-selection-range-in-column.test.ts
T
claude code agent 227 b35950ef94 test(editor-ext): extract shared ProseMirror table-test fixture (F1)
The schema + cell/row/table/doc builders + grid/stateFor/trFor were copied
verbatim into the 3 new table-utils test files (and the pre-existing
table-utils.test.ts) — a schema change would have to be synced across all four.
Move them into a shared table-test-helpers.ts (test-only, excluded from the
build like footnote-corpus.ts) and import it everywhere; cell uses the
(txt, attrs?) superset (a drop-in for the bare (txt) copies). No assertion
changes — test counts unchanged (223 passed + 3 expected-fail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:17:18 +03:00

76 lines
3.0 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { getSelectionRangeInColumn } from "./get-selection-range-in-column";
import { cell, row, table, doc, trFor } from "./table-test-helpers";
/**
* getSelectionRangeInColumn computes the rectangular column range (the set of
* column indexes, plus anchor/head cell positions) that a drag-reorder or
* column-select operation should act on, accounting for merged (colspan) cells.
* It keys off the table found from the current selection, so we drive it with a
* real EditorState whose selection sits inside the table.
*/
// A 2-row x 3-col grid; each column is identifiable by its top-row letter.
const grid3x2 = () =>
doc(
table(
row(cell("a"), cell("b"), cell("c")),
row(cell("d"), cell("e"), cell("f")),
),
);
describe("getSelectionRangeInColumn", () => {
it("returns a single-column range for a single index", () => {
// Asking for column 1 yields exactly indexes [1].
const tr = trFor(grid3x2());
const range = getSelectionRangeInColumn(tr, 1);
expect(range).toBeTruthy();
expect(range!.indexes).toEqual([1]);
});
it("anchor/head resolve to the top and bottom cells OF the requested column", () => {
// $head must point at the column's first (top) cell and $anchor at its last
// (bottom) cell — pinning that the returned positions belong to column 1,
// not some other column.
const tr = trFor(grid3x2());
const range = getSelectionRangeInColumn(tr, 1)!;
expect(tr.doc.nodeAt(range.$head.pos)?.textContent).toBe("b"); // top of col 1
expect(tr.doc.nodeAt(range.$anchor.pos)?.textContent).toBe("e"); // bottom of col 1
});
it("returns the inclusive span of columns for a multi-column request", () => {
// A 0..2 request must enumerate every covered column, in order.
const tr = trFor(grid3x2());
const range = getSelectionRangeInColumn(tr, 0, 2);
expect(range!.indexes).toEqual([0, 1, 2]);
});
it("returns a two-column span for an adjacent pair", () => {
const tr = trFor(grid3x2());
const range = getSelectionRangeInColumn(tr, 1, 2);
expect(range!.indexes).toEqual([1, 2]);
});
it("expands the range to cover a horizontally merged (colspan) cell", () => {
// Row 0 col 0 spans 2 columns. Requesting just column 0 must pull column 1
// into the range because they are merged together in the top row.
const d = doc(
table(
row(cell("ab", { colspan: 2 }), cell("c")),
row(cell("d"), cell("e"), cell("f")),
),
);
const tr = trFor(d);
const range = getSelectionRangeInColumn(tr, 0);
expect(range!.indexes).toEqual([0, 1]);
});
it("throws when the requested column is entirely out of range", () => {
// No cells exist at column 5 of a 3-wide table, so the function cannot pick
// an anchor cell and dereferences undefined — pin this as the current
// (caller-guarded) contract so a silent behavior change is caught.
const tr = trFor(grid3x2());
expect(() => getSelectionRangeInColumn(tr, 5)).toThrow();
});
});