[Bug]: Large JS files (>8KB) are truncated to 8192 bytes in browser tests causing SyntaxError
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 11.7k
- Forks
- 538
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 8
Description
What Happened
When running browser tests, all large JavaScript files (>8KB) are truncated to exactly 8192 bytes by the in-process AMPHP test server, causing SyntaxError: Unexpected end of input and SyntaxError: Invalid or unexpected token in the browser.
The errors appear on all pages that load large JS assets (Livewire, Filament, Vite bundles). Pages where all JS happens to be <8KB pass silently.
Evidence
Capturing window.__pestBrowser.jsErrors (with filename/line/col) after waitForLoadState('networkidle') shows:
[
{ "message": "Uncaught SyntaxError: Unexpected end of input", "filename": ".../vendor/livewire/livewire.min.js", "lineno": 1, "colno": 8193 },
{ "message": "Uncaught SyntaxError: Unexpected end of input", "filename": ".../js/filament/support/support.js", "lineno": 1, "colno": 8193 },
{ "message": "Uncaught SyntaxError: Invalid or unexpected token", "filename": ".../js/filament/tables/tables.js", "lineno": 1, "colno": 8189 },
{ "message": "Uncaught SyntaxError: Unexpected end of input", "filename": ".../build/assets/app.js", "lineno": 1, "colno": 8001 }
]
colno: 8193 = file received exactly 8192 bytes (1 × 8KB AMPHP read chunk) before EOF.
Actual file sizes: livewire.min.js = 237KB, support.js = 140KB, app.js = 187KB.
Root Cause
In LaravelHttpServer::asset(), JS files go through this path:
= fopen('php://temp', 'r+');
= fread(, filesize()); // reads full file ✓
= ->rewriteAssetUrl(); // rewrites URLs ✓
fwrite(, ); // writes to php://temp ✓
rewind(); // rewinds ✓
return new Response(200, [...], new ReadableResourceStream()); // ← BUG
ReadableResourceStream from AMPHP sets the stream to non-blocking mode via stream_set_blocking($resource, false). For php://temp in non-blocking mode, the underlying read returns at most one 8192-byte chunk per read event, and AMPHP's fiber-based event loop does not schedule subsequent reads within the same request lifecycle — so only the first 8KB is ever delivered to Playwright/Chromium.
Non-JS files are also served via ReadableResourceStream on the original file handle but they do not cause parse errors (images, CSS, fonts don't fail silently in the same way), so the truncation is hidden.
Fix
Replace the stream-based response with a plain string response, bypassing async streaming entirely:
private function asset(string $filepath): Response
{
$rawContent = file_get_contents($filepath);
if ($rawContent === false) {
return new Response(404);
}
$mimeTypes = new MimeTypes();
$contentType = $mimeTypes->getMimeTypes(pathinfo($filepath, PATHINFO_EXTENSION));
$contentType = $contentType[0] ?? 'application/octet-stream';
if (str_ends_with($filepath, '.js')) {
$rawContent = $this->rewriteAssetUrl($rawContent);
}
return new Response(200, [
'Content-Type' => $contentType,
'Content-Length' => (string) strlen($rawContent),
], $rawContent);
}
This also fixes the 0-byte file crash described in #1635 (no need for the filesize() === 0 guard in PR #203).
A PR with this fix is available at pestphp/pest-plugin-browser.
How to Reproduce
Any Laravel + Pest browser test suite that loads JS files larger than 8KB (Livewire, Filament, any Vite bundle). Use assertNoJavaScriptErrors() and it will fail. Or capture errors manually:
test('no js errors', function () {
$page = visit('/');
$page->page()->waitForLoadState('networkidle');
$errors = $page->script('() => window.__pestBrowser?.jsErrors ?? []');
// colno ~8193 on large JS files
dump($errors);
});
Pest Version
4.3.1
PHP Version
8.5 (also reproducible on 8.4 / 8.3)
Operation System
Linux
Notes
Related to #1635 (0-byte file crash). This is a separate truncation bug affecting all files >8KB.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at LaravelHttpServer::asset(), focusing on how JavaScript assets are returned through ReadableResourceStream. Reproduce with a browser test loading an asset larger than 8KB, then verify the response is complete and that the related 0-byte asset case remains covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100