如何等待直到设置了cookie?

时间:2019-02-17 11:34:44

标签: javascript cookies cucumber graphql cypress

我正在为应用程序的登录功能编写验收测试。在某些时候,我想仔细检查Cookie的到期时间。

单击“登录”按钮后,会将graphql查询发送到我的服务器,该服务器以Jwt进行响应。收到jwt时,应用程序使用

设置cookie。
Then("sa session s'ouvre pour {SessionDurationType}", expectedDuration => {
  cy.get('@graphql').then(() => {
    cy.wait(1000)
    cy.getCookie('token').then(cookie => {
      const tokenDuration = getTokenDuration(cookie.value)
     expect(tokenDuration.asSeconds()).to.equal(expectedDuration.asSeconds())
    })
  })
})

在赛普拉斯测试中,我通过以下方式检查令牌:

cy.get('@graphql')

使用cy.stub(win, 'fetch', fetch).as('graphql') ,我正在等待graphql查询返回响应。别名的定义如下:

cy.wait(1000)

应用程序收到消息后将设置cookie。

我的问题是我不喜欢以下电话:

{{1}}

没有那个电话,我总是得到一个未定义的cookie。

是否有一种方法可以在短于1000毫秒的时间内获得该Cookie?我尝试了很多事情都没有成功...

3 个答案:

答案 0 :(得分:1)

您必须编写一个递归承诺函数,请尝试以下操作

function checkCookie() {
  // cy.getCookie returns a thenebale
  return cy.getCookie('token').then(cookie => {
    const tokenDuration = getTokenDuration(cookie.value);
    // it checks the seconds right now, without unnecessary waitings
    if(tokenDuration.asSeconds() !== expectedDuration.asSeconds()) {
      // waits for a fixed milliseconds amount
      cy.wait(100);
      // returns the same function recursively, the next `.then()` will be the checkCookie function itself
      return checkCookie();
    }
    // only when the condition passes returns a resolving promise
    return Promise.resolve(tokenDuration.asSeconds());
  })
}

Then("sa session s'ouvre pour {SessionDurationType}", expectedDuration => {
  cy.get('@graphql').then(() => {
    checkCookie()
      .then(seconds => {
        expect(seconds).to.equal(expectedDuration.asSeconds())
      })
  })
})

请注意,必须改进此功能,因为

  • 我没有参数化expectedDuration等(这超出了向您展示如何执行此操作的范围)
  • 它会一直等待,而无需循环计数器检查

但是它可以工作(我在回复您之前在其他上下文中进行了检查),如果还有其他麻烦,请共享一个“有效的” GitHub存储库,以便我可以克隆并使用您自己的解决方案进行检查。

让我知道它是否不够清晰

更新

我们(meTommaso)已编写了一个插件来帮助您进行这种检查,其名称为cypress-wait-until

为此,感谢Open Source Saturday社区,我们在其中一个星期六(星期六)开发了该社区

答案 1 :(得分:1)

我不喜欢超时,我不得不说要更改dom。我已经提出了基于@NoriSte Answer和DomMutation观察者的解决方案。

   getFileUploadItem().get(".upload-item--state i")
    .should("have.class", "ngx-fileupload-icon--start")
    .then(item => {
        const iconEl = item.get(0);
        const states: string[] = [];

        return new Promise((resolve, reject) => {
          const observer = new MutationObserver((mutations: MutationRecord[]) => {
              const mutationEl = mutations[0].target as HTMLElement;
              const className  = mutationEl.getAttribute("class");

              states.push(className);

              if (className === "ngx-fileupload-icon--uploaded") {
                  resolve(states);
              }
          });

          observer.observe(iconEl, {
              subtree: true,
              attributes: true,
              attributeFilter: ["class"]
          });
        });
    })
    .then((value) => expect(value).to.deep.equal(
      ["ngx-fileupload-icon--progress", "ngx-fileupload-icon--uploaded"])
    );

答案 2 :(得分:0)

基于@NoriSte的回答,我想到了以下工作代码:

function awaitNonNullToken(elapsedTimeInMs = 0) {
  let timeDeltaInMs = 10

  if (elapsedTimeInMs > Cypress.env('timeoutInMs')) {
    return Promise.reject(new Error('Awaiting token timeout'))
  }

  return getTokenCookie().then(cookie => {
    if (cookie === null) {
      cy.wait(timeDeltaInMs)
      elapsedTimeInMs += timeDeltaInMs
      return awaitNonNullToken(elapsedTimeInMs)
    }
    return Promise.resolve(cookie.value)
  })
}

我将其转换为ES6类,我发现它更加优雅:

class TokenHandler {
  constructor () {
    this.TIME_DELTA_IN_MS = Cypress.env('timeDeltaInMs')
    this.TIMEOUT_IN_MS = Cypress.env('timeoutInMs')
    this.elapsedTimeInMs = 0
  }

  getToken () {
    if (this.elapsedTimeInMs > this.TIMEOUT_IN_MS) {
      return Promise.reject(new Error('Awaiting token timeout'))
    }
    return getTokenCookie().then(cookie => {
      if (cookie === null) {
        cy.wait(this.TIME_DELTA_IN_MS)
        this.elapsedTimeInMs += this.TIME_DELTA_IN_MS
        return this.getToken()
      }
      return Promise.resolve(cookie.value)
    })
  }
}

像这样重做我​​的步骤:

cy.get('@graphql').then(() => {
  const handler = new TokenHandler
  handler.getToken().then(token => {
    const tokenDuration = getTokenDuration(token)
    expect(tokenDuration.asSeconds()).to.equal(expectedDuration.asSeconds())
  })
})

这很好,谢谢。