【问题标题】:How do I wait until a cookie is set?如何等到设置 cookie?
【发布时间】:2019-07-10 23:36:20
【问题描述】:

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

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

设置 cookie
document.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'),我正在等待graphql 查询返回响应。别名是这样定义的:

cy.stub(win, 'fetch', fetch).as('graphql')

收到后,应用程序会设置 cookie。

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

cy.wait(1000)

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

有没有办法在可能远小于 1000 毫秒的时间内获取该 cookie?我尝试了很多事情都没有成功...

【问题讨论】:

    标签: javascript cookies cucumber graphql cypress


    【解决方案1】:

    你必须写一个递归的promise函数,试试下面的

    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 社区,我们在其中一个星期六开发了它?

    【讨论】:

      【解决方案2】:

      根据@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())
        })
      })
      

      这很好用,谢谢。

      【讨论】:

        【解决方案3】:

        我不喜欢这里的超时,我不得不说 dom 更改。我已经根据@NoriSte Answer 和 DomMutation Observers 提出了这个解决方案。

           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"])
            );

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-02-06
          • 1970-01-01
          • 2011-05-16
          • 2012-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多