17

After creating a new migration file, running the migration, then running my tests I receive:

Failure/Error: ActiveRecord::Migration.maintain_test_schema!

ActiveRecord::PendingMigrationError:

  Migrations are pending. To resolve this issue, run:

          bin/rails db:migrate RAILS_ENV=test

Isn't the following snippet in the rails_helper.rb supposed to apply the migrations to the test database for me?

# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!

Update

Here is my config/environments/test.rb as requested:

Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # The test environment is used exclusively to run your application's
  # test suite. You never need to work with it otherwise. Remember that
  # your test database is "scratch space" for the test suite and is wiped
  # and recreated between test runs. Don't rely on the data there!
  config.cache_classes = true

  # Do not eager load code on boot. This avoids loading your whole application
  # just for the purpose of running a single test. If you are using a tool that
  # preloads Rails for running tests, you may have to set it to true.
  config.eager_load = false

  # Configure public file server for tests with Cache-Control for performance.
  config.public_file_server.enabled = true
  config.public_file_server.headers = {
    'Cache-Control' => 'public, max-age=3600'
  }

  # Show full error reports and disable caching.
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false

  # Raise exceptions instead of rendering exception templates.
  config.action_dispatch.show_exceptions = false

  # Disable request forgery protection in test environment.
  config.action_controller.allow_forgery_protection = false
  config.action_mailer.perform_caching = false

  # Tell Action Mailer not to deliver emails to the real world.
  # The :test delivery method accumulates sent emails in the
  # ActionMailer::Base.deliveries array.
  config.action_mailer.delivery_method = :test

  # Print deprecation notices to the stderr.
  config.active_support.deprecation = :stderr

  # Raises error for missing translations
  # config.action_view.raise_on_missing_translations = true
end
ardavis
  • 9,842
  • 12
  • 58
  • 112

3 Answers3

12

On running your tests, the configurations are loaded in following order (unless you have customized the order of autoload_paths in your rails app):

  1. config/application.rb
  2. config/environments/test.rb
  3. spec/rails_helper.rb

So, the migration pending error you are receiving must be due to config.active_record.migration_error = true this configuration setup somewhere before on the rails engine loads rails_helper.rb where ActiveRecord::Migration.maintain_test_schema! directive is defined.

Try setting config.active_record.migration_error = false on your config/environments/test.rb to skip migration check as it is described in rspec upgrade guide.

Fa11enAngel
  • 4,690
  • 2
  • 39
  • 38
sa77
  • 3,563
  • 3
  • 24
  • 37
  • I haven't had a chance to verify that your solution works, but if it does, should that line be added to the RSpec install generator? – ardavis Jun 13 '17 at 12:00
  • 1
    Sorry, I wasn't clear. I know that line should go into the test.rb. Apparently it defaults to true. If the default RSpec "spec_helper" adds the line `ActiveRecord::Migration.maintain_test_schema!`, it seems to do absolutely nothing unless `config.active_record.migration_error` is set to false. They seem to go hand in hand, no? – ardavis Jun 13 '17 at 14:30
  • If the two lines are coupled, I'm sayihng the `config.active_record.migration_error = false` should be added to the `config/environments/test.rb` when the RSpec install command is executed. – ardavis Jun 13 '17 at 14:31
  • ideally yes.. the `config.active_record.migration_error` flag is to prevent any migration error .. and when that is out of the way .. the config on your rails_helper `ActiveRecord::Migration.maintain_test_schema!` should do the real thing .. of running pending migrations if any .. apparently it is not working as expected. could be due to different reasons. some i could think of are: do you have any custom configuration running than what rails gives out of the box ? or was your app upgraded from earlier version of rails to the recent one ? – sa77 Jun 13 '17 at 14:43
  • I created a new Rails 5.1 app, created migrations and ran them in development, installed RSpec, tried to run tests. I was assuming the `maintain_test_schema!` line would apply the schema for me. I have not modified the `test.rb` in any way. – ardavis Jun 13 '17 at 15:55
  • 2
    I've decided to award the bounty to this answer. Setting that config to false in my test.rb did allow the `maintain_test_schema!` RSpec config to properly apply the schema after running a migration in development only, then running the tests. I still think maybe the RSpec installation generator should modify/add that config line to the `test.rb` for us, but that's okay. Thank you! – ardavis Jun 18 '17 at 02:56
  • This didn't work for me. It was still crashing with "Migrations are pending" error at railties-4.2.5.1/lib/rails/test_help.rb:19. But what helped was adding "config.active_record.maintain_test_schema = false" to config/environments/test.rb – RealMan Nov 01 '19 at 10:29
4

It might be because of two reasons.

  1. You may have missed it to configure in config/environments/test.rb

Add config.active_record.maintain_test_schema = true if you don't have it or set it to true if you had set it to false.

From the docs

config.active_record.maintain_test_schema is a boolean value which controls whether Active Record should try to keep your test database schema up-to-date with db/schema.rb (or db/structure.sql) when you run your tests. The default is true.

  1. You might have pending migrations after the schema has loaded

From the rspec docs

What this does is that rather than just raising when the test schema has pending migrations, Rails will try to load the schema. An exception will now only be raised if there are pending migrations afterwards the schema has been loaded.

Check whether you have pending migrations with rake db:migrate:status

Also, If you are using SQLite 3.7.9, you should take a look at this discussion

Pavan
  • 33,316
  • 7
  • 50
  • 76
-5

You should run rails db:migrate RAILS_ENV=test to update your test DB first.

What this does is that, rather than just raising when the test schema has pending migrations, Rails will try to load the schema. An exception will now only be raised if there are pending migrations afterwards the schema has been loaded.

There are a few caveats to be aware of when using this:

  • Migrations still need to be run manually; although now this only has to be done in the 'development' environment.
  • An exception will be raised if the schema has not been initialized. The exception will provide instructions stating rake db:migrate needs to be run.
Badacadabra
  • 8,043
  • 7
  • 28
  • 49
Jack_Zhou
  • 1
  • 1
  • 2
    This doesn't answer the question of _why_ he has to update the test DB. – tangrs Jun 08 '17 at 03:55
  • What this does is that rather than just raising when the test schema has pending migrations, Rails will try to load the schema. An exception will now only be raised if there are pending migrations afterwards the schema has been loaded. There are a few caveates to be aware of when using this: Migrations still need to be run manually; although now this only has to be done in the 'development' environment An exception will be raised If the schema has not been initialized. The exception will provide instructions stating rake db:migrate needs to be run. – Jack_Zhou Jun 08 '17 at 04:02
  • Could you clarify what is meant by: 'Migrations still need to be run manually; although now this only has to be done in the 'development' environment'? This seems to be different than your answer, which specifies the migration to be run the test environment. – Josh Johnson Jun 08 '17 at 13:47