mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-04 06:10:30 -06:00
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:
@@ -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
|
||||
|
||||
@@ -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}}"
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user