@revoloo/cypress6
Version:
Cypress.io end to end testing tool
1,236 lines (944 loc) • 37.6 kB
JavaScript
const { _, Promise, $ } = Cypress
describe('src/cy/commands/actions/check', () => {
before(() => {
cy
.visit('/fixtures/dom.html')
.then(function (win) {
this.body = win.document.body.outerHTML
})
})
beforeEach(function () {
const doc = cy.state('document')
$(doc.body).empty().html(this.body)
})
context('#check', () => {
it('does not change the subject', () => {
const inputs = $('[name=colors]')
cy.get('[name=colors]').check().then(($inputs) => {
expect($inputs.length).to.eq(3)
expect($inputs.toArray()).to.deep.eq(inputs.toArray())
})
})
it('changes the subject if specific value passed to check', () => {
const checkboxes = $('[name=colors]')
cy.get('[name=colors]').check(['blue', 'red']).then(($chk) => {
expect($chk.length).to.eq(2)
const blue = checkboxes.filter('[value=blue]')
const red = checkboxes.filter('[value=red]')
expect($chk.get(0)).to.eq(blue.get(0))
expect($chk.get(1)).to.eq(red.get(0))
})
})
it('filters out values which were not found', () => {
const checkboxes = $('[name=colors]')
cy.get('[name=colors]').check(['blue', 'purple']).then(($chk) => {
expect($chk.length).to.eq(1)
const blue = checkboxes.filter('[value=blue]')
expect($chk.get(0)).to.eq(blue.get(0))
})
})
it('changes the subject when matching values even if noop', () => {
const checked = $(`<input type='checkbox' name='colors' value='blue' checked>`)
$('[name=colors]').parent().append(checked)
const checkboxes = $('[name=colors]')
cy.get('[name=colors]').check('blue').then(($chk) => {
expect($chk.length).to.eq(2)
const blue = checkboxes.filter('[value=blue]')
expect($chk.get(0)).to.eq(blue.get(0))
expect($chk.get(1)).to.eq(blue.get(1))
})
})
it('checks a checkbox', () => {
cy.get(':checkbox[name=\'colors\'][value=\'blue\']').check().then(($checkbox) => {
expect($checkbox).to.be.checked
})
})
it('checks a radio', () => {
cy.get(':radio[name=\'gender\'][value=\'male\']').check().then(($radio) => {
expect($radio).to.be.checked
})
})
it('is a noop if already checked', () => {
const checkbox = ':checkbox[name=\'colors\'][value=\'blue\']'
$(checkbox).prop('checked', true)
$(checkbox).change(() => {
throw new Error('should not fire change event')
})
cy.get(checkbox).check()
})
// readonly should only be limited to inputs, not checkboxes
it('can check readonly checkboxes', () => {
cy.get('#readonly-checkbox').check().then(($checkbox) => {
expect($checkbox).to.be.checked
})
})
it('can check checkboxes with `opacity: 0`', () => {
cy.get('[name=opacity]').check().then(($checkbox) => {
expect($checkbox).to.be.checked
})
})
it('does not require visibility with force: true', () => {
const checkbox = ':checkbox[name=\'birds\']'
$(checkbox).last().hide()
cy.get(checkbox).check({ force: true }).then(($checkbox) => {
expect($checkbox).to.be.checked
})
})
it('can check a collection', () => {
cy.get('[name=colors]').check().then(($inputs) => {
$inputs.each((i, el) => {
expect($(el)).to.be.checked
})
})
})
it('can check a specific value from a collection', () => {
cy.get('[name=colors]').check('blue').then(($inputs) => {
expect($inputs.filter(':checked').length).to.eq(1)
expect($inputs.filter('[value=blue]')).to.be.checked
})
})
it('can check multiple values from a collection', () => {
cy.get('[name=colors]').check(['blue', 'green']).then(($inputs) => {
expect($inputs.filter(':checked').length).to.eq(2)
expect($inputs.filter('[value=blue],[value=green]')).to.be.checked
})
})
it('can forcibly click even when being covered by another element', () => {
const checkbox = $('<input type=\'checkbox\' />').attr('id', 'checkbox-covered-in-span').prependTo($('body'))
$('<span>span on checkbox</span>').css({ position: 'absolute', left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: 'inline-block', backgroundColor: 'yellow' }).prependTo($('body'))
let clicked = false
checkbox.on('click', () => {
clicked = true
})
cy.get('#checkbox-covered-in-span').check({ force: true }).then(() => {
expect(clicked).to.be.true
})
})
it('passes timeout and interval down to click', (done) => {
const checkbox = $('<input type=\'checkbox\' />')
.attr('id', 'checkbox-covered-in-span')
.prependTo($('body'))
$('<span>span on checkbox</span>')
.css({
position: 'absolute',
left: checkbox.offset().left,
top: checkbox.offset().top,
padding: 5,
display: 'inline-block',
backgroundColor: 'yellow',
})
.prependTo($('body'))
cy.on('command:retry', _.once((options) => {
expect(options.timeout).to.eq(1000)
expect(options.interval).to.eq(60)
done()
}))
cy.get('#checkbox-covered-in-span').check({ timeout: 1000, interval: 60 })
})
it('can specify scrollBehavior in options', () => {
cy.get(':checkbox:first').then((el) => {
cy.spy(el[0], 'scrollIntoView')
})
cy.get(':checkbox:first').check({ scrollBehavior: 'bottom' })
cy.get(':checkbox:first').then((el) => {
expect(el[0].scrollIntoView).to.be.calledWith({ block: 'end' })
})
})
it('does not scroll when scrollBehavior is false in options', () => {
cy.get(':checkbox:first').scrollIntoView()
cy.get(':checkbox:first').then((el) => {
cy.spy(el[0], 'scrollIntoView')
})
cy.get(':checkbox:first').check({ scrollBehavior: false })
cy.get(':checkbox:first').then((el) => {
expect(el[0].scrollIntoView).not.to.be.called
})
})
it('does not scroll when scrollBehavior is false in config', { scrollBehavior: false }, () => {
cy.get(':checkbox:first').scrollIntoView()
cy.get(':checkbox:first').then((el) => {
cy.spy(el[0], 'scrollIntoView')
})
cy.get(':checkbox:first').check()
cy.get(':checkbox:first').then((el) => {
expect(el[0].scrollIntoView).not.to.be.called
})
})
it('calls scrollIntoView by default', () => {
cy.scrollTo('top')
cy.get(':checkbox:first').then((el) => {
cy.spy(el[0], 'scrollIntoView')
})
cy.get(':checkbox:first').check()
cy.get(':checkbox:first').then((el) => {
expect(el[0].scrollIntoView).to.be.calledWith({ block: 'start' })
})
})
it('waits until element is no longer disabled', () => {
const chk = $(':checkbox:first').prop('disabled', true)
let retried = false
let clicks = 0
chk.on('click', () => {
clicks += 1
})
cy.on('command:retry', _.after(3, () => {
chk.prop('disabled', false)
retried = true
}))
cy.get(':checkbox:first').check().then(() => {
expect(clicks).to.eq(1)
expect(retried).to.be.true
})
})
it('can set options.waitForAnimations', () => {
cy.stub(cy, 'ensureElementIsNotAnimating').throws(new Error('animating!'))
cy.get(':checkbox:first').check({ waitForAnimations: false }).then(() => {
expect(cy.ensureElementIsNotAnimating).not.to.be.called
})
})
it('can set options.animationDistanceThreshold', () => {
const $btn = cy.$$(':checkbox:first')
cy.spy(cy, 'ensureElementIsNotAnimating')
cy.get(':checkbox:first').check({ animationDistanceThreshold: 1000 }).then(() => {
const { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($btn)
const { args } = cy.ensureElementIsNotAnimating.firstCall
expect(args[1]).to.deep.eq([fromElWindow, fromElWindow])
expect(args[2]).to.eq(1000)
})
})
it('delays 50ms before resolving', () => {
cy.$$(':checkbox:first').on('change', (e) => {
cy.spy(Promise, 'delay')
})
cy.get(':checkbox:first').check().then(() => {
expect(Promise.delay).to.be.calledWith(50, 'click')
})
})
describe('assertion verification', () => {
beforeEach(function () {
cy.on('log:added', (attrs, log) => {
if (log.get('name') === 'assert') {
this.lastLog = log
}
})
return null
})
it('eventually passes the assertion', () => {
$(':checkbox:first').click(function () {
_.delay(() => {
$(this).addClass('checked')
}, 100)
})
cy.get(':checkbox:first').check().should('have.class', 'checked').then(function () {
const { lastLog } = this
expect(lastLog.get('name')).to.eq('assert')
expect(lastLog.get('state')).to.eq('passed')
expect(lastLog.get('ended')).to.be.true
})
})
it('eventually passes the assertion on multiple :checkboxs', () => {
$(':checkbox').click(function () {
_.delay(() => {
$(this).addClass('checked')
}, 100)
})
cy.get(':checkbox').invoke('slice', 0, 2).check().should('have.class', 'checked')
})
})
describe('events', () => {
it('emits click event', (done) => {
$('[name=colors][value=blue]').click(() => {
done()
})
cy.get('[name=colors]').check('blue')
})
it('emits change event', (done) => {
$('[name=colors][value=blue]').change(() => {
done()
})
cy.get('[name=colors]').check('blue')
})
it('emits focus event', () => {
let focus = false
$('[name=colors][value=blue]').focus(() => {
focus = true
})
cy.get('[name=colors]')
.check('blue')
.then(() => {
expect(focus).to.eq(true)
})
})
})
describe('errors', {
defaultCommandTimeout: 100,
}, () => {
beforeEach(function () {
this.logs = []
cy.on('log:added', (attrs, log) => {
this.lastLog = log
this.logs.push(log)
})
return null
})
it('throws when subject isnt dom', (done) => {
cy.on('fail', () => {
done()
})
cy.noop({}).check()
})
it('throws when subject is not in the document', (done) => {
let checked = 0
const checkbox = $(':checkbox:first').click((e) => {
checked += 1
checkbox.remove()
return false
})
cy.on('fail', (err) => {
expect(checked).to.eq(1)
expect(err.message).to.include('`cy.check()` failed because this element')
done()
})
cy.get(':checkbox:first').check().check()
})
it('throws when subject isnt a checkbox or radio', (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include('`cy.check()` can only be called on `:checkbox` and `:radio`. Your subject contains a: `<form id="by-id">...</form>`')
expect(err.docsUrl).to.include('https://on.cypress.io/check')
done()
})
// this will find multiple forms
cy.get('form').check()
})
it('throws when any member of the subject isnt a checkbox or radio', (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include('`cy.check()` can only be called on `:checkbox` and `:radio`. Your subject contains a: `<textarea id="comments"></textarea>`')
expect(err.docsUrl).to.include('https://on.cypress.io/check')
done()
})
// find a textare which should blow up
// the textarea is the last member of the subject
cy.get(':checkbox,:radio,#comments').check()
})
it('throws when any member of the subject isnt visible', function (done) {
const chk = $(':checkbox').first().hide()
cy.on('fail', (err) => {
const { lastLog } = this
expect(this.logs.length).to.eq(chk.length + 1)
expect(lastLog.get('error')).to.eq(err)
expect(err.message).to.include('`cy.check()` failed because this element is not visible')
done()
})
cy.get(':checkbox:first').check()
})
it('throws when subject is disabled', function (done) {
$(':checkbox:first').prop('disabled', true)
cy.on('fail', (err) => {
// get + type logs
expect(this.logs.length).eq(2)
expect(err.message).to.include('`cy.check()` failed because this element is `disabled`:\n')
done()
})
cy.get(':checkbox:first').check()
})
it('still ensures visibility even during a noop', function (done) {
const chk = $(':checkbox')
chk.show().last().hide()
cy.on('fail', (err) => {
const { lastLog } = this
expect(this.logs.length).to.eq(chk.length + 1)
expect(lastLog.get('error')).to.eq(err)
expect(err.message).to.include('`cy.check()` failed because this element is not visible')
done()
})
cy.get(':checkbox').check()
})
it('logs once when not dom subject', function (done) {
cy.on('fail', (err) => {
const { lastLog } = this
expect(this.logs.length).to.eq(1)
expect(lastLog.get('error')).to.eq(err)
done()
})
cy.check()
})
it('throws when input cannot be clicked', function (done) {
const checkbox = $('<input type=\'checkbox\' />').attr('id', 'checkbox-covered-in-span').prependTo($('body'))
$('<span>span on button</span>').css({ position: 'absolute', left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: 'inline-block', backgroundColor: 'yellow' }).prependTo($('body'))
cy.on('fail', (err) => {
expect(this.logs.length).to.eq(2)
expect(err.message).to.include('`cy.check()` failed because this element')
expect(err.message).to.include('is being covered by another element')
done()
})
cy.get('#checkbox-covered-in-span').check()
})
it('eventually fails the assertion', function (done) {
cy.on('fail', (err) => {
const { lastLog } = this
expect(err.message).to.include(lastLog.get('error').message)
expect(err.message).not.to.include('undefined')
expect(lastLog.get('name')).to.eq('assert')
expect(lastLog.get('state')).to.eq('failed')
expect(lastLog.get('error')).to.be.an.instanceof(chai.AssertionError)
done()
})
cy.get(':checkbox:first').check().should('have.class', 'checked')
})
it('does not log an additional log on failure', function (done) {
cy.on('fail', () => {
expect(this.logs.length).to.eq(3)
done()
})
cy.get(':checkbox:first').check().should('have.class', 'checked')
})
})
describe('.log', () => {
beforeEach(function () {
cy.on('log:added', (attrs, log) => {
this.lastLog = log
})
return null
})
it('logs immediately before resolving', (done) => {
const chk = $(':checkbox:first')
cy.on('log:added', (attrs, log) => {
if (log.get('name') === 'check') {
expect(log.get('state')).to.eq('pending')
expect(log.get('$el').get(0)).to.eq(chk.get(0))
done()
}
})
cy.get(':checkbox:first').check()
})
it('snapshots before clicking', function (done) {
$(':checkbox:first').change(() => {
const { lastLog } = this
expect(lastLog.get('snapshots').length).to.eq(1)
expect(lastLog.get('snapshots')[0].name).to.eq('before')
expect(lastLog.get('snapshots')[0].body).to.be.an('object')
done()
})
cy.get(':checkbox:first').check()
})
it('snapshots after clicking', () => {
cy.get(':checkbox:first').check().then(function () {
const { lastLog } = this
expect(lastLog.get('snapshots').length).to.eq(2)
expect(lastLog.get('snapshots')[1].name).to.eq('after')
expect(lastLog.get('snapshots')[1].body).to.be.an('object')
})
})
it('logs only 1 check event on click of 1 checkbox', () => {
const logs = []
const checks = []
cy.on('log:added', (attrs, log) => {
logs.push(log)
if (log.get('name') === 'check') {
checks.push(log)
}
})
cy.get('[name=colors][value=blue]').check().then(() => {
expect(logs.length).to.eq(2)
expect(checks).to.have.length(1)
})
})
it('logs only 1 check event on click of 1 radio', () => {
const logs = []
const radios = []
cy.on('log:added', (attrs, log) => {
logs.push(log)
if (log.get('name') === 'check') {
radios.push(log)
}
})
cy.get('[name=gender][value=female]').check().then(() => {
expect(logs.length).to.eq(2)
expect(radios).to.have.length(1)
})
})
it('logs only 1 check event on checkbox with 1 matching value arg', () => {
const logs = []
const checks = []
cy.on('log:added', (attrs, log) => {
logs.push(log)
if (log.get('name') === 'check') {
checks.push(log)
}
})
cy.get('[name=colors]').check('blue').then(() => {
expect(logs.length).to.eq(2)
expect(checks).to.have.length(1)
})
})
it('logs only 1 check event on radio with 1 matching value arg', () => {
const logs = []
const radios = []
cy.on('log:added', (attrs, log) => {
logs.push(log)
if (log.get('name') === 'check') {
radios.push(log)
}
})
cy.get('[name=gender]').check('female').then(() => {
expect(logs.length).to.eq(2)
expect(radios).to.have.length(1)
})
})
it('passes in $el', () => {
cy.get('[name=colors][value=blue]').check().then(function ($input) {
const { lastLog } = this
expect(lastLog.get('$el').get(0)).to.eq($input.get(0))
})
})
it('passes in coords', () => {
cy.get('[name=colors][value=blue]').check().then(function ($input) {
const { lastLog } = this
const { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($input)
expect(lastLog.get('coords')).to.deep.eq(fromElWindow)
})
})
it('ends command when checkbox is already checked', () => {
cy.get('[name=colors][value=blue]').check().check().then(function () {
const { lastLog } = this
expect(lastLog.get('state')).eq('passed')
})
})
it('#consoleProps', () => {
cy.get('[name=colors][value=blue]').check().then(function ($input) {
const { lastLog } = this
const { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($input)
const console = lastLog.invoke('consoleProps')
expect(console.Command).to.eq('check')
expect(console['Applied To']).to.eq(lastLog.get('$el').get(0))
expect(console.Elements).to.eq(1)
expect(console.Coords).to.deep.eq(
_.pick(fromElWindow, 'x', 'y'),
)
})
})
it('#consoleProps when checkbox is already checked', () => {
cy.get('[name=colors][value=blue]').invoke('prop', 'checked', true).check().then(function () {
const { lastLog } = this
expect(lastLog.get('coords')).to.be.undefined
expect(lastLog.invoke('consoleProps')).to.deep.eq({
Command: 'check',
'Applied To': lastLog.get('$el').get(0),
Elements: 1,
Note: 'This checkbox was already checked. No operation took place.',
Options: undefined,
})
})
})
it('#consoleProps when radio is already checked', () => {
cy.get('[name=gender][value=male]').check().check().then(function () {
const { lastLog } = this
expect(lastLog.get('coords')).to.be.undefined
expect(lastLog.invoke('consoleProps')).to.deep.eq({
Command: 'check',
'Applied To': lastLog.get('$el').get(0),
Elements: 1,
Note: 'This radio was already checked. No operation took place.',
Options: undefined,
})
})
})
it('#consoleProps when checkbox with value is already checked', () => {
$('[name=colors][value=blue]').prop('checked', true)
cy.get('[name=colors]').check('blue').then(function () {
const { lastLog } = this
expect(lastLog.get('coords')).to.be.undefined
expect(lastLog.invoke('consoleProps')).to.deep.eq({
Command: 'check',
'Applied To': lastLog.get('$el').get(0),
Elements: 1,
Note: 'This checkbox was already checked. No operation took place.',
Options: undefined,
})
})
})
it('logs deltaOptions', () => {
cy.get('[name=colors][value=blue]').check({ force: true, timeout: 1000 }).then(function () {
const { lastLog } = this
expect(lastLog.get('message')).to.eq('{force: true, timeout: 1000}')
expect(lastLog.invoke('consoleProps').Options).to.deep.eq({ force: true, timeout: 1000 })
})
})
})
})
context('#uncheck', () => {
it('does not change the subject', () => {
const inputs = $('[name=birds]')
cy.get('[name=birds]').uncheck().then(($inputs) => {
expect($inputs.length).to.eq(2)
expect($inputs.toArray()).to.deep.eq(inputs.toArray())
})
})
it('changes the subject if specific value passed to check', () => {
const checkboxes = $('[name=birds]')
cy.get('[name=birds]').check(['cockatoo', 'amazon']).then(($chk) => {
expect($chk.length).to.eq(2)
const cockatoo = checkboxes.filter('[value=cockatoo]')
const amazon = checkboxes.filter('[value=amazon]')
expect($chk.get(0)).to.eq(cockatoo.get(0))
expect($chk.get(1)).to.eq(amazon.get(0))
})
})
it('filters out values which were not found', () => {
const checkboxes = $('[name=birds]')
cy.get('[name=birds]').check(['cockatoo', 'parrot']).then(($chk) => {
expect($chk.length).to.eq(1)
const cockatoo = checkboxes.filter('[value=cockatoo]')
expect($chk.get(0)).to.eq(cockatoo.get(0))
})
})
it('changes the subject when matching values even if noop', () => {
const checked = $('<input type=\'checkbox\' name=\'birds\' value=\'cockatoo\'>')
$('[name=birds]').parent().append(checked)
const checkboxes = $('[name=birds]')
cy.get('[name=birds]').check('cockatoo').then(($chk) => {
expect($chk.length).to.eq(2)
const cockatoo = checkboxes.filter('[value=cockatoo]')
expect($chk.get(0)).to.eq(cockatoo.get(0))
expect($chk.get(1)).to.eq(cockatoo.get(1))
})
})
it('unchecks a checkbox', () => {
cy.get('[name=birds][value=cockatoo]').uncheck().then(($checkbox) => {
expect($checkbox).not.to.be.checked
})
})
it('unchecks a checkbox by value', () => {
cy.get('[name=birds]').uncheck('cockatoo').then(($checkbox) => {
expect($checkbox.filter(':checked').length).to.eq(0)
expect($checkbox.filter('[value=cockatoo]')).not.to.be.checked
})
})
it('unchecks multiple checkboxes by values', () => {
cy.get('[name=birds]').uncheck(['cockatoo', 'amazon']).then(($checkboxes) => {
expect($checkboxes.filter(':checked').length).to.eq(0)
expect($checkboxes.filter('[value=cockatoo],[value=amazon]')).not.to.be.checked
})
})
it('is a noop if already unchecked', () => {
let checked = false
const checkbox = '[name=birds][value=cockatoo]'
$(checkbox).prop('checked', false).change(() => {
checked = true
})
cy.get(checkbox).uncheck().then(() => {
expect(checked).to.be.false
})
})
it('can forcibly click even when being covered by another element', (done) => {
const checkbox = $('<input type=\'checkbox\' />').attr('id', 'checkbox-covered-in-span').prop('checked', true).prependTo($('body'))
$('<span>span on checkbox</span>').css({ position: 'absolute', left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: 'inline-block', backgroundColor: 'yellow' }).prependTo($('body'))
checkbox.on('click', () => {
done()
})
cy.get('#checkbox-covered-in-span').uncheck({ force: true })
})
it('passes timeout and interval down to click', (done) => {
const checkbox = $('<input type=\'checkbox\' />').attr('id', 'checkbox-covered-in-span').prop('checked', true).prependTo($('body'))
$('<span>span on checkbox</span>').css({ position: 'absolute', left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: 'inline-block', backgroundColor: 'yellow' }).prependTo($('body'))
cy.on('command:retry', (options) => {
expect(options.timeout).to.eq(1000)
expect(options.interval).to.eq(60)
done()
})
cy.get('#checkbox-covered-in-span').uncheck({ timeout: 1000, interval: 60 })
})
it('waits until element is no longer disabled', () => {
const chk = $(':checkbox:first').prop('checked', true).prop('disabled', true)
let retried = false
let clicks = 0
chk.on('click', () => {
clicks += 1
})
cy.on('command:retry', _.after(3, () => {
chk.prop('disabled', false)
retried = true
}))
cy.get(':checkbox:first').uncheck().then(() => {
expect(clicks).to.eq(1)
expect(retried).to.be.true
})
})
describe('assertion verification', () => {
beforeEach(function () {
cy.on('log:added', (attrs, log) => {
if (log.get('name') === 'assert') {
this.lastLog = log
}
})
return null
})
it('eventually passes the assertion', () => {
$(':checkbox:first').prop('checked', true).click(function () {
_.delay(() => {
$(this).addClass('unchecked')
}, 100)
})
cy.get(':checkbox:first').uncheck().should('have.class', 'unchecked').then(function () {
const { lastLog } = this
expect(lastLog.get('name')).to.eq('assert')
expect(lastLog.get('state')).to.eq('passed')
expect(lastLog.get('ended')).to.be.true
})
})
})
describe('events', () => {
it('emits click event', (done) => {
$('[name=colors][value=blue]').prop('checked', true).click(() => {
done()
})
cy.get('[name=colors]').uncheck('blue')
})
it('emits change event', (done) => {
$('[name=colors][value=blue]').prop('checked', true).change(() => {
done()
})
cy.get('[name=colors]').uncheck('blue')
})
})
describe('errors', {
defaultCommandTimeout: 100,
}, () => {
beforeEach(function () {
this.logs = []
cy.on('log:added', (attrs, log) => {
this.lastLog = log
this.logs.push(log)
})
return null
})
it('throws specifically on a radio', (done) => {
cy.get(':radio').uncheck()
cy.on('fail', (err) => {
expect(err.message).to.include('`cy.uncheck()` can only be called on `:checkbox`.')
expect(err.docsUrl).to.include('https://on.cypress.io/uncheck')
done()
})
})
it('throws if not a checkbox', (done) => {
cy.noop({}).uncheck()
cy.on('fail', () => {
done()
})
})
it('throws when any member of the subject isnt visible', function (done) {
// grab the first 3 checkboxes.
const chk = $(':checkbox').slice(0, 3).show()
cy.on('fail', (err) => {
const { lastLog } = this
const len = (chk.length * 2) + 6
expect(this.logs.length).to.eq(len)
expect(lastLog.get('error')).to.eq(err)
expect(err.message).to.include('`cy.uncheck()` failed because this element is not visible')
done()
})
cy
.get(':checkbox').invoke('slice', 0, 3).check().last().invoke('hide')
.get(':checkbox').invoke('slice', 0, 3).uncheck()
})
it('logs once when not dom subject', function (done) {
cy.on('fail', (err) => {
const { lastLog } = this
expect(this.logs.length).to.eq(1)
expect(lastLog.get('error')).to.eq(err)
done()
})
cy.uncheck()
})
it('throws when subject is not in the document', (done) => {
let unchecked = 0
const checkbox = $(':checkbox:first').prop('checked', true).click((e) => {
unchecked += 1
checkbox.prop('checked', true)
checkbox.remove()
return false
})
cy.on('fail', (err) => {
expect(unchecked).to.eq(1)
expect(err.message).to.include('`cy.uncheck()` failed because this element')
done()
})
cy.get(':checkbox:first').uncheck().uncheck()
})
it('throws when input cannot be clicked', function (done) {
const checkbox = $('<input type=\'checkbox\' />').attr('id', 'checkbox-covered-in-span').prop('checked', true).prependTo($('body'))
$('<span>span on button</span>').css({ position: 'absolute', left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: 'inline-block', backgroundColor: 'yellow' }).prependTo($('body'))
cy.on('fail', (err) => {
expect(this.logs.length).to.eq(2)
expect(err.message).to.include('`cy.uncheck()` failed because this element')
expect(err.message).to.include('is being covered by another element')
done()
})
cy.get('#checkbox-covered-in-span').uncheck()
})
it('throws when subject is disabled', function (done) {
$(':checkbox:first').prop('checked', true).prop('disabled', true)
cy.on('fail', (err) => {
// get + type logs
expect(this.logs.length).eq(2)
expect(err.message).to.include('`cy.uncheck()` failed because this element is `disabled`:\n')
done()
})
cy.get(':checkbox:first').uncheck()
})
it('eventually passes the assertion on multiple :checkboxs', () => {
$(':checkbox').prop('checked', true).click(function () {
_.delay(() => {
$(this).addClass('unchecked')
}, 100)
})
cy.get(':checkbox').invoke('slice', 0, 2).uncheck().should('have.class', 'unchecked')
})
it('eventually fails the assertion', function (done) {
$(':checkbox:first').prop('checked', true)
cy.on('fail', (err) => {
const { lastLog } = this
expect(err.message).to.include(lastLog.get('error').message)
expect(err.message).not.to.include('undefined')
expect(lastLog.get('name')).to.eq('assert')
expect(lastLog.get('state')).to.eq('failed')
expect(lastLog.get('error')).to.be.an.instanceof(chai.AssertionError)
done()
})
cy.get(':checkbox:first').uncheck().should('have.class', 'unchecked')
})
it('does not log an additional log on failure', function (done) {
cy.on('fail', () => {
expect(this.logs.length).to.eq(3)
done()
})
cy.get(':checkbox:first').uncheck().should('have.class', 'unchecked')
})
})
describe('.log', () => {
beforeEach(function () {
$('[name=colors][value=blue]').prop('checked', true)
cy.on('log:added', (attrs, log) => {
this.lastLog = log
})
return null
})
it('logs immediately before resolving', (done) => {
const chk = $(':checkbox:first')
cy.on('log:added', (attrs, log) => {
if (log.get('name') === 'uncheck') {
expect(log.get('state')).to.eq('pending')
expect(log.get('$el').get(0)).to.eq(chk.get(0))
done()
}
})
cy.get(':checkbox:first').check().uncheck()
})
it('snapshots before unchecking', function (done) {
$(':checkbox:first').change(() => {
const { lastLog } = this
expect(lastLog.get('snapshots').length).to.eq(1)
expect(lastLog.get('snapshots')[0].name).to.eq('before')
expect(lastLog.get('snapshots')[0].body).to.be.an('object')
done()
})
cy.get(':checkbox:first').invoke('prop', 'checked', true).uncheck()
})
it('snapshots after unchecking', () => {
cy.get(':checkbox:first').invoke('prop', 'checked', true).uncheck().then(function () {
const { lastLog } = this
expect(lastLog.get('snapshots').length).to.eq(2)
expect(lastLog.get('snapshots')[1].name).to.eq('after')
expect(lastLog.get('snapshots')[1].body).to.be.an('object')
})
})
it('logs only 1 uncheck event', () => {
const logs = []
const unchecks = []
cy.on('log:added', (attrs, log) => {
logs.push(log)
if (log.get('name') === 'uncheck') {
unchecks.push(log)
}
})
cy.get('[name=colors][value=blue]').uncheck().then(() => {
expect(logs.length).to.eq(2)
expect(unchecks).to.have.length(1)
})
})
it('logs only 1 uncheck event on uncheck with 1 matching value arg', () => {
const logs = []
const unchecks = []
cy.on('log:added', (attrs, log) => {
logs.push(log)
if (log.get('name') === 'uncheck') {
unchecks.push(log)
}
})
cy.get('[name=colors]').uncheck('blue').then(() => {
expect(logs.length).to.eq(2)
expect(unchecks).to.have.length(1)
})
})
it('passes in $el', () => {
cy.get('[name=colors][value=blue]').uncheck().then(function ($input) {
const { lastLog } = this
expect(lastLog.get('$el').get(0)).to.eq($input.get(0))
})
})
it('ends command when checkbox is already unchecked', () => {
cy.get('[name=colors][value=blue]').invoke('prop', 'checked', false).uncheck().then(function () {
const { lastLog } = this
expect(lastLog.get('state')).eq('passed')
})
})
it('#consoleProps', () => {
cy.get('[name=colors][value=blue]').uncheck().then(function ($input) {
const { lastLog } = this
const { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($input)
const console = lastLog.invoke('consoleProps')
expect(console.Command).to.eq('uncheck')
expect(console['Applied To']).to.eq(lastLog.get('$el').get(0))
expect(console.Elements).to.eq(1)
expect(console.Coords).to.deep.eq(
_.pick(fromElWindow, 'x', 'y'),
)
})
})
it('#consoleProps when checkbox is already unchecked', () => {
cy.get('[name=colors][value=blue]').invoke('prop', 'checked', false).uncheck().then(function () {
const { lastLog } = this
expect(lastLog.get('coords')).to.be.undefined
expect(lastLog.invoke('consoleProps')).to.deep.eq({
Command: 'uncheck',
'Applied To': lastLog.get('$el').get(0),
Elements: 1,
Note: 'This checkbox was already unchecked. No operation took place.',
Options: undefined,
})
})
})
it('#consoleProps when checkbox with value is already unchecked', () => {
cy.get('[name=colors][value=blue]').invoke('prop', 'checked', false)
cy.get('[name=colors]').uncheck('blue').then(function () {
const { lastLog } = this
expect(lastLog.get('coords')).to.be.undefined
expect(lastLog.invoke('consoleProps')).to.deep.eq({
Command: 'uncheck',
'Applied To': lastLog.get('$el').get(0),
Elements: 1,
Note: 'This checkbox was already unchecked. No operation took place.',
Options: undefined,
})
})
})
it('logs deltaOptions', () => {
cy.get('[name=colors][value=blue]').check().uncheck({ force: true, timeout: 1000 }).then(function () {
const { lastLog } = this
expect(lastLog.get('message')).to.eq('{force: true, timeout: 1000}')
expect(lastLog.invoke('consoleProps').Options).to.deep.eq({ force: true, timeout: 1000 })
})
})
})
})
})