fix: guard table handle add selection

This commit is contained in:
lucaronin
2026-05-02 10:58:46 +02:00
parent cd6847d59e
commit 7d66e2f8e1
5 changed files with 473 additions and 67 deletions

View File

@@ -18,16 +18,44 @@ function createTableBlock() {
}
}
function createSelectionStateThatRejectsNaNPositions() {
const selectionTransaction = {
setSelection: vi.fn(),
}
const resolvedPosition = {
posAtIndex: vi.fn((index: number) => index),
}
return {
doc: {
resolve: vi.fn((position: number) => {
if (!Number.isFinite(position)) {
throw new Error(`Position ${position} out of range`)
}
return resolvedPosition
}),
},
tr: selectionTransaction,
apply: vi.fn(),
}
}
function mountTableHandlesExtension() {
const editorRoot = document.createElement('div')
document.body.appendChild(editorRoot)
const selectionState = createSelectionStateThatRejectsNaNPositions()
const dispatch = vi.fn()
const editor = {
headless: true,
isEditable: true,
prosemirrorView: {
root: document,
},
exec: vi.fn((command: (state: never, dispatch: never) => unknown) =>
command(selectionState as never, dispatch as never),
),
transact: vi.fn(),
}
@@ -43,7 +71,31 @@ function mountTableHandlesExtension() {
root: document,
} as never) as TableHandlesView
return { editor, extension, view }
return { editor, extension, view, selectionState }
}
function showTableHandles(view: TableHandlesView) {
view.state = {
block: createTableBlock(),
show: true,
showAddOrRemoveRowsButton: true,
showAddOrRemoveColumnsButton: true,
rowIndex: 0,
colIndex: 0,
draggingState: undefined,
} as never
}
function expectAddRowAndColumnActionsToStaySafe(
extension: ReturnType<typeof mountTableHandlesExtension>['extension'],
index: number,
) {
expect(() =>
extension.addRowOrColumn(index, { orientation: 'row', side: 'below' }),
).not.toThrow()
expect(() =>
extension.addRowOrColumn(index, { orientation: 'column', side: 'right' }),
).not.toThrow()
}
describe('BlockNote table handles regression', () => {
@@ -114,6 +166,23 @@ describe('BlockNote table handles regression', () => {
view.destroy()
})
it('ignores add row or column actions when the selection target is stale', () => {
const { editor, extension, view } = mountTableHandlesExtension()
showTableHandles(view)
view.tablePos = undefined
expectAddRowAndColumnActionsToStaySafe(extension, 0)
expect(editor.exec).not.toHaveBeenCalled()
view.tablePos = 0
expectAddRowAndColumnActionsToStaySafe(extension, Number.NaN)
expect(editor.exec).not.toHaveBeenCalled()
view.destroy()
})
it('cancels stale table drops instead of throwing when no hovered row or column is available', () => {
const block = createTableBlock()
const editorRoot = document.createElement('div')