test/selection-scope.test.js
Rama main · réplica de lectura del repositorio original.
import { test } from "node:test";
import assert from "node:assert/strict";
import { scopeOpsToSelection } from "../src/ai/ops.js";
/**
* Holding a turn to the slides the user selected.
*
* The panel's selection reaches the model only as prose — "the request below
* applies to EXACTLY these" — and prose is a hint. A real turn asking to
* shorten slide 5's bullets edited slide 6 instead and reported success: the
* change list said one slide changed, and it was the wrong one.
*
* Nothing further down can catch that. Editing a slide the user did not mean
* produces a perfectly valid deck, so validation, the fit sweeps and the render
* are all clean. The only place it can be caught is between the model's ops and
* applying them.
*/
const upd = (index) => ({ op: "update_slide", index, patch: { headline: "x" } });
test("an op on an unselected slide is refused", () => {
const { ops, refused } = scopeOpsToSelection([upd(5)], [4]);
assert.deepEqual(ops, []);
assert.deepEqual(refused, [{ op: "update_slide", index: 5 }]);
});
test("ops on selected slides pass through untouched", () => {
const given = [upd(4), upd(7)];
const { ops, refused } = scopeOpsToSelection(given, [4, 7]);
assert.deepEqual(ops, given);
assert.deepEqual(refused, []);
});
test("with one slide selected, an op naming no slide is pointed at it", () => {
// "no index" is the same drift wearing a different shape, and with exactly
// one slide selected there is no ambiguity about what was meant.
const { ops, refused } = scopeOpsToSelection([{ op: "update_slide", patch: { headline: "x" } }], [3]);
assert.equal(ops.length, 1);
assert.equal(ops[0].index, 3);
assert.deepEqual(refused, []);
});
test("with several slides selected, an op naming no slide is refused", () => {
const { ops, refused } = scopeOpsToSelection([{ op: "update_slide", patch: {} }], [1, 2]);
assert.deepEqual(ops, []);
assert.equal(refused[0].index, null);
});
test("destructive and reordering ops are scoped too", () => {
for (const op of ["delete_slide", "replace_slide", "duplicate_slide"]) {
const { ops } = scopeOpsToSelection([{ op, index: 9 }], [0]);
assert.deepEqual(ops, [], `${op} outside the selection must not run`);
}
const { ops: moved } = scopeOpsToSelection([{ op: "move_slide", from: 9, to: 0 }], [0]);
assert.deepEqual(moved, [], "move_slide is scoped by its `from`");
});
test("additive and deck-level ops are never scoped", () => {
// Adding a slide while a selection is active is a legitimate request, and
// set_meta is about the deck rather than any slide.
const given = [
{ op: "append_slide", slide: { type: "bullets" } },
{ op: "insert_slide", index: 2, slide: { type: "bullets" } },
{ op: "set_meta", title: "T" },
];
const { ops, refused } = scopeOpsToSelection(given, [0]);
assert.deepEqual(ops, given);
assert.deepEqual(refused, []);
});
test("no selection means the whole deck, unchanged", () => {
const given = [upd(0), upd(5), { op: "delete_slide", index: 9 }];
for (const empty of [null, undefined, []]) {
assert.deepEqual(scopeOpsToSelection(given, empty).ops, given);
}
});