b35950ef94
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>
76 lines
3.0 KiB
TypeScript
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();
|
|
});
|
|
});
|