Skip to content

Instantly share code, notes, and snippets.

@phoet
Last active December 23, 2015 19:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save phoet/6683280 to your computer and use it in GitHub Desktop.
Save phoet/6683280 to your computer and use it in GitHub Desktop.
don't put all your stuff in /spec

it is an established convention to put all your rails tests or specifications in the test/spec folder. even jasmine javascript files go in spec/javascripts!?

cucumber features on the other hand go in the features folder.

i don't like cucumber, because of the additonal complexity that comes with the gherkin langauge, but i like the idea that they think about features to be something different.

when writing acceptance tests i put them in the acceptance folder and add a custom spec_helper file that is usually called acceptance_spec_helper.rb as rpsec runners get confused with multiple spec_helper.rb files.

acceptance tests and normal rails tests have orthogonal requirements that should be expressed in using different setups.

i like to have use_transactional_fixtures and random test execution turned on for normal rails tests, because it's super fast and each spec should be independend of other tests.

it's different when writing acceptance specifications with capybara and some headless browser that spawn a real rails process to run arbitrary JavaScript code within.

those processes have a basic problem when it comes to database queries. changes in one process/thread might not be seen in another one because of transaction visibility. this is often times hard to debug and mindboggling. there are some hacks to get rid of this problem by sharing the same database connection, but they introduce other problemes, mostly race conditions.

long story short, i like to turn use_transactional_fixtures of and use fixtures (or hardcoded factory data) for running acceptance tests, as this fits more into the idea of acceptance tests. if you combine this approach with stateful page-objects, than you can write pretty readable tests like LoginPage.new.login(:uschi). In this case, there is some fixture data with a user called Uschi.

I like to run DatabaseCleaner between each group of specs and recreate the fixtures, so they are fresh for each capybara spec file. This setup comes pretty close to how cucmber does it, without all the cucumber-world crazyness.

Some benefits that come with this approach:

  • faster spec runs for both suites
  • easy to separate out suites for CI
  • great for coverage reports
  • simple spec_helpers
  • separation of concerns via custom test modules

See the example configurations for more details.

require 'simplecov'
SimpleCov.command_name "acceptance"
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rails'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
Capybara.always_include_port = true
Dir[Rails.root.join("acceptance/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending!
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.order = "default"
config.before(:all) do
Capybara.default_host = 'testhost.com'
Capybara.app_host = 'testhost.com'
DatabaseCleaner.clean_with :truncation
generate_fixtures
end
config.before(:each) do
if example.metadata[:js] # some poltergeist specifics
Capybara.current_session.driver.add_header('Referer', 'some.host.com')
end
end
# acceptance helpers
config.include FixtureGenerator
config.include WidgetPathHelper
config.include AuthenticationHelper
end
require 'simplecov'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending!
RSpec.configure do |config|
config.use_transactional_fixtures = true
config.order = "random"
config.before(:each, type: :request) do
host!('testhost.com')
end
config.include AuthenticationHelper, type: :controller
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment