@revoloo/cypress6
Version:
Cypress.io end to end testing tool
322 lines (248 loc) • 8.47 kB
text/typescript
import { getActiveElByDocument, isFocused, elementFromPoint } from '../../../src/dom/elements'
const { $ } = Cypress
export {}
describe('src/dom/elements', () => {
context('.isAttached', () => {
beforeEach(() => {
cy.visit('/fixtures/iframe-outer.html')
})
it('no elements', () => {
const $el = $(null!)
expect(Cypress.dom.isAttached($el)).to.be.false
})
it('element', () => {
cy.get('span').then(($span) => {
expect(Cypress.dom.isAttached($span)).to.be.true
$span.remove()
expect(Cypress.dom.isAttached($span)).to.be.false
})
})
it('stale element', (done) => {
cy.get('span').then(($span) => {
expect(Cypress.dom.isAttached($span)).to.be.true
cy.on('window:load', () => {
expect(Cypress.dom.isAttached($span)).to.be.false
done()
})
cy.window().then((win) => {
win.location.reload()
})
})
})
it('window', () => {
cy.window().then((win) => {
// windows are always considered attached since
// their references will be replaced anyway with
// new windows
expect(Cypress.dom.isAttached(win)).to.be.true
})
})
it('document', (done) => {
cy.document().then((doc) => {
// documents are considered attached only if
// they have a defaultView (window) which will
// be null when the documents are stale
expect(Cypress.dom.isAttached(doc)).to.be.true
cy.on('window:load', () => {
expect(Cypress.dom.isAttached(doc)).to.be.false
done()
})
cy.window().then((win) => {
win.location.reload()
})
})
})
it('element in iframe', (done) => {
cy.get('iframe').then(($iframe) => {
const $doc = $iframe.contents() as JQuery<Document>
const $btn = $doc.find('button') as unknown as JQuery<HTMLButtonElement>
expect($btn.length).to.eq(1)
expect(Cypress.dom.isAttached($btn)).to.be.true
// when the iframe is reloaded
$iframe.on('load', () => {
// the element should be stale now
expect(Cypress.dom.isAttached($btn)).to.be.false
done()
})
const win = $doc.get(0).defaultView!
win.location.reload()
})
})
})
context('.isDetached', () => {
it('opposite of attached', () => {
const $el = $(null!)
expect(Cypress.dom.isDetached($el)).to.be.true
})
})
context('.isInputType', () => {
beforeEach(() => {
cy.visit('/fixtures/dom.html')
})
it('when type is a string', () => {
const $el = $('input[type="number"]')
expect(Cypress.dom.isInputType($el, 'number')).to.be.true
expect(Cypress.dom.isInputType($el, 'text')).to.be.false
})
it('when type is an array', () => {
const $el = $('input[type="number"]')
expect(Cypress.dom.isInputType($el, ['number', 'text', 'email'])).to.be.true
expect(Cypress.dom.isInputType($el, ['text', 'email'])).to.be.false
})
})
context('.isUndefinedOrHTMLBodyDoc', () => {
it('when $el undefined', () => {
const $el = undefined
expect(Cypress.dom.isUndefinedOrHTMLBodyDoc($el)).to.be.true
})
it('when $el[0] undefined', () => {
const $el = []
expect(Cypress.dom.isUndefinedOrHTMLBodyDoc($el)).to.be.true
})
it('DOM element does not exist', () => {
cy.visit('/fixtures/dom.html')
const $el = $('foo-bar-baz')
expect(Cypress.dom.isUndefinedOrHTMLBodyDoc($el)).to.be.true
})
it('when html', () => {
cy.visit('/fixtures/dom.html')
const $el = $('html')
expect(Cypress.dom.isUndefinedOrHTMLBodyDoc($el)).to.be.true
})
it('when body', () => {
cy.visit('/fixtures/dom.html')
const $el = $('body')
expect(Cypress.dom.isUndefinedOrHTMLBodyDoc($el)).to.be.true
})
it('when document', () => {
cy.visit('/fixtures/dom.html')
const $el = $('document')
expect(Cypress.dom.isUndefinedOrHTMLBodyDoc($el)).to.be.true
})
it('when existing DOM element', () => {
cy.visit('/fixtures/dom.html')
const $el = $('input')
expect(Cypress.dom.isUndefinedOrHTMLBodyDoc($el)).to.be.false
})
})
context('.getActiveElByDocument', () => {
beforeEach(() => {
cy.visit('/fixtures/active-elements.html')
})
it('returns active element by looking it up on document', () => {
cy.get('input:first').focus().then(($el) => {
expect(getActiveElByDocument($el)).to.equal($el[0])
})
})
it('returns null if element is not focused', () => {
cy.get('input:first').then(($el) => {
expect(getActiveElByDocument($el)).to.be.null
})
})
describe('in the shadow dom', () => {
beforeEach(() => {
cy.visit('/fixtures/shadow-dom.html')
})
it('returns active element for shadow dom by looking it up on shadow root', () => {
cy
.get('#shadow-element-1')
.find('input', { includeShadowDom: true }).focus().then(($el) => {
expect(getActiveElByDocument($el)).to.equal($el[0])
})
})
})
})
context('.isFocused', () => {
beforeEach(() => {
cy.visit('/fixtures/active-elements.html')
})
it('returns true if the element is the active element', () => {
cy.get('input:first').focus().then(($el) => {
expect(isFocused($el[0])).to.be.true
})
})
it('returns true if the active element is the body and it is contenteditable', () => {
cy.get('body').focus().then(($body) => {
$body[0].setAttribute('contenteditable', 'true')
expect(isFocused($body[0])).to.be.true
})
})
it('returns false if the element is not the active element', () => {
cy.get('input:first').then(($el) => {
expect(isFocused($el[0])).to.be.false
})
})
it('returns false if there is no active element', () => {
cy.get('input:first').focus().then(($el) => {
$el.blur()
expect(isFocused($el[0])).to.be.false
})
})
it('returns false if the active element is the body', () => {
cy.get('body').focus().then(($body) => {
expect(isFocused($body[0])).to.be.false
})
})
it('returns false if determining the active element errors', () => {
cy.get('input:first').focus().then(($el) => {
Object.defineProperty($el[0].ownerDocument, 'activeElement', {
get () {
throw new Error('unexpected error')
},
})
expect(isFocused($el[0])).to.be.false
})
})
describe('in the shadow dom', () => {
it('returns true if the element is the active element of the shadow root', () => {
cy.visit('/fixtures/shadow-dom.html')
cy
.get('#shadow-element-1')
.find('input', { includeShadowDom: true }).focus().then(($el) => {
expect(isFocused($el[0])).to.be.true
})
})
})
})
context('.elementFromPoint', () => {
let doc
let node
beforeEach(() => {
node = {}
doc = {
elementFromPoint: cy.stub().returns(node),
}
})
it('returns original node if node has no shadow root', () => {
expect(elementFromPoint(doc, 1, 2)).to.equal(node)
})
it('returns shadow dom element at point', () => {
const shadowNode = {}
const shadowHostNode = {
shadowRoot: {
elementFromPoint: cy.stub().returns(shadowNode),
},
}
doc.elementFromPoint.returns(shadowHostNode)
expect(elementFromPoint(doc, 1, 2)).to.equal(shadowNode)
})
it('returns original node if no element at point in shadow dom', () => {
const shadowHostNode = {
shadowRoot: {
elementFromPoint: cy.stub().returns(node),
},
}
doc.elementFromPoint.returns(shadowHostNode)
expect(elementFromPoint(doc, 1, 2)).to.equal(node)
})
// https://github.com/cypress-io/cypress/issues/7794
it('returns shadow host if its element at point is itself', () => {
const shadowHostNode = {} as any
shadowHostNode.shadowRoot = {
elementFromPoint: cy.stub().returns(shadowHostNode),
}
doc.elementFromPoint.returns(shadowHostNode)
expect(elementFromPoint(doc, 1, 2)).to.equal(shadowHostNode)
})
})
})