Go back to the main page

Testing a subdomain in Capybara

This article is over 2 years old. Proceed with caution.

Regards ♨ – Minimul

 

Pre requites:

  • Rails 3.2
  • Capybara.javascript_driver :webkit
  • Rspec

Some basics about a Capybara request

Capybara by default uses the rack-test driver, which shows up in the request as "www.example.com" (port 80). When using a different driver, such as capybara-webkit, Capybara first spins up the rails server via "rails s -e test -p <capybara assigned port>", and then tests through http://127.0.0.1<capybara assigned port>. It is worth noting based on my experience that blank values come through for request.domain and request.subdomain on a capybara-webkit request.

Hitting a subdomain

Spec'ing a subdomain using the rack-test driver is straight-forward as you simply insert in the subdomain instead of the "www" e.g. http://billstools.example.com. When using the capybara-webkit driver it is not as simple as you can't add a subdomain to 127.0.0.1 and you don't know the capybara generated port number.

Modify the default_host or app_host?

With both drivers, rack-test and webkit, you are going to have to monkey with the request url. For the rack-test driver you can directly alter the Capybara.default_host option. For other drivers you need to modify the Capybara.app_host setting. However, let's stop here and say that this is not the "correct" approach. The main reason is that changing the default_host or app_host option will change this value globally for each spec that follows. The author of Capybara, Jonas Nicklas, states "Never change Capybara.default_host, just don't." and recommends that subdomains are visited explicitly.

Navigate through explicit urls

So the correct approach is to navigate using explicit urls for subdomain specs. That's easy for a rack-test spec as you create a prefix to the relative path, e.g. http://billstools.example.com/inventory/blue-hammer, but how about a capybara-webkit/js-driver spec? Since you cannot add a subdomain to 127.0.0.1 you either need to edit your /etc/hosts file adding a mapping for 127.0.0.1 such as *.local.me or use free services such as lvh.me or smackaho.st which provide wildcard matching back to your localhost. I prefer the latter as with the former all of the other developers are also going to have to make those edits to their /etc/hosts file.

Code example: Helper method for testing subdomains in Capybara

# spec/support/misc.helpers.rb
def hosted_domain(options = {})
  path = options[:path] || "/" # use root path by default
  subdomain = options[:subdomain] || 'billstools'
  if example.metadata[:js]
    # figures out which port Capybara spun up on the "rails s -e test" command
    # ** note: on Capybara 2.x you can use Capybara.always_use_port in the spec_helper
    port = Capybara.current_session.driver.server_port
    url = "http://#{subdomain}.lvh.me:#{port}#{path}"
  else
    url = "http://#{subdomain}.example.com" + path
  end
end

require 'spec_helper'

describe "Contact us form" do
  let (:account) { Factory.create(:account, :subdomain => 'billstools') }
  let!(:inventory) { Factory.create(:inventory, :account => account) }

  before do
    visit hosted_domain path: hosted_inventory_path(inventory)
  end

  it "shows the page" do
    page.should have_content('Contact Us')
  end

  it "shows the page", :js => true do
    page.should have_content('Contact Us')
  end

end


Comment on this article?