我有可以请求令牌的命令,它可以解决响应时的承诺。兑现诺言之后,我将令牌放入SomeTest.js中的sessionStorage中。 它有效。但是我必须在每次测试中都使用完全相同的cy.window()...
。
SomeTest.js:
before(()=>{
cy.login().then(res=>
cy.window().then((window) => {
window.sessionStorage.setItem('token', JJSON.stringify(res))
})
);
});
commands.js中的命令
Cypress.Commands.add('login', function () {
fetcher.emit('tokenRequest',{email:'dummy@mail.com', password:'dummy'});
return new Cypress.Promise((resolve, reject) => {
fetcher.on('onTokenResponse',function(response) {
resolve(response);
});
});
});
我也想在命令login()
中设置sessionStorage。
SomeTest.js:
before(()=>{
cy.login();
});
commands.js中的命令
Cypress.Commands.add('login', function () {
fetcher.emit('tokenRequest',{email:'dummy@mail.com', password:'dummy'});
return new Cypress.Promise((resolve, reject) => {
fetcher.on('onTokenResponse',function(response) {
cy.window().then((window) => {
window.sessionStorage.setItem('token', JSON.stringify(response));
resolve(response);
})
});
});
});
但是它会引发错误:Uncaught CypressError: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.
,The cy command you invoked inside the promise was:> cy.window()
。
我知道问题在于我正试图打电话给另一个未退还的诺言。但是我如何实现这样的目标?
我需要
tokenRequest
tokenResponse
cy.window()
并设置一些sessionStorage项我已经找到了解决方法,并且将登录信息包装到了似乎可以正常工作的另一个函数/命令中,但是我不确定该解决方案的美观程度。
Cypress.Commands.add('loginFull', function () {
return cy.login().then((response)=>{
cy.window().then((window) => {
window.sessionStorage.setItem('token', JSON.stringify(response));
});
});
});
答案 0 :(得分:2)
一种有效的方法是将cy.window()
命令移到自定义命令的最外层,因此您不会尝试在Promise中使用它。
测试
describe('web socket event handler', () => {
let fetcher;
before(() => {
const io = require('socket.io-client');
fetcher = io.connect('http://127.0.0.1:5000');
cy.window().then(win => {
win.sessionStorage.clear(); // ensure clean before test
})
})
Cypress.Commands.add('login', function () {
cy.window().then(win => {
fetcher.emit('tokenRequest',{email:'dummy@mail.com', password:'dummy'});
return new Cypress.Promise((resolve, reject) => {
fetcher.on('onTokenResponse',function(response) {
win.sessionStorage.setItem('token', JSON.stringify(response));
return resolve(response);
});
});
});
});
it('waits for token', () => {
cy.login().then(_ => {
cy.window().then(win => {
console.log(win.sessionStorage.getItem('token'))
// logs "Response: dummy@mail.com"
})
})
})
})
服务器
io.on('connection', function(socket){
socket.on('tokenRequest', function(msg){
setTimeout(() => {
io.emit('onTokenResponse', `Response: ${msg.email}`);
}, 2000)
});
});
理想情况是希望使登录命令在fetcher事件上等待(有超时时间?)。
我尝试过这种方法Spying on the DOM API,但到目前为止还没有运气。
另一种方法是在事件侦听器中设置一个标志,并将命令添加到等待它的队列中。
Cypress.Commands.add('login', function () {
cy.window().then(win => {
fetcher.emit('tokenRequest',{email:'dummy@mail.com', password:'dummy'});
let flag = { done: false };
fetcher.on('onTokenResponse',function(response) {
win.sessionStorage.setItem('token', JSON.stringify(response));
flag.done = true;
})
cy.wrap(flag).its('done').should('equal', true); // wait here until done
});
});
现在您可以同步调用登录
it('waits for token', () => {
cy.login();
cy.window().then(win => {
console.log(win.sessionStorage.getItem('token'))
// logs "Response: dummy@mail.com"
})
})
答案 1 :(得分:1)
Cypress.Commands.add('login', function () {
function waitForSocket(callback) {
fetcher.emit('tokenRequest',{email:'dummy@mail.com', password:'dummy'});
fetcher.on('onTokenResponse',function(response) {
callback(response);
});
}
waitForSocket((res) => {
cy.window().then((window) => {
window.sessionStorage.setItem('token', JJSON.stringify(res))
})
})
});
错误指出:Cypress commands are already promises and they will wait/resolve themselves。因此,我认为对提取程序不应该有任何包装承诺。 编辑:我认为您可以将套接字任务包装在回调函数中。