admin管理员组

文章数量:1332383

I am using this Cypress image in a docker-pose.yml to run end to end tests: cypress/included:6.1.0

When the test runner starts it will verify that a server can be reached at baseUrl. If not, it retries 3 times.

My services and web server need a little more time to start.

How can I increase the timeout and/or number of retries for this check.

Preferably, in my case I'd like a retry-until-success policy, i.e. indefinite retries/wait.

I have checked the Timeouts section and the cypress.json documentation more generally. However none of those timeouts or retries seem to relate to this behavior.

Is there a setting for this?


TO CLARIFY: This is not a check I implemented (or want to) as part of my specs. This is, as far as I can tell so far, a feature of cyprus run, the default mand in the image. If possible I would like to configure this without adding to or revising the tests themselves.

Here is the docker-pose console output when cypress starts in the container:

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

I am using this Cypress image in a docker-pose.yml to run end to end tests: cypress/included:6.1.0

When the test runner starts it will verify that a server can be reached at baseUrl. If not, it retries 3 times.

My services and web server need a little more time to start.

How can I increase the timeout and/or number of retries for this check.

Preferably, in my case I'd like a retry-until-success policy, i.e. indefinite retries/wait.

I have checked the Timeouts section and the cypress.json documentation more generally. However none of those timeouts or retries seem to relate to this behavior.

Is there a setting for this?


TO CLARIFY: This is not a check I implemented (or want to) as part of my specs. This is, as far as I can tell so far, a feature of cyprus run, the default mand in the image. If possible I would like to configure this without adding to or revising the tests themselves.

Here is the docker-pose console output when cypress starts in the container:

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

Share Improve this question edited Dec 10, 2021 at 11:12 Douglas Reid asked Dec 18, 2020 at 14:19 Douglas ReidDouglas Reid 3,8086 gold badges33 silver badges50 bronze badges 3
  • 4 Take a look at start-server-and-test - you can start the server, wait for a url to respond, then run tests – user9161752 Commented Dec 19, 2020 at 1:13
  • 1 Seconded on start-server-and-test. Another option is wait-on i.e., wait-on http://localhost:5000 && cypress run in the package.json scripts – jayg_code Commented Dec 19, 2020 at 3:51
  • Thanks @HiramK.Hackenbacker, et al. Planning to try start-server-and-test / wait-on soon. – Douglas Reid Commented Dec 19, 2020 at 4:32
Add a ment  | 

2 Answers 2

Reset to default 5

You should ensure your server is running before calling cypress run using a utility like wait-on or start-server-and-test.

Cypress's check on the baseUrl is a final courtesy check just so you don't run through your whole test suite on a server that is not running.

For tips on ensuring your server is running before running Cypress, check out the Cypress docs here: https://on.cypress.io/continuous-integration#Boot-your-server

Disclaimer

@jennifer-shehane is correct; in most cases you should ensure that the server is running before starting cypress.

However

We're using Cypress primarily for API testing (for now), and one of the workflows we need to support includes a server restart. Of course, we could just drop in an arbitrarily long cy.wait(30000); before moving on to the next step, but that's inelegant and can waste a lot of time, especially if you're like me and end up running the tests over and over.

Since Cypress doesn't really work in the same asynchronous way we're usually accustomed to, the solution we came up with is to use a task.

Add this to 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;
};

and call it in your test:

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

This will poll the server (any given endpoint, I chose /auth/token) and if the connection is refused or reset, it will wait for 1 second and try again. The task will only return once it receives a response from the server.

本文标签: javascriptHow To Configure Cypress To Wait Longer (or Indefinitely) for BaseUrlStack Overflow