Do not allow typing into readonly fields. (#4729)

* Do not allow typing into readonly fields.

* fix failing spec + some chaining in cy

* Fix failing specs - refactor test generation.
This commit is contained in:
Jennifer Shehane
2019-07-18 14:28:56 +06:30
committed by GitHub
parent e06ad7828c
commit fcabf50cde
5 changed files with 48 additions and 15 deletions

View File

@@ -88,9 +88,9 @@ module.exports = (Commands, Cypress, cy, state, config) ->
isMonth = $dom.isType(options.$el, "month")
isWeek = $dom.isType(options.$el, "week")
hasTabIndex = $dom.isSelector(options.$el, "[tabindex]")
isReadonly = options.$el.is('[readonly]')
## TODO: tabindex can't be -1
## TODO: can't be readonly
isTypeableButNotAnInput = isBody or (hasTabIndex and not isTextLike)
@@ -107,6 +107,13 @@ module.exports = (Commands, Cypress, cy, state, config) ->
args: { num }
})
if (isReadonly)
node = $dom.stringify(options.$el)
$utils.throwErrByPath("type.readonly", {
onFail: options._log
args: { node }
})
if not (_.isString(chars) or _.isFinite(chars))
$utils.throwErrByPath("type.wrong_type", {
onFail: options._log

View File

@@ -894,6 +894,7 @@ module.exports = {
type:
empty_string: "#{cmd('type')} cannot accept an empty String. You need to actually type something."
readonly: "#{cmd('type')} cannot type into an element with a 'readonly' attribute. The element typed into was: {{node}}"
invalid: "Special character sequence: '{{chars}}' is not recognized. Available sequences are: {{allChars}}"
invalid_date: "Typing into a date input with #{cmd('type')} requires a valid date with the format 'yyyy-MM-dd'. You passed: {{chars}}"
invalid_month: "Typing into a month input with #{cmd('type')} requires a valid month with the format 'yyyy-MM'. You passed: {{chars}}"

View File

@@ -288,6 +288,16 @@
<button>submit me</button>
<input type="submit" value ="submit me2" />
</form>
<form>
<!-- All values are valid readonly -->
<input id="readonly-attr" readonly />
<input id="readonly-readonly" readonly="readonly" />
<input id="readonly-empty-str" readonly="" />
<!-- Although not strictly part of spec, Chrome respects any string -->
<input id="readonly-str" readonly="abc" />
</form>
</div>
<div id="input-types">

View File

@@ -115,9 +115,8 @@ describe('src/cy/commands/actions/type', () => {
blurred = true
})
cy
.get('input:text:first').type('foo')
.get('input:text:last').type('bar')
cy.get('input:text:first').type('foo')
cy.get('input:text:last').type('bar')
.then(() => {
expect(blurred).to.be.true
})
@@ -456,9 +455,8 @@ describe('src/cy/commands/actions/type', () => {
blur = true
})
cy
.get('#tabindex').type('f')
.get('input:first').focus().then(() => {
cy.get('#tabindex').type('f')
cy.get('input:first').focus().then(() => {
expect(blur).to.be.true
})
})
@@ -480,8 +478,7 @@ describe('src/cy/commands/actions/type', () => {
return keyups.push(e)
})
cy
.get('#tabindex').type('f{leftarrow}{rightarrow}{enter}')
cy.get('#tabindex').type('f{leftarrow}{rightarrow}{enter}')
.then(() => {
expect(keydowns).to.have.length(4)
expect(keypresses).to.have.length(2)
@@ -495,8 +492,7 @@ describe('src/cy/commands/actions/type', () => {
it('adds delay to delta for each key sequence', () => {
cy.spy(cy, 'timeout')
cy
.get(':text:first')
cy.get(':text:first')
.type('foo{enter}bar{leftarrow}', { delay: 5 })
.then(() => {
expect(cy.timeout).to.be.calledWith(5 * 8, true, 'type')
@@ -4192,6 +4188,25 @@ describe('src/cy/commands/actions/type', () => {
cy.get('input:first').type('a').type('b')
})
_.each([
{ id: 'readonly-attr', val: '' },
{ id: 'readonly-empty-str', val: '' },
{ id: 'readonly-readonly', val: 'readonly' },
{ id: 'readonly-str', val: 'abc' },
], (attrs) => {
it(`throws when readonly ${attrs.val} attr (${attrs.id})`, (done) => {
cy.get(`#${attrs.id}`).type('foo')
cy.on('fail', (err) => {
expect(err.message).to.include('cy.type() cannot type into an element with a \'readonly\' attribute.')
expect(err.message).to.include('The element typed into was:')
expect(err.message).to.include(`<input id="${attrs.id}" readonly="${attrs.val}">`)
done()
})
})
})
it('throws when not textarea or text-like', (done) => {
cy.get('form').type('foo')

View File

@@ -308,7 +308,7 @@ function getElementDimensions ($el) {
return dimensions
}
function getAttr (el, attr) {
function getNumAttrValue (el, attr) {
// nuke anything thats not a number or a negative symbol
const num = _.toNumber(el.css(attr).replace(/[^0-9\.-]+/, ''))
@@ -320,15 +320,15 @@ function getAttr (el, attr) {
}
function getPadding (el, dir) {
return getAttr(el, `padding-${dir}`)
return getNumAttrValue(el, `padding-${dir}`)
}
function getBorder (el, dir) {
return getAttr(el, `border-${dir}-width`)
return getNumAttrValue(el, `border-${dir}-width`)
}
function getMargin (el, dir) {
return getAttr(el, `margin-${dir}`)
return getNumAttrValue(el, `margin-${dir}`)
}
function getTotalFor (directions, dimensions) {