Skip to content

Commit

Permalink
fix: guard against selection without range
Browse files Browse the repository at this point in the history
  • Loading branch information
ph-fritsche committed May 12, 2022
1 parent bf00145 commit e6b230a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 3 deletions.
5 changes: 2 additions & 3 deletions src/utils/focus/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,13 @@ export function moveSelection(node: Element, direction: -1 | 1) {
} else {
const selection = node.ownerDocument.getSelection()

/* istanbul ignore if */
if (!selection) {
if (!selection?.focusNode) {
return
}

if (selection.isCollapsed) {
const nextPosition = getNextCursorPosition(
selection.focusNode as Node,
selection.focusNode,
selection.focusOffset,
direction,
)
Expand Down
76 changes: 76 additions & 0 deletions tests/utils/focus/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
setSelection,
setSelectionRange,
modifySelection,
moveSelection,
} from '#src/utils'
import {setup} from '#testHelpers'

Expand Down Expand Up @@ -183,3 +184,78 @@ describe('update selection when moving focus into element with own selection imp
expect(document.getSelection()).toHaveProperty('focusOffset', 0)
})
})

describe('move selection', () => {
test('do nothing without a selection range', () => {
const {element} = setup(`<div tabindex="0"></div>`)
document.getSelection()?.removeAllRanges()

moveSelection(element, 1)

expect(document.getSelection()).toHaveProperty('rangeCount', 0)
})

test('move to next cursor position', () => {
const {element} = setup(`<div tabindex="0">foo</div>`, {
selection: {focusNode: 'div/text()', focusOffset: 1},
})

moveSelection(element, 1)

expect(document.getSelection()).toHaveProperty(
'focusNode',
element.firstChild,
)
expect(document.getSelection()).toHaveProperty('focusOffset', 2)
})

test('move to next cursor position', () => {
const {element} = setup(`<div tabindex="0">foo</div>`, {
selection: {focusNode: 'div/text()', focusOffset: 1},
})

moveSelection(element, 1)

expect(document.getSelection()).toHaveProperty(
'focusNode',
element.firstChild,
)
expect(document.getSelection()).toHaveProperty('focusOffset', 2)
expect(document.getSelection()).toHaveProperty('isCollapsed', true)
})

test('collapse range', () => {
const {element} = setup(`<div tabindex="0">foo</div>`, {
selection: {focusNode: 'div/text()', anchorOffset: 1, focusOffset: 2},
})

moveSelection(element, 1)

expect(document.getSelection()).toHaveProperty(
'focusNode',
element.firstChild,
)
expect(document.getSelection()).toHaveProperty('focusOffset', 2)
expect(document.getSelection()).toHaveProperty('isCollapsed', true)
})

test('move cursor in input', () => {
const {element} = setup(`<input value="foo"/>`)

moveSelection(element, 1)

expect(element).toHaveProperty('selectionStart', 1)
expect(element).toHaveProperty('selectionEnd', 1)
})

test('collapse range in input', () => {
const {element} = setup(`<input value="foo"/>`, {
selection: {anchorOffset: 1, focusOffset: 2},
})

moveSelection(element, 1)

expect(element).toHaveProperty('selectionStart', 2)
expect(element).toHaveProperty('selectionEnd', 2)
})
})

0 comments on commit e6b230a

Please sign in to comment.