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>
128 lines
3.3 KiB
TypeScript
128 lines
3.3 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { CellSelection } from "@tiptap/pm/tables";
|
|
import { moveColumn } from "./move-column";
|
|
import {
|
|
schema,
|
|
cell,
|
|
row,
|
|
table,
|
|
doc,
|
|
grid,
|
|
stateFor,
|
|
} from "./table-test-helpers";
|
|
|
|
/**
|
|
* moveColumn reorders whole columns of a real ProseMirror table by mutating a
|
|
* Transaction (transpose -> move row -> transpose back -> replace). The invariant
|
|
* is that after the call each column appears at its new position with every
|
|
* cell's content preserved and nothing dropped or duplicated.
|
|
*/
|
|
|
|
// 2-row x 3-col table; column k is (rowX-col-k). Columns: 0=(a,d) 1=(b,e) 2=(c,f).
|
|
const grid3x2 = () =>
|
|
doc(
|
|
table(
|
|
row(cell("a"), cell("b"), cell("c")),
|
|
row(cell("d"), cell("e"), cell("f")),
|
|
),
|
|
);
|
|
|
|
describe("moveColumn", () => {
|
|
it("moves the first column to the last index, preserving column content", () => {
|
|
// origin 0 -> target 2 sends column (a,d) to the right: cols become 1,2,0.
|
|
const state = stateFor(grid3x2());
|
|
const tr = state.tr;
|
|
const ok = moveColumn({
|
|
tr,
|
|
originIndex: 0,
|
|
targetIndex: 2,
|
|
select: false,
|
|
pos: state.selection.from,
|
|
});
|
|
expect(ok).toBe(true);
|
|
expect(grid(tr)).toEqual([
|
|
["b", "c", "a"],
|
|
["e", "f", "d"],
|
|
]);
|
|
});
|
|
|
|
it("moves a later column to the first index", () => {
|
|
// origin 2 -> target 0 pulls column (c,f) to the front: cols become 2,0,1.
|
|
const state = stateFor(grid3x2());
|
|
const tr = state.tr;
|
|
const ok = moveColumn({
|
|
tr,
|
|
originIndex: 2,
|
|
targetIndex: 0,
|
|
select: false,
|
|
pos: state.selection.from,
|
|
});
|
|
expect(ok).toBe(true);
|
|
expect(grid(tr)).toEqual([
|
|
["c", "a", "b"],
|
|
["f", "d", "e"],
|
|
]);
|
|
});
|
|
|
|
it("never drops or duplicates cells when reordering columns", () => {
|
|
const state = stateFor(grid3x2());
|
|
const tr = state.tr;
|
|
moveColumn({
|
|
tr,
|
|
originIndex: 1,
|
|
targetIndex: 2,
|
|
select: false,
|
|
pos: state.selection.from,
|
|
});
|
|
expect(grid(tr).flat().sort()).toEqual(
|
|
["a", "b", "c", "d", "e", "f"].sort(),
|
|
);
|
|
expect(grid(tr)[0].length).toBe(3);
|
|
});
|
|
|
|
it("returns false (no-op) when target equals origin", () => {
|
|
const state = stateFor(grid3x2());
|
|
const tr = state.tr;
|
|
const before = grid(tr);
|
|
const ok = moveColumn({
|
|
tr,
|
|
originIndex: 1,
|
|
targetIndex: 1,
|
|
select: false,
|
|
pos: state.selection.from,
|
|
});
|
|
expect(ok).toBe(false);
|
|
expect(grid(tr)).toEqual(before);
|
|
});
|
|
|
|
it("returns false when pos is not inside a table", () => {
|
|
const d = doc(
|
|
schema.nodes.paragraph.createChecked(null, schema.text("plain")),
|
|
);
|
|
const state = stateFor(d);
|
|
const tr = state.tr;
|
|
const ok = moveColumn({
|
|
tr,
|
|
originIndex: 0,
|
|
targetIndex: 1,
|
|
select: false,
|
|
pos: state.selection.from,
|
|
});
|
|
expect(ok).toBe(false);
|
|
});
|
|
|
|
it("installs a CellSelection on the moved column when select is true", () => {
|
|
const state = stateFor(grid3x2());
|
|
const tr = state.tr;
|
|
const ok = moveColumn({
|
|
tr,
|
|
originIndex: 0,
|
|
targetIndex: 2,
|
|
select: true,
|
|
pos: state.selection.from,
|
|
});
|
|
expect(ok).toBe(true);
|
|
expect(tr.selection instanceof CellSelection).toBe(true);
|
|
});
|
|
});
|