Kau*_* NP 12 javascript ui-automation pug angular cypress
问题在标题中给出,即访问其父项被隐藏的元素.问题是,根据cypress.io文档 :
一个元素被认为是隐藏的,如果:
- 它的宽度或高度为0.
- 它的CSS属性(或祖先)是visibility:hidden.
- 它的CSS属性(或祖先)是display:none.
- 它的CSS属性是位置:固定,它是屏幕外或掩盖.
但是我正在使用的代码要求我单击其父级被隐藏的元素,而元素本身是可见的.
因此,每次我尝试单击该元素时,都会引发错误读取:
CypressError:超时重试:预期'<mdc-select-item #mdc-select-item-4.mdc-list-item>'为'可见'
此元素'<mdc-select-item #mdc-select-item-4.mdc-list-item>'不可见,因为其父元素'<mdc-select-menu.mdc-simple-menu.mdc-select__menu>'有CSS属性:'display:none'
我正在使用的元素是一个dropdown item写的pug.该元素是angular-mdc-web中定义的组件,它使用mdc-select下拉菜单mdc-select-item及其元素(项),这是我必须访问的.
类似结构的示例代码:
//pug
mdc-select(placeholder="installation type"
'[closeOnScroll]'="true")
mdc-select-item(value="false") ITEM1
mdc-select-item(value="true") ITEM2
Run Code Online (Sandbox Code Playgroud)
在上面,ITEM1是我必须访问的元素.我这样做cypress.io如下:
//cypress.io
// click on the dropdown menu to show the dropdown (items)
cy.get("mdc-select").contains("installation type").click();
// try to access ITEM1
cy.get('mdc-select-item').contains("ITEM1").should('be.visible').click();
Run Code Online (Sandbox Code Playgroud)
试过{force:true}强迫项目点击,但没有运气.尝试使用{enter}父按钮上的按键选择项目mdc-select,但再次没有运气,因为它抛出:
CypressError:cy.type()只能在textarea或:text上调用.您的主题是:<mdc-select-label class ="mdc-select__selected-text">选择... </ mdc-select-label>
也尝试使用该select命令,但它不可能,因为赛普拉斯引擎无法将元素识别为select元素(因为它不是,内部工作方式不同).它抛出:
CypressError:cy.select()只能在a上调用.您的主题是:<mdc-select-label class ="mdc-select__selected-text">选择... </ mdc-select-label>
该问题是,mdc-select-menu这是父为mdc-select-item具有的属性display:none通过在下拉项开放一些内部计算.
此属性被覆盖display:flex,但这没有帮助.
所有的想法.这适用于Selenium,但不适用cypress.io.任何线索除了转移到其他框架或更改UI代码之外可能存在什么样的情况?
经过大量的n牙,我想我有一个答案.
我认为,根本原因是mdc-select-item有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."
Run Code Online (Sandbox Code Playgroud)
但是,在使用时.should('be.visible'),即使我们能够真正看到孩子,我们仍然会遇到父母属性未通过孩子可见性检查.
我们需要一个替代测试.
参考jquery.js,这是元素本身可见性的一个定义(忽略父属性).
jQuery.expr.pseudos.visible = function( elem ) {
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
}
Run Code Online (Sandbox Code Playgroud)
所以我们可以用它作为替代方案的基础.
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
});
});
})
Run Code Online (Sandbox Code Playgroud)
脚注 - 使用'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
});
});
Run Code Online (Sandbox Code Playgroud)
使用should而不是then在可见性测试中没有区别,但请注意should版本可以多次重试该函数,因此它不能与click测试一起使用(例如).
从文档中,
.then()和.should()/.和()之间有什么区别?
使用.then()只允许您在回调函数中使用生成的主题,并且应该在需要操作某些值或执行某些操作时使用.
另一方面,当使用.should()或.and()的回调函数时,有一个特殊的逻辑来重新运行回调函数,直到没有断言在其中抛出.您应该注意不希望多次执行的.should()或.and()回调函数中的副作用.
您也可以通过扩展chai断言来解决问题,但是这方面的文档并不广泛,因此可能更多的工作.
| 归档时间: |
|
| 查看次数: |
6179 次 |
| 最近记录: |