pestphp / pestphp/pest

[Bug]: Large JS files (>8KB) are truncated to 8192 bytes in browser tests causing SyntaxError

Open
#1,664 0 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.