如何配置赛普拉斯等待更长时间(或无限期)的 BaseUrl?



我在docker-compose.yml中使用此赛普拉斯图像来运行端到端测试:cypress/included:6.1.0

当测试运行程序启动时,它将验证是否可以在baseUrl处访问服务器。 如果没有,它会重试 3 次。

我的服务和 Web 服务器需要更多时间才能启动。

如何增加此检查的超时和/或重试次数。

最好,就我而言,我想要一个重试直到成功的策略,即无限期重试/等待。

我已经检查了超时部分和更一般的cypress.json文档。但是,这些超时或重试似乎都与此行为无关。

有这个设置吗?


澄清一下:这不是我作为规范的一部分实施(或想要)的检查。据我所知,这是cyprus run的一个功能,图像中的默认命令。 如果可能的话,我想在不添加或修改测试本身的情况下对其进行配置。

以下是 cypress 在容器中启动时的 docker-compose 控制台输出:

cypress_1         | Cypress could not verify that this server is running:
cypress_1         |
cypress_1         |   > http://localhost:5000
cypress_1         |
cypress_1         | We are verifying this server because it has been configured as your `baseUrl`.
cypress_1         |
cypress_1         | Cypress automatically waits until your server is accessible before running tests.
cypress_1         |
cypress_1         | We will try connecting to it 3 more times...
cypress_1         | We will try connecting to it 2 more times...
cypress_1         | We will try connecting to it 1 more time...
cypress_1         |
cypress_1         | Cypress failed to verify that your server is running.
cypress_1         |
cypress_1         | Please start this server and then run Cypress again.
cypress_1 exited with code 1

在使用等待或启动服务器和测试等实用程序调用cypress run之前,应确保服务器正在运行。

赛普拉斯对baseUrl的检查是最后的礼貌检查,这样您就不会在未运行的服务器上运行整个测试套件。

有关在运行 Cypress之前确保服务器正在运行的提示,请查看此处的 Cypress 文档:https://on.cypress.io/continuous-integration#Boot-your-server

免责声明

@jennifer-shehane 是正确的;在大多数情况下,您应该确保服务器在启动 cypress 之前正在运行。

然而

我们主要使用 Cypress 进行 API 测试(目前),我们需要支持的工作流程之一包括服务器重启。当然,我们可以在继续下一步之前输入任意长的cy.wait(30000);,但这是不优雅的,可能会浪费大量时间,特别是如果你像我一样,最终一遍又一遍地运行测试。

由于 Cypress 实际上并没有以我们通常习惯的异步方式工作,因此我们想出的解决方案是使用任务。

将此添加到plugins/index.js

const https = require("https");
const { URL } = require("url");
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
require('@cypress/code-coverage/task')(on, config)
on("task", {
async waitForServerResponse({ server_url }) {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function makeRequest({ hostname, port, path }) {
return new Promise((resolve, reject) => {
const options = {
hostname,
port,
path,
body: {},
method: 'POST'
}
const req = https.request(options, response => {
response.on('data', d => {
resolve(d.toString());
});
});
req.on('error', error => {
reject(error);
});

req.end();
});
}
async function recursiveGet(retry = 1) {
try {
const res = await makeRequest({ hostname, port, path });
if (res?.code?.includes("ECONNREFUSED") || res?.code?.includes("ECONNRESET")) {
await sleep(1000);
await recursiveGet(retry + 1);
}
}
catch(error) {
if (error?.code?.includes("ECONNREFUSED") || error?.code?.includes("ECONNRESET")) {
await sleep(1000);
await recursiveGet(retry + 1);
}
}
}
if (!server_url) {
server_url = config.baseUrl;
}
const parsedUrl = new URL(server_url);
const hostname = parsedUrl?.hostname ?? "localhost";
const port = parsedUrl?.port ?? 443;
const path = parsedUrl?.pathname ?? "/";
return new Promise(async (resolve, reject) => {
// tasks should not resolve with undefined
setTimeout(() => reject(new Error("Timeout")), 60000);
await recursiveGet();
resolve(true);
});
}
});
return config;
};

并在测试中调用它:

it("Restarts the server", () => {
// Restart the server
cy.systemRestart().then(({ body, status }) => { // server returns success before actually restarting
expect(status).to.equal(200);
expect(body).property("success").to.eq(true);
cy.wait(1000); // initial wait 
cy.task("waitForServerResponse", { server_url: server_url + "/auth/token" });
cy.login();
cy.adminIndex().then(({ body, status }) => {
if (body?.properties) {
expect(status).to.equal(200);
expect(body).property("properties").to.be.a("object");
const bootedAt = new Date(body.properties.system.bootedAt).getTime();
const now = new Date().getTime();
const diff = Math.ceil(Math.abs(now - bootedAt) / 1000); // ms -> s
expect(diff).to.be.lessThan(20); // seconds
}
});
});
});

这将轮询服务器(任何给定的端点,我选择了/auth/token),如果连接被拒绝或重置,它将等待 1 秒并重试。该任务仅在收到来自服务器的响应后才会返回。

最新更新