Is this your first visit? You may want to subscribe to the feed.

Articles tagged with cucumber

Capybaras eating cucumbers

(or, testing static sites with Cucumber and Capybara)

While working on an app built purely in HTML and Javascript, we needed a good way to write integration tests. We played around with a few different approaches, including “functional” tests using one of the Javascript unit testing libraries. But for now, we settled on using Selenium.

OMG you’re crazy!

No, we’re not. The latest version of Cucumber comes with capybara, which makes it super simple to use Selenium. Capybara just uses any rack app, so we made a simple rack app that serves our static files. So here is what we ended up with in features/support/env.rb:

require 'rubygems'
require 'spec'
require 'cucumber'
require 'rack'
require 'capybara'
require 'capybara/dsl'

Capybara.app = Rack::Builder.new do
  map "/" do
    use Rack::Static, :urls => ["/"], :root => 'public'
    run lambda {|env| [404, {}, '']}
  end
end.to_app

require 'capybara/cucumber'
require 'capybara/session'

Capybara.default_selector = :css
Capybara.default_driver = :selenium

Now just copy over the web_steps.rb that cucumber generates from another project, and proceed as normal.

Code: cucumber May 11, 2010 ● updated May 11, 2010 1 comment

Cucumber scenarios that depend on Sphinx

I love writing apps that make heavy use of search indexes, but testing them can be a bit of a pain. Here is how I got ThinkingSphinx to play nice with Cucumber.

Here is the relevant part of what I put in features/support/env.rb:

# Cucumber::Rails.use_transactional_fixtures

# http://github.com/bmabey/database_cleaner
require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
Before do
  DatabaseCleaner.clean
end

ts = ThinkingSphinx::Configuration.instance
ts.build
FileUtils.mkdir_p ts.searchd_file_path
ts.controller.index
ts.controller.start
at_exit do
  ts.controller.stop
end
ThinkingSphinx.deltas_enabled = true
ThinkingSphinx.updates_enabled = true
ThinkingSphinx.suppress_delta_output = true

# Re-generate the index before each Scenario
Before do
  ts.controller.index
end

What’s going on here?

Start by commenting out the line about using transactional fixtures in env.rb. Using transactional fixtures will run each scenario inside of a transaction and roll it back at the end of the scenario to revert the database state. Thinking Sphinx uses an after_commit callback for kicking off the delta indexing, but the callback never gets run when transactional fixtures are enabled because the entire scenario is run inside of a big transaction.

Once we’ve disabled transactional fixtures, our test database will start to fill up, likely causing some problems. So we need to add a Before block that clears out the database before each scenario. I’m using database_cleaner, which gives you some different strategies for cleaning the database. Alternatively, the brute-force solution is just to reload the schema before each scenario, but this is slower than truncating the data.

Before do
  ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
  ActiveRecord::Schema.verbose = false
  load "#{RAILS_ROOT}/db/schema.rb"
end

Next, we start Sphinx when env.rb is loaded, and shut it down when the Ruby process exists. We also enable deltas and updates, which are disabled by default in test mode. Finally, we define a Before block that updates the index before each scenario so we don’t end up with a stale index.

Putting it all together

I’m using Sphinx’s delayed delta support, so whenever I update records, I need to have delayed_job process jobs. Instead of trying to get delayed_job to run in the background, I took the easy way out and defined a step: “When the system processes jobs”.

Scenario: Posting a new listing
  Given I am logged in as "MovinMan" 
  When I create a new listing titled "Lots of Boxes" near "49423" 
  And the system processes jobs
  And I browse listings near "49423" 
  Then I can see a listing titled "Lots of Boxes" 

Which is just implemented as:

When 'the system processes jobs' do
  Delayed::Job.work_off
end

If you’re just using the default deltas, and not delayed deltas, then you can update the index like this:

When /^the system updates the index$/ do
  MyModel.sphinx_indexes.first.delta_object.index(MyModel)
end

I hope that helps. Post your suggestions in the comments for improving this.

