在多次咬牙切齿之后,我想我有一个答案。
我认为根本原因是mdc-select-item
has display:flex
,这使得它超出了它的父母的界限(严格来说,这感觉就像 display flex 的错误应用,但是如果我没记错教程的话......)。
赛普拉斯在确定可见性时会进行大量父级检查,请参阅visibility.coffee,
## WARNING:
## developer beware. visibility is a sink hole
## that leads to sheer madness. you should
## avoid this file before its too late.
...
when $parent = parentHasDisplayNone($el.parent())
parentNode = $elements.stringify($parent, "short")
"This element '#{node}' is not visible because its parent '#{parentNode}' has CSS property: 'display: none'"
...
when $parent = parentHasNoOffsetWidthOrHeightAndOverflowHidden($el.parent())
parentNode = $elements.stringify($parent, "short")
width = elOffsetWidth($parent)
height = elOffsetHeight($parent)
"This element '#{node}' is not visible because its parent '#{parentNode}' has CSS property: 'overflow: hidden' and an effective width and height of: '#{width} x #{height}' pixels."
但是,当使用 时.should('be.visible')
,即使我们实际上可以看到孩子,我们也会遇到无法通过孩子可见性检查的父属性。
我们需要一个替代测试。
解决方法
参考jquery.js,这是元素本身可见性的一种定义(忽略父属性)。
jQuery.expr.pseudos.visible = function( elem ) {
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
}
所以我们可以用它作为替代方案的基础。
describe('Testing select options', function() {
// Change this function if other criteria are required.
const isVisible = (elem) => !!(
elem.offsetWidth ||
elem.offsetHeight ||
elem.getClientRects().length
)
it('checks select option is visible', function() {
const doc = cy.visit('http://localhost:4200')
cy.get("mdc-select").contains("installation type").click()
//cy.get('mdc-select-item').contains("ITEM1").should('be.visible') //this will fail
cy.get('mdc-select-item').contains("ITEM1").then (item1 => {
expect(isVisible(item1[0])).to.be.true
});
});
it('checks select option is not visible', function() {
const doc = cy.visit('http://localhost:4200')
cy.get("mdc-select").contains("installation type").click()
cy.document().then(function(document) {
const item1 = document.querySelectorAll('mdc-select-item')[0]
item1.style.display = 'none'
cy.get('mdc-select-item').contains("ITEM1").then (item => {
expect(isVisible(item[0])).to.be.false
})
})
});
it('checks select option is clickable', function() {
const doc = cy.visit('http://localhost:4200')
cy.get("mdc-select").contains("installation type").click()
//cy.get('mdc-select-item').contains("ITEM1").click() // this will fail
cy.get('mdc-select-item').contains("ITEM1").then (item1 => {
cy.get('mdc-select-item').contains("ITEM2").then (item2 => {
expect(isVisible(item2[0])).to.be.true //visible when list is first dropped
});
item1.click();
cy.wait(500)
cy.get('mdc-select-item').contains("ITEM2").then (item2 => {
expect(isVisible(item2[0])).to.be.false // not visible after item1 selected
});
});
})
脚注 - 使用“then”(或“each”)
您通常在 cypress 中使用断言的方式是通过命令链,它基本上包装了正在测试的元素并处理诸如重试和等待 DOM 更改之类的事情。
.should('be.visible')
但是,在这种情况下,我们在标准可见性断言和用于构建页面的框架之间存在矛盾,因此我们使用then(fn)
( ref ) 来访问未包装的 DOM。然后,我们可以使用stand jasmine expect 语法应用我们自己版本的可见性测试。
事实证明,您也可以使用带有 的函数.should(fn)
,这也可以
it('checks select option is visible - 2', function() {
const doc = cy.visit('http://localhost:4200')
cy.get("mdc-select").contains("installation type").click()
cy.get('mdc-select-item').contains("ITEM1").should(item1 => {
expect(isVisible(item1[0])).to.be.true
});
});
使用should
而不是then
在可见性测试中没有区别,但请注意该should
版本可以多次重试该功能,因此它不能与click
测试一起使用(例如)。
从文档中,
.then() 和 .should()/.and() 有什么区别?
使用 .then() 只允许您在回调函数中使用产生的主题,并且应该在您需要操作某些值或执行某些操作时使用。
另一方面,当使用带有 .should() 或 .and() 的回调函数时,有特殊的逻辑可以重新运行回调函数,直到其中没有断言抛出。您应该注意不希望多次执行的 .should() 或 .and() 回调函数中的副作用。
你也可以通过扩展 chai 断言来解决这个问题,但是这方面的文档并不广泛,因此可能需要更多的工作。