Headless Selenium Screenshots with Cucumber 3

Posted by jcnnghm Wed, 30 Dec 2009 11:24:00 GMT

 I was finally able to get Selenium integrated with Webrat and Cucumber on my Linux development server.  I followed this excellent guide to setting up the selenium server to run headless.  This enables me to run my tests without actually seeing the Firefox window.  This does, unfortunately, make debugging a bit more difficult.

Because of that, I created a Cucumber step to save a screenshot of the webpage in the tmp/screenshots folder.  This includes the entire page, not just the viewable portion.  Not only does this simplify debugging, but it also makes it trivially difficult to capture a large number of screenshots from the testing framework to compile visual reports.  I believe that making sure everything looks right is as much a part of testing as making sure it actually works.

 

Then /^I save a screenshot with filename "([^\"]*)"$/ do |filename|
  selenium.capture_entire_page_screenshot(File.expand_path("tmp/screenshots/#{filename}.png"), "")
end

Set Restriction Info with Facebooker 1

Posted by jcnnghm Tue, 22 Sep 2009 11:03:00 GMT

I’ve been working on a Facebook App and I was trying find out exactly how to go about setting content restrictions with Facebooker. While the documentation for the Admin.setRestricitionInfo API call is pretty clear, the Facebooker documentation is less clear.  It looked to me at first glance that the Facebooker::Admin.set_restriction_info method would have to be called with every request.  This seemed terribly innefecient to me, so I tried some other methods out until I found something that worked. In config/initializers, I created a facebook_permissions.rb file, and inserted the following code:

Facebooker::Admin.new(Facebooker::Session.create).set_restriction_info(‘type’ => ‘alcohol’)

This code will run every time your server starts, updating your application restriction settings.  Run the following command from script/console to double-check that the restrictions are being set correctly:

Facebooker::Admin.new(Facebooker::Session.create).get_restriction_info(‘type’)

Select Random Rows Using Ruby On Rails

Posted by jcnnghm Fri, 07 Aug 2009 00:59:00 GMT

Today I was looking for a way to randomly select rows from a database using Rails. I implemented the following message, which will randomly select a specified number of random rows, or as many rows as are available if the requested number is greater than the available number.

def find_random(random_count, options = {})
  if random_count > count(options)
    find_every(options).sort_by{rand}
  else
    find_every(options.merge({:offset => rand(count(options) - random_count + 1), :limit => random_count})).sort_by{rand}
  end
end

The code first attempts to determine if there are enough records to randomize. After that, it randomly selects an offset and returns the specified number of rows at that offset, after randomly sorting them. The benefit that this has over the other methods, is that it should scale well with very large data sets. The downside is, of course, that the are sequential from the given offset. In my situation, this works fine. Depending on what the data is used for, this may not work well for you. If that is the case, the approach I would take is to randomly generate a number of offsets, and select individual records at each offset. This should perform reasonably quickly as long as only a random items are selected.

Rails Forum Plugins 2

Posted by jcnnghm Thu, 06 Aug 2009 00:09:00 GMT

 I’ve been looking into adding some forum functionality into my Baltimore and Annapolis bars website.  While I was researching different forum implementations to find out what kind of forum I’d like to have on the site, I came across a couple of rails plugins that will take care of all the heavy lifting.

First is Savage Beast, the second version of a plugin designed specifically to add forums to Rails sites.  While Savage Beast is functional, it doesn’t appear to be actively updated.  It was forked a few months ago to bring it in compliance with Rails 2.3.  Unfortunately, as of this writing, that hasn’t been completed yet.  Savage beast is definitely worth watching, but at this time I think it would take too much work to get it production ready.

On the other hand, we have Community Engine,  Community Engine uses the Engines plugin, now integrated into rails, to add all kinds of social networking features into your rails project.  In addition to forums, the plugin brings user profiles, blogs, photos, and a messaging system.  The plugin has a ton of github activity, forks, and followers, and is definitely under active development.  Even better, the plugin is already Rails 2.3 compliant.  The only apparent problem with Community Engine is how many features it really has.  I have a feeling it could be quite difficult to integrate the software into an already-developed website.

I intend to begin integrating it over the next few days, and I’ll keep this up to date with how it’s going.

Slow Runt 3

Posted by jcnnghm Tue, 03 Jun 2008 12:52:00 GMT

While unit testing some code that I’ve been working on that uses the excellent runt library, I ran into a bit of code that was quite slow. When calling the include? method of the Runt::DIMonth class with a negative value for the week of the month argument (i.e. DIMonth.new(-1,6).include?(date)) it took over 120 seconds to execute my unit tests.

I replaced the method max_day_of_month (Runt::TExprUtils), as listed below:

def max_day_of_month(date)
  result = 1
  next_month = nil
  if(date.mon==12)
    next_month = Date.new(date.year+1,1,1)
  else
    next_month = Date.new(date.year,date.mon+1,1)
  end
  date.step(next_month,1){ |d| result=d.day unless d.day < result }
  result
end

with the following code:

def max_day_of_month(date)
  month = date.month
  year = date.year
  if month == 2
    !year.nil? && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) ?  29 : 28
  elsif month <= 7
    month % 2 == 0 ? 30 : 31
  else
     month % 2 == 0 ? 31 : 30
  end
end

