背景
我使用3台后端服务器为我的一个在线SaaS应用程序提供容错能力。所有重要的API调用(例如获取用户数据)都与所有3台服务器联系,并使用第一个成功解决的响应的值(如果有)。
export function getSuccessValueOrThrow$<T>(
observables$: Observable<T>[],
tryUntilMillies = 30000,
): Observable<T> {
return race(
...observables$.map(observable$ => {
return observable$.pipe(
timeout(tryUntilMillies),
catchError(err => {
return of(err).pipe(delay(5000), mergeMap(_err => throwError(_err)));
}),
);
})
);
}
getSuccessValueOrThrow $的调用如下:
const shuffledApiDomainList = ['server1-domain', 'server2-domain', 'server3-domain';
const sessionInfo = await RequestUtils.getSuccessValueOrThrow(
...(shuffledApiDomainList.map(shuffledDomain => this.http.get<SessionDetails>(`${shuffledDomain}/file/converter/comm/session/info`))),
).toPromise();
注意:如果一个请求的解析速度比其他请求快,通常,race
rxjs函数将取消其他两个请求。在Chrome开发者网络标签上,它看起来像下面,由于太慢而取消了发出的第一个请求。
问题:
我使用 / file / converter / comm / session / info (简称为Endpoint 1)来获取与用户相关的一些数据。该请求分派给所有3个后端服务器。如果一个解决,则剩余的2个请求将被取消,即它们将返回null。
在我的Cypress E2E测试中,
cy.route('GET', '/file/converter/comm/session/info').as('getSessionInfo');
cy.visit('https://www.ps2pdf.com/compress-mp4');
cy.wait('@getSessionInfo').its('status').should('eq', 200)
如果因为将getSessionInfo别名挂接到了某个请求而最终被getSuccessValueOrThrow$
取消,则有时会失败,因为不是成功的请求。下图显示了如何获得别名为getSessionInfo的3个请求中的1个成功但由于第一个请求失败,所以测试失败。
在赛普拉斯中,如何等待成功,即状态= 200请求?
答案 0 :(得分:0)
cy.wait()
产生一个对象,其中包含XHR的HTTP请求和响应属性。您得到的错误是因为您正在XHR对象中寻找属性status
,但这是Response Object的属性。您首先必须转到响应对象:
cy.wait('@getSessionInfo').should(xhr => {
expect(xhr.response).to.have.property('status', 200);
});
编辑:由于我们的后端使用graphql,因此所有调用都使用单个/graphql
端点。因此,我不得不提出一种解决方案,以区分每个呼叫。
我通过使用onResponse()
的{{1}}方法并在赛普拉斯environment对象中累积数据来做到这一点:
cy.route()
然后您可以像这样使用它:
cy.route({
method: 'GET',
url: '/file/converter/comm/session/info',
onResponse(xhr) {
if (xhr.status === 200) {
Cypress.env('sessionInfo200') = xhr;
}
}
})
答案 1 :(得分:0)
方法1
如果状态不是200,请使用.should()
回调并重复cy.wait
调用:
function waitFor200(routeAlias, retries = 2) {
cy.wait(routeAlias).then(xhr => {
if (xhr.status === 200) return // OK
else if (retries > 0) waitFor200(routeAlias, retries - 1); // wait for the next response
else throw "All requests returned non-200 response";
})
}
// Usage example.
// Note that no assertions are chained here,
// the check has been performed inside this function already.
waitFor200('@getSessionInfo');
// Proceed with your test
cy.get('button').click(); // ...
方法2
首先修改要测试的内容。 可能-页面上有一些内容告诉用户成功的操作。例如。显示/隐藏微调器或进度条,或者仅显示页面内容以显示从后端获取的新数据。
因此,通过这种方法,您将完全删除cy.wait()
,并专注于用户在页面上看到的内容-对实际页面内容进行断言。
答案 2 :(得分:0)
我这样等待:
const isOk = cy.wait("@getSessionInfo").then((xhr) => {
return (xhr.status === 200);
});