From 80991e98ca83489ffd71454aadcf71a37f916cde Mon Sep 17 00:00:00 2001
From: Ben Kucera <14625260+Bkucera@users.noreply.github.com>
Date: Wed, 23 Oct 2019 11:50:10 -0400
Subject: [PATCH 1/4] fix force typing in disabled input, selection on
non-selectionrange inputs
---
packages/driver/src/cy/keyboard.ts | 20 ++++++-----
packages/driver/src/dom/selection.ts | 8 +++--
.../integration/commands/actions/type_spec.js | 33 +++++++++----------
3 files changed, 33 insertions(+), 28 deletions(-)
diff --git a/packages/driver/src/cy/keyboard.ts b/packages/driver/src/cy/keyboard.ts
index 198cfaea1f89..8fa079074ce7 100644
--- a/packages/driver/src/cy/keyboard.ts
+++ b/packages/driver/src/cy/keyboard.ts
@@ -280,7 +280,8 @@ const validateTyping = (
keys: KeyDetails[],
currentIndex: number,
onFail: Function,
- skipCheckUntilIndex?: number,
+ skipCheckUntilIndex: number | undefined,
+ force: boolean
) => {
const chars = joinKeyArrayToString(keys.slice(currentIndex))
const allChars = joinKeyArrayToString(keys)
@@ -328,15 +329,17 @@ const validateTyping = (
return {}
}
- if (!isFocusable) {
+ if (!isFocusable && isTextLike && !force) {
const node = $dom.stringify($el)
- if (isTextLike) {
- $utils.throwErrByPath('type.not_actionable_textlike', {
- onFail,
- args: { node },
- })
- }
+ $utils.throwErrByPath('type.not_actionable_textlike', {
+ onFail,
+ args: { node },
+ })
+ }
+
+ if (!isFocusable && !isTextLike) {
+ const node = $dom.stringify($el)
$utils.throwErrByPath('type.not_on_typeable_element', {
onFail,
@@ -660,6 +663,7 @@ export class Keyboard {
currentKeyIndex,
options.onFail,
_skipCheckUntilIndex,
+ options.force
)
_skipCheckUntilIndex = skipCheckUntilIndex
diff --git a/packages/driver/src/dom/selection.ts b/packages/driver/src/dom/selection.ts
index 5f210a3e9679..945dde65a1a1 100644
--- a/packages/driver/src/dom/selection.ts
+++ b/packages/driver/src/dom/selection.ts
@@ -154,6 +154,10 @@ const setSelectionRange = function (el, start, end) {
$elements.callNativeMethod(el, 'setSelectionRange', start, end)
}
+const isSelectionCollapsed = function (selection: Selection) {
+ return !selection.toString()
+}
+
const deleteRightOfCursor = function (el) {
if ($elements.canSetSelectionRangeElement(el)) {
const { start, end } = getSelectionBounds(el)
@@ -167,7 +171,7 @@ const deleteRightOfCursor = function (el) {
const selection = _getSelectionByEl(el)
- if (selection.isCollapsed) {
+ if (isSelectionCollapsed(selection)) {
$elements.callNativeMethod(
selection,
'modify',
@@ -195,7 +199,7 @@ const deleteLeftOfCursor = function (el) {
const selection = _getSelectionByEl(el)
- if (selection.isCollapsed) {
+ if (isSelectionCollapsed(selection)) {
$elements.callNativeMethod(
selection,
'modify',
diff --git a/packages/driver/test/cypress/integration/commands/actions/type_spec.js b/packages/driver/test/cypress/integration/commands/actions/type_spec.js
index 0fa74a8cf242..8445495d5754 100644
--- a/packages/driver/test/cypress/integration/commands/actions/type_spec.js
+++ b/packages/driver/test/cypress/integration/commands/actions/type_spec.js
@@ -199,6 +199,12 @@ describe('src/cy/commands/actions/type', () => {
})
})
+ it('can force click when element is disabled', function () {
+ cy.$$('input:text:first').prop('disabled', true)
+ cy.get('input:text:first').type('foo', { force: true })
+ .should('have.value', 'foo')
+ })
+
it('can forcibly click even when being covered by another element', () => {
const $input = $('')
.attr('id', 'input-covered-in-span')
@@ -1810,6 +1816,13 @@ describe('src/cy/commands/actions/type', () => {
})
})
+ it('can delete all with {selectall}{backspace} in non-selectionrange element', () => {
+ cy.get('input[type=email]:first')
+ .should(($el) => $el.val('sdfsdf'))
+ .type('{selectall}{backspace}')
+ .should('have.value', '')
+ })
+
it('can backspace a selection range of characters', () => {
// select the 'ar' characters
cy
@@ -4415,22 +4428,6 @@ describe('src/cy/commands/actions/type', () => {
cy.get('input:text:first').type('foo')
})
- it('throws when subject is disabled and force:true', function (done) {
- cy.timeout(200)
-
- cy.$$('input:text:first').prop('disabled', true)
-
- cy.on('fail', (err) => {
- // get + type logs
- expect(this.logs.length).eq(2)
- expect(err.message).to.include('cy.type() failed because it targeted a disabled element.')
-
- done()
- })
-
- cy.get('input:text:first').type('foo', { force: true })
- })
-
it('throws when submitting within nested forms')
it('logs once when not dom subject', function (done) {
@@ -4532,11 +4529,11 @@ https://on.cypress.io/type`)
})
})
- describe('naughtly strings', () => {
+ describe('naughty strings', () => {
_.each(['Ω≈ç√∫˜µ≤≥÷', '2.2250738585072011e-308', '田中さんにあげて下さい',
'', '⁰⁴⁵₀₁₂', '🐵 🙈 🙉 🙊',
'', '$USER'], (val) => {
- it(`allows typing some naughtly strings (${val})`, () => {
+ it(`allows typing some naughty strings (${val})`, () => {
cy
.get(':text:first').type(val)
.should('have.value', val)
From c2f2a9a400608da66ad2855def552f2a66f336c3 Mon Sep 17 00:00:00 2001
From: Ben Kucera <14625260+Bkucera@users.noreply.github.com>
Date: Wed, 23 Oct 2019 11:56:43 -0400
Subject: [PATCH 2/4] rename clearer error
---
packages/driver/src/cy/keyboard.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/driver/src/cy/keyboard.ts b/packages/driver/src/cy/keyboard.ts
index 8fa079074ce7..5959cf6394fd 100644
--- a/packages/driver/src/cy/keyboard.ts
+++ b/packages/driver/src/cy/keyboard.ts
@@ -211,7 +211,7 @@ const getKeyDetails = (onKeyNotFound) => {
onKeyNotFound(key, _.keys(getKeymap()).join(', '))
- throw Error(`Not a valid key: ${key}`)
+ throw new Error('this can never happen')
}
}
From c863af2bd27ce56bad54ad2bc3b7ca80a4109ee8 Mon Sep 17 00:00:00 2001
From: Ben Kucera <14625260+Bkucera@users.noreply.github.com>
Date: Wed, 23 Oct 2019 12:13:44 -0400
Subject: [PATCH 3/4] add comments
---
packages/driver/src/cy/keyboard.ts | 3 +++
packages/driver/src/dom/selection.ts | 3 +++
2 files changed, 6 insertions(+)
diff --git a/packages/driver/src/cy/keyboard.ts b/packages/driver/src/cy/keyboard.ts
index 5959cf6394fd..588204d0c785 100644
--- a/packages/driver/src/cy/keyboard.ts
+++ b/packages/driver/src/cy/keyboard.ts
@@ -329,6 +329,8 @@ const validateTyping = (
return {}
}
+ // throw error if element, which is normally typeable, is disabled for some reason
+ // don't throw if force: true
if (!isFocusable && isTextLike && !force) {
const node = $dom.stringify($el)
@@ -338,6 +340,7 @@ const validateTyping = (
})
}
+ // throw error if element cannot receive keyboard events under any conditions
if (!isFocusable && !isTextLike) {
const node = $dom.stringify($el)
diff --git a/packages/driver/src/dom/selection.ts b/packages/driver/src/dom/selection.ts
index 945dde65a1a1..bf70d7522d6c 100644
--- a/packages/driver/src/dom/selection.ts
+++ b/packages/driver/src/dom/selection.ts
@@ -154,6 +154,9 @@ const setSelectionRange = function (el, start, end) {
$elements.callNativeMethod(el, 'setSelectionRange', start, end)
}
+// Whether or not the selection contains any text
+// since Selection.isCollapsed will be true when selection
+// is inside non-selectionRange input (e.g. input[type=email])
const isSelectionCollapsed = function (selection: Selection) {
return !selection.toString()
}
From d0f6dd0a168f6fbe7fde065f4bba42cf812c5f0f Mon Sep 17 00:00:00 2001
From: Ben Kucera <14625260+Bkucera@users.noreply.github.com>
Date: Wed, 23 Oct 2019 12:37:47 -0400
Subject: [PATCH 4/4] fix test names
---
.../test/cypress/integration/commands/actions/type_spec.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/driver/test/cypress/integration/commands/actions/type_spec.js b/packages/driver/test/cypress/integration/commands/actions/type_spec.js
index 8445495d5754..0b518ecd7a05 100644
--- a/packages/driver/test/cypress/integration/commands/actions/type_spec.js
+++ b/packages/driver/test/cypress/integration/commands/actions/type_spec.js
@@ -183,7 +183,7 @@ describe('src/cy/commands/actions/type', () => {
})
describe('actionability', () => {
- it('can forcibly click even when element is invisible', () => {
+ it('can forcibly type + click even when element is invisible', () => {
const $txt = cy.$$(':text:first').hide()
expect($txt).not.to.have.value('foo')
@@ -199,13 +199,13 @@ describe('src/cy/commands/actions/type', () => {
})
})
- it('can force click when element is disabled', function () {
+ it('can force type when element is disabled', function () {
cy.$$('input:text:first').prop('disabled', true)
cy.get('input:text:first').type('foo', { force: true })
.should('have.value', 'foo')
})
- it('can forcibly click even when being covered by another element', () => {
+ it('can forcibly type + click even when being covered by another element', () => {
const $input = $('')
.attr('id', 'input-covered-in-span')
.css({