在赛普拉斯命令中处理多个承诺

时间:2020-02-27 16:03:08

标签: javascript cypress

我有什么

我有可以请求令牌的命令,它可以解决响应时的承诺。兑现诺言之后,我将令牌放入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()


我知道问题在于我正试图打电话给另一个未退还的诺言。但是我如何实现这样的目标?

我需要

  1. 发出tokenRequest
  2. 等待tokenResponse
  3. 获取cy.window()并设置一些sessionStorage项

编辑:

我已经找到了解决方法,并且将登录信息包装到了似乎可以正常工作的另一个函数/命令中,但是我不确定该解决方案的美观程度。

Cypress.Commands.add('loginFull', function () {
    return cy.login().then((response)=>{
        cy.window().then((window) => {
            window.sessionStorage.setItem('token', JSON.stringify(response));
        });
    });
});

2 个答案:

答案 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。因此,我认为对提取程序不应该有任何包装承诺。 编辑:我认为您可以将套接字任务包装在回调函数中。