The same unit tests can now be performed in under two seconds. I didn’t write the algorithm, it’s taken verbatim from the Rails ActiveSupport::CoreExtensions::Time::Calculations::ClassMethods module daysinmonth method. That method appears to be the cause of the issue.

Testing Authorize.net with ActiveMerchant 6

Posted by jcnnghm Sun, 27 Apr 2008 18:55:00 GMT

I had some trouble testing Authorize.net with the excellent rails credit card processing gem ActiveMerchant. The documentation calls for the code ActiveMerchant::Billing::Base.mode = :test, however, this resulted in the following error: The merchant login ID or password is invalid or the account is inactive.

To solve the problem, a key test with the String value true can be added to the gateway initialization hash, as follows:

if ENV['RAILS_ENV'] != 'production'
  gateway = ActiveMerchant::Billing::Base.gateway(:authorize_net).new(
    :login => "login",
    :password => "transkey", :test => 'true')
else
  gateway = ActiveMerchant::Billing::Base.gateway(:authorize_net).new(
    :login => "login",
    :password => "transkey")
end

Using this code, the account is placed into test mode when not run in production mode.

Multi Bit Shift Launch

Posted by jcnnghm Mon, 25 Feb 2008 12:54:00 GMT

I was finally able to launch my new product, Multi Bit Shift, a Flex multiple file upload applet complete with a Rails plugin to ease the integration. I learned a lot from this project, since this is the first that I have made use of project management software, in particular FogBugz, which I would highly recommend.

In particular, I learned that I grossly underestimated the amount of time required to produce proper documentation, the MBS website, and the product screencasts. Proper documentation is really what separates real, professional products from amateur contributions, so it is absolutely vital to dedicate whatever time is necessary to make sure everything is both well and thoroughly documented.

The website, and to a lesser extent the screencasts were also quite time consuming. I had my company, Compucated Solutions produce the design and integrate it with software that I wrote to manage the site. I am very pleased with the design and presentation at this point, but I must admit that I did spend considerable time writing and formatting content, as well as coding up the necessary software bits. I look at this kind of as an investment though, because when I go to release software in the future I have a very flexible engine that I can now quickly roll products out on.

The screencasts were also quite time consuming. I ultimately settled on the TechSmith’s Camtasia Studio product, as recommended by Jeff Atwood to produce the video. I am quite pleased by the results although I would like to be able to set the background color of the video files, and perhaps tweak the appearance a bit. While the software was a little pricey at $299 considering there are lots of competitors and viable alternatives, I ultimately settled on this particular product because it does what it does so very well. If you need to produce screencasts, seriously consider Camtasia, it is worth the premium. If you don’t need to produce screencasts, I suggest that you reconsider because they are a really excellent way to quickly convey complex information.

Besides just creating the screencasts, I also decided to make use of Amazon’s Simple Storage Service to host them. While I probably have ample bandwidth to host the screencasts on my equipment, I ultimately came to the conclusion that the users would have a better user experience if they were hosted by someone else. I have to say that, at this point, I am extremely impressed by the Amazon S3 service. It’s fast, reliable, flexible, easy to use, and inexpensive. I’m currently using the Firefox S3Fox plugin to manage the storage space. It really doesn’t get much easier.

All said and done, I believe I spent just as much, or even more time, documenting and launching this software than I actually did on the design and coding. In the future, I believe I’ll have to give much more thought in the product planning stages to the actual launch requirements (like a website, screencasts, docs, etc…) and the time required for their production.

Rails Boolean Field Helper

Posted by jcnnghm Thu, 07 Feb 2008 22:10:00 GMT

I wrote this some time ago and I thought it was worth reposting here, primarily so it would be easier for me to find. This details the handling of binary fields from front to back in Ruby on Rails.

Creation:

Active Record migrations are quite good at creating tables. The below migration will add table “table” to the db with a boolean field a_boolean when rake db:migrate is run.

class CreateTable < ActiveRecord::Migration
  def self.up
    create_table :table do |t|
      t.column :a_boolean, :boolean
    end
  end

  def self.down
      drop_table :table
  end
end

Boolean Form Field Select Helper:

The following line creates a select box with true and false represented by Yes and No. The currently selected value (while editing) is automatically selected.

<%= select('table', 'a_boolean', [["Yes",true],["No",false]]) %>

Validation:

This validation will confirm that the field is either true or false.

validates_each :a_boolean do |record, attr, value|
  record.errors.add attr, 'is invalid.' if value != true && value != false
end

state_select and Rails 2.0.2 1

Posted by jcnnghm Tue, 05 Feb 2008 09:23:00 GMT

Because of a change in the workings of Rails 2.0.2, the excellent state_select plugin doesn’t work properly. Fortunately, the fix is really easy. After line 35, enter the following code, value = value(object).

This should give you a new to_state_select_tag, like this:

def to_state_select_tag(country, options, html_options)
  html_options = html_options.stringify_keys
  add_default_name_and_id(html_options)
  value = value(object)
  selected_value = options.has_key?(:selected) ? options[:selected] : value
  content_tag("select", add_options(state_options_for_select(selected_value, country), options, value), html_options)
end

That change got the state_select plugin to work for me under Rails 2.

Update: This has been fixed in the latest version. If you are experiencing this issue, update to the latest version.