Code: cucumber Jun 01, 2009 ● updated Jun 25, 2009 13 comments

Testing Facebook with Cucumber

For those that haven’t heard: Cucumber is pretty much the greatest thing since sliced bread. It dramatically improved the quality and stability of our applications, and the outside-in approach that it encourages forces you to stay focused on what’s important.

When we started working on a Facebook application a few months ago, we couldn’t fathom not using Cucumber. So we had to figure out a way to test it. It took us a few months to evolve it to a point where we could extract it, but this week we pushed a change to Facebooker to make life a little easier. So grab the latest version of Facebooker and keep on reading…

First, in features/support/env.rb, replace the default Rails world with the one in Facebooker:

# require 'cucumber/rails/world'
require 'facebooker/rails/cucumber'

Given I am logged in as a Facebook user

Most of our Facebook application requires that a user be logged in. So most of our scenarios started with “Given I am logged in as a Facebook user”.

Scenario: Uploading a video
  Given I am logged in as a Facebook user
  When I upload a video
  Then I can see a video on my blog

And here is our implementation for that step:

Given "I am logged in as a Facebook user" do
  @current_user = User.create! :facebook_id => 1
  @current_user.facebook_user.friends = [
    Facebooker::User.new(:id => 2, :name => 'Bob'),
    Facebooker::User.new(:id => 3, :name => 'Sam')
  ]
  @integration_session.default_request_params.merge!(
    :fb_sig_user => @current_user.facebook_id,
    :fb_sig_friends => @current_user.facebook_user.friends.map(&:id).join(',')
  )
end

Our application has a User model with a facebook_id attribute and a #facebook_user method which returned an instance of Facebooker::User. Due to how the Facebook session is being mocked, it is important that we set our fake user’s id to 1 for now (I’ll try to figure out a way around this). We also manually add some friends for our application to use. Lastly, we merge in our user’s id and friend ids into the default request params so that any requests we make include those parameters.

Drop your…canvas

There were some places in our app where requests don’t go through the canvas. For example, we have a few multipart forms, which have to submit directly to your application. To mimic this, wrap webrat calls in #without_canvas:

When "I upload a video" do
  visit root_path

  without_canvas do
    fill_in 'Title', :with => 'A video'
    fill_in 'Description', :with => 'Caption for video'
    attach_file 'Video', "#{RAILS_ROOT}/features/support/sample.mpg", "video/mpeg"
    click_button 'Upload Video'
  end
  follow_redirect!
end

Note that if your action redirects to a URL with :canvas => true, webrat will see that as an “external” redirect and won’t follow it. Just call #follow_redirect! and it’ll go on it’s merry way.

Accessing the Facebook API

Instead of making requests to the Facebook API in your tests, Facebooker will try to read a canned response fixture from features/support/facebook/. It will give you a friendly error whenever this happens, so just follow the directions and you should be on your way.

Feedback & Patches

I’m sure there are things that don’t work right, so let me know if you run into any troubles. If you have any ideas for making the Cucumber support better, please share them here or on the Facebooker mailing list.

Code: cucumber Mar 05, 2009 ● updated Mar 05, 2009 13 comments

Behavior Driven Development with Cucumber

The Great Lakes Ruby Bash was a good time. There were several quality presentations, including Jim Weirich’s talk “Playing it Safe – How to write library friendly code in Ruby”, Larry Karnowski’s talk “Usability on Rails”, and Brandon Dimcheff’s “Metawhat? A look into the mysterious metaclass”.

I presented a talk titled “Behavior Driven Development with Cucumber”. Despite the fact that half of the audience didn’t know what the hell I was talking about, I think it went well. I uploaded the slides from my talk to slideshare if you’re interested. I’m not sure that they’ll really be very helpful, but I may try to record audio to go with them at some point.

As far as I know, no audio or video was captured at the conference.

Code: cucumber Oct 14, 2008 ● updated Oct 14, 2008 0 comments

Subscribe

Browse by Tag