We recently joined an existing Rails 4.1 project that uses AngularJS. We
Capybara::ElementNotFound failures in RSpec feature specs
confidence in the test suite, preventing us from using a fluid outside-in
Finding the Problem
We saw in Capybara screenshots that the pages (rendered with AngularJS) were
failing to fully load, but only in tests. In order to learn more, we reviewed
test.log, and saw this error:
RuntimeError (Circular dependency detected while autoloading constant MyClass)
This looked like a race condition while loading files. Lazily loading files is
not threadsafe in Ruby, and
since Webrick is multithreaded and
disabled by default in test, we suspected that concurrency was enabled.
In production environments, Rails 4.1 uses
Rack::Lock if classes won’t be
cached (true in development by default, but false in production by default).
Rack::Lock creates a mutex around requests that guards against threadsafety
issues in multithreaded environments such as Webrick (the test server). We
Rack::Lock would be used in tests as well, but to make sure we
RAILS_ENV=test rake middleware, and saw that
Rack::Lock was missing.
The reason we were seeing the circular dependency error was that Capybara was
making many concurrent requests to a multithreaded server (Webrick) with
Rack::Lock disabled. This became an especially insidious problem in an
AngularJS app, given the number of concurrent requests being triggered via AJAX.
We concluded that we needed to force
Rack::Lock middleware to be added in
test. This was echoed in this Rails
raised on GitHub.
allow_concurrency is true. It follows that we
can explicitly set
allow_concurrency to false in our test environment to force
Rack::Lock to be added.
# config/test.rb config.allow_concurrency = false
The issue will be fixed in Rails 4.2, but in the interim, explicitly disabling concurrency has fixed the circular dependency error we were seeing.
Practicing Red/Green/Refactor and outside-in testing depends on getting reliable failures from the tests, and we didn’t have that. Resolving flakiness in the test suite thus made a notable improvement in our TDD workflow while reviving confidence in the tests.