Playwright JavaScript File Caching Guide
How Playwright Handles Cache
Default Behavior
- Browser Cache: Playwright uses the browser’s native HTTP cache (Chromium/Firefox/WebKit)
- Per Context: Each browser context has its own isolated cache
- Per Site: Cache is effectively per origin/domain within a context
- Automatic: The browser automatically caches based on HTTP cache headers
Cache Storage Location
- Chromium:
~/.cache/ms-playwright/chromium-<version>/Default/Cache/ - Firefox:
~/.cache/ms-playwright/firefox-<version>/default/ - WebKit:
~/.cache/ms-playwright/webkit-<version>/
Cache is stored per browser type and version, not per site. However, the browser’s cache mechanism ensures files are cached per origin/domain.
Configuring Cache in Playwright
Option 1: Use Browser Context with Cache Enabled (Default)
import { test } from '@playwright/test';
test('test with cache', async ({ context }) => {
// Cache is enabled by default
const page = await context.newPage();
await page.goto('https://example.com');
// JS files are cached automatically
});
Option 2: Disable Cache (For Testing)
test('test without cache', async ({ context }) => {
// Disable cache for fresh requests
await context.route('**/*', route => {
route.continue({ headers: { ...route.request().headers(), 'Cache-Control': 'no-cache' } });
});
const page = await context.newPage();
await page.goto('https://example.com');
});
Option 3: Custom Cache Interception
Intercept and cache JavaScript files manually:
import { test } from '@playwright/test';
test('cache JS files manually', async ({ page, context }) => {
const jsCache = new Map<string, { data: Buffer; headers: Record<string, string> }>();
// Intercept JS file requests
await context.route('**/*.js', async (route) => {
const url = route.request().url();
// Check cache
if (jsCache.has(url)) {
const cached = jsCache.get(url)!;
await route.fulfill({
body: cached.data,
headers: cached.headers,
status: 200
});
return;
}
// Fetch and cache
const response = await route.fetch();
const buffer = await response.body();
jsCache.set(url, {
data: buffer,
headers: response.headers()
});
await route.fulfill({
response,
body: buffer
});
});
await page.goto('https://example.com');
});
Viewing Downloaded/Cached Files
Method 1: Network Logging
test('log all JS files', async ({ page }) => {
const jsFiles: string[] = [];
page.on('response', async (response) => {
if (response.request().resourceType() === 'script') {
const url = response.url();
const status = response.status();
jsFiles.push(`${status} ${url}`);
// Optionally save the file
if (status === 200) {
const buffer = await response.body();
const filename = url.split('/').pop() || 'script.js';
// Save to disk if needed
}
}
});
await page.goto('https://example.com');
console.log('JS files loaded:', jsFiles);
});
Method 2: Download All JS Files
test('download all JS files', async ({ page }) => {
const fs = require('fs');
const path = require('path');
const downloadDir = './downloaded-js';
if (!fs.existsSync(downloadDir)) {
fs.mkdirSync(downloadDir, { recursive: true });
}
page.on('response', async (response) => {
if (response.request().resourceType() === 'script' && response.status() === 200) {
const url = response.url();
const urlObj = new URL(url);
const filename = urlObj.pathname.split('/').pop() || 'script.js';
const filepath = path.join(downloadDir, filename);
const buffer = await response.body();
fs.writeFileSync(filepath, buffer);
console.log(`Downloaded: ${filename} from ${url}`);
}
});
await page.goto('https://example.com');
await page.waitForLoadState('networkidle');
});
Cache Per Site/Origin
While Playwright’s cache is per browser context, you can organize cache by site:
test('cache per site', async ({ context }) => {
const siteCache = new Map<string, Map<string, Buffer>>();
await context.route('**/*.js', async (route) => {
const url = new URL(route.request().url());
const origin = url.origin;
const pathname = url.pathname;
// Get or create cache for this origin
if (!siteCache.has(origin)) {
siteCache.set(origin, new Map());
}
const originCache = siteCache.get(origin)!;
// Check cache
if (originCache.has(pathname)) {
await route.fulfill({
body: originCache.get(pathname)!,
contentType: 'application/javascript'
});
return;
}
// Fetch and cache
const response = await route.fetch();
const buffer = await response.body();
originCache.set(pathname, buffer);
await route.fulfill({ response, body: buffer });
});
const page = await context.newPage();
await page.goto('https://example.com');
});
Checking What’s Cached
View Cache in Browser DevTools
test('inspect cache', async ({ page }) => {
await page.goto('https://example.com');
// Open DevTools (if not headless)
// Or use CDP to inspect cache
const client = await page.context().newCDPSession(page);
const cacheData = await client.send('Network.getResponseBody', {
requestId: '...' // Get from network events
});
});
List All Cached Resources
test('list cached resources', async ({ page }) => {
const cachedResources: Array<{url: string; type: string}> = [];
page.on('response', async (response) => {
const request = response.request();
const url = response.url();
const fromCache = response.fromServiceWorker() ||
(await response.headerValue('x-from-cache')) === 'true';
if (fromCache || response.status() === 304) {
cachedResources.push({
url,
type: request.resourceType()
});
}
});
await page.goto('https://example.com');
await page.waitForLoadState('networkidle');
console.log('Cached resources:', cachedResources.filter(r => r.type === 'script'));
});
Best Practices
- Use Default Cache: Let the browser handle caching automatically
- Clear Cache When Needed: Use
context.clearCookies()and navigate withcache: falseoption - Monitor Cache: Log responses to see what’s being cached
- Test Cache Behavior: Verify your site works with cached and fresh resources
Clearing Cache
test('clear cache', async ({ context }) => {
// Clear browser cache
const pages = context.pages();
for (const page of pages) {
await page.evaluate(() => {
if ('caches' in window) {
caches.keys().then(keys => {
keys.forEach(key => caches.delete(key));
});
}
});
}
// Or create new context (fresh cache)
const newContext = await context.browser()!.newContext();
});