Skip to content

Make browser tests read the built assets even with the dev server running - #340

Closed
paulocastellano wants to merge 1 commit into
mainfrom
fix/browser-tests-use-built-assets
Closed

paulocastellano wants to merge 1 commit into
mainfrom
fix/browser-tests-use-built-assets

Conversation

@paulocastellano

Copy link
Copy Markdown
Contributor

Three browser tests fail on any machine with npm run dev running, and pass in CI. Same root cause for all three.

FAILED  AuthLegalLinksTest > the login screen shows the legal sentence to a logged out visitor
FAILED  AuthLegalLinksTest > the register screen shows the legal sentence to a logged out visitor
FAILED  RepurposeAccountHealthTest > a repurpose whose source was deleted explains itself instead of rendering a hole

What was happening

tests/BrowserTestCase says in its own docblock that these tests load the built Vite assets, but $fakesVite = false only turns off the manifest fake. Laravel's Vite helper still prefers public/hot whenever that file exists — and it exists on every machine running npm run dev. So the browser tests were loading the app from the Vite dev server, not from the build npm run build had just produced.

That alone would be tolerable. What makes it fail is the interaction with i18n:

  • resources/js/app.ts:63 resolves translations lazily with import.meta.glob('../../lang/*.json').
  • lang/php_*.json is generated by the laravel-vue-i18n/vite plugin and gitignored (.gitignore:6).
  • The plugin deletes those files when a build finishes. Run npm run build while npm run dev is up and the dev server's runtime glob resolves nothing.

The page then renders raw translation keys. From the failure screenshot: auth.login.title, auth.login.email, auth.legal. So assertVisible('@legal-links') passed (the div is there) while assertSeeLink('Terms of Service') could not find the links, and RepurposeAccountHealthTest saw the literal repurposes.health.source_missing instead of the banner sentence.

CI has no hot file, so it always used the manifest and never saw any of this.

The fix

protected function setUp(): void
{
    parent::setUp();

    Vite::useHotFile(base_path('tests/.vite-hot-file-that-never-exists'));
}

Pointing the hot file at a path that can never exist makes the browser tests use the manifest unconditionally — what the class already claimed to do, and what CI has been doing all along. No effect in CI, where the hot file is absent either way.

This works because the HTTP server the browser plugin runs lives in the test process: Pest\Browser\Drivers\LaravelHttpServer::handleRequest() resolves the kernel out of the same container, so a setUp() override reaches the rendered page.

Verification

php artisan test tests/Browser --compact, with npm run dev running:

Before After
Result 40 passed, 3 failed 43 passed
Duration 57.65s 37.21s

vendor/bin/pint passes. BrowserTestCase is only extended by tests/Browser (tests/Pest.php:32), so nothing else is touched.

…ning

tests/BrowserTestCase already says these tests load the built Vite assets,
but it only turned off the manifest fake. Laravel still prefers public/hot
when it exists, so on any machine with `npm run dev` running the browser
tests silently loaded the app from the Vite dev server instead of the build
that `npm run build` had just produced.

That is enough on its own to make three tests fail locally while CI, which
has no hot file, stays green. The dev server resolves
`import.meta.glob('../../lang/*.json')` lazily at runtime, and the
laravel-vue-i18n Vite plugin deletes lang/php_*.json when a build finishes,
so the page rendered raw translation keys -- "auth.legal" instead of the
sentence with the Terms of Service and Privacy Policy links, and the raw
repurposes.health.source_missing key instead of the banner.

Pointing the hot file at a path that can never exist makes the browser tests
use the manifest unconditionally, which is what they claim to do and what CI
has been doing all along.

    AuthLegalLinksTest        the login screen shows the legal sentence
    AuthLegalLinksTest        the register screen shows the legal sentence
    RepurposeAccountHealthTest  a repurpose whose source was deleted ...

The HTTP server the browser plugin runs lives in the test process
(Pest\Browser\Drivers\LaravelHttpServer resolves the kernel out of the same
container), so a setUp() override reaches the rendered page.
@paulocastellano

Copy link
Copy Markdown
Contributor Author

Folded into #339 so the dead-code removal ships with a browser suite that is actually green locally.

@paulocastellano
paulocastellano deleted the fix/browser-tests-use-built-assets branch September 7, 2026 20:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant