如何在赛普拉斯测试中等待成功的响应

时间:2020-05-11 00:53:14

标签: cypress e2e-testing

背景

我使用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开发者网络标签上,它看起来像下面,由于太慢而取消了发出的第一个请求。

enter image description here

问题:

我使用 / 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个成功但由于第一个请求失败,所以测试失败。

enter image description here

在赛普拉斯中,如何等待成功,即状态= 200请求?

3 个答案:

答案 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);
});