Cypress是一個非常流行的測驗工具,然而實際使用程序中發現一些問題,這里做些記錄,
問題發現
在 Cypress 下 click 是非常常用的指令,然而在一些特殊場景下 click 并不能如想象中那般正常作業,
比如現在有一個彈窗,我們需要測驗在點擊遮罩層時是否可以正常關閉彈窗,

測驗代碼比較簡單:
/// <reference types="cypress" />
context('Actions', () => {
beforeEach(() => {
cy.visit('http://localhost:3300/Modal');
});
it('Override', () => {
cy.get('.mantine-Button-root').click();
cy.get('.mantine-Modal-root').should('exist');
cy.get('.mantine-Modal-overlay').click();
});
});
然后執行 Cypress,發現一切如想象中那般簡單,很順利就通過了,

然而當往 Model 中填充了一些內容后,卻發現突然這里就報錯了,

當然,報錯是沒問題,遮罩層確實被內容遮擋了,問題是剛剛明明也是一樣被遮擋,為何就不報錯,只是因為內容多了一點就報錯,這就很不合適了,
查看檔案會發現 click 還支持坐標或位置引數,

然而,并沒有什么用,也就是說這個點擊位置無關,應該是和 Cypress 判斷元素遮擋有關系,看起來 Cypress 遮擋計算還需要優化,
原因排查
排查原始碼可以發現 Cypress 的 click 會經過一些判定:
if (force !== true) {
// now that we know our element isn't animating its time
// to figure out if it's being covered by another element.
// this calculation is relative from the viewport so we
// only care about fromElViewport coords
$elAtCoords =
options.ensure.notCovered && ensureElIsNotCovered(cy, win, $el, coords.fromElViewport, options, _log, onScroll);
Cypress.ensure.isNotHiddenByAncestors($el, name, _log);
}
其中比較重要的引數是 coords.fromElViewport,其數值長這樣:
{
"top": 0,
"left": 0,
"right": 1000,
"bottom": 660,
"topCenter": 330,
"leftCenter": 500,
"x": 500,
"y": 330
}
注意其中的 x 和 y,可以認為就是中心點的坐標,
然后 Cypress 會使用該坐標獲取該位置最頂層的元素:
const getElementAtPointFromViewport = function (fromElViewport) {
// get the element at point from the viewport based
// on the desired x/y normalized coordinations
let elAtCoords;
elAtCoords = $dom.getElementAtPointFromViewport(win.document, fromElViewport.x, fromElViewport.y);
if (elAtCoords) {
$elAtCoords = $dom.wrap(elAtCoords);
return $elAtCoords;
}
return null;
};
const ensureDescendents = function (fromElViewport) {
// figure out the deepest element we are about to interact
// with at these coordinates
$elAtCoords = getElementAtPointFromViewport(fromElViewport);
debug('elAtCoords', $elAtCoords);
debug('el has pointer-events none?');
ensureElDoesNotHaveCSS($el, 'pointer-events', 'none', name, log);
debug('is descendent of elAtCoords?');
ensureIsDescendent($el, $elAtCoords, name, log);
return $elAtCoords;
};
可以發現這里直接使用 x 和 y 去獲取元素,然后和當前目標元素去做了對比,
這也就是為什么 click 有時候可以點,有時候不可以的原因了,簡單說就是中心點被遮了就可以點,沒被遮就不可以點,還真是簡單粗暴 ??,這也導致了 click 的不穩定現象,
結果驗證
那我們來驗證下是不是如此,首先我們先創建一個非常小的遮擋元素,然后放在中央位置,測驗下是不是會出問題,代碼如下:
import style from './Covered-1.module.css';
const Covered = () => {
return (
<div className={style.parent} data-test-id='parent'>
<div className={style.mask} data-test-id='mask'></div>
<div className={style.child} data-test-id='child'></div>
</div>
);
};
export default Covered;
.parent {
width: 100%;
height: 100%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.mask {
background: rgb(0, 0, 0, 0.3);
position: absolute;
inset: 0;
}
.child {
background: purple;
width: 5px;
height: 5px;
z-index: 10;
}
測驗用例就點擊 mask 即可,
/// <reference types="cypress" />
context('Actions', () => {
beforeEach(() => {
cy.visit('http://localhost:3300/Covered-1');
});
it('Override', () => {
cy.get('[data-test-id="mask"]').click();
});
});
結果果然不出所料:

為了嚴謹,我們再測驗下另一個 case,我們將四周全部用元素遮擋住,只留下中心一點,然后點擊,驗證下是不是可以正常,代碼如下:
import style from './Covered-2.module.css';
const Covered = () => {
return (
<div className={style.parent} data-test-id='parent'>
<div className={style.mask} data-test-id='mask'></div>
<div className={style.child + ' ' + style.left} data-test-id='child'></div>
<div className={style.child + ' ' + style.right} data-test-id='child'></div>
<div className={style.child + ' ' + style.top} data-test-id='child'></div>
<div className={style.child + ' ' + style.bottom} data-test-id='child'></div>
</div>
);
};
export default Covered;
.parent {
width: 100%;
height: 100%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.mask {
background: rgb(0, 0, 0, 0.3);
position: absolute;
inset: 0;
}
.child {
background: purple;
z-index: 10;
position: absolute;
top: 0;
left: 0;
}
.left,
.right {
width: 49%;
height: 100%;
}
.right {
right: 0;
left: unset;
}
.top,
.bottom {
height: 49%;
width: 100%;
}
.bottom {
top: unset;
bottom: 0;
}
測驗代碼無需更改:
/// <reference types="cypress" />
context('Actions', () => {
beforeEach(() => {
cy.visit('http://localhost:3300/Covered-2');
});
it('Override', () => {
cy.get('[data-test-id="mask"]').click();
});
});
不出所料,果然可以點擊,

最后
說實在的 Cypress 這樣的遮擋檢查方式不太妥當,過于簡單粗暴而且很容易讓人困惑,理論上而言可以使用 layer 層層比對交叉區域來判定更為妥當,不知道是不是有什么檔案導致放棄了,
還有點擊的方式感覺也可以再優化一下,比如提供了坐標或者方位,那就應該以提供的坐標或方位來做遮擋判定,現在遇到這種情況只能使用 force,然而使用了 force 這個測驗的意義就少了一大半,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/552647.html
標籤:其他
下一篇:返回列表
