rails

Fixing slow, flaky system tests in Vite-Rails

Turn off autoBuild.

By default, Vite-Rails automatically detects changes in your JavaScript, JSX, SCSS, etc. source files and then compiles them as needed. This is really convenient in local development. But when running a large test suite, this “auto build” behavior can cause problems.

Sporadic failures when using Rails parallel testing

Rails 6.0 introduced parallel testing, and it is now enabled by default for test suites containing 50 or more tests. This can lead to some interesting race conditions.

When Vite-Rails is detecting and recompiling assets on the fly, parallel testing means that multiple compilations can be triggered simultaneously. The manifest.json file, which is the bill-of-materials for the compilation output, can get corrupted as a result.

You may see system tests fail with sporadic errors like these:

JSON::ParserError: unexpected token at ''

or

ViteRuby::MissingEntrypointError: Vite Ruby can't find logo.svg in public/vite-test/manifest.json or public/vite-test/manifest-assets.json.

Slow system tests

To detect if any source files have changed, Vite-Rails traverses all of your frontend code and computes a checksum for every file. It does this every time an asset is referenced. Furthermore, Vite-Rails also needs to check whether the Vite dev server is running, which involves attempting a socket connection and waiting for a timeout.

That means every vite_javascript_tag, vite_image_tag, etc. in your views end up triggering a potentially expensive set of operations. Repeat these over dozens of system tests, and this can add up.

In my experience, this auto-detection can add about 10% overhead to a Rails system test suite.

Solution: disable autoBuild

The solution, as hinted at in the Vite-Ruby CI docs, is to disable autoBuild.

{
  ...,
  "test": {
    "autoBuild": false,
    "publicOutputDir": "vite-test",
    "port": 3037
  }
}
config/vite.json
Set autoBuild: false for the test environment.

However, this introduces a big inconvenience. With autoBuild off, you have to remember to explicitly build your assets with RAILS_ENV=test rake assets:precompile before running tests.

To fix the testing experience, add the following line to rails_helper.rb (RSpec) or test_helper.rb (Minitest):

ViteRuby.commands.build
This builds Vite assets exactly once (if files have changed), when the test suite is loaded. In practice, this is much more efficient than the auto-build approach of detecting source code changes during every single test.

With these changes, you no longer have to run an explicit assets:precompile before running tests, either locally or in CI.

Further reading

The solution described in this post is also included in mattbrictson/rails-template. Specify the --javascript vite option to generate a new project with Vite best practices.

Share this? Copy link

Feedback? Email me!

Hi! 👋 I’m Matt Brictson, a software engineer in San Francisco. This site is my excuse to practice UI design, fuss over CSS, and share my interest in open source. I blog about Rails, design patterns, and other development topics.

Recent articles

RSS
View all posts →

Open source projects

mattbrictson/rails-template

App template for Rails 7 projects; best practices for TDD, security, deployment, and developer productivity. Now with optional Vite integration! ⚡️

1,055
Updated 1 month ago

mattbrictson/tomo

A friendly CLI for deploying Rails apps ✨

360
Updated 20 days ago

More on GitHub →