[英]How do I wait until a cookie is set?
I am writing the acceptance tests for my application's login feature. 我正在为我的应用程序的登录功能编写验收测试。 At some point, I want to double-check the cookie's expiry time.
在某些时候,我想仔细检查Cookie的到期时间。
Upon clicking on the "Login" button, a graphql query is sent to my server which responds with a Jwt. 单击“登录”按钮后,graphql查询将发送到我的服务器,该服务器以Jwt进行响应。 Upon reception of the jwt, the application sets the cookie with
收到jwt时,应用程序将cookie设置为
document.cookie = ...
In my Cypress test, I check the token in the following way: 在赛普拉斯测试中,我通过以下方式检查令牌:
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())
})
})
})
With cy.get('@graphql')
, I am waiting for the graphql query to return a response. 使用
cy.get('@graphql')
,我正在等待graphql查询返回响应。 The alias is defined like this: 别名的定义如下:
cy.stub(win, 'fetch', fetch).as('graphql')
Upon reception, the application sets the cookie. 接收后,应用程序设置cookie。
My problem is that I am not fond of the following call: 我的问题是我不喜欢以下电话:
cy.wait(1000)
Without that call, I always get an undefined cookie. 没有那个电话,我总是得到一个未定义的cookie。
Is there a way to get that cookie within some time that might be much less than 1000 ms? 有没有办法在可能少于1000毫秒的时间内获得该Cookie? I tried many things without success...
我尝试了很多事情都没有成功...
You must write a recursive promise function, try the following 您必须编写一个递归的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())
})
})
})
Note that the function must be improved because 请注意,该功能必须改进,因为
expectedDuration
etc. (it's out of the scope of showing you how to do that) expectedDuration
等。(这超出了向您展示如何执行此操作的范围) But it works (I checked in another context before replying to you) and if you have some more troubles please share a "working" GitHub repo so I can clone and check it with your own solution. 但是它可以工作(我在回复您之前在其他上下文中进行了检查),如果您还有其他麻烦,请共享一个“有效的” GitHub存储库,以便我可以克隆并使用您自己的解决方案进行检查。
Let me know if it isn't enough clear 😉 让我知道是否不够清楚😉
UPDATE 更新
We ( me and Tommaso ) have written a plugin to help you with this kind of checks, its name is cypress-wait-until . 我们( 我和Tommaso )已经写了一个插件来帮助您进行这种检查,它的名称是cypress-wait-until 。
Please thank the Open Source Saturday community for that, we developed it during one of them Saturdays 😊 请为此感谢Open Source Saturday社区,我们在其中一个星期六(星期六)开发了它。
I dont like the timeout in this i have to say for dom changes. 我不喜欢超时,我不得不为dom更改而说。 I have come up with this solution based on @NoriSte Answer together with DomMutation Observers.
我已经提出了基于@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"]) );
Based on @NoriSte's answer, I came up with the following working code: 基于@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)
})
}
I transformed that into an ES6 class that I find a bit more elegant: 我将其转换为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)
})
}
}
and reworked my step like this: 然后像这样重做我的步骤:
cy.get('@graphql').then(() => {
const handler = new TokenHandler
handler.getToken().then(token => {
const tokenDuration = getTokenDuration(token)
expect(tokenDuration.asSeconds()).to.equal(expectedDuration.asSeconds())
})
})
This is working perfectly, thanks. 这工作得很好,谢谢。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.