关于前端:Cypress-踩坑记-DOM-遮挡

41次阅读

共计 4064 个字符,预计需要花费 11 分钟才能阅读完成。

Cypress 是一个十分风行的测试工具,然而理论应用过程中发现一些问题,这里做些记录。

问题发现

Cypressclick 是十分罕用的指令,然而在一些非凡场景下 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 遮挡计算还须要优化。

起因排查

排查源码能够发现 Cypressclick 会通过一些断定:

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
}

留神其中的 xy,能够认为就是中心点的坐标。

而后 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;
};

能够发现这里间接应用 xy 去获取元素,而后和以后指标元素去做了比照。

这也就是为什么 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 这个测试的意义就少了一大半。

正文完
 0