Я потратил 8 часов на решение аналогичной проблемы и нашел решение. Исправление настолько простое, что я могу плакать.
Сначала диагноз
Причина, по которой вы получаете "SQLite3::BusyException: database is locked
", заключается в том, что вы запускаете асинхронный поток, а именно отправку формы, которая в итоге проигрывает гонку "запись в базу данных" в основной поток вашего теста. По сути, поскольку ваш тест уже завершен и выполняется процедура очистки базы данных «после каждого» (определенная в вашем spec_helper), действие формы только что начало пытаться запустить бизнес-логику (которая опирается на данные, которые ваш тест после каждый крючок занят уничтожением).
Скорее всего, эта проблема возникает в тестах, которые щелкают по кнопке AJAX POST, а затем завершают работу, не сообщая что-либо об изменении представления.
Второе исправление
Как оказалось, Capybara предназначена для "синхронизации" всех ваших запросов. Но только если вы неявно позволите это. Обратите внимание, что после отправки формы у вас не будет Капибары, которая будет смотреть на вашу страницу. Поэтому он думает, что вы закончили, и выводит ваши данные из области видимости (в то время как поток отправки формы висит в фоновом режиме.)
Просто добавьте следующую строку кода в конец теста, и он должен неожиданно заработать:
page.should_not have_content "dude, you forgot to assert anything about the view"
В-третьих, сделай это красиво
Не используйте execute_script. Вот для чего Капибара. Но также не полагайтесь на "click_on", потому что это не очень хорошая абстракция. Вы должны знать слишком много о его внутренностях. Вместо этого используйте CSS-селекторы так:
page.find("#submit_button").click
И еще одна вещь - ваш тест не должен пытаться манипулировать DOM. Хороший тест Selenium предполагает выполнение тех же шагов, что и обычный пользователь.
Итак, в заключение
it "should pass when answering all correct", :js => true do
login_as(student, :scope => :student)
visit ("/student_courses")
page.find(".my-js-enabled-button").click
page.find("#submit_button").click
# Synchronizes your view to your database state before exiting test,
# Therefore makes sure no threads remain unfinished before your teardown.
page.should_not have_content "dude, you forgot to expect / assert anything."
end