Can't get puppeteer/chromium to cache assets

Viewed 106

I have a huge number of jest tests which use puppeteer and jest-environment-puppeteer to load a SPA, then drive certain interactions. The tests take a very long time to run, and after a lot of investigation it seems that a substantial portion of time is taken by the headless browser reloading the page and assets for every test. Since none of this will ever change within the context of a test run, it seems like a lot of wasted effort, so I'm trying to get chromium to cache the page and assets.

The approach the tests use is to create a single browser instance, then load a new page for each test, using request interception to give canned responses (including the static assets). Here is the puppeteer config:

module.exports = {
  launch: {
    executablePath: '/usr/bin/chromium-browser',
    dumpio: true,
    args: [
      '--disable-software-rasterizer',
      '--disable-gpu',
      '--no-sandbox',
      '--remote-debugging-port=9222',
      '--remote-debugging-address=0.0.0.0',
      '--no-zygote',
      '--window-size=1280,1024',
      '--hide-scrollbars',
      '--no-default-browser-check',
      '--no-startup-window',
      '--disable-smooth-scrolling',
      '--enable-font-antialiasing',
      '--disable-background-networking',
      '--disable-background-timer-throttling',
      '--disable-backgrounding-occluded-windows',
      '--disable-boot-animation',
      '--disable-breakpad',
      '--disable-client-side-phishing-detection',
      '--disable-component-extensions-with-background-pages',
      '--disable-default-apps',
      '--disable-dev-shm-usage',
      '--disable-extensions',
      '--disable-features=site-per-process',
      '--disable-hang-monitor',
      '--disable-ipc-flooding-protection',
      '--disable-low-res-tiling',
      '--disable-popup-blocking',
      '--disable-prompt-on-repost',
      '--disable-renderer-backgrounding',
      '--disable-sync',
      '--disable-translate',
      '--metrics-recording-only',
      '--no-first-run',
      '--safebrowsing-disable-auto-update',
      '--password-store=basic',
      '--use-mock-keychain',
    ],
  },
  browserContext: 'default',
};

Within the intercepting request handler, I'm setting Cache-Control: max-age=604800 in the responses with code that looks like this:

async handleRequest(request) {
    const url = request.url();
    const method = request.method();

    const asset = this.assetRegistry.find(a => a.url === url && a.method === method);
    if (asset) {
      const body = fs.readFileSync(asset.file);
      request.respond({
        status: asset.status || 200,
        contentType: resourceTypes[request.resourceType()] || null,
        headers: { 'Cache-Control': 'max-age=604800' },
        body,
      });
      return true;
    }
    ...
}

I have confirmed that the header is set correctly by inspecting the response from page.goto.

The html that is rendered is pretty standard, and contains references to the assets using standard tags, e.g.

<link rel="preload" href="<%= staticAssetUrl %>/fonts/Roboto-Regular.woff2" as="font" type="font/woff2" crossorigin>
...
<script type="text/javascript" src="<%= buildAssetUrl %>/app.js"></script>

Other things I have checked:

  • I am using the latest versions of puppeteer and jest-environment-puppeteer
  • I am only creating a single browser instance in global setup
  • I have tried explicitly setting page.setCacheEnabled(true) (this should be the default anyway)
  • The URL requested by the browser is identical for subsequent requests (i.e. no fingerprinting)
0 Answers
Related