Skip to content

Commit

Permalink
Add {home} and {end} to cy.type() (#3071)
Browse files Browse the repository at this point in the history
* implemented fix draft

* removed an extra comment

* fixed two colliding variable names

* actual behaviour for home/end is begin/end of line, not paragraph

* refactored the selection method to use only selection.modify

* added some unit tests for {home}

* added more tests for home and end

* disclaimer for selection.modify API
  • Loading branch information
silviuaavram authored and brian-mann committed Mar 15, 2019
1 parent 6ff6ec5 commit 2122320
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 0 deletions.
28 changes: 28 additions & 0 deletions packages/driver/src/cypress/keyboard.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ keyStandardMap = {
"{leftarrow}": "ArrowLeft",
"{rightarrow}": "ArrowRight",
"{uparrow}": "ArrowUp",
"{home}": "Home",
"{end}": "End",
"{alt}": "Alt",
"{ctrl}": "Control",
"{meta}": "Meta",
Expand Down Expand Up @@ -211,6 +213,32 @@ $Keyboard = {
options.setKey = "{downarrow}"
@ensureKey el, null, options, ->
$selection.moveCursorDown(el)

## charCode = 36
## no keyPress
## no textInput
## no input
"{home}": (el, options) ->
options.charCode = 36
options.keypress = false
options.textInput = false
options.input = false
options.setKey = "{home}"
@ensureKey el, null, options, ->
$selection.moveCursorToLineStart(el)

## charCode = 35
## no keyPress
## no textInput
## no input
"{end}": (el, options) ->
options.charCode = 35
options.keypress = false
options.textInput = false
options.input = false
options.setKey = "{end}"
@ensureKey el, null, options, ->
$selection.moveCursorToLineEnd(el)
}

modifierChars: {
Expand Down
20 changes: 20 additions & 0 deletions packages/driver/src/dom/selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,24 @@ const _moveCursorUpOrDown = function (el, up) {
}
}

const moveCursorToLineStart = (el) => {
return _moveCursorToLineStartOrEnd(el, true)
}

const moveCursorToLineEnd = (el) => {
return _moveCursorToLineStartOrEnd(el, false)
}

const _moveCursorToLineStartOrEnd = function (el, toStart) {
if ($elements.isContentEditable(el) || $elements.isInput(el) || $elements.isTextarea(el)) {
const selection = _getSelectionByEl(el)

// the selection.modify API is non-standard, may work differently in other browsers, and is not in IE11.
// https://developer.mozilla.org/en-US/docs/Web/API/Selection/modify
return $elements.callNativeMethod(selection, 'modify', 'move', toStart ? 'backward' : 'forward', 'lineboundary')
}
}

const isCollapsed = function (el) {
if ($elements.isTextarea(el) || $elements.isInput(el)) {
const { start, end } = getSelectionBounds(el)
Expand Down Expand Up @@ -579,6 +597,8 @@ module.exports = {
moveCursorRight,
moveCursorUp,
moveCursorDown,
moveCursorToLineStart,
moveCursorToLineEnd,
replaceSelectionContents,
isCollapsed,
interceptSelect,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,106 @@ describe "src/cy/commands/actions/type", ->
expect($input).to.have.value("fodo")
done()

context "{home}", ->
it "sets which and keyCode to 36 and does not fire keypress events", (done) ->
cy.$$("#comments").on "keypress", ->
done("should not have received keypress")

cy.$$("#comments").on "keydown", (e) ->
expect(e.which).to.eq 36
expect(e.keyCode).to.eq 36
expect(e.key).to.eq "Home"
done()

cy.get("#comments").type("{home}").then ($input) ->
done()

it "does not fire textInput event", (done) ->
cy.$$("#comments").on "textInput", (e) ->
done("textInput should not have fired")

cy.get("#comments").type("{home}").then -> done()

it "does not fire input event", (done) ->
cy.$$("#comments").on "input", (e) ->
done("input should not have fired")

cy.get("#comments").type("{home}").then -> done()

it "can move the cursor to input start", ->
cy.get(":text:first").invoke("val", "bar").type("{home}n").then ($input) ->
expect($input).to.have.value("nbar")

it "does not move the cursor if already at bounds 0", ->
cy.get(":text:first").invoke("val", "bar").type("{selectall}{leftarrow}{home}n").then ($input) ->
expect($input).to.have.value("nbar")

it "should move the cursor to the start of each line in textarea", ->
cy.$$('textarea:first').get(0).value = 'foo\nbar\nbaz'

cy.get("textarea:first")
.type("{home}11{uparrow}{home}22{uparrow}{home}33").should('have.value', "33foo\n22bar\n11baz")

it "should move cursor to the start of each line in contenteditable", ->
cy.$$('[contenteditable]:first').get(0).innerHTML =
'<div>foo</div>' +
'<div>bar</div>' +
'<div>baz</div>'

cy.get("[contenteditable]:first")
.type("{home}11{uparrow}{home}22{uparrow}{home}33").then ($div) ->
expect($div.get(0).innerText).to.eql("33foo\n22bar\n11baz\n")

context "{end}", ->
it "sets which and keyCode to 35 and does not fire keypress events", (done) ->
cy.$$("#comments").on "keypress", ->
done("should not have received keypress")

cy.$$("#comments").on "keydown", (e) ->
expect(e.which).to.eq 35
expect(e.keyCode).to.eq 35
expect(e.key).to.eq "End"
done()

cy.get("#comments").type("{end}").then ($input) ->
done()

it "does not fire textInput event", (done) ->
cy.$$("#comments").on "textInput", (e) ->
done("textInput should not have fired")

cy.get("#comments").type("{end}").then -> done()

it "does not fire input event", (done) ->
cy.$$("#comments").on "input", (e) ->
done("input should not have fired")

cy.get("#comments").type("{end}").then -> done()

it "can move the cursor to input end", ->
cy.get(":text:first").invoke("val", "bar").type("{selectall}{leftarrow}{end}n").then ($input) ->
expect($input).to.have.value("barn")

it "does not move the cursor if already at end of bounds", ->
cy.get(":text:first").invoke("val", "bar").type("{selectall}{rightarrow}{end}n").then ($input) ->
expect($input).to.have.value("barn")

it "should move the cursor to the end of each line in textarea", ->
cy.$$('textarea:first').get(0).value = 'foo\nbar\nbaz'

cy.get("textarea:first")
.type("{end}11{uparrow}{end}22{uparrow}{end}33").should('have.value', "foo33\nbar22\nbaz11")

it "should move cursor to the end of each line in contenteditable", ->
cy.$$('[contenteditable]:first').get(0).innerHTML =
'<div>foo</div>' +
'<div>bar</div>' +
'<div>baz</div>'

cy.get("[contenteditable]:first")
.type("{end}11{uparrow}{end}22{uparrow}{end}33").then ($div) ->
expect($div.get(0).innerText).to.eql("foo33\nbar22\nbaz11\n")

context "{uparrow}", ->
beforeEach ->
cy.$$("#comments").val("foo\nbar\nbaz")
Expand Down

0 comments on commit 2122320

Please sign in to comment.