Route::fulfill() sends isBase64 through to route.fulfill(), but that option does not exist in Playwright's JS API — so every binary response served through a fulfilled route reaches the browser as the base64 string, not the decoded bytes.
Where
playwright-symfony base64-encodes binary bodies and flags them, in two places:
// src/Client/ResponseConverter.php:92
$options['body'] = base64_encode($body);
$options['isBase64'] = true;
(same in src/Client/Interception/AssetServer.php:124)
The Node server passes the options straight through:
// bin/playwright-server.js:124
fulfill: () => route.fulfill(command.options),
But route.fulfill() accepts only body (string|Buffer), contentType, headers, json, path, response, status — isBase64 appears nowhere in playwright-core@1.62.1's types.d.ts. It is a protocol-level field the Python/Java/.NET bindings set, not a public JS option. So it is dropped and the base64 text becomes the response body.
Reproduction
Fetch any font or image through an intercepted route:
const r = await fetch('/assets/…/inter-latin-wght-normal.woff2');
const b = new Uint8Array(await r.arrayBuffer());
String.fromCharCode(...b.slice(0, 8)); // "d09GMgAB" ← base64 of "wOF2"
b.length; // 64344 for a 48256-byte file (4/3)
The browser then reports:
Failed to decode downloaded font: http://localhost/assets/…/inter-latin-wght-normal.woff2
OTS parsing error: invalid sfntVersion: 1680881991
1680881991 is 0x64336137, i.e. the ASCII "d3a7" — base64 text where the wOF2 magic should be.
Text types are unaffected: ResponseConverter::isBinaryContentType() excludes text/*, JSON, JS, XML and SVG, which is why HTML/CSS/JS pages work and only fonts and raster images break.
Suggested fix
Decode in the server before handing the body to Playwright:
fulfill: () => route.fulfill(
command.options?.isBase64
? {...command.options, body: Buffer.from(command.options.body, 'base64'), isBase64: undefined}
: command.options
),
Impact
In-process E2E tests render with fallback fonts and broken images, so anything asserting on rendered typography, image pixels, or layout that depends on web-font metrics is untestable. It fails silently — the request is a 200 and only the browser console shows the decode error.
Found while moving a Symfony app's E2E suite onto zenstruck/browser's PlaywrightBrowser; reproduced identically through both ResponseConverter and AssetServer, on playwright-php/playwright v1.4.0 + playwright-symfony v0.10.0.
Route::fulfill()sendsisBase64through toroute.fulfill(), but that option does not exist in Playwright's JS API — so every binary response served through a fulfilled route reaches the browser as the base64 string, not the decoded bytes.Where
playwright-symfonybase64-encodes binary bodies and flags them, in two places:(same in
src/Client/Interception/AssetServer.php:124)The Node server passes the options straight through:
But
route.fulfill()accepts onlybody(string|Buffer),contentType,headers,json,path,response,status—isBase64appears nowhere inplaywright-core@1.62.1'stypes.d.ts. It is a protocol-level field the Python/Java/.NET bindings set, not a public JS option. So it is dropped and the base64 text becomes the response body.Reproduction
Fetch any font or image through an intercepted route:
The browser then reports:
1680881991is0x64336137, i.e. the ASCII"d3a7"— base64 text where thewOF2magic should be.Text types are unaffected:
ResponseConverter::isBinaryContentType()excludestext/*, JSON, JS, XML and SVG, which is why HTML/CSS/JS pages work and only fonts and raster images break.Suggested fix
Decode in the server before handing the body to Playwright:
Impact
In-process E2E tests render with fallback fonts and broken images, so anything asserting on rendered typography, image pixels, or layout that depends on web-font metrics is untestable. It fails silently — the request is a 200 and only the browser console shows the decode error.
Found while moving a Symfony app's E2E suite onto
zenstruck/browser'sPlaywrightBrowser; reproduced identically through bothResponseConverterandAssetServer, onplaywright-php/playwrightv1.4.0 +playwright-symfonyv0.10.0.