Wednesday, June 2, 2010

Cucumber and Subdomains Revisited (the Capybara chronicles)

Well, I've been working steadily on RoR development for the last year.  I finally landed a job in November as a full time RoR developer, and it's AWESOME!

But that's not the point of this post.  In my last post, I had just figured out how to get Cucumber with Webrat to work with subdomains.  Then I needed to test JS.  But I don't want to run Selenium or Culerity or anything else for ALL my tests.  That would be waaaaay to slow.  Sooooo....over to Capybara I go.

And guess what?  Just about every test failed, because subdomains don't work the same.  Crap!  I'm not knocking Capybara.  I think it's awesome.  The benefits far outweigh this little foible for sure!  I just didn't anticipate this issue.

Just to be clear, the issue is not calling a 'visit' to a hard-coded url with a subdomain.  That's easy and seems to work just fine.  It's when you get redirected to other pages after that.  The subdomain isn't carried along and things start to break down.

So off to the research pits I go.  And I don't find much that helps.  Capybara's Github page does give a suggestion (https://gist.github.com/643a758320a2926bd2ed) about how to handle this with default_url_options.  I tried it.  I couldn't get it to work.  And I didn't really like it anyway.  Probably not a big deal, but it just offends my sensibilities to change code for tests.  Back to Google...still nothing.

So off to the Capybara code itself.  After some digging, I've come up with this solution using default_host and app_host that handles subdomains for the regular Capybara tests (Rack::Test) and for Capybara's Culerity driver.  Don't forget to add entries to your /etc/hosts file for all of the subdomains you'll be using with Culerity, or things will go boom.

One thing I'd like to improve about this is the port being a variable pulled from Capybara somehow (instead of hard-coded to 9887), but I couldn't figure out how to do that, and it isn't terribly important to me right now.  I'll be happy to update the gist if anyone figures this out.  Just let me know.

I didn't test this with any of the other drivers (like Selenium) because I'm only using Culerity so far.  Haven't had any reason to do any others yet.  If anyone else tests this with any of the other drivers, let me know, and I'll edit the post with that info.

Edit
Got a question about what relevant gems I'm using and realized that was important information!  So here they are:

Cucumber - 0.7.2
Capybara - 0.3.8
Langalex's Culerity - 0.2.10

13 comments:

JamesAlmond said...

I've been using a very similar solution for a while now that I blogged about earlier today: http://jamesalmond.posterous.com/testing-subdomains-using-capybara

Chris Booth said...

Thanks for sharing that James

Steve V said...

I just switched from Webrat to Capybara, and am using the replacement for host! in your gist, but have a small problem. It seems to work great for one subdomain per scenario, but if there's more than one it will only navigate to the first one. I have a scenario that starts at one subdomain, makes sure some stuff is okay, and then navigates to another subdomain. I have verified that I'm setting the default_host properly before going to the second site, but it just wants to go to the first one only. Any idea what this is, or how to get around it?

Thanks,
Steve

Tim Brandes said...

Thanks guys, both James and Chris, this helped me a lot setting up a test environment with capybara where I run everything on user based subdomains!

I am using the lvh.me solution suggested by Ryan Bates in Railscasts 221 and I just run it through a Cucumber background step like this:
Capybara.default_host = "#{@club.subdomain}.lvh.me"
Capybara.app_host = "http://#{@club.subdomain}.lvh.me:9887" if Capybara.current_driver == :culerity

Works awesome!

John Polling said...

Thanks for this. Saved me a load of time :)

Is there any particular reason you must use example.com as the domain?

Chris Booth said...

@JohnPolling Nope, that's just the default that Cucumber uses, and I didn't have a particular reason to change it.

John Polling said...

@Chris ok. When I change the domain the tests fail. Also, I've just tried using culerity and the tests fail with NativeException: java.net.UnknownHostException: admin.example.com.

Just wondering if you have any suggestions?

John Polling said...

@Chris ignore me...I forgot to add the subdomains into my hosts file. Doh!

Chris Booth said...

Oh I've done that! :)

tsdbrown said...

After quite some time trying to get this working alopne I finally found your post which has been a great help.

Being new to cucumber I thought it may have been me, especially as the first feature I'm testing is signup, which as Steve V mentions needs to handle redirect to a different subdomain. With your gist and the lvh.me trick the test is finally passing.

I total agree with you about not changing the code to suit the test, I didn't feel too comfortable with that solution either.

Thanks again for the post!

nader said...

So in Capybara master the port is now dynamically selected using TCP. I wonder if you've found a way to test subdomains given you can't hardcode the port anymore?

Anonymous said...

Hi,

I just start working with capybara.I am unable to find any command in capybara for get the total number of characters in text field save.

Suggest something

Thanks

sj26 said...

Here's what I came up with:

https://gist.github.com/1939812