我在Cypress support / index.js中有一个函数,该函数旨在获取cy.document
outerWidth
和outerHeight
的尺寸,然后将其返回以供将来在测试中使用。我的问题是,当测试运行并且将值与其他值进行比较时,断言说值是NaN
。我通过控制台检查了声明点的值,该值是空的,因此我必须做错了什么,我不确定是什么。我的职责如下,非常感谢您的帮助。
function getViewport() {
var viewport = {}
cy.document().then((doc) => {
let width = Cypress.$(doc).outerWidth()
let height = Cypress.$(doc).outerHeight()
viewport['bottom'] = height
viewport['height'] = height
viewport['left'] = 0
viewport['right'] = width
viewport['top'] = 0
viewport['width'] = width
viewport['x'] = 0
viewport['y'] = 0
}).then(() => {
return viewport
})
return viewport
}
调用getViewport()
的代码是
export const getRect = (obj) => {
var rect
if (obj == 'viewport') {
rect = getViewport()
} else {
rect = getElement(obj)
if (Cypress.config('parseLayoutToInt')) { rect = parseAllToInt(rect) }
}
return rect
}
这是由自定义命令调用的,其中subject
是prevSubject
,元素是字符串“ viewport”
Cypress.Commands.add('isInside', { prevSubject: true }, (subject, element, expected) => {
var minuend, subtrahend, diff
minuend = getRect(element)
subtrahend = getRect(subject)
diff = getRectDiff(minuend, subtrahend, expected);
expect(diff).to.deep.equal(expected);
})
答案 0 :(得分:2)
就像@NoriSte所说的,cy
命令是异步的,因此您不能将它们与同步代码混合使用。
您要执行的操作类似于:
function getViewport() {
return cy.document().then( doc => {
rect = /* do something synchronous */
return rect;
});
}
无论如何,为了回答原始问题(在标题中),我使用了两种模式来存储值以供以后在赛普拉斯中使用:
在then
回调中包装下一个命令:
cy.document().then( doc => {
return doc.documentElement.getBoundingClientRect();
}).then( viewportRect => {
cy.doSomething(viewportRect);
cy.doSomethingElse();
});
缓存到变量并从排队的命令内部访问缓存的值:
let viewportRect;
cy.document().then( doc => {
return doc.documentElement.getBoundingClientRect();
}).then( rect => viewportRect = rect );
cy.doSomething();
// this is important -- you need to access the `viewportRect`
// asynchronously, else it will be undefined at the time of access
// because it's itself assigned asynchronously in the first command'd callback
cy.then(() => {
doSomething(viewportRect);
});
在您的问题中提出实际问题(如果我正确理解的话),我已经制定了解决方案,您可以从中学习:
const getRect = (selector) => {
if (selector == 'viewport') {
return cy.document().then( doc => {
return doc.documentElement.getBoundingClientRect();
});
} else if ( typeof selector === 'string' ) {
return cy.get(selector).then( $elem => {
return $elem[0].getBoundingClientRect();
});
// assume DOM elem
} else {
return cy.wrap(selector).then( elem => {
return Cypress.$(elem)[0].getBoundingClientRect();
});
}
};
const isInside = (containerRect, childRect) => {
if ( !containerRect || !childRect ) return false;
return (
childRect.top >= containerRect.top &&
childRect.bottom <= containerRect.bottom &&
childRect.left >= containerRect.left &&
childRect.right <= containerRect.right
);
};
Cypress.Commands.add('isInside', { prevSubject: true }, (child, container, expected) => {
return getRect(child).then( childRect => {
getRect(container).then( containerRect => {
expect(isInside(containerRect, childRect)).to.equal(expected);
});
});
});
describe('test', () => {
it('test', () => {
cy.document().then( doc => {
doc.body.innerHTML = `
<div class="one"></div>
<div class="two"></div>
<style>
.one, .two {
position: absolute;
}
.one {
background: rgba(255,0,0,0.3);
width: 400px;
height: 400px;
}
.two {
background: rgba(0,0,255,0.3);
width: 200px;
height: 200px;
}
</style>
`;
});
cy.get('.two').isInside('.one', true);
cy.get('.one').isInside('.two', false);
});
it('test2', () => {
cy.document().then( doc => {
doc.body.innerHTML = `
<div class="one"></div>
<div class="two"></div>
<style>
body, html { margin: 0; padding: 0 }
.one, .two {
position: absolute;
}
.one {
background: rgba(255,0,0,0.3);
width: 400px;
height: 400px;
}
.two {
background: rgba(0,0,255,0.3);
width: 200px;
height: 200px;
left: 300px;
}
</style>
`;
});
cy.get('.two').isInside('.one', false);
cy.get('.one').isInside('.two', false);
});
it('test3', () => {
cy.document().then( doc => {
doc.body.innerHTML = `
<div class="one"></div>
<style>
body, html { margin: 0; padding: 0 }
.one {
position: absolute;
background: rgba(255,0,0,0.3);
width: 400px;
height: 400px;
left: -100px;
}
</style>
`;
});
cy.get('.one').isInside('viewport', false);
});
});
答案 1 :(得分:0)
为什么您的getViewport
函数中存在同步返回?我说的是最后一个return viewport
function getViewport() {
var viewport = {}
cy.document().then((doc) => {
...
})
return viewport // <-- ?????
}
这样做,所有cy.document().then((doc)
等代码都是无用的。
我不知道这是否是问题,但是我无法在本地运行您的代码,因为它缺少许多功能。您可以共享一个“工作中”的GitHub存储库以进行更多测试吗?
答案 2 :(得分:0)
我也遇到了这个问题,并选择了async / await解决方案:
function getDocument() {
return new Promise(resolve => {
cy.document().then(d => {
console.log('deeee', d);
resolve(d);
});
});
}
describe('Stuff', () => {
it('Sees the toasty character', async () => {
const document = await getDocument();
// Your test code here
});
});
即使赛普拉斯命令并不是真正的承诺,您也可以创建自己的承诺,并在准备好时解决它。然后await
在您的测试代码中承诺。
希望有帮助!