cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.43k stars 3.14k forks source link

Allow for the browser caching of files during tests #18335

Open mellis481 opened 2 years ago

mellis481 commented 2 years ago

What would you like?

The ability to browser cache files in Cypress tests.

Why is this needed?

In applications that leverage the microfrontend architecture, each microfrontend has a single entry point (.js file). In many cases, this single .js file includes everything in that module and it can be somewhat large. Code splitting is possible, but it does not fully mitigate the problem described below.

An application that uses the microfrontend architecture relies heavily on browser caching. Each *.js file is versioned with a unique URL and has a cache-control header with a large max-age ie. it's browser cached for a long time. This means that the initial load time of a new version of a microfrontend is long, but subsequent loads in a browser are fast.

Since browser caching files is not possible in Cypress tests, every Cypress test (it block) for a microfrontend has a long initial load time because it's downloading the *.js file in full and not retrieving it from browser cache. Having Cypress tests always taking a long time to execute is quite suboptimal.

Other

No response

alesbrelih commented 2 years ago

@mellis481 Did you figure something out about this problem? I'm having the same issue inside docker container 🤔

mellis481 commented 2 years ago

@alesbrelih Nope.

mellis481 commented 2 years ago

@jennifer-shehane Are you able to speak to this topic?

wasong commented 2 years ago

Came across this issue as well. My js bundles are identical and loading them is 80% of the test duration.

josh803316 commented 2 years ago

Are there any recommended ways around this? We are also noticing that our Github actions cypress tests are slow and a great deal of the time is spent downloading assets over and over.

pmk1c commented 2 years ago

When using Vite, you can use the following configuration to massively speed up your Cypress Component Tests:

import { startDevServer } from "@cypress/vite-dev-server";

export default (on, config) => {
  on("dev-server:start", async (options) => {
    const enableBrowserCache = !!process.env.CYPRESS_VITE_BROWSER_CACHE;

    return startDevServer({
      options,
      viteConfig: {
        server: {
          headers: enableBrowserCache
            ? {
                "cache-control": "max-age=31536000,immutable",
              }
            : undefined,
        },
      },
    });
  });

  return config;
};

Vite already uses this cache-control setting for loading node_modules. We use the same setting for all files now, so the browser does not even attempt to load all needed JS modules on every test run, since only the attempt takes some time, even if Vite tells the browser to use its cache in the response. We set the environment variable CYPRESS_VITE_BROWSER_CACHE only when running all Tests at once in CI mode. When using the Cypress UI locally while developing, you don't want this heavy browser cache, since changes in your files would not get picked up.

With this configuration, testing ~100 components went from taking 4-5 minutes on CI to 1 minute.

Edit: This does not seem to work anymore with Cypress 10 though, which is quite frustrating. We can set the same options in cypress.config.ts, but since Cypress 10 seems to launch a new browser for every spec, the cache is invalidated between specs. Is this intended behaviour?

mellis481 commented 2 years ago

@pmk1c Thanks for sharing. I had not come across Vite before. In the microfrontend ecosystem, each microfrontend does not have an .html file (there is only one .html file in the entire ecosystem). From what I was able to quickly read in their documentation, Vite is entirely based on the entry point being one or more *.html files so Vite will not work for single-spa-based microfrontends.

lems3 commented 1 year ago

Edit: This does not seem to work anymore with Cypress 10 though, which is quite frustrating. We can set the same options in cypress.config.ts, but since Cypress 10 seems to launch a new browser for every spec, the cache is invalidated between specs. Is this intended behaviour?

My current understanding is that yes, it is the intended behavior.

The way we more or less went around the issue for now is to call cy.visit() in our before() hook instead of a beforeEach().

We change the testIsolation parameter to false, and call the clear AllCookies/LocalStorage/AllSessionStorage functions manually in our before() function. This way, each time we run our spec file we make sure to have a clean browser session, but each test in the spec file uses the same browser window.

It may not fit your need, our test are non-destructive and always ends up by testing if anything we triggered (like a pop-up) can be closed properly.

emilyrohrbough commented 1 year ago

Can you please provide a minimal example of where this is behaving unexpectedly? Cypress does not clear the browser cache between tests, only between specs, so it sounds like something else may be at play here.

amakhrov commented 4 months ago

We also observe that. cache-control seems ignored in e2e tests - both with Chrome and Electron

RockChild commented 2 months ago

We also observe that. cache-control seems ignored in e2e tests - both with Chrome and Electron

Similar issue. I tried to set Cache-control header when overwriting the visit and it seems to not be set.

Cypress.Commands.overwrite('visit', (originalFn, url, options={}) => {
  const pageUrl = new URL(url);
  options.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate';
  return originalFn(pageUrl.toString(), options);
});

When I run the test and check Request headers in the network, the cache-control is set by default image